A protocol is only as good as its field definitions. VDA 5050 looks simple from a distance — five topics, JSON over MQTT — but the correctness lives in the details: which fields are required, what the enums mean, and how the topic hierarchy encodes identity.
The difference between a correct VDA 5050 implementation and one that only looks correct is the exact field set. This post walks through it.
The topic hierarchy
Every message lives at a topic built from five levels:
interfaceName / majorVersion / manufacturer / serialNumber / topic
uagv / v2 / acme / AGV-001 / order
| Level | Meaning | Example |
|---|---|---|
interfaceName |
The logical interface | uagv |
majorVersion |
Protocol major version | v2 |
manufacturer |
Vendor string (no / or $) |
acme |
serialNumber |
Unique per vehicle | AGV-001 |
topic |
The message type | order |
The version level is a subtle trap. The standard's topic uses the major version (v2), while the message body carries the full version ("2.1.0"). Mixing these up — putting 2.1.0 in the topic — is a common integration bug.
QoS and retain, per topic
Not all topics are equal. The standard prescribes different delivery guarantees for each:
| Topic | Publisher | QoS | Retained | Notes |
|---|---|---|---|---|
order |
master | 0 | no | Fire-and-forget; a new order supersedes |
instantActions |
master | 0 | no | Immediate commands |
state |
vehicle | 0 | no | Event-driven, at least every 30 s |
connection |
vehicle / broker | 1 | yes | Retained so late subscribers see current status |
factsheet |
vehicle | 0 | yes | Retained capability declaration |
The retained connection topic is what lets a fleet manager that restarts mid-shift immediately learn which vehicles are online — it reads the last retained value instead of waiting for the next heartbeat.
The common message header
Every message on every topic carries the same five header fields:
| Field | Type | Meaning |
|---|---|---|
headerId |
uint32 | Per-topic counter, +1 per message |
timestamp |
ISO 8601 UTC | Send time |
version |
string | Full protocol version, "2.1.0" |
manufacturer |
string | Matches the topic level |
serialNumber |
string | Matches the topic level |
The headerId is a per-topic monotonic counter. It's how a subscriber detects a dropped or reordered message — a gap in the sequence means something was lost.
The five schemas
order — master → vehicle
The transport order. Its core is a list of nodes (waypoints) and edges (connections), each with a sequenceId and a released flag. The released flag is the single most important field in the whole standard — it marks the base (drive this now) versus the horizon (plan only, don't drive yet).
state — vehicle → master
The vehicle's self-report: orderId, lastNodeId, nodeStates, edgeStates, driving, agvPosition, batteryState, operatingMode, errors[], actionStates, safetyState. The master never infers vehicle state from timers — it reads it from state.
instantActions — master → vehicle
Immediate commands that bypass the order queue: startPause, stopPause, cancelOrder, startCharging, stopCharging, initPosition, stateRequest, factsheetRequest. Each carries a blockingType (NONE / SOFT / HARD).
connection — vehicle → master
A single enum: ONLINE, OFFLINE, or CONNECTIONBROKEN. The last-will pattern publishes CONNECTIONBROKEN automatically when a vehicle drops unexpectedly.
factsheet — vehicle → master
The static capability declaration: kinematics, speed limits, dimensions, supported actions, protocol limits. This is what makes a fleet genuinely vendor-agnostic.
The field-level discipline
The standard is explicit about what's required and what's optional, and a disciplined implementation respects that boundary. Fields that exist in the schema but aren't needed — like NURBS trajectories, which let the master prescribe exact path geometry to vehicles that need it — are simply omitted, not invented. The extension policy is: use the standard's own extension points, never add top-level fields.
Next: Order Lifecycle & State Machine — how a vehicle actually executes an order, and why the base/horizon split is the key to safe incremental movement.