-
Couldn't load subscription status.
- Fork 1.6k
add open loop option for MPPI #5617
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
Conversation
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
| state.wz.col(0) = static_cast<float>(state.speed.angular.z); | ||
| const bool open = settings_.open_loop; | ||
|
|
||
| const float vx0 = open ? control_sequence_.vx(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct considering we pop the initial one when we send it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines of code, the purpose is to take the last command velocity sent to the motor, give it to the MPPI predict() steps.
I think that control_sequence_.vx(0) is the last cmd_vel that sent to the motor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But control_sequence_.vx(0) is not the last command sent to the motors. After we send a command to the motors, the trajectory is slid over to initialize for the next iteration
navigation2/nav2_mppi_controller/src/optimizer.cpp
Lines 273 to 285 in 47d13ce
| void Optimizer::shiftControlSequence() | |
| { | |
| auto size = control_sequence_.vx.size(); | |
| utils::shiftColumnsByOnePlace(control_sequence_.vx, -1); | |
| utils::shiftColumnsByOnePlace(control_sequence_.wz, -1); | |
| control_sequence_.vx(size - 1) = control_sequence_.vx(size - 2); | |
| control_sequence_.wz(size - 1) = control_sequence_.wz(size - 2); | |
| if (isHolonomic()) { | |
| utils::shiftColumnsByOnePlace(control_sequence_.vy, -1); | |
| control_sequence_.vy(size - 1) = control_sequence_.vy(size - 2); | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think control_sequence_.vx(0) is now control_sequence_.vx(1) from the last iteration, since it is shifted in https://github.com/enwaytech/navigation2/blob/main/nav2_mppi_controller/src/optimizer.cpp#L219
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we don't always use 1st point, we sometimes use 0th depending on the setting of the control frequency and timestep https://github.com/enwaytech/navigation2/blob/main/nav2_mppi_controller/src/optimizer.cpp#L443
I think you need to use the last control velocity as the state initial for open loop. If you stored that and set it in the open loop setting, that seems to me to be the easiest way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay, forgot that setup where we dont always shift control sequence.
So now we will create member variable in Optimizer, store the last_cmd_vel then use it next iteration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SteveMacenski, Should I create those variables in State struct ?
https://github.com/enwaytech/navigation2/blob/5c763e22d4b188a18d7d323e992159c181bb21e9/nav2_mppi_controller/include/nav2_mppi_controller/models/state.hpp#L40
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So now we will create member variable in Optimizer, store the last_cmd_vel then use it next iteration.
Sounds good! I thnk this can be a member of the Optimizer class, since its not regarding the current trajectory state
nav2_mppi_controller/include/nav2_mppi_controller/models/optimizer_settings.hpp
Outdated
Show resolved
Hide resolved
Fix linting Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Codecov Report✅ All modified and coverable lines are covered by tests.
... and 11 files with indirect coverage changes 🚀 New features to boost your workflow:
|
| state.wz.col(0) = static_cast<float>(state.speed.angular.z); | ||
| const bool open = settings_.open_loop; | ||
|
|
||
| const float vx0 = open ? control_sequence_.vx(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But control_sequence_.vx(0) is not the last command sent to the motors. After we send a command to the motors, the trajectory is slid over to initialize for the next iteration
navigation2/nav2_mppi_controller/src/optimizer.cpp
Lines 273 to 285 in 47d13ce
| void Optimizer::shiftControlSequence() | |
| { | |
| auto size = control_sequence_.vx.size(); | |
| utils::shiftColumnsByOnePlace(control_sequence_.vx, -1); | |
| utils::shiftColumnsByOnePlace(control_sequence_.wz, -1); | |
| control_sequence_.vx(size - 1) = control_sequence_.vx(size - 2); | |
| control_sequence_.wz(size - 1) = control_sequence_.wz(size - 2); | |
| if (isHolonomic()) { | |
| utils::shiftColumnsByOnePlace(control_sequence_.vy, -1); | |
| control_sequence_.vy(size - 1) = control_sequence_.vy(size - 2); | |
| } | |
| } |
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
nav2_mppi_controller/include/nav2_mppi_controller/optimizer.hpp
Outdated
Show resolved
Hide resolved
|
How as this tested and would it be useful to setup a new unit test for the optimizer that sets the open loop to true and checks that it initializes exactly the first value? That would be good I think and cover the missing lines |
Do you mean https://github.com/ros-navigation/navigation2/pull/5617/files#diff-6d2fd58ab98a8266e2217a3d534624786349d5f40e08547ec5125ff64ecae5a5R238 ? last_command_vel_ = geometry_msgs::msg::Twist();
// and
last_command_vel_ = control.twist;is it should be a test case where EXPECT_FLOAT_EQ(opt.last_command_vel_.linear.x, 0.0f); |
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How should I do to cover below lines ?
Like so 😉 Just check that they are populated correctly.
Or, make a unit test where you set the open loop parameter to true in a node before constructing the MPPI optimizer. Then send it some info with an odometry velocity twist of something ridiculous. Check that the trajectory is reasonable for the first and second time the velocity is requested (first for initialization conditions; second for normal conditions)
| if (settings_.open_loop) { | ||
| last_command_vel_ = control.twist; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (settings_.open_loop) { | |
| last_command_vel_ = control.twist; | |
| } | |
| last_command_vel_ = control.twist; |
| if (settings_.open_loop) { | ||
| last_command_vel_ = geometry_msgs::msg::Twist(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (settings_.open_loop) { | |
| last_command_vel_ = geometry_msgs::msg::Twist(); | |
| } | |
| last_command_vel_ = geometry_msgs::msg::Twist(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you also update state_.speed = robot_speed;? Or, actually set the state_.speed to be the last command. Then the lines you changed for
state.vx.col(0) = settings_.open_loop ? last_command_vel_.linear.x :
static_cast<float>(state.speed.linear.x);
Can be reverted. That way anything that may use state (such as the critics) are all using the same consistent thing. You'd then move hte open_loop setting check for what to set in the prepare() method. Right now, the state object is inconsistent in the information its storing, so I think this is actually a better idea.
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
Signed-off-by: Chanh Hoang <chanhhoang999x@gmail.com>
|
Hi @adivardi , |
Hi, sure, but I am traveling for ROSCon. So it will only be in 2 weeks. |
|
@chanhhoang99 can you verify this work well for you on Kilted? The P.S. If either or both of you are at ROSCon, come find me. I have some merch for Nav2 contributors 😉 |
|
@SteveMacenski , |
Basic Info
Description of contribution in a few bullet points
Description of documentation updates required from your changes
Description of how this change was tested
With
Before the change
Screencast.from.2025-10-16.11-15-26.mp4
After the change
https://www.youtube.com/watch?v=HbLMPBcHRgI
Future work that may be required in bullet points
For Maintainers:
backport-*.