Skip to content

Vehicle Bridge#

The vehicle bridge is a JSON socket that sends commands to one vehicle and returns its observations and reports. This page gives the protocol for the Maxxum and for the Polaris, the timing of the commands and the CAN transports.

Each agent has its own vehicle bridge. The option is -RlPort=<port>, and the game has no default port. The tools and the ROS 2 launch files use port 5556 for the Polaris. The examples use port 5555 for the Maxxum. The ROS 2 bridge connects to this socket and gives the commands and the reports as ROS 2 topics: refer to Topics. The figure of the three sockets is on the page Simulator Control Channel.

Item Type Function
-RlPort= Option Opens the vehicle bridge of agent 0.
-RlPorts= Option Opens one vehicle bridge for each agent.
-RlCanUdp= Option Opens the CAN transport on a UDP port.
-RlCan= Option Opens the CAN transport on a SocketCAN interface.
Transport Protocol TCP on 127.0.0.1, one JSON object in each line.
Command Timing Protocol The physics step at which a command applies.
Control and Timeouts Protocol The keyboard, the safety brake and a slow client.
Barrier Game to client The end of a lockstep step.
Driving Action Client to game Steering, pedal and differential lock.
reset Client to game Moves the vehicle to a pose and starts a new episode.
implement Client to game The hitch, the PTO and the operator controls of the Maxxum.
Session Commands Client to game Clock, workers, harvest function and HUD text.
Observation Game to client The state of the vehicle, each 0.1 s.
dbw Client to game Enables or disables the drive-by-wire of the Polaris.
steering_cmd Client to game The steering command of the Polaris.
throttle_cmd Client to game The throttle command of the Polaris.
brake_cmd Client to game The brake command of the Polaris.
gear_cmd Client to game The gear command of the Polaris.
ulc_cmd Client to game The speed command of the Polaris.
drive_mode Client to game The drive mode switch of the Polaris.
dbw_report Game to client The drive-by-wire reports of the Polaris, at 50 Hz.
dbw_client.py Tool A Python client for the Polaris.
CAN Transport Protocol J1939 frames on UDP or SocketCAN.
Differences in ACRES Core Table The behaviour of the Core server.

Options#

-RlPort=#

Opens the vehicle bridge of agent 0 on 127.0.0.1 at the given port. The game writes ACRES_RL_LISTENING port=<port> to its log when the socket is open. In an agents file, the key rl_port of an agent does the same for that agent.

Name Type Unit Default Description
-RlPort= integer no bridge The TCP port.
Packaged/Linux/Acres.sh -VehicleDemo -RlPort=5555
ACRES_RL_LISTENING port=5555

-RlPorts=#

Opens one vehicle bridge for each agent of a session with more than one vehicle. The list gives the ports in the sequence of the agents. An agent with its own rl_port or -RlPort= keeps that port. The operation hello of the simulator control channel gives the port of each agent.

Name Type Unit Default Description
-RlPorts= integer list no bridge The TCP ports, with commas between them.
Packaged/Linux/Acres.sh -VehicleDemo -Vehicles=maxxum,polaris \
    -Implement=chisel_plow -RlPorts=5555,5556 \
    -RlCanUdp=5570 -SimControl=5600
ACRES_RL_LISTENING port=5555
ACRES_RL_LISTENING port=5556
ACRES_AGENT_SPAWNED index=1 name=polaris vehicle=polaris

The agents in the reply to hello:

[{"name":"maxxum","vehicle":"maxxum","index":0,
  "implement":"chisel_plow","sensor_stream":0,
  "rl_port":5555,"can_udp":5570},
 {"name":"polaris","vehicle":"polaris","index":1,
  "implement":"","sensor_stream":0,
  "rl_port":5556,"can_udp":0}]

-RlCanUdp=#

Opens the CAN transport of agent 0 on a UDP port of 127.0.0.1. In an agents file, the key can_udp of an agent opens a CAN transport for that agent. This option is available only on Linux.

Name Type Unit Default Description
-RlCanUdp= integer no transport The UDP port.
Packaged/Linux/Acres.sh -VehicleDemo -RlCanUdp=5570
ACRES_RL_CAN_UDP_OPEN port=5570

-RlCan=#

Opens the CAN transport of agent 0 on a SocketCAN interface, for example a virtual interface vcan0. The interface must exist before the game starts. This option is available only on Linux.

Name Type Unit Default Description
-RlCan= string no transport The name of the SocketCAN interface.
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
Packaged/Linux/Acres.sh -VehicleDemo -RlCan=vcan0
ACRES_RL_CAN_OPEN interface=vcan0

Protocol#

Transport#

The vehicle bridge is a TCP socket on the loopback address 127.0.0.1. A program on a different computer cannot connect. Each message is one JSON object in one line of UTF-8 text. A newline character ends the line. The socket accepts one client at a time.

A client message can contain the keys of more than one command. The bridge ignores a line that is not a JSON object and writes ACRES_RL_BAD_MESSAGE to the log. The bridge sends no reply to a command. The observation and the dbw_report show the effect.

The positions and angles of this socket use the Unreal convention, not the world frame of the simulator control channel. The x axis points east and the y axis points south. The yaw angle is 0 for east and increases to the south.

sleep 0.5 | nc 127.0.0.1 5555 2>/dev/null | head -n 1
import json, socket

sock = socket.create_connection(("127.0.0.1", 5555))
stream = sock.makefile("rw")
observation = json.loads(stream.readline())
stream.write(json.dumps({"steer": 0.2, "pedal": 0.6}) + "\n")
stream.flush()

The first line that a client of a Maxxum receives is an observation:

{"t":4.9583,"episode_t":4.9583,"x":-38.7149,"y":132.8721,
 "z":1.5173,"yaw_deg":-89.9207,"vx":0.5757, ...}

Command Timing#

A command has no time stamp field. A receiver thread reads the sockets 1000 times each second. It gives each line and each CAN frame the wall-clock time of its arrival.

The game processes the commands one time in each frame. One frame can contain as many as 12 physics steps. For each command, the game calculates a due time in simulation time from the arrival time. The command goes into the command queue of the agent. The first physics step that starts at or after the due time applies it. Thus the physics steps get the commands in the sequence and with the intervals of their arrival.

This rule applies to the driving action, to the drive-by-wire commands and to the CAN driving frames. The other commands apply when the frame processes them. In lockstep, each command applies at the next physics step.

read k-1     a command arrives     read k
   |----------------x----------------|   wall clock
   |<- fraction f ->|
   |----------------x----------------|   simulation time
   t0        due = t0 + f T        t0 + T

The game reads the sockets at the start of each frame. The time T is the simulation time that frame k adds, 0.1 s maximum. The fraction f is the position of the arrival between the two reads.

Control and Timeouts#

While the bridge of a Maxxum has a client, the driving action of the client replaces the keyboard. The bridge holds the brake until the first driving action arrives. The bridge also holds the brake when no driving action arrives for 1 s on the wall clock. The observation then has stale equal to true. In lockstep, the 1 s limit does not apply. For a client that sends only drive-by-wire commands, stale stays true.

A client that sends drive-by-wire commands to a Polaris has no 1 s limit. The drive-by-wire model stops a subsystem when no command for it arrives for 0.1 s of simulation time. Send each drive-by-wire command again at a rate from 20 Hz to 100 Hz. Refer to Drive-by-Wire and ULC.

When a client disconnects, the bridge applies the brake and gives the control back to the keyboard. For a Polaris, the bridge also disables the drive-by-wire.

Limit Value Effect
No driving action 1 s, wall clock The bridge holds the brake.
No CAN command frame 3 s, wall clock The CAN controller loses the control.
No drive-by-wire command 0.1 s, simulation time The subsystem of the Polaris disengages.
Client does not read 1 MiB of output waits The bridge disconnects the client.
Line without a newline 1 MiB The bridge disconnects the client.

An observation after 5 s of driving actions, and an observation 1.5 s after the last action:

{"t": 10.1167, "vx": 2.6861, "steer_rad": 0.06632,
 "rpm": 1691.2, "stale": false}
{"t": 11.65, "vx": -0.0311, "stale": true}

The reports of a Polaris 0.4 s after the last drive-by-wire command:

{"t": 16.8833,
 "steering_report": {"steering_wheel_angle": 60.0,
  "cmd": 60.0, "cmd_type": 0, "enabled": false,
  "override_active": false, "timeout": true},
 "ulc_report": {"cmd_type": 0, "vel_ref": 2.0988,
  "vel_meas": 2.0988, "accel_ref": 0.0,
  "accel_meas": 0.2464, "enabled": false, "timeout": true},
 "system_report": {"enabled": true, "override": false}}
ACRES_RL_CONNECTED port=5555
ACRES_RL_DISCONNECTED peer closed

Barrier#

In lockstep, the bridge sends a barrier line at the end of each step request. All observations and reports of the steps are before the barrier. A client that reads to the barrier has all data of the request.

Name Type Unit Default Description
type string barrier.
step integer The physics step that the world reached. It is equal to barrier in the reply of the step request.
{"type":"barrier","step":85}
import sys
sys.path.insert(0, "Tools/SimControl")
from sim_control import JsonBridge, SimControl

ctl, dbw = SimControl(5600), JsonBridge(5556)
dbw.send({"dbw": {"enable": True}})
reply = ctl.call("step", steps=12)
dbw.wait_barrier(reply["barrier"])
print(len(dbw.reports), dbw.report["ulc_report"])

Maxxum#

The messages of this section also operate a Polaris, with the differences that each row gives.

Driving Action#

Sets the steering and the pedals. The bridge keeps the last value of each key. On the Maxxum, the bridge selects the forward gear F10. On the Polaris, the gear lever stays in its position.

Name Type Unit Default Description
steer number From -1 to 1. A fraction of one half of the maximum steering angle. Positive is left.
curvature number 1/m The curvature of the path. Positive is left. The steering angle is atan(curvature × wheelbase).
pedal number From -1 to 1. A positive value is the throttle, a negative value is the brake.
difflock number A value above 0 locks the differential of the rear axle. Maxxum only.

When one message has steer and curvature, the bridge uses curvature.

action = {"steer": 0.2, "pedal": 0.6}
for _ in range(50):                 # 5 s at 10 Hz
    stream.write(json.dumps(action) + "\n")
    stream.flush()
    observation = json.loads(stream.readline())
print(observation["vx"], observation["steer_rad"])
2.6861 0.06632

The action {"curvature": 0.05, "pedal": 0.4, "difflock": 1} for 2 s gives this observation:

{"t": 13.7083, "vx": 2.2266, "steer_rad": 0.13132,
 "difflock": 1, "stale": false}

reset#

Moves the vehicle to a pose on the ground and starts a new episode of the bridge. The marks and the crop damage of the fields stay. The pose applies at the next physics step.

Name Type Unit Default Description
reset.x number m spawn pose The east coordinate of the body origin.
reset.y number m spawn pose The south coordinate of the body origin.
reset.yaw_deg number deg spawn pose The yaw angle: 0 is east, 90 is south.
reset.speed number m/s 0 The start speed, from 0 to 8.
reset.restore_field boolean false true to remove the marks and the crop damage of the field below the pose.

A reset without x and y puts the vehicle at its spawn pose. The observation shows the progress: episode increases immediately, and reset_epoch increases when the physics applied the pose.

stream.write(json.dumps({"reset": {}}) + "\n")
stream.flush()

The first observation after this reset:

{"t": 16.9167, "episode_t": 0.0917, "x": -38.7097,
 "y": 134.5131, "yaw_deg": -90.0, "episode": 1,
 "reset_pending": false, "reset_epoch": 1}

A reset with a pose and a start speed:

{"reset": {"x": -28.72, "y": 134.42, "yaw_deg": 0,
           "speed": 2, "restore_field": true}}
ACRES_RL_RESET episode=1 x=-38.71 y=134.51 yaw=-90.0
    speed=0.00 restored_field=0
ACRES_RL_RESET episode=2 x=-28.72 y=134.42 yaw=0.0
    speed=2.00 restored_field=0

implement#

Sets the implement controls and the operator controls. The keys hand_throttle and park_brake apply to each vehicle. The other keys apply to a Maxxum with an implement. The hitch keys apply to an implement on the hitch.

Name Type Unit Default Description
implement.raise boolean true lifts the implement. For the square baler: true lifts the pickup.
implement.pto boolean true engages the PTO.
implement.transport boolean true selects the transport position.
implement.hitch_lever number The position of the hitch lever, from 0 to 1.
implement.hitch_mode string position, draft or float.
implement.draft_setpoint_n number N The draft set-point, from 1000 to 60000.
implement.hand_throttle number The hand throttle, from 0 to 1.
implement.park_brake boolean true applies the park brake.

The implement models are on the page Implement Mechanics.

stream.write(json.dumps({"implement": {
    "raise": False, "hitch_mode": "position",
    "hitch_lever": 0.3, "hand_throttle": 0.5}}) + "\n")
stream.flush()

The observation of a Maxxum with the chisel plow, 3 s later:

{"implement": "chisel_plow", "implement_depth_m": 0.1344,
 "hitch_lever": 0.3, "hitch_lift_deg": 7.27,
 "hitch_mode": 0, "raised": false, "pto_on": false,
 "draft_n": 11344.0}

Session Commands#

These keys change the session or the HUD.

Name Type Unit Default Description
env_clock.date string The local date as YYYY-MM-DD. The weather starts again at this time.
env_clock.hour number h 12 The local hour of the day.
workers list of [x, y] m Replaces the workers of the bridge with workers at these points.
cmd string harvester together with on sets the harvest function.
on boolean false The state for cmd.
hud string A status text for the HUD, 160 characters maximum.
reward number A number for the HUD.
success_pct number % A success rate for the HUD.

The workers are available only when the session has -NpcWorkers or -NpcVehicles. The harvest function is available only when the session has -FarmHarvester.

{"env_clock": {"date": "2026-07-04", "hour": 15.5}}
{"workers": [[-30.0, 120.0], [-25.0, 110.0]]}
{"hud": "run 12", "reward": 48.3, "success_pct": 60}

Observation#

While the bridge has a client, it sends one observation for each 0.1 s of simulation time. This is 12 physics steps. The observation has no key type. A Polaris client gets it together with the dbw_report lines.

Name Type Unit Default Description
t number s The physics time of the vehicle.
episode_t number s The time since the last reset.
x, y, z number m The body origin: x east, y south, z up.
yaw_deg number deg The yaw angle: 0 is east, 90 is south.
vx, vy number m/s The velocity in the body frame: x forward, y right.
yaw_rate number rad/s Positive when the vehicle turns right.
cross_slope number rad Positive when the ground goes down to the right.
slip number list The slip ratio of the four wheels: front left, front right, rear left, rear right.
steer_rad number rad The steering angle. Positive is left.
rpm number rev/min The engine speed.
difflock integer 0 open, 1 rear locked, 2 front and rear locked.
theta_here, theta_5, theta_10 number m³/m³ The soil water content below the vehicle, 5 m ahead and 10 m ahead.
lidar number list m 16 ranges of the front half, from 90° left to 90° right, 30 m maximum.
bunker_kg, harvest_kg number kg The crop mass in the bunker and the total harvested mass.
crushed_m2 number m² The crop area that the session crushed.
draft_n number N The draft force of the implement.
implement string The implement identifier. Empty without an implement.
implement_depth_m number m The mean depth of the tools.
pto_kw, pto_rpm number kW, rev/min The power and the speed of the PTO shaft.
hitch_lever number The hitch lever, from 0 to 1.
hitch_lift_deg number deg The lift angle of the lower links.
hitch_mode integer 0 position, 1 draft, 2 float.
raised, pto_on boolean The state of the implement and of the PTO switch.
struck boolean true when the vehicle hit a worker since the last observation.
episode integer The resets that clients requested on this bridge.
reset_pending boolean true until the physics applies the last reset.
reset_epoch integer The resets that the physics applied.
workers integer The number of workers of the bridge.
stale boolean true when no driving action is in effect.
agent, vehicle string The name of the agent and maxxum or polaris.

The 16 lidar values are a fast summary for controllers, not the LiDAR of the sensor rig.

{"t":5.0167,"episode_t":5.0167,"x":-38.715,"y":132.8379,
 "z":1.5157,"yaw_deg":-89.9152,"vx":0.5929,"vy":-0.0043,
 "yaw_rate":0.00152,"cross_slope":-0.00587,
 "slip":[0.00945,0.00844,-0.00569,-0.00595],
 "steer_rad":0.0,"rpm":796.3,"difflock":0,
 "theta_here":0.2,"theta_5":0.2,"theta_10":0.2,
 "lidar":[30.0,30.0,25.129,20.258,30.0,30.0,30.0,30.0,
  30.0,30.0,30.0,30.0,30.0,30.0,30.0,30.0],
 "bunker_kg":0.0,"harvest_kg":0.0,"crushed_m2":0.0,
 "draft_n":0.0,"struck":false,"episode":0,
 "reset_pending":false,"reset_epoch":0,"workers":0,
 "stale":true,"implement":"chisel_plow",
 "implement_depth_m":0.0,"pto_kw":0.0,"hitch_lever":0.235,
 "hitch_lift_deg":32.0,"hitch_mode":0,"raised":true,
 "pto_on":false,"pto_rpm":0.0,"agent":"maxxum",
 "vehicle":"maxxum"}

Polaris#

The Polaris uses the commands and the reports of the Dataspeed drive-by-wire. The keys and the units are those of the ROS 2 messages of ds_dbw_msgs, thus the ROS 2 bridge passes each message without a change. The model of the actuators and of the ULC is on the page Drive-by-Wire and ULC.

The bridge accepts the keys clear, ignore, enable_shift and enable_shift_park and ignores them. The bridge refuses a command type that the model does not have and writes ACRES_DBW_REJECTED to the log one time, for example ACRES_DBW_REJECTED steering_cmd cmd_type 1 (not modelled). A Maxxum refuses all commands of this section.

WARNING

The same messages move the real vehicle on the real ROS 2 topics. Keep the simulator traffic on the loopback address.

dbw#

Enables or disables the drive-by-wire system. This is the function of the topics /vehicle/enable and /vehicle/disable. A driver input on the keyboard is an override. It disables the system until the next enable.

Name Type Unit Default Description
dbw.enable boolean false true enables the system.
dbw.disable boolean false true disables the system.
sock = socket.create_connection(("127.0.0.1", 5556))
stream = sock.makefile("rw")

def send(message):
    stream.write(json.dumps(message) + "\n")
    stream.flush()

send({"dbw": {"enable": True}})
ACRES_DBW_ENABLED agent=polaris t=10.508
ACRES_DBW_DISABLED agent=polaris t=17.217

steering_cmd#

The steering command, with the fields of ds_dbw_msgs/msg/SteeringCmd.

Name Type Unit Default Description
steering_cmd.cmd number by type 0 The command value.
steering_cmd.cmd_type integer 0 0 none, 2 steering wheel angle in deg, 3 curvature in 1/m, 4 yaw rate in rad/s, 14 percent.
steering_cmd.cmd_rate number deg/s 0 The rate limit of the steering wheel. 0 selects the default.
steering_cmd.cmd_accel number deg/s² 0 The acceleration limit. 0 selects the default.
steering_cmd.enable boolean false true to let the actuator follow the command.

The model does not have the type 1 (torque).

send({"steering_cmd": {"cmd": 60.0, "cmd_type": 2,
                       "cmd_rate": 200.0, "enable": True}})

throttle_cmd#

The throttle command, with the fields of ds_dbw_msgs/msg/ThrottleCmd.

Name Type Unit Default Description
throttle_cmd.cmd number % 0 The command value.
throttle_cmd.cmd_type integer 0 0 none, 13 raw pedal percent, 14 percent of the full range.
throttle_cmd.rate_inc number %/s 0 The rate limit for an increase.
throttle_cmd.rate_dec number %/s 0 The rate limit for a decrease.
throttle_cmd.enable boolean false true to let the actuator follow the command.
send({"throttle_cmd": {"cmd": 20.0, "cmd_type": 14,
                       "enable": True}})

brake_cmd#

The brake command, with the fields of ds_dbw_msgs/msg/BrakeCmd.

Name Type Unit Default Description
brake_cmd.cmd number by type 0 The command value.
brake_cmd.cmd_type integer 0 0 none, 1 pressure in bar, 14 percent.
brake_cmd.rate_inc number by type 0 The rate limit for an increase, for each second.
brake_cmd.rate_dec number by type 0 The rate limit for a decrease, for each second.
brake_cmd.enable boolean false true to let the actuator follow the command.

The model does not have the torque types and the acceleration types.

send({"brake_cmd": {"cmd": 15.0, "cmd_type": 1,
                    "enable": True}})

gear_cmd#

The gear command. The value is a number or an object with the key value, as in ds_dbw_msgs/msg/GearCmd. The command has an effect only while the drive-by-wire system is on.

Name Type Unit Default Description
gear_cmd.cmd integer 0 0 none, 1 park, 2 reverse, 3 neutral, 4 high, 5 low.
send({"gear_cmd": {"cmd": 5}})
send({"gear_cmd": {"cmd": {"value": 5}}})

ulc_cmd#

The command of the ULC, with the fields of ds_dbw_msgs/msg/UlcCmd. The ULC controls the throttle and the brake.

Name Type Unit Default Description
ulc_cmd.cmd number by type 0 The command value.
ulc_cmd.cmd_type integer 0 0 none, 1 speed in m/s, 2 acceleration in m/s².
ulc_cmd.limit_accel number m/s² 0 The acceleration limit. 0 selects the default.
ulc_cmd.limit_decel number m/s² 0 The deceleration limit. 0 selects the default.
ulc_cmd.limit_jerk_throttle number m/s³ 0 The jerk limit of the throttle. 0 selects the default.
ulc_cmd.limit_jerk_brake number m/s³ 0 The jerk limit of the brake. 0 selects the default.
ulc_cmd.enable boolean false true to let the ULC control the speed.
ulc_cmd.coast_decel boolean false true to decelerate without the brake.
import time

start = time.monotonic()
while time.monotonic() - start < 6:      # 50 Hz
    send({"ulc_cmd": {"cmd": 2.0, "cmd_type": 1,
                      "limit_accel": 1.0, "limit_decel": 1.5,
                      "enable": True},
          "steering_cmd": {"cmd": 60.0, "cmd_type": 2,
                           "cmd_rate": 200.0, "enable": True}})
    time.sleep(0.02)

The ULC report and the steering report after 6 s:

{"ulc_report": {"cmd_type": 1, "vel_ref": 2.0,
  "vel_meas": 1.8815, "accel_ref": 0.0,
  "accel_meas": 0.7373, "enabled": true, "timeout": false},
 "steering_report": {"steering_wheel_angle": 60.0,
  "cmd": 60.0, "cmd_type": 2, "enabled": true,
  "override_active": false, "timeout": false}}

drive_mode#

Sets the drive mode switch of the Polaris. This switch is not a part of the drive-by-wire. It applies immediately.

Name Type Unit Default Description
drive_mode string awd awd, 2wd or turf.
send({"drive_mode": "2wd"})

The next report has "drive_mode": 1.

dbw_report#

While the bridge has a client, it sends the reports at 50 Hz of simulation time. One line contains all reports of one instant. Each object has the fields of the report message of ds_dbw_msgs with the same name.

Name Type Unit Default Description
type string dbw_report.
agent string The name of the agent.
t number s The physics time of the report.
drive_mode integer 0 turf, 1 two-wheel drive, 2 all-wheel drive.
road_wheel_rad number rad The road wheel angle. Positive is left.
stop_hold boolean true when the ULC holds the vehicle at a stop.

steering_report

Name Type Unit Default Description
steering_wheel_angle number deg The angle of the steering wheel.
cmd number deg The steering wheel angle that the actuator follows.
cmd_type integer The type of the active command.

throttle_report

Name Type Unit Default Description
percent_input number % The pedal of the driver.
percent_cmd number % The command.
percent_output number % The output of the actuator.
cmd_type integer The type of the active command.

brake_report

Name Type Unit Default Description
pressure_input number bar The pressure from the pedal of the driver.
pressure_cmd number bar The command as a pressure.
pressure_output number bar The output of the actuator as a pressure.
percent_cmd number % The command as a percentage.
percent_output number % The output of the actuator as a percentage.
cmd_type integer The type of the active command.

gear_report

Name Type Unit Default Description
gear integer The gear: 1 park, 2 reverse, 3 neutral, 4 high, 5 low.
cmd integer The gear command.
driver integer The position of the gear lever.

ulc_report

Name Type Unit Default Description
cmd_type integer The type of the active command.
vel_ref number m/s The speed reference.
vel_meas number m/s The speed that the ULC measures.
accel_ref number m/s² The acceleration reference.
accel_meas number m/s² The measured acceleration.

vehicle_velocity

Name Type Unit Default Description
vehicle_velocity_brake number m/s The speed from the wheel speed sensors.
vehicle_velocity_propulsion number m/s The speed from the drivetrain.
dir_src integer The source of the direction: 1.

system_report

Name Type Unit Default Description
enabled boolean true while the drive-by-wire system is on.
override boolean true after an input of the driver.

The reports for steering, throttle, brake and ULC also have the keys enabled and timeout. The reports for steering, throttle and brake also have the key override_active. timeout is true from 0.1 s to 1 s after the last command of the subsystem.

{"type":"dbw_report","agent":"polaris","t":16.4667,
 "steering_report":{"steering_wheel_angle":60.0,"cmd":60.0,
  "cmd_type":2,"enabled":true,"override_active":false,
  "timeout":false},
 "throttle_report":{"percent_input":0.0,
  "percent_cmd":34.065,"percent_output":34.065,
  "cmd_type":14,"enabled":true,"override_active":false,
  "timeout":false},
 "brake_report":{"pressure_input":0.0,"pressure_cmd":0.0,
  "pressure_output":0.094,"percent_cmd":0.0,
  "percent_output":0.117,"cmd_type":1,"enabled":true,
  "override_active":false,"timeout":false},
 "gear_report":{"gear":5,"cmd":5,"driver":5},
 "ulc_report":{"cmd_type":1,"vel_ref":2.0,
  "vel_meas":1.8815,"accel_ref":0.0,"accel_meas":0.7373,
  "enabled":true,"timeout":false},
 "vehicle_velocity":{"vehicle_velocity_brake":1.8815,
  "vehicle_velocity_propulsion":1.8951,"dir_src":1},
 "system_report":{"enabled":true,"override":false},
 "drive_mode":2,"road_wheel_rad":0.06918,
 "stop_hold":false}

dbw_client.py#

The file Learning/acres_learn/envs/dbw_client.py is a client for the Polaris. It uses only the standard library. As a program, it sends the commands at 50 Hz and writes the reports to a CSV file. At the end it commands a stop for 3 s and then disables the drive-by-wire.

Name Type Unit Default Description
--port integer 5556 The port of the vehicle bridge.
--host string 127.0.0.1 The address of the vehicle bridge.
--steps path or demo A JSON list of timed speeds and steering angles, or the demonstration of the program.
--path path A JSON file with a path that the client follows with curvature commands.
--delay number s 0 The time to wait after the connection.
--log path The CSV file for the reports.
--hud string empty A status text for the HUD.

The class Bridge of the file gives the same functions to a Python program.

Member Function
Bridge(host, port) Connects to the vehicle bridge.
Bridge.enable(on) Sends dbw.enable or dbw.disable.
Bridge.command(speed, steer_deg, curvature, gear) Sends one ULC command with a steering command and a gear command.
Bridge.poll(timeout) Reads the lines that arrived.
Bridge.reports, Bridge.obs The list of all reports and the last observation.
echo '[{"t":0,"speed":0,"steer_deg":12.5,"gear":"L"},
 {"t":1,"speed":2},{"t":6,"end":true}]' > /data/steps.json
cd Learning
python -m acres_learn.envs.dbw_client --port 5556 \
    --steps /data/steps.json --log /data/dbw_reports.csv
import sys, time
sys.path.insert(0, "Learning")
from acres_learn.envs.dbw_client import GEAR, Bridge

bridge = Bridge("127.0.0.1", 5556)
bridge.enable(True)
end = time.time() + 5.0
while time.time() < end:
    bridge.command(speed=2.0, steer_deg=12.5, gear=GEAR["L"])
    bridge.poll(0.02)
print(len(bridge.reports), "reports")
print(bridge.reports[-1]["ulc_report"])
bridge.enable(False)

The output of the program:

connected to 127.0.0.1:5556
done: 451 DBW reports received

The output of the Python example:

250 reports
{'cmd_type': 1, 'vel_ref': 2.0, 'vel_meas': 2.062,
 'accel_ref': 0.0, 'accel_meas': -0.9618,
 'enabled': True, 'timeout': False}

J1939 CAN#

CAN Transport#

The CAN transport carries the observation and the driving action of the Maxxum as SAE J1939 frames. This page gives only the transport. The frames and their signals are on the page Wheel and CAN Signals.

Each frame is the 16 bytes of the Linux structure can_frame: a 4-byte identifier, a 1-byte length, 3 unused bytes and 8 data bytes. The byte sequence is little-endian. The identifier has 29 bits and the flag 0x80000000 for the extended format. The bridge ignores frames with an 11-bit identifier, remote frames and error frames.

Transport Option Behaviour
UDP -RlCanUdp=<port> One frame in each datagram on 127.0.0.1. The game sends its frames to the sender of the last datagram.
SocketCAN -RlCan=<interface> Raw frames on the interface. The game sends its frames always.

The game sends the 13 frames of one observation each 0.1 s of simulation time. On UDP, the game sends no frame before it receives the first datagram. The game accepts command frames only from the source address 0x2A. In lockstep, the game sends the frame 0xFF1E with the step number as the barrier.

import socket, struct

CAN_EFF_FLAG = 0x80000000
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp.settimeout(1.0)
# Guidance command: curvature 0, steering active.
data = struct.pack("<HB5x", 32128, 0xFD)
frame = struct.pack("<IB3x8s", 0x0CAC802A | CAN_EFF_FLAG, 8, data)
udp.sendto(frame, ("127.0.0.1", 5570))
can_id, length, data = struct.unpack("<IB3x8s", udp.recv(16))
print(hex(can_id & 0x1FFFFFFF), data.hex())
0xcf00400 ffffffe218ffffff

The identifiers of the 13 frames of one observation:

0x0CADFF80 0x0CF00400 0x0CFE4880 0x18FF1080 0x18FF1180
0x18FF1280 0x18FF1380 0x18FF1480 0x18FF1580 0x18FF1680
0x18FF1780 0x18FF1880 0x18FF1F80

Differences in ACRES Core#

The Core server opens one vehicle bridge for each of its Polaris agents. The option is --rl-ports, and the default port is 5556.

Item Game Core Server
Vehicles Maxxum and Polaris. Polaris only.
Commands All commands of this page. The drive-by-wire commands of the Polaris and reset.
Observation One line each 0.1 s. No observation.
dbw_report 50 Hz. 50 Hz, the same format.
Barrier JSON line and CAN frame. JSON line.
reset with only yaw_deg The vehicle goes to its spawn position with this yaw angle. The vehicle turns at its position.
CAN transport UDP and SocketCAN. None.
Command timing Arrival time, and the next step in lockstep. The same rule.