Skip to content

Drive the demo's traffic on the controller FMU - #48

Draft
edufford wants to merge 3 commits into
mainfrom
traffic-on-fmu
Draft

edufford wants to merge 3 commits into
mainfrom
traffic-on-fmu

Conversation

@edufford

Copy link
Copy Markdown
Owner

Every car the spawner asks for is now [radar, controller, physics],
with the packaged controller FMU as the controller, so it follows the
car ahead in its lane with IDM and wants its spawn speed back on a free
road. The ego and traffic_scale's cars keep constant speed. The ego
does until it shares a lane with traffic, and the scaling run because
it measures the conductor, and an FMU per car is its own experiment.

The world hash moves from eccd08f9a316bbbc to 580e8d37b14c6abd, for
every traffic car's scans and acceleration commands and the poses they
changed. Every traffic car slows somewhat, since IDM brakes for a lead
well before it is close, and the slowest falls from 16.2 to 13.3 m/s.
The ego's poses and the turnover are unchanged: fourteen cars, eight
retired. README's sample output moves with the hash.

The mapping gives the FMU's pose inputs the state the physics is built
from, since at the instant a car joins its controller steps before its
physics has published, and would otherwise steer from the origin. Its
keys are concrete, because a scenario knows its world where a native
constructor does not. Building a car can now fail for a missing package
or an FMU that will not instantiate, so the scenario functions return a
ScenarioError wrapping those beside ConductorError.

Two tests guard following: no two same-lane cars ever overlap, and some
traffic car changes speed by more than 1 m/s. Pointing the radar
binding at a key nobody publishes fails both. A unit test decodes what
one FMU step published as the plant's own AccelCmd and SteerCmd.
Writing it showed a free road is not exactly zero: FREE_ROAD is a
long finite range, so a car at its desired speed is commanded -3e-16.

cargo xtask verify now packages the FMUs before the tests, since the
tests and the demo cannot start without a package, and an edited law
would otherwise pass locally on the copy packaged before it and fail in
CI. It costs 0.7 s when nothing changed. Validation and the comparison
of each package against its laws stay in verify-fmus.

The examples' log drops an FMU's trace of its own calls, about 1,700
lines a run, through one init_logging the six mains share. It drops
a message only when its target is exactly trace and its module path
is the fmu that fmi gives everything an FMU logs. Targets would
match the target as a prefix and cannot see module paths, so it would
silence any target beginning with the word.

Measured and deferred: each FMU car costs about 70 ms to join on
Windows, since fmi 0.8 loads a fresh copy of the DLL per instance,
taking the release demo from 0.07 s to 1.27 s. PLAN.md's deferred list
carries the shared archive that would fix it. The spawner can place a
car right beside one already in the lane, 0.99 m bumper to bumper at
worst with seed 42, since its frontier is where it last spawned rather
than where the cars now are; that is left for the ego-lane change.


Draft notes (deleted before merge)

M6-PLAN.md PR E. Three commits, each passing cargo xtask verify on
its own: verify packaging, traffic on the FMU, the log filter.

  • Review the diff, especially controller_mapping and the two
    highway tests.
  • CI on all four agents agrees on 580e8d37b14c6abd. This is the
    first time the hash runs through the FMU's own compiled laws on
    each platform.
  • Decide whether the spawner fix stays with PR G as agreed.

Found on the way and left alone: PoseLogger re-logs a retired car's
last pose every second, on main too, against the rule that per-actor
state is dropped on leave. Worth an issue or a small PR of its own.

Not run: cargo xtask verify-fmus, since nothing here touches the FMU
crate or the laws it links.

🤖 Generated with Claude Code

edufford and others added 3 commits October 12, 2026 18:23
The demo's traffic is about to drive on the controller FMU, and from
then on neither the tests nor the demo can start without a package.
Leaving packaging to verify-fmus kept the editing loop Rust-only while
nothing in the demo loaded an FMU. After that it would let an edited
law pass locally on the copy packaged before it and fail in CI.

Packaging costs 0.7 s when nothing changed and a release build of the
FMU crate when a law did. Validation with fmpy and the feature-gated
comparison of each package against its laws stay in verify-fmus, since
asking for that feature rebuilds much of the graph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every car the spawner asks for is now [radar, controller, physics],
with the packaged FMU as the controller, so it follows the car ahead
in its lane with IDM and wants its spawn speed back on a free road.
The ego and traffic_scale's cars keep constant speed. The ego does
until it shares a lane with traffic, and the scaling run because it
measures the conductor, and an FMU per car is its own experiment.

The world hash moves from eccd08f9a316bbbc to 580e8d37b14c6abd, for
every traffic car's scans and acceleration commands and the poses
they changed. Every traffic car slows somewhat, the slowest from 16.2
to 13.3 m/s. The ego's poses and the turnover are unchanged: fourteen
cars, eight retired. README's sample output moves with it.

The mapping gives the FMU's pose inputs the state the physics is
built from, since at the instant a car joins its controller steps
before its physics has published. Its keys are concrete, because a
scenario knows its world where a native constructor does not.

Two new tests guard following: no two same-lane cars ever overlap,
and some traffic car changes speed by more than 1 m/s. Pointing the
radar binding at a key nobody publishes fails both. A unit test
decodes what one FMU step published as the plant's own commands.

Measured and deferred: each FMU car costs about 70 ms to join on
Windows, since fmi 0.8 loads a fresh copy of the DLL per instance,
taking the release demo from 0.07 s to 1.27 s. PLAN.md's deferred
list carries the shared archive. The spawner can place a car right
beside one already in the lane, 0.99 m bumper to bumper at worst with
seed 42, and that is left for the ego-lane change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fmi-export reports every FMI call under a trace category, one line
per car per step and about 1,700 a run, and fmi logs them at INFO
with the category as the target. That buries the pose log the demo
exists to show. Turning logging off at instantiation would silence
the FMU's errors too, since they travel the same way.

So the six example mains share one init_logging, whose filter drops
a message only when its target is exactly trace and its module path
is the fmu that fmi gives everything an FMU logs. Targets would have
been shorter and is wrong here: it matches a target as a prefix and
cannot see module paths, so it would silence any target beginning
with the word, from any crate. Giving the filter a wrong module path
brings all 1,730 lines back, which is what shows the module path is
visible when the filter runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant