📄 V2X Intersection

V2X Intersection

The V2X MAP and SPAT application brings your intersection into the era of connected and automated vehicles — enabling full support for MAP (Geometric Intersection Description/Map Data) and SPaT (Signal Phase and Timing) messages.

This powerful app works seamlessly with just about any traffic controller, transforming your existing infrastructure into a V2X-ready hub without requiring costly replacements.

It generates and broadcasts standardized MAP and SPaT data via your RSU (Roadside Unit), providing approaching connected vehicles with precise, real-time information about intersection geometry, lane configurations, and current/future signal states.

Concepts

MAP Message

This is like sending a detailed digital blueprint of the intersection to your car.

It tells the car exactly:

  • Where each lane starts and ends
  • Which lanes go straight, turn left, turn right, etc.
  • How lanes connect
  • Stop lines, crosswalks, and other road rules

Without the MAP, the car wouldn't know which light controls which lane — it's the static "map" that gives context.

SPAT Message

This is the real-time status update from the traffic light.

It tells your car:

  • Which lights are currently red, yellow, or green
  • How many seconds are left until the light changes (e.g., "Green for 12 more seconds")
  • Sometimes even predicted future changes

It updates super frequently (often every 1/10th of a second) so your car always knows the latest timing.

RSU (Road Side Unit)

This is just a smart radio box (usually mounted on traffic light poles, signs, or other roadside spots). It connects to the connected-car network and broadcasts important messages directly to nearby vehicles.

Your app sends the MAP and SPaT messages to the RSU, which then blasts them out frequently so cars approaching the intersection always get the latest info in time.

  • SPaT (the live traffic light status and countdown) uses a "send once and forget" style — the RSU gets the update, transmits it right away (often 10 times per second or every 100ms in real deployments), then discards it. When the light changes or a new timing update comes, the app sends a fresh one — keeping everything super current without wasting airtime.
  • MAP (the fixed intersection blueprint showing lanes, turns, etc.) uses a "store and repeat" style — the RSU holds onto it since the intersection layout rarely changes. It still broadcasts it repeatedly (typically every 1–5 seconds or so) so any new car rolling up hears the geometry immediately and can make sense of the SPaT data.

It works with most modern RSUs that follow the common standard (NTCIP-1218), which lets cities manage these smart radios easily.

PSID (Provider Service Identifier)

This is like the channel name or topic tag for the message.

Cars pick up tons of wireless signals all the time (emergency braking warnings, road hazard alerts, ice on the road, etc.). The PSID tells the car exactly what kind of info it's getting: "This is intersection map & traffic light timing data!"

For MAP and SPaT messages (intersection safety stuff), they typically use a dedicated PSID (often the one assigned for intersection applications in the U.S. standards). You just select the right PSID in the app, and your MAP/SPaT messages go out on the correct "channel" so cars know to process them for smart features like red-light warnings, speed advice to catch green lights, or smoother self-driving decisions.

User Interface

Status Page

This page provides information about what is being broadcast to the RSU

  1. Information on what the SPAT message is broadcasting
  2. Status of the RSU
  3. Lane movement status. This will list which movements are available and what state they're in
  4. MAP geometry

    1. Blue - crosswalk
    2. Green - bike lane
    3. Pink - vehicle lane
    4. Orange - railroad
  5. Lane number
  6. Information on MAP message broadcasting
  7. Settings

Settings

  1. Enable/disable the application
  2. Traffic Signal interface that you want to broadcast
  3. RSU to send MAP and SPAT messages to
  4. Intersection ID - set to any number that is unique systemwide
  5. SPAT broadcast settings
  6. MAP broadcast settings
💡

Lane geometry is configured from the Traffic Signal interface

REST API

PUT /api/app/v2x-intersection

Update app settings
💡
This endpoint will only update settings you include in the request. So only include settings you intend to modify.
PUT /api/app/v2x-intersection HTTP/1.1
Host: 127.0.0.1
Accept: application/json
Content-Type: application/json
Authorization: bearer 109b893ceb1c26e3e64e9abf7cdd2aa1c0d25f61

{"settings":{"enabled":true,"intersection":{"id":10012},"interface":{"traffic-signal":16,"v2x":21},"spat":{"transmission":500,"channel":172,"priority":1,"psid":"0p8002"},"map":{"refresh":60,"channel":172,"priority":1,"transmission":500,"psid":"0pe0000017"}}}

HTTP/1.1 200 OK
Content-Type: application/json
settings.enabled
boolean
Enable/disable the application
settings.interface.v2x
number
Interface ID of the RSU
settings.interface.traffic-signal
number
Interface ID of the traffic signal
settings.intersection.id
number
Intersection ID transmitted in the MAP message
settings.map.transmission
number
Rate, in milliseconds, to transmit the MAP message. This is the interval value sent to the RSU for the SRM (store and repeat message).
settings.map.refresh
number
How frequent, in seconds, the MAP message is re-uploaded to the RSU for SRM broadcasting
settings.map.channel
number
V2X channel to broadcast the MAP message on
settings.map.priority
number
V2X priority to assign to the MAP message. See IEEE 1609.3 for the values
settings.map.psid
string
V2X PSID to assign to the MAP message
settings.spat.channel
number
V2X channel to broadcast the SPAT message on
settings.spat.priority
number
V2X priority to assign to the SPAT message. See IEEE 1609.3 for the values
settings.spat.psid
string
V2X PSID to assign to the SPAT message
settings.spat.transmission
number
Minimum rate that the SPAT message will be broadcast at. A new SPAT message is sent in real-time when the state of the traffic signal changes, but if a SPAT has not been generated within this minimum time, then it will automatically send out a SPAT message of the current state of the signal

GET /api/app/v2x-intersection

Get app settings
GET /api/app/v2x-intersection HTTP/1.1
Host: 127.0.0.1
Accept: application/json
Authorization: bearer 109b893ceb1c26e3e64e9abf7cdd2aa1c0d25f61

HTTP/1.1 200 OK
Content-Type: application/json

{"app":{"name":"v2x-intersection","settings":{"_version_":[2,71],"enabled":true,"interface":{"traffic-signal":16,"v2x":21},"intersection":{"id":10012},"map":{"channel":172,"intersection":{"layer-id":0},"priority":1,"psid":"0pe0000017","refresh":60,"transmission":500},"spat":{"channel":172,"priority":1,"psid":"0p8002","transmission":500}},"defaults":{"enabled":false,"interface":{"traffic-signal":0,"v2x":0},"intersection":{"id":0},"map":{"channel":178,"intersection":{"lanes":null,"layer-id":0},"psid":"0p8003","refresh":60,"transmission":500},"spat":{"channel":178,"priority":1,"psid":"0p8002","transmission":500}},"manifest":{"description":"Enables V2X capabilities for a traffic intersection","name":"V2X Intersection","version":"1.0.0"}}}

GET /api/app/v2x-intersection/status

Get status information from the app. The status contains V2X message information being transmitted, details of the most recently transmitted SPAT and MAP messages, and interface information
GET /api/app/v2x-intersection/status HTTP/1.1
Host: 127.0.0.1
Accept: application/json
Authorization: bearer 109b893ceb1c26e3e64e9abf7cdd2aa1c0d25f61

HTTP/1.1 200 OK
Content-Type: application/json

{"status":{"map":{"lanes":[{"approach":4,"connections":null,"departure":0,"geometry":[[47.617393845895876,-122.2011320898677],[47.617396557923634,-122.20148077703963],[47.61742819823725,-122.20148211814414],[47.61742639021985,-122.20113745428573]],"id":1,"type":"vehicle"},{"approach":4,"connections":null,"departure":0,"geometry":[[47.617432718280504,-122.20147943593513],[47.61745351047436,-122.20148077703963],[47.61745079844953,-122.20118171073447],[47.617429102245936,-122.20118305183898]],"id":2,"type":"vehicle"},{"approach":4,"connections":[{"maneuver":"straight","state":"stop-and-remain","to":4}],"departure":0,"geometry":[[47.61745351047436,-122.20148211814414],[47.61748334273806,-122.20148345924865],[47.61747701468354,-122.20117366410743],[47.61744989444124,-122.20117366410743]],"id":3,"type":"vehicle"},{"approach":0,"connections":null,"departure":14,"geometry":[[47.61745170245783,-122.20197564460288],[47.61748063071478,-122.20197430349837],[47.617481534722565,-122.20223715998183],[47.61745441448261,-122.20223715998183]],"id":4,"type":"vehicle"},{"approach":4,"connections":null,"departure":0,"geometry":[[47.617327316420536,-122.2015464911605],[47.61754970251363,-122.20153039790641],[47.6175623586043,-122.20155185557853],[47.61754879850702,-122.2015813598777],[47.61732370037871,-122.20158806540023],[47.617311948240975,-122.20156928993713]],"id":5,"type":"crosswalk"}],"message":{"revision":0,"timestamp":1750886883}},"spat":{"message":{"revision":110,"timestamp":1750886939},"signal-groups":[{"id":6,"state":"stop-and-remain"},{"id":4,"state":"stop-and-remain"},{"id":16,"state":"stop-and-remain"},{"id":1,"state":"stop-and-remain"},{"id":14,"state":"stop-and-remain"},{"id":8,"state":"stop-and-remain"},{"id":22,"state":"stop-and-remain"},{"id":12,"state":"permissive-movement-allowed"},{"id":3,"state":"stop-and-remain"},{"id":24,"state":"stop-and-remain"},{"id":2,"state":"protected-movement-allowed"},{"id":7,"state":"stop-and-remain"},{"id":18,"state":"stop-and-remain"},{"id":26,"state":"stop-and-remain"},{"id":5,"state":"protected-clearance"},{"id":28,"state":"stop-and-remain"}]},"traffic-signal":{"state":{"name":"operational","timestamp":1750886703}},"v2x":{"state":{"name":"inoperative","timestamp":1750886703}}}}
status.v2x.state.name
string
Current state of the RSU

Values: unknown, inoperative, operational, fault
status.v2x.state.timestamp
number
Unix epoch timestamp, in seconds, of when it went into this state
status.traffic-signal.state.name
string
Current state of the traffic signal

Values: unknown, inoperative, operational, fault
status.traffic-signal.state.timestamp
number
Unix epoch timestamp, in seconds, of when it went into this state
status.spat.message.revision
number
Last SPAT message revision number that was broadcast
status.spat.message.timestamp
number
Unix epoch timestamp, in seconds, of when the last SPAT message was broadcast
status.spat.signal-groups[].id
number
Signal group ID. Mapped to specific movements
status.spat.signal-groups[].state
string
State of this signal group. See V2X SPAT specification for possible values
status.map.message.revision
number
Last MAP message revision number that was sent to the RSU
status.map.message.timestamp
number
Unix epoch timestamp, in seconds, of when the last MAP message was sent to the RSU
status.map.lanes[]
array
The list of lanes being broadcast in the MAP message
status.map.lanes[].approach
number
Approach ID. A value of 0 indicates that this is not an approach
status.map.lanes[].departure
number
Departure ID. A value of 0 indicates that this is not a departure
status.map.lanes[].id
number
Lane ID
status.map.lanes[].type
number
Type of lane

Values: vehicle, crosswalk, bike, tracked-vehicle
status.map.lanes[].geometry[]
array[latitude,longitude]
Points that make up the geometry of the lane. Connecting the points will draw the polygon outlining the lane on a GIS map
status.map.lanes[].connections[]
array
A list of connections (or movements) permitted from this lane. Connections are links between 2 lanes, a movement, and the state of that movement from SPAT
status.map.lanes[].connections[].id
number
ID of the lane ID this lane connects with
status.map.lanes[].connections[].state
string
The current state of the signal group governing this movement
status.map.lanes[].connections[].maneuver
string
The maneuver travelers execute when traveling between these 2 lanes