Repository navigation
xil: the dyno's robot driver takes a transport delay, an actuator function and an accel mode - #421
Merged
Merged
Conversation
yunlishao
approved these changes
Oct 7, 2026
yunlishao-vibe
marked this pull request as ready for review
October 7, 2026 16:16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The simulated dyno's robot driver gets what the ORNL rig work needs to model a real driver (comma.ai openpilot on the hub dyno): a transport delay, a hook for pedal dynamics the application defines itself, and a second control mode that tracks an acceleration command instead of a speed.
RobotDriver(delay_s=...): transport delay on the pedaldelay_sago;(0, 0)until there is one.dt.driver.pedalstays the command just made; only the returned(throttle, brake)is delayed.0.0is off and the default. A default bench is bit-identical to before.RobotDriver(actuator=fn): the application's own pedal dynamicsfn(throttle, brake, dt) -> (throttle, brake), called after the delay, with the last word on what reaches the car. FIXS does not clamp what it returns.fnhas areset(),RobotDriver.reset()calls it.fixs.xil.dynosim(driver={'delay_s': ..., 'actuator': fn}), sofixs/xil.pyis unchanged.RobotDriver(mode='accel'): track the acceleration commandmode='speed'(default) is the existing PI on speed error, bit-identical to before.mode='accel': PI ona_ref - a_meas, no feedforward;v_refis ignored.a_measis dv/dt through a first-order filter (accel_filter_s, 0.1 s).kp_accel0.05,ki_accel0.5. With anarefinferred from speed these are about 3x the speed-mode loop (see below);kp_accel0.0425,ki_accel0.025 match speed mode.max_accel_mps2/max_decel_mps2clampa_refdirectly.a_ref <= 0atv <= standstill_ref_mpsholds the brake.a_refis required in accel mode.What a delay does to the default PI
Dyno alone,
dt0.05, step 0 -> 15 -> 5 m/s, default gains, envelope 1.8 m/s^2:End to end, MLK eco-driving rung 6 (
Transport: udp,startInGear, openpilot hold 0.3 / 0.1), first 200 s of ego time:Same runs with the robot in accel mode (the server still infers
aref = (vref - vdyno) / 0.1):Accel mode at 0.5 and 0.7 s does not drive: the speed saws between 0 and 9-11 m/s, about 4 m/s either side of the advisory. Its launch time, cruise time and distance count that oscillation. One run per cell; after the first light the runs meet different signal phases, so later numbers compare trajectories that have diverged. Of accel mode's 130 stops at 0 s, 121 are in 160-200 s, creeping at a red light 1.6 m from the line: a 0.15 m/s creep sits inside the hold's band, whose
aref < 0.1isv > 0.14under the inferredaref, and accel mode reaches that in a step.At 0.7 s in speed mode the dyno limit-cycles at the 0.15 m/s creep request (0 -> 0.55 -> 0 m/s, about 1.8 s period), with or without the hold. Detuning the PI steadies the creep but lets a 15 m/s step overshoot to 20-22 m/s, so no single gain set covers both.
Why accel mode differs: the same error, with gains times 1/T
Eco-driving sends
vref = v_carla + a_eco*T(T = 0.1 s) and the server infersaref = (vref - v_dyno)/T. Written ine = vref - v_dyno, accel mode is a PID on the same speed error as speed mode:The delay sits in
L(s) = C(s) * b/s * exp(-tau*s)(b ~ 7.25 m/s^2 per unit pedal below base speed). Linearised: speed mode crosses over near 3.3 rad/s with ~67 deg of phase margin, a delay margin of ~0.35 s, which matches the dyno-alone table above; default accel mode crosses near 9 rad/s with ~37 deg, a delay margin of ~0.07 s.Dyno alone, creep 0.15 m/s for 20 s then 10 m/s (creep range / step peak / last 20 s):
So with
arefinferred from speed, the mode choice is a gain choice. The modes differ in kind only if the rig receives eco-driving's owna_eco(the packet's second float is unused).Related Issues
No tracker. Follows #416. The application side (the knob in
udp_dyno_server.py) goes to ORNL-Real-Sim/FIXS_Applications ontest/xil_udp_lockstep.How to test
New in
test_xil_dyno.py: accel mode (tracks a constanta_ref, ignoresv_ref, clamps to the envelope, holds at rest, needsa_ref, unknown mode refused); the delayed output equals an undelayed driver's output fromdelay_searlier;reset()empties the delay line and resets the actuator; the actuator sees the delayed command and has the last word; a 0.2 s delay still settles on 15 m/s.Checklist
tests/Python/unit: 530 passed, 8 skipped)