The multirate MPC at 5 ms over a non-uniform shooting grid - #26
Open
baggepinnen wants to merge 1 commit into
Open
The multirate MPC at 5 ms over a non-uniform shooting grid#26baggepinnen wants to merge 1 commit into
baggepinnen wants to merge 1 commit into
Conversation
`FurutaMPCMultirate` solved at 8 ms over 75 uniform shooting intervals, because the period and the horizon were one number: 0.6 s at 5 ms would have cost 120 decision variables. JuliaComputing/MPCComponents.jl#44 separates them. `ACADOSMPC`'s `time_steps` gives each interval its own length and `linear_time_steps(Ts, Np, horizon)` grows them from `Ts` to span the horizon, so the controller now solves at 5 ms over 50 intervals covering 0.8 s, with the encoders read and the state estimated at 1 ms as before. The first interval stays at `Ts`, the one whose control is applied and held for a clock period. `FurutaMPCMultirate` gains a `horizon` parameter beside `Ts` and `Np` (`horizon = Np * Ts` recovers the uniform grid) and an `integrator_stages` parameter, since a stretched grid makes the integrator's order a real choice. The single-rate `FurutaMPC` is unchanged. Measured with `test/mpc_rollouts.jl`, which gains a multirate mode: it ticks `FurutaMPCMultirateHardware` against the simulated pendulum with the QUBE's encoder quantization, separates the solving ticks from the ticks between them, and takes its whole configuration from `key=value` arguments so that two of them are measured from the same seeds. 50 rollouts of 10 s balanced in all 50 at every configuration; against the previous default the solve falls from 1.23 to 0.82 ms at the median and from 2.78 to 1.64 ms at the 99th percentile of a period that is itself 3 ms shorter, and the catch from 1.04 to 0.36 s from rest and from 1.14 to 0.97 s from the random operating space. The horizon is not what pays for that: a uniform 0.25 s grid at the same `Ts` and `Np` catches sooner still (0.75 s from random starts, 1.07 s at the 90th percentile against 1.47) and halves the nonzero acados statuses, on the identified and on the perturbed plant alike. `energy_weight = 1e5` on the pendulum's energy makes the stage cost a shaping term that plans the pump without seeing the catch, and stretching the grid dilutes it with stage weights of up to 5.4 while pushing the terminal LQR cost 0.8 s out. NOTES.md records the comparison, so that `horizon = Np * Ts` is one word away. Two smaller measurements, also in NOTES.md: one step of the 2-stage integrator over the longest interval is off by up to 4.1 rad/s against a fine reference (0.034 over the shortest), and buying that back with `integrator_stages = 4` costs 65 % more solve time and swings up no better; and `qp_cond_N = 5` survives the re-sweep at `Np = 50`, where 3 to 10 are again within a few percent and 1, 2 and the uncondensed horizon are again worse. The clock documentation asked for a power-of-two ratio between the two periods. What the code needs is an integer ratio whose tick instants coincide exactly in floating point, which 5 x 1 ms does; the three components and `src/mpc.jl` say that now. Both manifests take MPCComponents from the `main` that carries #44, and `Project.toml`'s `[sources]` note names it as the second pull request this package needs from that branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013damsLv5TqkpHHcMi8RdKT
baggepinnen
force-pushed
the
mpc/nonuniform-grid-5ms
branch
from
September 11, 2026 10:51
263e119 to
bb0a49d
Compare
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.
FurutaMPCMultiratenow solves at 5 ms over 50 shooting intervals that cover 0.8 s, with theencoders read and the state estimated at 1 ms as before. The interval count and the horizon are no
longer the same number: JuliaComputing/MPCComponents.jl#44 gave
ACADOSMPCatime_stepsparameter, and
MPCComponents.linear_time_steps(Ts, Np, horizon)lays outNpintervals that growfrom
Tsto span the horizon, so 0.8 s costs 50 decision variables instead of the 160 a uniform5 ms grid would need. The first interval stays at
Ts, the one whose control is applied and heldfor a clock period, and each stage's cost is weighted by its interval's length over
Ts.FurutaMPCMultiratetherefore gains ahorizonparameter besideTsandNp(withhorizon = Np * Tsrecovering the uniform grid) and anintegrator_stagesparameter, since astretched grid makes the integrator's order a real choice rather than a constant. The single-rate
FurutaMPCis untouched.Measurements
test/mpc_rollouts.jlgained a multirate mode: it ticksFurutaMPCMultirateHardwareagainst thesimulated pendulum with the QUBE's encoder quantization, reports the solving ticks against the MPC
period and the ticks in between against the sensing period, and takes the whole configuration from
key=valuearguments so that two of them can be measured from the same seeds. 50 rollouts of 10 s,identified plant, every configuration swinging up and balancing in all 50:
Ts/Np/ horizonintegrator_stages = 4and from the random operating space:
Ts/Np/ horizonThe computational budget is comfortable: 0.82 ms of a 5 ms period at the median and 1.64 ms at the
99th percentile, 17 % utilization against the 15 % the 8 ms controller had, with the same 0.2 % of
solves running over the period as before (the allocation tail NOTES.md already documents). The
solve does not fit a 1 ms sensing slot, as it did not before; that remains jitter on the sensing
clock, and the rig's
dtandexeclog columns are what measure it.One result worth deciding on: the 0.8 s horizon is not what the improvement comes from. A
uniform 0.25 s grid at the same
TsandNpcatches sooner from both start sets (0.75 s against0.97 s at the median from random starts, 1.07 against 1.47 at the 90th percentile, 1.28 against
1.92 in the worst rollout), returns a nonzero acados status half as often, and costs the same. The
same ordering holds on the perturbed plant, where a long horizon should help most: 0.86 / 1.25 /
1.55 s against 1.14 / 2.07 / 3.68 s.
energy_weight = 1e5on the pendulum's energy makes the stagecost a shaping term that plans the pump without needing to see the catch, and stretching the grid
both dilutes that with stage weights of up to 5.4 and pushes the terminal LQR cost 0.8 s out. The
0.8 s horizon asked for is what this branch sets;
horizon = Np * Tsis the whole change to theother, and NOTES.md records the comparison.
Two smaller findings, both in NOTES.md:
the 2-stage scheme over 27 ms is off by up to 4.1 rad/s against a fine reference (0.034 rad/s
over 5 ms). Buying that back with
integrator_stages = 4costs 65 % more solve time and swingsup no better, so the default stays 2.
qp_cond_N = 5survives the smaller horizon. Re-swept atNp = 50: 3 to 10 are within a fewpercent, 1, 2 and the uncondensed horizon are worse -- the same shape as at
Np = 60.Also here
Manifest.tomlandtest/Manifest.tomltake MPCComponents from themainthat carries #44(the tree hash only; the environment is otherwise untouched), and
Project.toml's[sources]note names the second pull request this package needs from that branch.
needs is an integer ratio whose tick instants coincide exactly in floating point, which 5 x 1 ms
does (
m * 0.005 == 5m * 0.001for everym); the prose in the three components and insrc/mpc.jlsays that now.test/mpc_tests.jlpins the new defaults: divisors(1, 5), the MPC solving on ticks 1, 6, 11,16 with one motor write each.
Not covered: no rig run. The device sustaining 1 kHz reads under a 5 ms solve is a measurement on
the hardware, and the log's
dtandexeccolumns are where it shows.🤖 Generated with Claude Code
https://claude.ai/code/session_013damsLv5TqkpHHcMi8RdKT