Skip to content

Drive-by-Wire and ULC#

This page gives the model of the Dataspeed drive-by-wire of the Polaris: the command path, the watchdog, the actuators and the ULC. The model accepts the commands of ds_dbw_msgs 2.3.11 and gives the same reports as the real vehicle.

Drive-by-wire command path: a ROS 2 command becomes a line on the vehicle bridge, the receiver thread stamps its arrival, the command clock gives it a solver time, the command queue holds it until the matching physics step, the watchdog examines its age, the actuators and the ULC move the vehicle model, and the reports go out at 50 Hz. The real vehicle has the same commands and reports. Drive-by-wire command path SIMULATOR: A COMMAND ARRIVES ROS 2 command /vehicle/*/cmd ds_dbw_msgs ROS 2 bridge sim_bridge one line for each Vehicle bridge -RlPort= JSON lines, TCP Receiver thread 1000 reads each second, arrival time Command clock arrival time to solver time EACH PHYSICS STEP, 1/120 S Driver keyboard, replay, drive script Watchdog command age: 0.1 s maximum Enable, override system enable, fresh flags Take the snapshots that are due at this step Command queue inbox snapshots, each with its time Drive-by-wire actuators StepDbw Steering servo ULC Gear actuator Pedal emulation Brake pressure commands that are fresh without DBW control Vehicle model engine, CVT, wheels, chassis Reports, 50 Hz dbw_report /vehicle/*/report wheel speeds for the ULC REAL VEHICLE: THE SAME COMMANDS AND REPORTS ROS 2 command /vehicle/*/cmd the same topics Dataspeed gateway commands on the CAN bus DBW firmware timeout, actuators, ULC Polaris Ranger steering column, pedal, brake Reports, 50 Hz /vehicle/*/report the same topics
The path of a command from a ROS 2 topic to the actuators, and the path of the reports. The red row shows the same path on the real vehicle. Open the diagram

Scope and Assumptions#

The drive-by-wire layer is AcresSim::StepDbw in AcresUtvModel.cpp. It is the first call of each physics step of the Polaris. The layer computes these quantities.

  • Which subsystems have drive-by-wire control: steering, throttle, brake and ULC.
  • The steering wheel angle, the throttle pedal, the line pressure of the brakes and the gear.
  • The speed reference, the acceleration reference and the pedal requests of the ULC.
  • The wheel speed that the reports show.

Polaris Ranger Dynamics gives the vehicle that these outputs move.

The model makes these assumptions.

  • The steering servo is linear: a delay, a first-order lag and a rate limit. It has no stick-slip at standstill.
  • The firmware of the ULC is not public. The control law is a structure that reproduces the recorded reports.
  • The kinematic map of the curvature mode uses the steering ratio and the wheelbase of the vehicle model.
  • The model has no CAN bus between the gateway and the actuators. A command has no CRC and no rolling counter.
  • The model does not compute steering torque, brake torque or acceleration commands for the brake. It rejects these command types.

The fields of the commands and the reports keep the units of the messages: degrees, percent, bar, m/s and m/s².

WARNING

Do not send drive-by-wire commands outside the DDS loopback fence. The real vehicle uses the same topics and can move.

Symbols#

Symbol Quantity Unit
\(t_k\) Solver time at the start of physics step \(k\) s
\(a_i\) Age of the last message of subsystem \(i\) s
\(T_{out}\) Command timeout s
\(\theta^*\) Steering target after the conversion of the command deg
\(\theta_r\), \(\dot\theta_r\) Steering reference and its rate deg, deg/s
\(\theta_{sw}\) Steering wheel angle deg
\(\dot\theta_{max}\), \(\ddot\theta_{max}\) Rate limit and acceleration limit of the steering reference deg/s, deg/s²
\(d_s\), \(\tau_s\), \(\dot\theta_{slew}\) Delay, lag and slew limit of the steering servo s, s, deg/s
\(i_k\), \(L_k\) Steering ratio and wheelbase of the kinematic map -, m
\(q_c\), \(q\) Throttle command after the rate limits, emulated pedal %
\(P_c\), \(P\) Brake pressure command, line pressure bar
\(P_{max}\) Full-scale pressure bar
\(v_w\) Wheel speed that the reports show (vehicle_velocity_brake) m/s
\(\kappa_v\) Speed scale of the wheel speed -
\(s_g\) Direction of the engaged gear: -1 in reverse, 1 in all other gears -
\(v_{cmd}\) Speed command of the ULC m/s
\(v_{ref}\), \(a_{ref}\) Speed reference and acceleration reference of the ULC m/s, m/s²
\(a_{max}\), \(d_{max}\) Acceleration limit and deceleration limit of the ULC m/s²
\(j_t\), \(j_b\) Jerk limits of the ULC: limit_jerk_throttle, limit_jerk_brake m/s³
\(e\) Speed error of the ULC along the gear direction m/s
\(a_d\) Acceleration demand of the ULC m/s²
\(I_e\) Integral of the speed error m

The function \(\operatorname{lag}\) is in Polaris Ranger Dynamics. Two more functions limit a rate.

\[ \operatorname{move}(x, x^*, \Delta) = x + \operatorname{clamp}(x^* - x,\ -\Delta,\ \Delta) \]
\[ \operatorname{move}_2(x, x^*, \Delta_{up}, \Delta_{down}) = x + \operatorname{clamp}(x^* - x,\ -\Delta_{down},\ \Delta_{up}) \]

A limit in a command has this rule: 0 selects the default, and infinity removes the limit. A default of 0 also removes the limit.

Command Types#

Source: FAcresRlBridge::HandleDbw in AcresRlBridge.cpp, FDbwPath::Post in CoreSimDbw.cpp.

The ROS 2 bridge changes each ROS 2 command into one JSON line on the vehicle bridge. Vehicle Bridge gives the wire format.

ROS 2 Topic Message Key on the Vehicle Bridge
/vehicle/enable std_msgs/Empty dbw with enable
/vehicle/disable std_msgs/Empty dbw with disable
/vehicle/steering/cmd ds_dbw_msgs/SteeringCmd steering_cmd
/vehicle/throttle/cmd ds_dbw_msgs/ThrottleCmd throttle_cmd
/vehicle/brake/cmd ds_dbw_msgs/BrakeCmd brake_cmd
/vehicle/gear/cmd ds_dbw_msgs/GearCmd gear_cmd
/vehicle/ulc/cmd ds_dbw_msgs/UlcCmd ulc_cmd

The model accepts these command types. The type is the field cmd_type. The unit and the range apply to the field cmd.

Command Type Unit Range Other Fields
Steering 2 angle deg ±280 cmd_rate deg/s, cmd_accel deg/s², enable
Steering 3 curvature 1/m ±0.2 The same fields
Steering 4 yaw rate rad/s ±8.5 The same fields
Steering 14 percent % ±100 100 % is 280°
Throttle 14 percent % 0 to 100 rate_inc, rate_dec %/s, enable
Throttle 13 raw pedal % 15 to 80 The same fields
Brake 14 percent % 0 to 100 100 % is 80 bar. rate_inc, rate_dec, enable
Brake 1 pressure bar 0 to 80 rate_inc, rate_dec bar/s, enable
Gear 1 P, 2 R, 3 N, 4 H, 5 L 0 is no command
ULC 1 velocity m/s ±45 limit_accel, limit_decel, limit_jerk_throttle, limit_jerk_brake, enable, coast_decel
ULC 2 acceleration m/s² -6 to 3 The same fields

The value 4 of the gear is DRIVE in ds_dbw_msgs. It selects H on the Polaris. The value 5 is LOW and selects L. A cmd_type of 0 gives the subsystem no command.

The bridge rejects all other command types and writes the warning ACRES_DBW_REJECTED one time for each type. Examples are the steering torque, the brake torque and the brake acceleration. The bridge accepts the fields clear, ignore, enable_shift and enable_shift_park and ignores them. A drive-by-wire command for the Maxxum has no effect.

The key drive_mode with the value awd, 2wd or turf sets the AWD switch. It is not a Dataspeed message.

Timestamped Command Queue#

Source: AcresCommandTiming.h (FCommandClock, TTimedCommands), FAcresRlBridge::BeginCommandRead, AAcresVehiclePawn::PostDbw.

The game reads its sockets one time for each rendered frame. One frame can advance the physics by 12 steps. Without the queue, all messages of a slow frame arrive at the first step and the other steps see no message. The command timeout then stops a subsystem although the controller sends at a constant rate. The queue applies each command at the physics step that agrees with its arrival time.

Arrival time. A receiver thread reads the sockets 1000 times each second. It records the wall-clock time \(w\) of each complete line.

Command clock. At each frame, BeginRead stores four values.

Value Meaning
\(W_{prev}\), \(W_{last}\) The wall-clock times of the previous read and of this read
\(S_0\) The solver time that the physics has before this frame
\(F\) The solver time that this frame adds: the frame time, limited to MaxPhysicsDeltaTime (0.1 s). 0 during a pause of the world.

ApplyAt maps the arrival time linearly into the solver interval of the frame.

\[ t_{apply}(w) = S_0 + \operatorname{clamp}\!\left(\frac{w - W_{prev}}{W_{last} - W_{prev}}, 0, 1\right) F \]

The result is "the next step" in three conditions: lockstep, the first read, and a solver without a fixed step.

Queue. Each message updates the inbox. The inbox holds the last command of each subsystem and one sequence number for each subsystem. Push adds a snapshot of the full inbox with its time \(t_{apply}\). A snapshot never applies before the snapshot that is ahead of it. When its time is not later, it replaces that snapshot.

Take. Physics step \(k\) takes all snapshots that obey this condition and keeps the last one.

\[ t_{apply} \le t_k + 0.002\ \text{s} \]

The tolerance of 0.002 s allows for the rounding of the solver time. A new sequence number marks the command of that subsystem as fresh.

The test program polaris_tests compares the two methods with a controller at 50 Hz and frames of 0.03 s to 0.14 s.

Method Result in 60 s
Commands applied when the frame reads them 485 physics steps without control. The largest command age is 0.100 s.
Commands applied at their arrival time 0 physics steps without control. The largest command age is 0.017 s.
A controller that stops The subsystem releases 0.1083 s after the last command.

In lockstep, each command applies at the next step. Time Stepping and Determinism gives the lockstep rules.

Enable, Disable and Override#

Source: AAcresVehiclePawn::StepPolarisControls in AcresPolaris.cpp, FDbwPath::Step in CoreSimDbw.cpp.

Each physics step builds one command structure (FDbwCommand) from three sources.

Source When It Acts What It Gives
Bridge client The system is enabled and the last message of the subsystem is younger than 0.25 s The commands of the inbox
Session driver: replay, route review, drive script A session driver is active and the bridge does not command the subsystem A steering angle command and a ULC speed command, fresh at each step
Driver: keyboard or the actions steer and pedal The system is not enabled Steering wheel angle, pedal, brake pressure and gear lever

The rules of the system enable are these.

  • The message enable enables the system. The message disable disables it. The game writes ACRES_DBW_ENABLED or ACRES_DBW_DISABLED to its log.
  • A pedal key or a steering key while the system is enabled is an override. The game disables the system and writes ACRES_DBW_OVERRIDE.
  • The override flag stays in the reports until the next enable.
  • When the bridge client disconnects, the game disables the system.
  • The gear command applies while the system is enabled. It stays until the next gear command.

A session driver sends the commands of the path follower of the lab: a steering angle and a ULC speed. The steering angle command has the limits 171.9 deg/s and 1000 deg/s². The session driver selects R for a negative speed. For a positive speed it keeps H when the lever is in H and selects L in all other conditions.

While the system is enabled, the pedals of the driver are 0 and the driver does not steer. ACRES Core has no keyboard and no session driver. The Core server holds the steering wheel at the centre and starts with the lever in P. Enable drive-by-wire and send a gear command before a speed command. The game also starts in P; its session driver selects L or R. The Core batch API keeps its explicit reset gear, which defaults to L for training.

Watchdog#

Source: StepDbw.

The model counts the age of the last message of each subsystem. A fresh command sets the age to 0. Each other step adds \(\Delta t\).

\[ a_i \leftarrow \begin{cases} 0 & \text{a fresh command of subsystem } i \text{ arrived in this step} \\ a_i + \Delta t & \text{in all other conditions} \end{cases} \]

A subsystem has drive-by-wire control only when all these conditions are true.

  1. The system is enabled.
  2. The enable flag of the command is true.
  3. The command type is not 0.
  4. \(a_i \le T_{out}\), with \(T_{out}\) = 0.1 s.

The ULC has one more condition: no user throttle command and no user brake command has control. A user command thus stops the ULC.

When the ULC loses control, the throttle and the brake keep its last output for 0.087 s more (dbw.ulc_actuator_timeout_s). After that time the pedal and the pressure command go to the driver values.

With a step of 1/120 s, a subsystem keeps control for 12 steps after its last command and releases at step 13, 0.108 s later. In a session of the packaged game, the steering report showed enabled: false approximately 0.11 s after the last command. The brake report showed it approximately 0.19 s after the last command.

A report shows timeout: true when the age is more than \(T_{out}\) and less than 1 s.

Note

A client must send each command at 20 Hz or more. The real vehicle has the same timeout.

Lean proofs show three properties of this path. Refer to Verification.

  • The queue keeps the sequence of the commands.
  • A controller with a short period never causes a timeout.
  • A controller that stops causes the release at step 13.

Steering Actuator#

Source: StepDbw, Reference, Delayed, CurvatureToSteeringWheelDeg.

Target. The command type gives the target angle \(\theta^*\) of the steering wheel in degrees.

Type Target
Angle \(\operatorname{clamp}(\text{cmd}, -280, 280)\)
Percent \(\operatorname{clamp}(\text{cmd}, -100, 100) \cdot 280 / 100\)
Curvature \(\dfrac{180}{\pi}\, i_k \arctan\!\left(\operatorname{clamp}(\text{cmd}, -0.2, 0.2)\, L_k\right)\)
Yaw rate The curvature equation with \(\kappa = \operatorname{clamp}(\text{cmd}, -8.5, 8.5) / v_y\)

For the yaw rate, \(v_y\) has the sign of the wheel speed and a magnitude of 0.5 m/s minimum. \(i_k\) and \(L_k\) are the steering ratio and the wheelbase of the vehicle model when the keys dbw.steering.kinematic_* are 0. The curvature map does not add the steering centre \(\theta_c\). A curvature of 0 thus gives a steering wheel angle of 0°. The target then has the limit of the steering lock, ±487°.

Reference generator. The reference moves to the target in minimum time with a rate limit and an acceleration limit. The limits are cmd_rate and cmd_accel of the command. Their defaults are 100 deg/s and 500 deg/s². With \(E = \theta^* - \theta_r\):

\[ \dot\theta_{des} = \operatorname{sgn}(E) \min\!\left(\dot\theta_{max},\ \sqrt{2\, \ddot\theta_{max}\, \lvert E\rvert}\right) \]
\[ \dot\theta_r \leftarrow \operatorname{move}(\dot\theta_r,\ \dot\theta_{des},\ \ddot\theta_{max}\, \Delta t), \qquad \theta_r \leftarrow \theta_r + \dot\theta_r\, \Delta t \]

When the step goes across the target, the reference becomes the target and the rate becomes 0. When the subsystem gets control, the reference starts at the actual steering wheel angle with the rate 0. The report field cmd is this reference.

Servo. The reference goes through a transport delay \(d_s\), a first-order lag and a slew limit.

\[ \theta_{sw} \leftarrow \operatorname{clamp}\!\left(\operatorname{move}\!\left(\theta_{sw},\ \operatorname{lag}(\theta_{sw},\ \theta_r(t - d_s),\ \tau_s),\ \dot\theta_{slew}\, \Delta t\right),\ -487,\ 487\right) \]

The delay line interpolates linearly between the stored values of the reference.

Without control. The steering wheel follows the driver. If there is no driver input, the wheel keeps its angle. The reference then follows the steering wheel angle.

Gear Actuator#

Source: StepDbw.

The wanted gear is the gear command when the system is enabled and the command is not 0. If not, it is the gear lever of the driver.

The actuator accepts a new gear only when \(\lvert v_w\rvert \le 0.3\) m/s (dbw.gear.max_speed_mps). A change has a duration of 1 s (dbw.gear.shift_s). The transmission is in neutral during the change.

At a higher speed the actuator keeps the engaged gear. The change starts when the speed is below the limit and the request is still there.

Throttle Pedal Emulation#

Source: StepDbw.

The throttle has control when a user throttle command has control or the ULC drives the pedals. The raw pedal type maps the sensor range to percent.

\[ q^* = \begin{cases} \dfrac{\text{cmd} - 15}{80 - 15} \cdot 100 & \text{raw pedal} \\ \text{cmd} & \text{percent} \\ q_{ulc}(t - d_u) & \text{the ULC drives} \end{cases} \]
\[ q_c \leftarrow \operatorname{move}_2\!\left(q_c,\ \operatorname{clamp}(q^*, 0, 100),\ \dot q_{up}\, \Delta t,\ \dot q_{down}\, \Delta t\right) \]
\[ q = \operatorname{clamp}\!\left(q_c(t - d_t) + q_{bias},\ 0,\ 100\right) \]

The rate limits are rate_inc and rate_dec of a user command. The default has no limit. The ULC has no rate limit here. The delay \(d_t\) is 0 (dbw.throttle.delay_s). The report shows \(q_c\) as percent_cmd and \(q\) as percent_output. Without control, \(q\) is the pedal of the driver and \(q_c\) is 0.

Brake Pressure#

Source: StepDbw, UtvBrakeOutputBar.

Command. The pressure command is the largest of the driver pressure and the command of the drive-by-wire.

\[ P^* = \operatorname{clamp}\!\left(\max(P_{driver},\ P_{dbw}),\ 0,\ P_{max}\right), \qquad P_{dbw} = \begin{cases} \text{cmd} & \text{pressure} \\ \text{cmd} \cdot P_{max} / 100 & \text{percent} \\ P_{ulc}(t - d_u) & \text{the ULC drives} \end{cases} \]

A user command applies its rate limits rate_inc and rate_dec to \(P_c\). In the percent type the limits are in %/s. In all other conditions \(P_c = P^*\). The command then goes through the delay \(d_b\) = 0.0333 s.

Apply. When the delayed command is more than the line pressure, the pressure increases in minimum time. The reference generator of the steering gives the equation. The rate limit is 200 bar/s and the acceleration limit is 690.2 bar/s². With \(E = P_c(t - d_b) - P\):

\[ \dot P_{des} = \min\!\left(\dot P_{max},\ \sqrt{2\, \ddot P_{max}\, E}\right), \qquad \dot P \leftarrow \operatorname{move}(\dot P,\ \dot P_{des},\ \ddot P_{max}\, \Delta t), \qquad P \leftarrow P + \dot P\, \Delta t \]

Release. When the delayed command is not more than the line pressure, the pressure decreases with a lag. The time constant increases as the pressure decreases.

\[ \tau_r(P) = \tau_{10} \left(\frac{10}{\max(0.1,\ P)}\right)^{k_r}, \qquad P \leftarrow \operatorname{lag}\!\left(P,\ P_c(t - d_b),\ \tau_r(P)\right) \]

\(\tau_{10}\) is 0.0415 s, the lag at 10 bar. \(k_r\) is 0.695. The pressure thus decreases fast at first and slowly at the end.

Output. The wheels and the report use \(\operatorname{clamp}(P + P_{bias}, 0, P_{max})\). \(P_{bias}\) is 0 for the calibrated vehicle.

ULC#

Source: StepDbw.

The ULC controls the speed with the throttle pedal and the brake pressure.

ULC speed loop: the reference generator shapes the speed command, the error between the reference and the wheel speed gives an acceleration demand, the pedal selection chooses the throttle law, the brake pressure law or the stop hold, and the outputs go to the pedal emulation and the brake actuator of the vehicle. ULC speed loop ULC command signed speed, limits Reference speed reference, jerk limited Σ + − Demand accel reference plus gain × error Pedal selection throttle above 0.35, brake below −0.30 error demand accel reference Throttle law offset, accel term, error and integral Brake pressure law mass estimate × demand Stop hold 16 bar below 0.1 m/s throttle brake standstill Pedal emulation throttle pedal, percent Brake actuator line pressure, bar delay 0.03 s delay 0.03 s Vehicle model engine, CVT, driveline, brakes and wheels in the engaged gear Wheel speed mean of 4 wheels × scale 0.93 measured speed The loop uses speeds along the direction of the engaged gear. A user throttle command or a user brake command stops the ULC.
The speed loop of the ULC as the code computes it. Open the diagram

Measured speed. The wheel speed is the mean spin of the four wheels at the unloaded tyre radius, with the speed scale \(\kappa_v\) = 0.9304.

\[ v_w = s_g\, \kappa_v\, R_t \left\lvert \tfrac{1}{4} \sum_{j=0}^{3} \omega_j \right\rvert, \qquad v_u = v_w + v_{bias} \]

The report field vehicle_velocity_propulsion uses the two rear wheels. \(v_{bias}\) is 0 for the calibrated vehicle. The real wheel speed signal reads low: the ULC held 1.338 m/s for a command of 1.2 m/s in the grass log. The scale reproduces this.

Start. When the ULC gets control, \(v_{ref} = v_u\), \(a_{ref} = 0\), \(I_e = 0\) and the ULC selects no pedal.

Reference, velocity type. The loop uses speeds along the gear direction. The goal is \(G = s_g \operatorname{clamp}(v_{cmd}, -45, 45)\). With \(V = s_g v_{ref}\) and \(E = G - V\):

\[ \rho = \begin{cases} \min\!\left(a_{max},\ \sqrt{2\, j_b\, E}\right) & E > 0 \\ -\min\!\left(d_{max},\ \sqrt{2\, j_t\, \lvert E\rvert}\right) & E < 0 \\ 0 & \lvert E\rvert < 10^{-9} \end{cases} \]
\[ a_{ref} \leftarrow \operatorname{move}_2(a_{ref},\ \rho,\ j_t\, \Delta t,\ j_b\, \Delta t), \qquad V \leftarrow V + \rho\, \Delta t, \qquad v_{ref} = s_g V \]

The jerk limits in the square roots are intentional. Positive acceleration returns to zero with brake jerk. Negative acceleration returns to zero with throttle jerk. Tests with unequal limits check both travel directions and both signs of speed error. They also check that the speed reference reaches its goal without overshoot.

When the step goes across the goal, \(V\) becomes \(G\). The defaults of the limits are \(a_{max}\) = 1.2 m/s², \(d_{max}\) = 1.5 m/s² and \(j_t = j_b\) = 1 m/s³.

Reference, acceleration type. The command is the acceleration reference. The speed reference follows the measured speed.

\[ a_{ref} \leftarrow \operatorname{move}_2\!\left(a_{ref},\ \operatorname{clamp}(\text{cmd}, -6, 3),\ j_t\, \Delta t,\ j_b\, \Delta t\right), \qquad v_{ref} = v_u \]

Demand. The error and the acceleration demand are:

\[ e = s_g\, (v_{ref} - v_u), \qquad a_d = a_{ref} + K_p\, e \]

Stop hold. The stop hold is active when the vehicle is stationary and the reference does not ask for motion.

\[ \lvert v_w\rvert < v_{stop} \ \text{ and } \ \left(a_{ref} < 0 \ \text{ or } \ \left(\lvert v_{ref}\rvert < v_{stop} \text{ and } \lvert v_{goal}\rvert < v_{stop}\right)\right) \]

\(v_{stop}\) is 0.1 m/s. \(v_{goal}\) is the limited command. In the acceleration type it is \(v_u + a_{ref}\). The stop hold asks for 20 % of the full-scale pressure, 16 bar. It sets \(I_e = 0\) and selects no pedal.

Pedal selection. Without the stop hold, the demand selects the pedal with hysteresis.

Condition Selected Pedal
\(a_d > 0.35\) m/s² Throttle
\(a_d < -0.30\) m/s² Brake. No pedal when coast_decel is true.
Between the two thresholds The pedal of the previous step stays.

Throttle law. The proportional term increases with the measured speed up to the launch speed \(v_l\) = 0.5 m/s.

\[ \phi = \operatorname{clamp}\!\left(\frac{\lvert v_u\rvert}{\max(0.01,\ v_l)}, 0, 1\right) \]
\[ q_{ulc} = \operatorname{clamp}\!\left(q_0 + g_a\, a_{ref} + g_v\, \phi\, e + g_i\, I_e,\ 0,\ 100\right) \]

At standstill \(\phi\) is 0. The ULC then starts the vehicle with the offset and the integral only.

Brake pressure law. The pressure decelerates the mass estimate \(m_u\) at the demand.

\[ P_{ulc} = \operatorname{clamp}\!\left(\frac{m_u\, (-a_d)\, R_t}{\max(1,\ 2 (G_f + G_r))},\ 0,\ P_{max}\right) \]

Integral. Each step without the stop hold adds the error.

\[ I_e \leftarrow \operatorname{clamp}(I_e + e\, \Delta t,\ -I_{max},\ I_{max}) \]

Output. The requests \(q_{ulc}\) and \(P_{ulc}\) go to the pedal emulation and the brake after the delay \(d_u\) = 0.03 s.

Reverse. The gear direction \(s_g\) gives the sign. In reverse the command, the reference and the measured speed are negative. A command against the gear direction asks for a stop, for example a positive speed in reverse.

The ULC does not change the gear. A client must stop the vehicle and send a gear command. The gear manager of the scouting task does this for a signed speed command. Refer to Framework.

Without control. \(v_{ref}\) follows \(v_u\). \(a_{ref}\), \(I_e\) and \(a_d\) are 0. The stop hold is off.

Reports#

Source: AAcresVehiclePawn::PublishPolaris, FAcresRlBridge::SendDbwReports, FDbwPath::Publish.

The model makes one report at each 0.02 s of physics time, thus 50 Hz. A physics step is 1/120 s. The interval between two reports is thus 2 or 3 steps. A pause of more than one report period starts the report grid again. The report goes to the vehicle bridge as one line of the type dbw_report. The ROS 2 bridge publishes its parts on the report topics.

Part Field Value
steering_report steering_wheel_angle \(\theta_{sw}\) in degrees
cmd The steering reference \(\theta_r\) in degrees
cmd_type, enabled, override_active, timeout The command type and the status flags
throttle_report percent_input The pedal of the driver
percent_cmd, percent_output \(q_c\) and \(q\)
brake_report pressure_input The pressure of the driver in bar
pressure_cmd, pressure_output \(P_c\) and the output pressure in bar
percent_cmd, percent_output The same values in percent of 80 bar
gear_report gear, cmd, driver The engaged gear, the gear command and the gear lever
ulc_report vel_ref, vel_meas \(v_{ref}\) and \(v_w\)
accel_ref, accel_meas \(a_{ref}\) and the measured acceleration
vehicle_velocity vehicle_velocity_brake, vehicle_velocity_propulsion The wheel speed of four wheels and of the rear wheels
dir_src 1: the gear gives the sign
system_report enabled, override The system enable and the override flag
Top level agent, t The name of the agent and the physics time in seconds
drive_mode, road_wheel_rad, stop_hold The AWD switch, the bicycle angle and the stop hold

The measured acceleration is the derivative of \(v_w\) after a first-order lag of 0.1 s. The throttle and the brake report the type 14 or 1 while the ULC drives them.

This report is from a session of the packaged game. The vehicle was stationary and the stop hold was active. The game sends the report as one line. The line breaks are only for this page.

{"type":"dbw_report","agent":"polaris","t":30.0000,
 "steering_report":{"steering_wheel_angle":12.500,"cmd":12.500,"cmd_type":2,"enabled":true,
                    "override_active":false,"timeout":false},
 "throttle_report":{"percent_input":0.000,"percent_cmd":0.000,"percent_output":0.000,"cmd_type":14,
                    "enabled":true,"override_active":false,"timeout":false},
 "brake_report":{"pressure_input":0.000,"pressure_cmd":16.000,"pressure_output":16.000,
                 "percent_cmd":20.000,"percent_output":20.000,"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":0.0000,"vel_meas":0.0005,"accel_ref":0.0000,"accel_meas":-0.0003,
               "enabled":true,"timeout":false},
 "vehicle_velocity":{"vehicle_velocity_brake":0.0005,"vehicle_velocity_propulsion":0.0005,"dir_src":1},
 "system_report":{"enabled":true,"override":false},
 "drive_mode":2,"road_wheel_rad":-0.00005,"stop_hold":true}

The game also writes the reports to dbw.csv in the session folder. It does this with -SessionLog, -VehicleRecord or -DbwLog. Session Log gives the columns.

Hardware Shifts#

Source: FDbwParameters, AAcresVehiclePawn::AsyncPhysicsTickActor.

Four offsets change the vehicle during a session. They are 0 for the calibrated vehicle. The simulator control channel sets them. Refer to Simulator Control Channel.

Offset Key of the Object shift Effect
Steering offset steering_offset_deg The steering centre becomes \(\theta_c\) minus the offset.
ULC speed bias \(v_{bias}\) ulc_speed_bias_mps The ULC adds it to the measured speed. The vehicle then moves slower by this value.
Throttle bias \(q_{bias}\) throttle_bias_pct The pedal emulation adds it to the pedal.
Brake bias \(P_{bias}\) brake_bias_bar The brake output adds it to the line pressure.

The Game and ACRES Core#

The game and ACRES Core use the same model. Some parts are the same source file and some parts are a second implementation of the same logic.

Part Game ACRES Core
Actuators, watchdog and ULC AcresUtvModel.cpp, StepDbw The same source file
Command clock and queue AcresCommandTiming.h The same header
Messages to the inbox FAcresRlBridge::HandleDbw FDbwPath::Post in ROS/acres_core_sim
Command of one step AAcresVehiclePawn::StepPolarisControls FDbwPath::Step
Report fields and the 50 Hz grid PublishPolaris, SendDbwReports FDbwPath::Publish, FDbwPath::ReportJson
Chassis Chaos rigid body FAcresPolaris::Step in Core/Source/AcresCorePolaris.cpp
Keyboard, override, session driver Yes No

Core/Scripts/replay_logs.py replays the recorded logs in the two chassis models and compares them. Refer to Calibrate against Real Logs.

Parameters#

The keys are in the block dbw of Acres/Content/Simulation/polaris.json.

Name Type Unit Default Description
dbw.command_timeout_s number s 0.1 The command timeout of a subsystem.
dbw.ulc_actuator_timeout_s number s 0.087 The time that the throttle and the brake keep the last output of the ULC.
dbw.speed_scale number 0.9304 The wheel speed of the reports divided by the spin multiplied by the tyre radius.
dbw.steering.default_rate_deg_s number deg/s 100 The rate limit of the steering reference when cmd_rate is 0.
dbw.steering.default_accel_deg_s2 number deg/s² 500 The acceleration limit of the steering reference when cmd_accel is 0.
dbw.steering.delay_s number s 0.0205 The transport delay of the steering servo.
dbw.steering.tau_s number s 0.1323 The first-order lag of the steering servo.
dbw.steering.slew_deg_s number deg/s 500 The slew limit of the column motor.
dbw.steering.lock_deg number deg 487 The limit of the steering wheel angle.
dbw.steering.command_range_deg number deg 280 The range of the angle type and of the percent type.
dbw.steering.max_curvature_per_m number 1/m 0.2 The range of the curvature type.
dbw.steering.max_yaw_rate_rad_s number rad/s 8.5 The range of the yaw rate type.
dbw.steering.kinematic_ratio number 0 The steering ratio of the curvature map. 0 uses steering.ratio.
dbw.steering.kinematic_wheelbase_m number m 0 The wheelbase of the curvature map. 0 uses geometry.wheelbase_m.
dbw.throttle.delay_s number s 0.0 The delay of the pedal emulation.
dbw.throttle.default_rate_pct_s number %/s 0 The default rate limit of the pedal. 0 is no limit.
dbw.brake.max_bar number bar 80 The full-scale pressure.
dbw.brake.delay_s number s 0.0333 The delay of the brake actuator.
dbw.brake.apply_accel_bar_s2 number bar/s² 690.2405 The acceleration limit of the pressure increase.
dbw.brake.slew_bar_s number bar/s 200 The rate limit of the pressure increase.
dbw.brake.release_tau_s number s 0.0415 The release lag at 10 bar.
dbw.brake.release_exponent number 0.695 The exponent of the release lag.
dbw.gear.shift_s number s 1.0 The duration of a gear change.
dbw.gear.max_speed_mps number m/s 0.3 The maximum speed for a gear change.
dbw.ulc.default_accel_mps2 number m/s² 1.2 The acceleration limit when limit_accel is 0.
dbw.ulc.default_decel_mps2 number m/s² 1.5 The deceleration limit when limit_decel is 0.
dbw.ulc.default_jerk_throttle_mps3 number m/s³ 1.0 The jerk limit when limit_jerk_throttle is 0.
dbw.ulc.default_jerk_brake_mps3 number m/s³ 1.0 The jerk limit when limit_jerk_brake is 0.
dbw.ulc.kp number 1/s 1.0 The gain \(K_p\) of the acceleration demand.
dbw.ulc.delay_s number s 0.03 The delay \(d_u\) of the outputs of the ULC.
dbw.ulc.throttle_offset_pct number % 13.2426 The offset \(q_0\) of the throttle law.
dbw.ulc.throttle_accel_pct number %/(m/s²) 0.7056 The gain \(g_a\) of the acceleration reference.
dbw.ulc.throttle_speed_pct number %/(m/s) 27.2515 The gain \(g_v\) of the speed error.
dbw.ulc.throttle_integral_pct number %/m 5.8321 The gain \(g_i\) of the integral.
dbw.ulc.integral_limit_m number m 5 The limit \(I_{max}\) of the integral.
dbw.ulc.launch_speed_mps number m/s 0.5 The launch speed \(v_l\).
dbw.ulc.throttle_on_mps2 number m/s² 0.35 The demand above which the ULC selects the throttle.
dbw.ulc.brake_on_mps2 number m/s² -0.3 The demand below which the ULC selects the brake.
dbw.ulc.mass_kg number kg 1250 The mass estimate \(m_u\) of the brake pressure law.
dbw.ulc.stop_brake_pct number % 20 The brake of the stop hold.
dbw.ulc.stop_speed_mps number m/s 0.1 The speed \(v_{stop}\) of the stop hold.

The fit to the logs gives these values with their standard errors. The file Tools/PolarisModel/Data/fit_results.json contains the full results.

Key Fitted Value Standard Error Log
dbw.command_timeout_s 0.100 s 0.004 s dbw_direct_test_01
dbw.ulc_actuator_timeout_s 0.087 s 0.004 s dbw_direct_test_01
dbw.steering.delay_s 0.0205 s 0.0567 s dbw_direct_test_01
dbw.steering.tau_s 0.1323 s 0.0639 s dbw_direct_test_01
dbw.brake.delay_s 0.0333 s 0.0033 s dbw_direct_test_01
dbw.brake.apply_accel_bar_s2 690.2 bar/s² 34.8 bar/s² dbw_direct_test_01
dbw.brake.release_tau_s 0.0415 s 0.0075 s dbw_direct_test_01
dbw.brake.release_exponent 0.695 0.169 dbw_direct_test_01
dbw.ulc.throttle_offset_pct 13.24 % 0.28 % dbw_direct_test_01
dbw.ulc.throttle_accel_pct 0.71 0.52 dbw_direct_test_01
dbw.ulc.throttle_integral_pct 5.83 0.70 dbw_direct_test_01
dbw.ulc.throttle_speed_pct 27.25 9.75 grass_diag_20260731_174757
dbw.speed_scale 0.9304 0.0336 grass_diag_20260731_174757

The delay and the lag of the steering have a correlation of -0.89. Their sum is 0.153 s with a standard error of 0.030 s.

Code Map#

Item File Function
Parameters and state Acres/Source/Acres/AcresUtvModel.h FDbwParameters, FDbwCommand, FDbwState
Watchdog, actuators, ULC Acres/Source/Acres/AcresUtvModel.cpp StepDbw
Reference generator, delay line Acres/Source/Acres/AcresUtvModel.cpp Reference, Delayed
Curvature map Acres/Source/Acres/AcresUtvModel.cpp CurvatureToSteeringWheelDeg
Brake output Acres/Source/Acres/AcresUtvModel.cpp UtvBrakeOutputBar
Command clock and queue Acres/Source/Acres/AcresCommandTiming.h FCommandClock, TTimedCommands
Messages of the vehicle bridge Acres/Source/Acres/AcresRlBridge.cpp FAcresRlBridge::HandleDbw, BeginCommandRead
Command of one step, override Acres/Source/Acres/AcresPolaris.cpp AAcresVehiclePawn::StepPolarisControls
Reports Acres/Source/Acres/AcresPolaris.cpp, AcresRlBridge.cpp PublishPolaris, FlushDbwReports, SendDbwReports
Command path of ACRES Core ROS/acres_core_sim/src/CoreSimDbw.cpp FDbwPath
ROS 2 topics ROS/acres_sim/src/vehicle_bridge.cpp The subscriptions of vehicle/*/cmd
Messages ROS/vendor/ds_dbw_msgs/msg SteeringCmd.msg, UlcCmd.msg and the other files
Tests Tools/PolarisModel/polaris_tests.cpp Groups 5, 9, 11 and 12
Proofs Verification/AcresVerification CommandTiming.lean, Watchdog.lean

Limitations#

  • The fit of the actuators uses one log of 20 s in which the vehicle was stationary.
  • The steering servo is linear. The recorded step shows an undershoot of 2.3° that the model does not reproduce.
  • The log never reached the slew limit of the steering and the rate limit of the brake. These two values are estimates.
  • The structure of the ULC comes from its recorded behaviour and not from its firmware.
  • The proportional gain of the ULC comes from one log at 1.3 m/s on grass. Its standard error is large.
  • On firm ground the ULC changes between the throttle and the brake, and the speed oscillates around the command. In a session of the packaged game, the wheel speed was 1.5 to 2.4 m/s for a command of 2 m/s.
  • The default limits of the real ULC change with the speed. The model uses constant defaults.
  • No document gives the kinematic ratio and the wheelbase of the real curvature mode.
  • The model does not have these functions of the real system: latched overrides, fault flags, the CRC and the rolling counter.

References#

  • Dataspeed Inc. Drive-by-Wire System Overview: the control modes of the Polaris Ranger and the ULC.
  • Dataspeed Inc. ds_dbw_msgs 2.3.11: the message definitions. The repository has a copy in ROS/vendor/ds_dbw_msgs.
  • Recorded logs of the Purdue Polaris Ranger: dbw_direct_test_01 and grass_diag_20260731_174757. The event tables are in Tools/PolarisModel/Data.