From 5ea887337f5e237131c667fdf1393856df2c52ad Mon Sep 17 00:00:00 2001
From: "V. Oguz TOKMAK" <5289529+vahapt@users.noreply.github.com>
Date: Thu, 19 Jun 2025 21:49:12 +0300
Subject: [PATCH 1/6] Added support for MPPI Controller to adjust wz_std
parameter based on linear speed
Signed-off-by: V. Oguz TOKMAK <5289529+vahapt@users.noreply.github.com>
---
nav2_mppi_controller/README.md | 43 ++++++++--------
.../models/constraints.hpp | 38 ++++++++++++++
.../models/optimizer_settings.hpp | 1 +
.../nav2_mppi_controller/models/state.hpp | 10 +++-
.../nav2_mppi_controller/optimizer.hpp | 7 +++
.../tools/noise_generator.hpp | 2 +-
nav2_mppi_controller/src/noise_generator.cpp | 23 +++++++--
nav2_mppi_controller/src/optimizer.cpp | 50 +++++++++++++++++--
nav2_mppi_controller/test/critics_tests.cpp | 12 ++---
nav2_mppi_controller/test/models_test.cpp | 3 +-
.../test/motion_model_tests.cpp | 8 +--
.../test/noise_generator_test.cpp | 10 ++--
.../test/optimizer_unit_tests.cpp | 13 +++--
13 files changed, 170 insertions(+), 50 deletions(-)
diff --git a/nav2_mppi_controller/README.md b/nav2_mppi_controller/README.md
index 68db5b73719..448dbb89282 100644
--- a/nav2_mppi_controller/README.md
+++ b/nav2_mppi_controller/README.md
@@ -38,26 +38,29 @@ This process is then repeated a number of times and returns a converged solution
## Configuration
### Controller
- | Parameter | Type | Definition |
- | --------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
- | motion_model | string | Default: DiffDrive. Type of model [DiffDrive, Omni, Ackermann]. |
- | critics | string | Default: None. Critics (plugins) names |
- | iteration_count | int | Default 1. Iteration count in MPPI algorithm. Recommend to keep as 1 and prefer more batches. |
- | batch_size | int | Default 1000. Count of randomly sampled candidate trajectories |
- | time_steps | int | Default 56. Number of time steps (points) in each sampled trajectory |
- | model_dt | double | Default: 0.05. Time interval (s) between two sampled points in trajectories. |
- | vx_std | double | Default 0.2. Sampling standard deviation for VX |
- | vy_std | double | Default 0.2. Sampling standard deviation for VY |
- | wz_std | double | Default 0.4. Sampling standard deviation for Wz |
- | vx_max | double | Default 0.5. Max VX (m/s) |
- | vy_max | double | Default 0.5. Max VY in either direction, if holonomic. (m/s) |
- | vx_min | double | Default -0.35. Min VX (m/s) |
- | wz_max | double | Default 1.9. Max WZ (rad/s) |
- | temperature | double | Default: 0.3. Selectiveness of trajectories by their costs (The closer this value to 0, the "more" we take in consideration controls with less cost), 0 mean use control with best cost, huge value will lead to just taking mean of all trajectories without cost consideration |
- | gamma | double | Default: 0.015. A trade-off between smoothness (high) and low energy (low). This is a complex parameter that likely won't need to be changed from the default of `0.1` which works well for a broad range of cases. See Section 3D-2 in "Information Theoretic Model Predictive Control: Theory and Applications to Autonomous Driving" for detailed information. |
- | visualize | bool | Default: false. Publish visualization of trajectories, which can slow down the controller significantly. Use only for debugging. |
- | retry_attempt_limit | int | Default 1. Number of attempts to find feasible trajectory on failure for soft-resets before reporting failure. |
- | regenerate_noises | bool | Default false. Whether to regenerate noises each iteration or use single noise distribution computed on initialization and reset. Practically, this is found to work fine since the trajectories are being sampled stochastically from a normal distribution and reduces compute jittering at run-time due to thread wake-ups to resample normal distribution. |
+ | Parameter | Type | Definition |
+ |----------------------------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+ | motion_model | string | Default: DiffDrive. Type of model [DiffDrive, Omni, Ackermann]. |
+ | critics | string | Default: None. Critics (plugins) names |
+ | iteration_count | int | Default 1. Iteration count in MPPI algorithm. Recommend to keep as 1 and prefer more batches. |
+ | batch_size | int | Default 1000. Count of randomly sampled candidate trajectories |
+ | time_steps | int | Default 56. Number of time steps (points) in each sampled trajectory |
+ | model_dt | double | Default: 0.05. Time interval (s) between two sampled points in trajectories. |
+ | vx_std | double | Default 0.2. Sampling standard deviation for VX |
+ | vy_std | double | Default 0.2. Sampling standard deviation for VY |
+ | wz_std | double | Default 0.4. Sampling standard deviation for Wz |
+ | vx_max | double | Default 0.5. Max VX (m/s) |
+ | vy_max | double | Default 0.5. Max VY in either direction, if holonomic. (m/s) |
+ | vx_min | double | Default -0.35. Min VX (m/s) |
+ | wz_max | double | Default 1.9. Max WZ (rad/s) |
+ | temperature | double | Default: 0.3. Selectiveness of trajectories by their costs (The closer this value to 0, the "more" we take in consideration controls with less cost), 0 mean use control with best cost, huge value will lead to just taking mean of all trajectories without cost consideration |
+ | gamma | double | Default: 0.015. A trade-off between smoothness (high) and low energy (low). This is a complex parameter that likely won't need to be changed from the default of `0.1` which works well for a broad range of cases. See Section 3D-2 in "Information Theoretic Model Predictive Control: Theory and Applications to Autonomous Driving" for detailed information. |
+ | visualize | bool | Default: false. Publish visualization of trajectories, which can slow down the controller significantly. Use only for debugging. |
+ | retry_attempt_limit | int | Default 1. Number of attempts to find feasible trajectory on failure for soft-resets before reporting failure. |
+ | regenerate_noises | bool | Default false. Whether to regenerate noises each iteration or use single noise distribution computed on initialization and reset. Practically, this is found to work fine since the trajectories are being sampled stochastically from a normal distribution and reduces compute jittering at run-time due to thread wake-ups to resample normal distribution. |
+ | advanced.wz_std_decay_strength | double | Default: -1.0 (disabled). Defines the strength of the reduction function.
Allows 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.4, wz_std_decay_to = 0.05, wz_std_decay_strength = 3.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`
[Playground](https://www.wolframalpha.com/input?i=plot+%5B%28a-b%29+*+e%5E%28-c+*+x%29+%2B+b%5D+with+a%3D0.5%2C+b%3D0.05%2C+c%3D3) |
+ | advanced.wz_std_decay_to | double | Default: 0.0. Target wz_std value while linear speed goes to infinity. Must be between 0 and wz_std. Has no effect if `advanced.wz_std_decay_strength` <= 0.0 |
+
| publish_optimal_trajectory | bool | Publishes the full optimal trajectory sequence each control iteration for downstream control systems, collision checkers, etc to have context beyond the next timestep. |
diff --git a/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp b/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
index bd8b972473d..ed9c434e92b 100644
--- a/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
+++ b/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
@@ -46,6 +46,44 @@ struct SamplingStd
float wz;
};
+struct AdvancedConstraints
+{
+ // TODO(vahapt): also add documentation to https://github.com/ros-navigation/docs.nav2.org/blob/master/configuration/packages/configuring-mppic.rst
+ /**
+ * @brief Defines the strength of the reduction function
+ * Allows 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.4, wz_std_decay_to = 0.05, wz_std_decay_strength = 3.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+ * Playground + * Default: -1.0 (disabled) + */ + float wz_std_decay_strength; + + /** + * @brief Target wz_std value while linear speed goes to infinity. + * Must be between 0 and wz_std. + * Has no effect if `advanced.wz_std_decay_strength` <= 0.0 + * Default: 0.0 + */ + float wz_std_decay_to; + + bool validateWzStdDecayTo(const float & initial_wz_std) + { + // Assume valid if angular decay is disabled + if (wz_std_decay_strength <= 0.0f) { + return true; + } + + if (wz_std_decay_to < 0.0f || wz_std_decay_to > initial_wz_std) { + return false; + } + return true; + } +}; + } // namespace mppi::models #endif // NAV2_MPPI_CONTROLLER__MODELS__CONSTRAINTS_HPP_ diff --git a/nav2_mppi_controller/include/nav2_mppi_controller/models/optimizer_settings.hpp b/nav2_mppi_controller/include/nav2_mppi_controller/models/optimizer_settings.hpp index 9416b53e1ba..dac1abd9166 100644 --- a/nav2_mppi_controller/include/nav2_mppi_controller/models/optimizer_settings.hpp +++ b/nav2_mppi_controller/include/nav2_mppi_controller/models/optimizer_settings.hpp @@ -30,6 +30,7 @@ struct OptimizerSettings models::ControlConstraints base_constraints{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; models::ControlConstraints constraints{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; models::SamplingStd sampling_std{0.0f, 0.0f, 0.0f}; + models::AdvancedConstraints advanced_constraints{0.0f, 0.0f}; float model_dt{0.0f}; float temperature{0.0f}; float gamma{0.0f}; diff --git a/nav2_mppi_controller/include/nav2_mppi_controller/models/state.hpp b/nav2_mppi_controller/include/nav2_mppi_controller/models/state.hpp index a8c81c3b07d..3c2a4bce57c 100644 --- a/nav2_mppi_controller/include/nav2_mppi_controller/models/state.hpp +++ b/nav2_mppi_controller/include/nav2_mppi_controller/models/state.hpp @@ -41,10 +41,16 @@ struct State geometry_msgs::msg::PoseStamped pose; geometry_msgs::msg::Twist speed; + /** + * @brief Internal variable that holds wz_std after decay is applied. + * If decay is disabled, SamplingStd.wz == wz_std_adaptive + */ + float wz_std_adaptive; + /** * @brief Reset state data */ - void reset(unsigned int batch_size, unsigned int time_steps) + void reset(unsigned int batch_size, unsigned int time_steps, float wz_std) { vx.setZero(batch_size, time_steps); vy.setZero(batch_size, time_steps); @@ -53,6 +59,8 @@ struct State cvx.setZero(batch_size, time_steps); cvy.setZero(batch_size, time_steps); cwz.setZero(batch_size, time_steps); + + wz_std_adaptive = wz_std; // reset initial adaptive value to parameterized value } }; } // namespace mppi::models diff --git a/nav2_mppi_controller/include/nav2_mppi_controller/optimizer.hpp b/nav2_mppi_controller/include/nav2_mppi_controller/optimizer.hpp index 2ced1fe2fc4..fb878673227 100644 --- a/nav2_mppi_controller/include/nav2_mppi_controller/optimizer.hpp +++ b/nav2_mppi_controller/include/nav2_mppi_controller/optimizer.hpp @@ -217,6 +217,13 @@ class Optimizer Eigen::Array
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`
[Playground](https://www.wolframalpha.com/input?i=plot+%5B%28a-b%29+*+e%5E%28-c+*+x%29+%2B+b%5D+with+a%3D0.5%2C+b%3D0.05%2C+c%3D3) |
- | advanced.wz_std_decay_to | double | Default: 0.0. Target wz_std value while linear speed goes to infinity. Must be between 0 and wz_std. Has no effect if `advanced.wz_std_decay_strength` <= 0.0 |
+ | Parameter | Type | Definition |
+ |----------------------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+ | motion_model | string | Default: DiffDrive. Type of model [DiffDrive, Omni, Ackermann]. |
+ | critics | string | Default: None. Critics (plugins) names |
+ | iteration_count | int | Default 1. Iteration count in MPPI algorithm. Recommend to keep as 1 and prefer more batches. |
+ | batch_size | int | Default 1000. Count of randomly sampled candidate trajectories |
+ | time_steps | int | Default 56. Number of time steps (points) in each sampled trajectory |
+ | model_dt | double | Default: 0.05. Time interval (s) between two sampled points in trajectories. |
+ | vx_std | double | Default 0.2. Sampling standard deviation for VX |
+ | vy_std | double | Default 0.2. Sampling standard deviation for VY |
+ | wz_std | double | Default 0.4. Sampling standard deviation for Wz |
+ | vx_max | double | Default 0.5. Max VX (m/s) |
+ | vy_max | double | Default 0.5. Max VY in either direction, if holonomic. (m/s) |
+ | vx_min | double | Default -0.35. Min VX (m/s) |
+ | wz_max | double | Default 1.9. Max WZ (rad/s) |
+ | temperature | double | Default: 0.3. Selectiveness of trajectories by their costs (The closer this value to 0, the "more" we take in consideration controls with less cost), 0 mean use control with best cost, huge value will lead to just taking mean of all trajectories without cost consideration |
+ | gamma | double | Default: 0.015. A trade-off between smoothness (high) and low energy (low). This is a complex parameter that likely won't need to be changed from the default of `0.1` which works well for a broad range of cases. See Section 3D-2 in "Information Theoretic Model Predictive Control: Theory and Applications to Autonomous Driving" for detailed information. |
+ | visualize | bool | Default: false. Publish visualization of trajectories, which can slow down the controller significantly. Use only for debugging. |
+ | retry_attempt_limit | int | Default 1. Number of attempts to find feasible trajectory on failure for soft-resets before reporting failure. |
+ | regenerate_noises | bool | Default false. Whether to regenerate noises each iteration or use single noise distribution computed on initialization and reset. Practically, this is found to work fine since the trajectories are being sampled stochastically from a normal distribution and reduces compute jittering at run-time due to thread wake-ups to resample normal distribution. |
+ | advanced.wz_std_decay_strength | double | Default: -1.0 (disabled). Defines the strength of the reduction function.
`wz_std_decay_strength` and `wz_std_decay_to` defines a function that 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 are: `wz_std = 0.4, wz_std_decay_to = 0.05, wz_std_decay_strength = 3.0`
The following is used as the decay function 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`
[Visualize the decay function here](https://www.wolframalpha.com/input?i=plot+%5B%28a-b%29+*+e%5E%28-c+*+x%29+%2B+b%5D+with+a%3D0.5%2C+b%3D0.05%2C+c%3D3) |
+ | advanced.wz_std_decay_to | double | Default: 0.0. Target wz_std value while linear speed goes to infinity. Must be between 0 and wz_std. Has no effect if `advanced.wz_std_decay_strength` <= 0.0 |
| publish_optimal_trajectory | bool | Publishes the full optimal trajectory sequence each control iteration for downstream control systems, collision checkers, etc to have context beyond the next timestep. |
diff --git a/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp b/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
index ed9c434e92b..9296a8b38e7 100644
--- a/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
+++ b/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
@@ -15,6 +15,10 @@
#ifndef NAV2_MPPI_CONTROLLER__MODELS__CONSTRAINTS_HPP_
#define NAV2_MPPI_CONTROLLER__MODELS__CONSTRAINTS_HPP_
+#include
`wz_std_decay_strength` and `wz_std_decay_to` defines a function that 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 are: `wz_std = 0.4, wz_std_decay_to = 0.05, wz_std_decay_strength = 3.0`
`f(x) = (wz_std - wz_std_decay_to) * e^(-wz_std_decay_strength * v_linear) + wz_std_decay_to`
[Visualize the decay function here](https://www.wolframalpha.com/input?i=plot+%5B%28a-b%29+*+e%5E%28-c+*+x%29+%2B+b%5D+with+a%3D0.5%2C+b%3D0.05%2C+c%3D3) |
| advanced.wz_std_decay_to | double | Default: 0.0. Target wz_std value while linear speed goes to infinity. Must be between 0 and wz_std. Has no effect if `advanced.wz_std_decay_strength` <= 0.0 |
-
- | publish_optimal_trajectory | bool | Publishes the full optimal trajectory sequence each control iteration for downstream control systems, collision checkers, etc to have context beyond the next timestep. |
-
#### Trajectory Visualizer
| Parameter | Type | Definition |
From aaeb6274d9939a996fed585920564a50cea7673f Mon Sep 17 00:00:00 2001
From: Vahap Oguz TOKMAK <5289529+vahapt@users.noreply.github.com>
Date: Sun, 22 Jun 2025 21:33:21 +0300
Subject: [PATCH 4/6] Added support for MPPI Controller to adjust wz_std
parameter based on linear speed
Added test cases
Signed-off-by: Vahap Oguz TOKMAK <5289529+vahapt@users.noreply.github.com>
---
.../test/noise_generator_test.cpp | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/nav2_mppi_controller/test/noise_generator_test.cpp b/nav2_mppi_controller/test/noise_generator_test.cpp
index 17d4e2f8087..ce95d661d74 100644
--- a/nav2_mppi_controller/test/noise_generator_test.cpp
+++ b/nav2_mppi_controller/test/noise_generator_test.cpp
@@ -254,6 +254,23 @@ TEST(NoiseGeneratorTest, AdaptiveStds)
generator.computeAdaptiveStds(state);
EXPECT_NEAR(0.052489355206489563f, *settings.sampling_std.wz_std_adaptive, EPSILON);
EXPECT_NEAR(0.1f, settings.sampling_std.wz, EPSILON); // wz_std should stay the same
+
+ // Enable AdaptiveStd, with invalid input
+ settings.advanced_constraints.wz_std_decay_strength = 3.0f;
+ settings.advanced_constraints.wz_std_decay_to = 0.2f; // > than wz_std
+ state.speed.linear.x = 1.0f;
+ generator.reset(settings, false); // sets initial sizing and zeros out noises
+ generator.computeAdaptiveStds(state);
+ // expect wz_std == wz_std_adaptive as adaptive std will be automatically disabled
+ EXPECT_EQ(settings.sampling_std.wz, *settings.sampling_std.wz_std_adaptive);
+ try {
+ settings.sampling_std.validateConstraints(settings.advanced_constraints, false);
+ FAIL() << "Expected to throw runtime error";
+ } catch (const std::runtime_error & e) {
+ EXPECT_TRUE(!std::string(e.what()).empty());
+ }
+
+ generator.shutdown();
}
int main(int argc, char **argv)
From b9691c5e8904a0a02429ba75e8e960d3f348dfff Mon Sep 17 00:00:00 2001
From: Vahap Oguz TOKMAK <5289529+vahapt@users.noreply.github.com>
Date: Mon, 30 Jun 2025 10:47:49 +0300
Subject: [PATCH 5/6] Added support for MPPI Controller to adjust wz_std
parameter based on linear speed
- Refactored the code to simplify flow
- Merged to latest `main` branch
Signed-off-by: Vahap Oguz TOKMAK <5289529+vahapt@users.noreply.github.com>
---
.../models/constraints.hpp | 36 -----
.../models/optimizer_settings.hpp | 3 +-
.../nav2_mppi_controller/optimizer.hpp | 5 -
.../tools/noise_generator.hpp | 46 +++---
nav2_mppi_controller/src/noise_generator.cpp | 132 +++++++++++-------
nav2_mppi_controller/src/optimizer.cpp | 19 +--
.../test/noise_generator_test.cpp | 34 ++---
7 files changed, 123 insertions(+), 152 deletions(-)
diff --git a/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp b/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
index 9296a8b38e7..5626b461776 100644
--- a/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
+++ b/nav2_mppi_controller/include/nav2_mppi_controller/models/constraints.hpp
@@ -15,10 +15,6 @@
#ifndef NAV2_MPPI_CONTROLLER__MODELS__CONSTRAINTS_HPP_
#define NAV2_MPPI_CONTROLLER__MODELS__CONSTRAINTS_HPP_
-#include