VRU Awareness Service
The VRU Awareness Service protects Vulnerable Road Users — pedestrians, cyclists, and other unprotected road users — by broadcasting their presence to nearby vehicles using VRU Awareness Messages (VAMs).
Note
The VRU Awareness Service implements ETSI TS 103 300-3 V2.2.1. VAMs are similar to CAMs but specifically designed for VRUs who need extra protection on the road.
What Are VRUs?
Vulnerable Road Users include anyone not protected by a vehicle body:
Type |
Station Type |
Examples |
|---|---|---|
🚶 Pedestrian |
1 |
Walkers, joggers, people with mobility aids |
🚴 Cyclist |
2 |
Bicycles, e-bikes, cargo bikes |
🛵 Moped |
3 |
Scooters, mopeds (< 50cc) |
🏍️ Motorcycle |
4 |
Motorcycles, motorbikes |
🛴 Other |
Various |
E-scooters, skateboards, wheelchairs |
VAM vs CAM
Aspect |
CAM |
VAM |
|---|---|---|
For |
Vehicles |
Vulnerable Road Users |
Purpose |
Vehicle awareness |
VRU protection |
BTP Port |
2001 |
2004 |
Clustering |
No |
Yes (groups of VRUs) |
Device |
Vehicle OBU |
Smartphone, wearable, bike computer |
Architecture
The VRU Awareness Service consists of several components:
flowchart TB
subgraph APP["Application Layer"]
EX["Application"]
end
subgraph "Facilities Layer"
LDM[(Local Dynamic Map)]
subgraph VRUAW["VRU Awareness Service"]
direction LR
RM[Reception<br/>Management] ~~~ TM[Transmission<br/>Management]
TM ~~~ CM[Cluster Management<br/>⚠️ Not Implemented]
end
end
subgraph "Location"
LOC[Location Service]
end
subgraph "Transport"
BTP[BTP Router<br/>Port 2018]
end
APP --- LDM
LDM ---|"Store Received"| VRUAW
LOC -->|"Position Updates"| VRUAW
VRUAW <-->|"Facilities-BTP SAP"| BTP
style VRUAW fill:#fff3e0,stroke:#f57c00
style LDM fill:#e8f5e9
style CM fill:#ffebee,stroke:#c62828,stroke-dasharray: 5 5
Components:
Component |
Description |
|---|---|
VRU Basic Service |
Main service coordinating all VAM operations |
VAM Transmission Management |
Handles when and how VAMs are sent |
VAM Reception Management |
Processes incoming VAMs (automatic) |
Cluster Management |
Groups nearby VRUs (⚠️ not yet implemented) |
VAM Coder |
Encodes/decodes ASN.1 format |
Device Data Provider |
Provides VRU device information |
Getting Started
Step 1: Configure Device Data Provider
Unlike vehicles (which use VehicleData), VRUs use a DeviceDataProvider:
from flexstack.facilities.vru_awareness_service.vam_transmission_management import (
DeviceDataProvider,
)
# Configure VRU device
device_data = DeviceDataProvider(
station_id=12345, # Unique identifier
station_type=2, # 2 = Cyclist
)
Station Types for VRUs:
Value |
Type |
Description |
|---|---|---|
1 |
Pedestrian |
Person on foot |
2 |
Cyclist |
Bicycle rider |
3 |
Moped |
Light motorized two-wheeler |
4 |
Motorcycle |
Motorcycle rider |
Step 2: Set Up Prerequisites
The VRU Awareness Service requires:
BTP Router — for transport (port 2004)
Location Service — for position updates
from flexstack.btp.router import Router as BTPRouter
from flexstack.geonet.router import Router as GNRouter
from flexstack.geonet.mib import MIB
from flexstack.geonet.gn_address import GNAddress, M, ST, MID
from flexstack.utils.static_location_service import ThreadStaticLocationService as LocationService
from flexstack.linklayer.raw_link_layer import RawLinkLayer
MAC_ADDRESS = b'\x00\x11\x22\x33\x44\x55'
# Location Service
location_service = LocationService()
# GeoNetworking + BTP
mib = MIB(
itsGnLocalGnAddr=GNAddress(
m=M.GN_MULTICAST,
st=ST.CYCLIST, # VRU type
mid=MID(MAC_ADDRESS),
),
)
gn_router = GNRouter(mib=mib, sign_service=None)
ll = RawLinkLayer(iface="lo", mac_address=MAC_ADDRESS, receive_callback=gn_router.gn_data_indicate)
gn_router.link_layer = ll
btp_router = BTPRouter(gn_router)
gn_router.register_indication_callback(btp_router.btp_data_indication)
location_service.add_callback(gn_router.refresh_ego_position_vector)
Step 3: Create VRU Awareness Service
from flexstack.facilities.vru_awareness_service.vru_awareness_service import (
VRUAwarenessService,
)
# Create the VRU Awareness Service
vru_service = VRUAwarenessService(
btp_router=btp_router,
device_data_provider=device_data,
)
# Connect location updates to trigger VAM transmission
location_service.add_callback(
vru_service.vam_transmission_management.location_service_callback
)
That’s it! The service will now:
✅ Automatically send VAMs when location updates arrive
✅ Automatically receive VAMs from other VRUs
VAM Generation Rules
VAMs are generated when any of these conditions are met:
Trigger |
Condition |
|---|---|
⏱️ Time elapsed |
Time since last VAM exceeds |
📍 Position change |
Distance moved exceeds |
🏃 Speed change |
Speed difference exceeds |
🧭 Direction change |
Heading change exceeds |
This ensures VAMs are sent when relevant changes occur, not just periodically.
VAM Message Structure
A VAM contains information specific to VRUs:
flowchart LR
subgraph CAM["Vulnerable Road User (VRU) Awareness Message (VAM)"]
direction LR
header["ITS PDU Header"]
basic["Basic Container"]
HF["High Frequency Container"]
LF["Low Frequency Container (optional)"]
CL["Cluster Information Container (optional)"]
CLOP["Cluster Operation Container (optional)"]
MOT["Motion Prediction Container (optional)"]
header ~~~ basic
basic ~~~ HF
HF ~~~ LF
LF ~~~ CL
CL ~~~ CLOP
CLOP ~~~ MOT
end
Container |
Contents |
|---|---|
Basic |
VRU type, reference position |
High Frequency |
Speed, heading, acceleration (sent often) |
Low Frequency |
Profile info, path history (sent less often) |
Cluster |
Info about grouped VRUs (when clustering is active) |
VRU Clustering
Warning
VRU Clustering is not yet implemented in FlexStack.
Clustering allows multiple VRUs traveling together (e.g., a group of cyclists) to be represented by a single VAM, reducing network load while maintaining awareness.
flowchart LR
subgraph "Without Clustering"
V1[VAM 1]
V2[VAM 2]
V3[VAM 3]
V4[VAM 4]
end
subgraph "With Clustering"
VC[Cluster VAM<br/>4 VRUs]
end
V1 & V2 & V3 & V4 -.->|"Future"| VC
Complete Example
Here’s a complete script for a cyclist broadcasting VAMs:
1#!/usr/bin/env python3
2"""
3VRU Awareness Service Example
4
5Broadcasts VAMs for a cyclist to alert nearby vehicles.
6Run with: sudo python vru_example.py
7"""
8
9import logging
10import random
11import time
12
13from flexstack.linklayer.raw_link_layer import RawLinkLayer
14from flexstack.geonet.router import Router as GNRouter
15from flexstack.geonet.mib import MIB
16from flexstack.geonet.gn_address import GNAddress, M, ST, MID
17from flexstack.btp.router import Router as BTPRouter
18from flexstack.utils.static_location_service import ThreadStaticLocationService
19from flexstack.facilities.vru_awareness_service.vru_awareness_service import (
20 VRUAwarenessService,
21)
22from flexstack.facilities.vru_awareness_service.vam_transmission_management import (
23 DeviceDataProvider,
24)
25
26logging.basicConfig(level=logging.INFO)
27
28# Configuration
29POSITION = [41.386931, 2.112104] # Barcelona
30MAC_ADDRESS = bytes([(random.randint(0, 255) & 0xFE) | 0x02] +
31 [random.randint(0, 255) for _ in range(5)])
32STATION_ID = random.randint(1, 2147483647)
33
34
35def main():
36 # Location Service
37 location_service = ThreadStaticLocationService(
38 period=1000,
39 latitude=POSITION[0],
40 longitude=POSITION[1],
41 )
42
43 # GeoNetworking
44 mib = MIB(
45 itsGnLocalGnAddr=GNAddress(
46 m=M.GN_MULTICAST,
47 st=ST.CYCLIST, # This is a cyclist
48 mid=MID(MAC_ADDRESS),
49 ),
50 )
51 gn_router = GNRouter(mib=mib, sign_service=None)
52 location_service.add_callback(gn_router.refresh_ego_position_vector)
53
54 # BTP
55 btp_router = BTPRouter(gn_router)
56 gn_router.register_indication_callback(btp_router.btp_data_indication)
57
58 # VRU Awareness Service
59 device_data = DeviceDataProvider(
60 station_id=STATION_ID,
61 station_type=2, # Cyclist
62 )
63 vru_service = VRUAwarenessService(
64 btp_router=btp_router,
65 device_data_provider=device_data,
66 )
67 location_service.add_callback(
68 vru_service.vam_transmission_management.location_service_callback
69 )
70
71 # Link Layer
72 btp_router.freeze_callbacks()
73 link_layer = RawLinkLayer(
74 "lo",
75 MAC_ADDRESS,
76 receive_callback=gn_router.gn_data_indicate,
77 )
78 gn_router.link_layer = link_layer
79
80 print("✅ VRU Awareness Service running!")
81 print("🚴 Broadcasting VAMs as a cyclist...")
82 print("Press Ctrl+C to exit\n")
83
84 try:
85 while True:
86 time.sleep(1)
87 except KeyboardInterrupt:
88 print("\n👋 Shutting down...")
89
90 location_service.stop_event.set()
91 location_service.location_service_thread.join()
92 link_layer.sock.close()
93
94
95if __name__ == "__main__":
96 main()
Use Cases
Cyclists broadcast their position to nearby vehicles, reducing collision risk at intersections and blind spots.
Pedestrians with smartphones can alert approaching vehicles when crossing streets.
Electric scooter riders share their presence with traffic, especially important in urban environments.
Motorcyclists increase their visibility to cars and trucks that might not see them.
See Also
Getting Started — Complete V2X tutorial
Cooperative Awareness (CA) Basic Service — Vehicle Cooperative Awareness Messages
Decentralized Environmental Notification (DEN) Service — Hazard warnings with DENMs
Local Dynamic Map — Store and query received VAMs
Basic Transport Protocol (BTP) — Transport layer (BTP port 2004)