Repository navigation
feat: optional MPC command-delay compensation (Subburaman & Stasse 2024) - #159
Conversation
Subburaman & Stasse, "Delay Robust MPC for Whole-Body Torque Control of Humanoids" (Humanoids 2024). Three new params, all off by default: - reference_interpolation: slide the feedback reference from the received knot to the next knot (read from a new mpc_x_next topic) across the MPC cycle instead of holding it, killing the staircase reference. - mpc_period: MPC solve period, to normalise the interpolation factor. - feedback_lowpass_cutoff_hz: optional 2nd-order Butterworth on u_fb. No-op until the MPC node publishes knot 1 + mpc_x_next and the param is on.Fixed-base only. Tested on TIAGo Pro 25.
debug_publish param -> publishes a std_msgs/Float64MultiArray each control cycle: [time, alpha, q_ref, v_ref, u_ff, u_fb_raw, u_fb, u_cmd], layout.dim labels the blocks. Realtime-safe (try-lock RealtimePublisher). Off by default; for offline analysis of the interpolation / low-pass.
for more information, see https://pre-commit.ci
Scalar param multiplying the Riccati feedback torque K*(x - x_ref) before it is added to the feedforward: control = feedforward + feedback_gain_scale * u_fb.
reference_interpolation now reads its interpolation target directly from input_control_.next_states.front() (populated by controlMsgToEigen from the /control message itself) instead of a separate mpc_x_next subscription.
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
|
@clementPene I greatly appreciate your contribution. |
Yes but commits b5ca4e2 and e4b111b need to be revert one's loco-3d/linear-feedback-controller-msgs#81 is merged, because I modified messages. |
@nim65s Will handle that once merged. |
|
@olivier-stasse could you take quick look or at least acknowledge that you see that this PR exists. @nim65s could you take a look? I will review as will. @LouiseMsn and @timtmit could you take look as well? |
MaximilienNaveau
left a comment
There was a problem hiding this comment.
Some small things need to be debated.
I agree with the current implementation. I think we needed that for a while and thank you @clementPene for making it happen.
I would need the approval of @timtmit and @LouiseMsn and @olivier-stasse to make sure everyone is on the same page. You guys are the main users.
| /// @brief Scale the feedback torque before it is added to the feedforward. | ||
| /// @param scale 1.0 = nominal, 0.0 = feedforward only, 0<s<1 lowers the | ||
| /// fast-loop gain. Applied after the optional low-pass. | ||
| void set_feedback_gain_scale(double scale) { fb_scale_ = scale; } |
There was a problem hiding this comment.
You should make a proper setter here in the sens that you need to check the validity of this parameter.
Either you add assert, and pray someone in release will have compile his code in debug first:
assert (scale_ <= 1.0 && scale_ >= 0.0 && "fb_scale_ must be in [0, 1]"Or you forcibly bound the scale:
if (scale_ > 1.0) { fb_scale_ = 1.0; }
else if (scale_ < 0.0) { fb_scale_ = 0.0; }
else { fb_scale_ = scale; }In anycase you need assume that the user will do something stupid...
| /// @brief Enable a per-joint 2nd-order Butterworth low-pass on the feedback | ||
| /// torque u_fb = K*(x - x_ref). @param cutoff_hz 0 disables it (default). | ||
| /// @param sample_rate_hz the rate compute_control() is called at. | ||
| void configure_feedback_lowpass(double cutoff_hz, double sample_rate_hz); |
There was a problem hiding this comment.
I am not sure I am comfortable with this idea. You would introduce some delay here.
Is there a reference to the paper in this PR?
Do they also add a low pass filter?
There was a problem hiding this comment.
I added the link to the PR description. yes, they use a low pass filter on u_fb because using interpolation creates some oscillations. I had the same result, you can see some graphs here
| # (loco-3d/linear-feedback-controller-msgs#81, not merged upstream | ||
| # yet) -- revert to github:loco-3d/linear-feedback-controller-msgs#main | ||
| # once that PR is merged. | ||
| UPSTREAM_WORKSPACE: github:clementPene/linear-feedback-controller-msgs#feat/control-next-state |
There was a problem hiding this comment.
commits modifying CI are revert. But merging PR on lfc messages is not enough, it needs to be release
| # (loco-3d/linear-feedback-controller-msgs#81, not merged upstream | ||
| # yet) -- remove this override once that PR is merged, CI will then | ||
| # go back to the nixpkgs-released version automatically. | ||
| rosOverrideAttrs.linear-feedback-controller-msgs = { |
There was a problem hiding this comment.
@nim65s to be fixed, loco-3d/linear-feedback-controller-msgs#81 is merged
|
@nim65s could you check the nix integration so we can merge this with passing CI? |
What
Optional MPC command-delay compensation for the fast (LFC) loop, following
Subburaman & Stasse, Delay Robust MPC for Whole-Body Torque Control of
Humanoids (IEEE Humanoids 2024).
Four new parameters, all disabled by default.
reference_interpolationfalsecontrol.initial_state(q, v) is linearly interpolated across the control period towardscontrol.next_states.front(), instead of being held constant. Each state carries its ownheader.stamp; the interpolation period is read from the two stamps, not assumed. Falls back to holding the reference when the control carries nonext_states.feedback_gain_scale1.0K*(x-x_ref)before it is added to the feedforward.0.0= feedforward only (no fast state feedback — pair withremove_gravity_compensation_effortif the low-level does its own gravity compensation).0<s<1lowers the fast-loop gain, e.g. to damp a closed-loop resonance.feedback_lowpass_cutoff_hz0.0u_fbbefore it is added to the feedforward (the paper's u³ step). 0 disables.debug_publishfalse/lfc_debug(std_msgs/Float64MultiArray):[time, alpha, q_ref, v_ref, u_ff, u_fb_raw, u_fb, u_cmd]. Realtime-safe. For offline analysis; off in production.Companion changes
linear_feedback_controller_msgs:Control.msggainsSensor[] next_states(fork branch
feat/control-next-state, not yet a PR) — replaces the oldseparate
mpc_x_nexttopic. Each element carries its ownheader.stamp.agimus_controller: fillsnext_stateson/controlinstead ofpublishing
/mpc_x_next(PR #328, companion). This PR is a no-op untilboth land and
reference_interpolationis enabled.Testing
Exercised on a TIAGo Pro 25 (real robot, fixed-base right-arm deburring demo):
reference_interpolationon: the ~1-MPC-period command lag (measured≈ 11 ms) is compensated; the staircase reference becomes a ramp and
u_fbis smoother.
feedback_lowpass_cutoff_hz: works as a biquad. On our compliant SEA arman aggressive cutoff (40 Hz) excited a closed-loop resonance, so it is
deliberately opt-in and off by default; the paper's ~66 Hz is benign.
feedback_gain_scale: unit-tested (see below); not yet exercised onrobot.
debug_publish: used throughout for offline bag analysis.Unit tests added for
feedback_gain_scaleandfeedback_lowpass_cutoff_hzat the
LFController/LinearFeedbackControllerlevel.next_statesconsumption (
LinearFeedbackControllerRos) has no unit coverage -- thatclass has no test harness at all, pre-existing gap.
Scope / limitations
interp ==
pin::interpolate).feedback_lowpass_cutoff_hzneeds the controller update rate; disabledwith a warning if unknown.