Chapter 18.1: TraCI Protocol
18.1.1 TraCI: Traffic Control Interface
TraCI (Traffic Control Interface) is the protocol through which external programs interact with a running SUMO simulation. Unlike file-based coupling (read outputs, modify inputs, restart), TraCI provides real-time bidirectional communication: you can query vehicle states and modify simulation parameters within the same timestep.
TraCI uses a custom TCP binary protocol. The server (SUMO) listens on a specified port, and clients connect to send commands and receive responses. This architecture enables:
- Per-step queries: vehicle speed, position, emissions, waiting time
- Per-step control: reroute vehicles, change traffic light phases, modify speed limits
- Multi-client support: multiple controllers connected simultaneously
- Language independence: any language that can open a TCP socket can speak TraCI
18.1.2 TCP Binary Protocol Structure
Every TraCI message follows a strict binary format. Understanding this format is essential for implementing clients in languages without official TraCI libraries (e.g., Java, Rust, C++).
Message Envelope
┌─────────────────────────────────────────────────────────┐ │ TraCI Message Format │ ├──────────────┬──────────────────────────────────────────┤ │ Bytes 0-3 │ Total message length (4 bytes, big-endian) │ ├──────────────┼──────────────────────────────────────────┤ │ Byte 4 │ Command length (1 byte, or 0 → 4-byte) │ ├──────────────┼──────────────────────────────────────────┤ │ Byte 5 │ Command ID (1 byte) │ ├──────────────┼──────────────────────────────────────────┤ │ Bytes 6+ │ Command content (variable) │ └──────────────┴──────────────────────────────────────────┘ If command length byte = 0, next 4 bytes give extended length. Multiple commands can be packed into one message.
Key Command IDs
| Command | ID (hex) | Direction | Purpose |
|---|---|---|---|
| CMD_SIMSTEP | 0x02 | Client → Server | Advance simulation by one step |
| GET_VEHICLE_VARIABLE | 0xa4 | Client → Server | Query vehicle state |
| RESPONSE_GET_VEHICLE | 0xb4 | Server → Client | Vehicle state response |
| SET_VEHICLE_VARIABLE | 0xc4 | Client → Server | Modify vehicle state |
| GET_TL_VARIABLE | 0xa2 | Client → Server | Query traffic light state |
| SET_TL_VARIABLE | 0xc2 | Client → Server | Change traffic light phase |
| CMD_CLOSE | 0x7f | Client → Server | Close connection gracefully |
18.1.3 Variable IDs and Data Types
When querying a vehicle, the variable ID specifies which property to retrieve. The response includes a type byte indicating the data format:
Vehicle Variable IDs
| Variable | ID (hex) | Return Type | Unit |
|---|---|---|---|
| Speed | 0x40 | double (0x0b) | m/s |
| Position 2D | 0x42 | position2D (0x01) | m, m |
| NOₓ emission | 0x64 | double (0x0b) | mg/s |
| PMₓ emission | 0x65 | double (0x0b) | mg/s |
| CO₂ emission | 0x60 | double (0x0b) | mg/s |
| Acceleration | 0x72 | double (0x0b) | m/s² |
| Route ID | 0x53 | string (0x0c) | — |
Response Parsing
A response to a GET command follows this structure:
Response structure: [cmd_length: 1B] [response_id: 1B] [variable_id: 1B] [object_id: string] [type_byte: 1B] [value: variable] Type bytes: 0x08 = integer (4 bytes) 0x09 = byte 0x0b = double (8 bytes, IEEE 754) 0x0c = string (4-byte length + UTF-8 bytes) 0x01 = position2D (two doubles: x, y) 0x0e = string list (4-byte count + strings)
18.1.4 Java SUMOController Outline
For production deployments, a Java controller provides type safety and performance. Here is the architectural outline:
public class SUMOController {
private Socket socket;
private DataOutputStream out;
private DataInputStream in;
public void connect(String host, int port) throws IOException {
socket = new Socket(host, port);
out = new DataOutputStream(socket.getOutputStream());
in = new DataInputStream(socket.getInputStream());
}
public void simulationStep() throws IOException {
// CMD_SIMSTEP = 0x02
byte[] cmd = buildCommand(0x02, new byte[0]);
sendMessage(cmd);
readResponse();
}
public double getVehicleSpeed(String vehId) throws IOException {
// GET_VEHICLE_VARIABLE=0xa4, VAR_SPEED=0x40
byte[] content = encodeString(vehId);
byte[] cmd = buildCommand(0xa4, (byte)0x40, content);
sendMessage(cmd);
return parseDoubleResponse();
}
public void setTrafficLightPhase(String tlsId, int phase)
throws IOException {
// SET_TL_VARIABLE=0xc2, TL_PHASE_INDEX=0x22
byte[] content = concat(encodeString(tlsId),
new byte[]{0x08}, // TYPE_INT
encodeInt(phase));
byte[] cmd = buildCommand(0xc2, (byte)0x22, content);
sendMessage(cmd);
readResponse();
}
private byte[] buildCommand(int cmdId, byte varId, byte[] content) {
int cmdLen = 1 + 1 + 1 + content.length; // len + cmdId + varId + content
ByteBuffer buf = ByteBuffer.allocate(cmdLen);
buf.put((byte) cmdLen);
buf.put((byte) cmdId);
buf.put(varId);
buf.put(content);
return buf.array();
}
private void sendMessage(byte[] cmd) throws IOException {
int totalLen = 4 + cmd.length;
out.writeInt(totalLen);
out.write(cmd);
out.flush();
}
}18.1.5 Python: TraCI Message Builder/Parser
This implementation builds and parses TraCI binary messages from scratch, demonstrating the protocol at the byte level.
TraCI Binary Protocol Builder & Parser
PythonClick Run to execute the Python code
Code will be executed with Python 3 on the server
18.1.6 Key Takeaways
- TraCI is a TCP binary protocol with 4-byte big-endian length prefix, 1-byte command ID, and variable-length content.
- Command IDs distinguish GET (0xa*) vs SET (0xc*) operations across domains (vehicles, traffic lights, edges, lanes).
- Variable IDs (speed=0x40, NOx=0x64, position=0x42) specify which property to query or modify.
- Response parsing requires reading the type byte to determine how to decode the value (double, int, string, position2D).
- The protocol is language-agnostic: the Python and Java implementations shown here demonstrate that any language with socket and binary packing support can control SUMO.