Skip to content

The multirate MPC model does not compile for the run_ode! / mpc_gui route (upstream clock-inference bug) #27

Description

@baggepinnen

FurutaMPCMultirateHardware cannot be compiled for the run_ode! route -- the one that steps a
program's clocked partition with an ODE solver against the device so that the MPC's predicted
trajectories are recorded for MPCComponents.mpc_gui. The single-rate FurutaMPCHardware compiles
for it (see the second half of test/hardware_mpc.jl); the multirate model does not:

spec = program_spec(FurutaMPCMultirateHardware)
model = FurutaMPCMultirateHardware(; name = spec.name, log_file = "run_mpc_gui.csv", spec.ode_kwargs...)
ssys = mtkcompile(model; additional_passes = [SynchToolkit.compile_lustre])
ERROR: ArgumentError: Found clock partition with multiple associated clocks. Involved variables:
[control_system₊estimator_elbow₊rate(t), ..., (control_system₊mpc₊u(t))[1], ...,
 ModelingToolkitBase.SampleTime(nothing)(), ...]

The sensing partition and the MPC's have been merged into one. realtime = true is the whole
cause -- output_trajectories has nothing to do with it, and with realtime = false the model
compiles:

(realtime = false, output_trajectories = true)  -> compiles
(realtime = false, output_trajectories = false) -> compiles
(realtime = true,  output_trajectories = false) -> Found clock partition with multiple associated clocks

The cause is upstream, in ModelingToolkit's clock inference:
JuliaComputing/StateSelection.jl#159. SampleTime() is a single nullary symbolic term, and while
its substitution by a period is per equation and correct, inference treats the term as a variable
and therefore as a graph node shared by every equation that mentions it. Two equations on two
clocks that both mention it become one partition with two clocks. A model may contain at most one
SampleTime() if it has more than one clock.

This model has exactly two: HardwareMeasurement's SampleTimeSource, on the sensing clock (it is
what keeps hw_measure in the equations rather than evaluated while the model is built), and
HardwareDiagnostics', used only in the realtime branch, on the MPC's clock. Both are in
dyad/hardware_loop.dyad.

A local workaround exists and is deliberately not applied: giving HardwareDiagnostics the period
it paces to as an ordinary Ts parameter -- defaulting to SampleTime() so that every single-rate
program stays as it is, and passed as a number by FurutaMPCMultirateHardware -- removes the second
mention, and the dep input still anchors the pacing call in the equations, so the
SampleTimeSource subcomponent can go. Measured on the route it unblocks, a 0.5 s run against
bound callbacks gives 100 MPC solves and 500 encoder reads and estimator updates, x_pred of
nx × (Np + 1) per solve, late recorded on the MPC's clock only, and elapsed reaching 0.497 s,
so the pacing is on the wall clock and mpc_gui has what it reads. Whether to carry that workaround
or wait for the upstream fix is what this issue is for.

Until then: the multirate controller runs on the rig through the compiled program
(compile_program → ProgramRuntime → run_inprocess!), which is unaffected -- run_inprocess!
keeps time in its own loop and needs no realtime pacing inside the model. What is unavailable is
the mpc_gui inspection route for the multirate controller.

Two caveats on that route regardless of this issue, both documented in FurutaMPCMultirateHardware:
realtime = true paces the MPC's clock only, so the five fast reads bunch just before each MPC slot
instead of spreading, which makes it a route for inspecting predictions rather than a substitute for
a rig run; and the GUI itself has not been opened on a multirate solution, only the data it consumes
checked.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions