Skip to content

Added support for MPPI Controller to adjust wz_std parameter based on linear speed #5281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: jazzy
Choose a base branch
from

Conversation

vahapt
Copy link

@vahapt vahapt commented Jun 17, 2025

Basic Info

Info Please fill out this column
Ticket(s) this addresses (#5274)
Primary OS tested on (Ubuntu 24.04)
Robotic platform tested on (Gazebo Simulation, physical robot)
Does this PR contain AI generated software? (No)

Description of contribution in a few bullet points

Added feature enables dynamic modification of wz_std (angular deviation) based on linear velocity of the robot.

When a robot with high inertia (e.g. 500kg) is moving fast and if wz_std is above 0.3, oscillation behavior can be observed.
Lowering wz_std stabilizes the robot but then the maneuvers take more time.

Dynamically reducing wz_std as vx, vy increase (speed of the robot) solves both problems.
Suggested values to start with: wz_std = 0.3, wz_std_decay_to = 0.05, wz_std_decay_strength = 5.0

The following is used as the decay function
f(x) = (wz_std - wz_std_decay_to) * e^(-wz_std_decay_strength * v_linear) + wz_std_decay_to

Description of documentation updates required from your changes

2 new parameters are added to nav2_mppi_controller, README.md updated accordingly

  • advanced.wz_std_decay_strength
  • advanced.wz_std_decay_to

Description of how this change was tested

On both physical and simulated robots, changes deployed and parameters changed through live parameter update.
Robot behavior change and oscillation effects observed and confirmed.

It should be noted that tests are performed with a differential drive robot setup, thus holonomic behavior or potential anomalies with ackermann control are not tested yet.

Default configuration disables this feature, thus regression risks are minimal.


Future work that may be required in bullet points

  • Tests on Omnidirectional and Ackermann robots should be performed
  • Unit tests can be added
  • Decay function might be enhanced based on the user feedback

For Maintainers:

  • Check that any new parameters added are updated in docs.nav2.org
  • Check that any significant change is added to the migration guide
  • Check that any new features OR changes to existing behaviors are reflected in the tuning guide
  • Check that any new functions have Doxygen added
  • Check that any new features have test coverage
  • Check that any new plugins is added to the plugins page
  • If BT Node, Additionally: add to BT's XML index of nodes for groot, BT package's readme table, and BT library lists

… linear speed

Signed-off-by: vahapt <5289529+vahapt@users.noreply.github.com>
Copy link
Contributor

mergify bot commented Jun 17, 2025

@vahapt, all pull requests must be targeted towards the main development branch.
Once merged into main, it is possible to backport to @jazzy, but it must be in main
to have these changes reflected into new distributions.

@vahapt vahapt marked this pull request as draft June 17, 2025 15:41
Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the good docs in the readme. Please add that in the config guide too https://docs.nav2.org/configuration/packages/configuring-mppic.html

}

//boundary check, if wz_std_decay_to is out of bounds, print a warning
if (s.sampling_std.wz_std_decay_to < 0.0f || s.sampling_std.wz_std_decay_to > s.sampling_std.wz)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check this in getParams to disable it and warn once on startup? The continuous warning here would be annoying.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the value is changed after startup we should warn again. I'll adjust it to print only once per change.

@@ -419,8 +460,11 @@ void Optimizer::updateControlSequence()
xt::noalias(costs_) +=
s.gamma / powf(s.sampling_std.vx, 2) * xt::sum(
xt::view(control_sequence_.vx, xt::newaxis(), xt::all()) * bounded_noises_vx, 1, immediate);

float wz_std = calculateDecayForAngularDeviation();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't we want to reduce the next iteration's wz_std appropriately? This just impacts the scoring, not reducing the std used in the future for sampling to create less options. I'd like to know more about how you came up with this modification and if it has theoretical backing. I thought this was going to reduce wz_std used in sampling with speed, not only the computation of the optimal trajectory from a fully s.sampling_std.wz-sampled batch

Copy link
Author

@vahapt vahapt Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't we want to reduce the next iteration's wz_std appropriately?

That's correct, I probably missed the actual point and just noticed same value is also used in NoiseGenerator.
Just to make sure we're on the same page, we should also be applying calculated value to this section (noises_wz_) of the code right?

void NoiseGenerator::generateNoisedControls()
{
  auto & s = settings_;

  xt::noalias(noises_vx_) = xt::random::randn<float>(
    {s.batch_size, s.time_steps}, 0.0f,
    s.sampling_std.vx);
  xt::noalias(noises_wz_) = xt::random::randn<float>(
    {s.batch_size, s.time_steps}, 0.0f,
    s.sampling_std.wz);
  if (is_holonomic_) {
    xt::noalias(noises_vy_) = xt::random::randn<float>(
      {s.batch_size, s.time_steps}, 0.0f,
      s.sampling_std.vy);
  }
}

I'd like to know more about how you came up with this modification and if it has theoretical backing.

Initial idea for the modification came up with observing the oscillation behavior of the physical robot.
While the robot is moving I've changed wz_std parameter through rqt. Thus, I should have actually executed future for sampling to create less options properly.
With today's tests I've observed similar stability behavior, apparently it was not the best.

if it has theoretical backing

It's mostly based on field observations. To add some theory, while we're driving a car, the forces exerted on front wheels tends to move the wheels to the center. This implicitly changes driver behavior while steering. I wanted to implement something similar.

Please correct me if I'm missing something.

Copy link
Member

@SteveMacenski SteveMacenski Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should also be applying calculated value to this section (noises_wz_) of the code right?

Yes! Note that regenerate_noises would need to be true with this feature since we'd need to regenerate the noises each iteration since the wz would change (though maybe we could have it only regenerate those that changed values in this case, only wz's.

While the robot is moving I've changed wz_std parameter through rqt.

Got it, so you didn't test the code in this PR yet, correct? This wouldn't have the impact you had in mind, I don't think. I also think that the change of wz then might want to happen in the main function of the optimizer, not in the control sequence -- that way we update the wz to be sampled in a given iteration with the given robot speed. For instance, in the prepare function. Then, the wz should be reset to the parameterized value in the reset function for the next MPPI path to track.

if it has theoretical backing

This was geared towards the question when this was only updating wz used in the cost scoring. If we update it for the actual noised trajectory sampling + scoring, then this is totally fine to change as long as it is consistent within an iteration and the jumps aren't too discontinous.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that regenerate_noises would need to be true
It is true

Got it, so you didn't test the code in this PR yet, correct?

I did test and strangely observed the behavior we were expecting. Once implemented properly, maybe I will be able to reduce the strength from 5.0 to 1.0~2.0.

I also think that the change of wz then might want to happen in the main function of the optimizer, not in the control sequence -- that way we update the wz to be sampled in a given iteration with the given robot speed. For instance, in the prepare function.

Agreed.

Then, the wz should be reset to the parameterized value in the reset function for the next MPPI path to track.

For that part I'm thinking to introduce another wz_optimized (or wz_clamped) internal variable instead of backing up wz, processing it and then restoring it. That would end up in a cleaner code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK!

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
…raints.hpp

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
…raints.hpp

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
@vahapt vahapt requested a review from SteveMacenski June 17, 2025 18:48
@SteveMacenski
Copy link
Member

I see a bunch of things closed and a re-review request, but I don't see any changes pushed

@vahapt
Copy link
Author

vahapt commented Jun 17, 2025

I see a bunch of things closed and a re-review request, but I don't see any changes pushed

I misclicked and github does not provide cancel button :)

@SteveMacenski
Copy link
Member

hah - no worries

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.

2 participants