@@ -53,7 +53,9 @@ namespace
5353constexpr int kMppiHorizon = 80 ;
5454constexpr int kRefHorizon = kMppiHorizon ;
5555constexpr float kDt = 0 .1F ;
56+ constexpr size_t kMaxIter = 10 ;
5657constexpr int kNumRollouts = 32 * 1024 ;
58+ constexpr float kLambda = 1500 .0F ;
5759constexpr float kInitArcLength = 1 .5F ;
5860constexpr size_t kTrackingIndexResetThreshold = 15U ;
5961// constexpr int kMaxVizRollouts = 200; // rollout viz disabled
@@ -338,6 +340,39 @@ void buildRolloutVisualization(
338340}
339341#endif
340342
343+ // / @brief check if the given trajectory needs to be optimized
344+ [[nodiscard]] bool is_optimization_required (const autoware::mppi_optimizer::Trajectory & trajectory)
345+ {
346+ const auto is_stopping = std::find_if (
347+ trajectory.points .begin (), trajectory.points .end (),
348+ [&](const autoware_planning_msgs::msg::TrajectoryPoint & p) {
349+ return p.longitudinal_velocity_mps < 0.02 ;
350+ }) != trajectory.points .end ();
351+ auto length = 0.0 ;
352+ for (auto i = 0UL ; i + 1 < trajectory.points .size (); ++i) {
353+ length += std::hypot (
354+ trajectory.points [i].pose .position .x - trajectory.points [i + 1 ].pose .position .x ,
355+ trajectory.points [i].pose .position .y - trajectory.points [i + 1 ].pose .position .y );
356+ }
357+ const auto is_short = length < 4.0 ;
358+ return !is_stopping || !is_short;
359+ }
360+
361+ // / @brief override initial 0 velocities with engage velocities
362+ void set_initial_engage_velocity (autoware::mppi_optimizer::Trajectory & trajectory)
363+ {
364+ constexpr auto engage_velocity = 0.25 ;
365+ if (trajectory.points .size () < 3 ) return ;
366+ const auto wants_to_move = std::find_if (
367+ trajectory.points .begin (), trajectory.points .end (),
368+ [&](const autoware_planning_msgs::msg::TrajectoryPoint & p) {
369+ return p.longitudinal_velocity_mps > engage_velocity;
370+ }) != trajectory.points .end ();
371+ if (wants_to_move && trajectory.points [0 ].longitudinal_velocity_mps < 0.05 ) {
372+ trajectory.points [0 ].longitudinal_velocity_mps = engage_velocity;
373+ trajectory.points [1 ].longitudinal_velocity_mps = engage_velocity;
374+ }
375+ }
341376} // namespace
342377
343378struct FirstOrderDubinsMppiInterface ::Impl
@@ -375,6 +410,8 @@ struct FirstOrderDubinsMppiInterface::Impl
375410 bool ignore_obstacles{false };
376411 bool ignore_drivable_area{false };
377412 bool force_cold_start_each_step{false };
413+ /* * Warm-start u_nom from shifted previous u_opt when available. */
414+ bool use_last_control_as_nominal{false };
378415
379416 Impl () : feedback(&model, kDt ), sampler(SAMPLER ::SAMPLING_PARAMS_T {}) {}
380417
@@ -432,8 +469,7 @@ struct FirstOrderDubinsMppiInterface::Impl
432469 sampler = SAMPLER (sp);
433470
434471 controller = std::make_unique<Mppi>(
435- &model, &cost, &feedback, &sampler, kDt , 1 , user_cost_params_.lambda , 0 .0F , kMppiHorizon ,
436- u_nom);
472+ &model, &cost, &feedback, &sampler, kDt , kMaxIter , kLambda , 0 .0F , kMppiHorizon , u_nom);
437473 auto cp = controller->getParams ();
438474 cp.dynamics_rollout_dim_ = dim3 (32 , 2 , 1 );
439475 cp.cost_rollout_dim_ = dim3 (32 , 2 , 1 );
@@ -471,6 +507,15 @@ struct FirstOrderDubinsMppiInterface::Impl
471507 sim_time = 0 .0F ;
472508 }
473509
510+ void seedNominalControlFromLastOptimized ()
511+ {
512+ // Drop the control already applied at the previous cycle; hold the terminal command.
513+ for (int t = 0 ; t < kMppiHorizon - 1 ; ++t) {
514+ u_nom.col (t) = u_opt.col (t + 1 );
515+ }
516+ u_nom.col (kMppiHorizon - 1 ) = u_opt.col (kMppiHorizon - 1 );
517+ }
518+
474519 void seedNominalControlFromDiffusionReference (
475520 const Trajectory & reference, const size_t start_idx)
476521 {
@@ -509,6 +554,16 @@ struct FirstOrderDubinsMppiInterface::Impl
509554 }
510555 }
511556
557+ void seedNominalControl (const Trajectory & reference, const size_t start_idx)
558+ {
559+ // After a tracking reset, step_count is 0 and u_opt was cleared — fall back to DP seed.
560+ if (use_last_control_as_nominal && step_count > 0 ) {
561+ seedNominalControlFromLastOptimized ();
562+ return ;
563+ }
564+ seedNominalControlFromDiffusionReference (reference, start_idx);
565+ }
566+
512567 void updateDiffusionReference (
513568 const Trajectory & reference, const Odometry & odometry,
514569 const std::optional<geometry_msgs::msg::AccelWithCovarianceStamped> & acceleration,
@@ -539,7 +594,7 @@ struct FirstOrderDubinsMppiInterface::Impl
539594 resetTrackingState ();
540595 }
541596 tracking_start_idx = new_start_idx;
542- seedNominalControlFromDiffusionReference (reference, tracking_start_idx);
597+ seedNominalControl (reference, tracking_start_idx);
543598
544599 const float ego_yaw = yawFromOdometry (odometry);
545600 const float ego_v = static_cast <float >(odometry.twist .twist .linear .x );
@@ -708,9 +763,9 @@ void FirstOrderDubinsMppiInterface::setRuntimeOptions(
708763 setDebugTrajectoryLogging (
709764 options.enable_debug_trajectory_log , options.debug_trajectory_log_directory );
710765 setAblationOptions (
711- options.ignore_obstacles , options.ignore_drivable_area , options.force_cold_start_each_step );
766+ options.ignore_obstacles , options.ignore_drivable_area , options.force_cold_start_each_step ,
767+ options.use_last_control_as_nominal );
712768}
713-
714769void FirstOrderDubinsMppiInterface::setDebugTrajectoryLogging (
715770 const bool enable, const std::string & directory)
716771{
@@ -723,20 +778,22 @@ void FirstOrderDubinsMppiInterface::setDebugTrajectoryLogging(
723778
724779void FirstOrderDubinsMppiInterface::setAblationOptions (
725780 const bool ignore_obstacles, const bool ignore_drivable_area,
726- const bool force_cold_start_each_step)
781+ const bool force_cold_start_each_step, const bool use_last_control_as_nominal )
727782{
728783 if (!impl_) {
729784 throw std::runtime_error (" FirstOrderDubinsMppiInterface implementation is missing" );
730785 }
731786 impl_->ignore_obstacles = ignore_obstacles;
732787 impl_->ignore_drivable_area = ignore_drivable_area;
733788 impl_->force_cold_start_each_step = force_cold_start_each_step;
789+ impl_->use_last_control_as_nominal = use_last_control_as_nominal;
734790 RCLCPP_INFO (
735791 mppiLogger (),
736792 " MPPI ablation options: ignore_obstacles=%s ignore_drivable_area=%s "
737- " force_cold_start_each_step=%s" ,
793+ " force_cold_start_each_step=%s use_last_control_as_nominal=%s " ,
738794 ignore_obstacles ? " true" : " false" , ignore_drivable_area ? " true" : " false" ,
739- force_cold_start_each_step ? " true" : " false" );
795+ force_cold_start_each_step ? " true" : " false" ,
796+ use_last_control_as_nominal ? " true" : " false" );
740797}
741798
742799bool FirstOrderDubinsMppiInterface::copySampleCostDistribution (
@@ -796,9 +853,14 @@ FirstOrderDubinsMppiOptimizationResult FirstOrderDubinsMppiInterface::optimizeTr
796853 throw std::runtime_error (" FirstOrderDubinsMppiInterface implementation is missing" );
797854 }
798855 FirstOrderDubinsMppiOptimizationResult result;
799- if (input.points .size () < 2U ) {
856+ const auto not_enough_input_points = input.points .size () < 2U ;
857+ const auto optimization_required = is_optimization_required (input);
858+ if (not_enough_input_points || !optimization_required) {
800859 RCLCPP_WARN (
801- mppiLogger (), " MPPI skipped: trajectory has %zu points (need >= 2)" , input.points .size ());
860+ mppiLogger (), " MPPI skipped: %s" ,
861+ not_enough_input_points ? " trajectory has fewer than 2 points"
862+ : " trajectory does not require optimization" );
863+
802864 result.trajectory = input;
803865 result.debug .reference_trajectory = input;
804866 result.debug .optimized_trajectory = input;
@@ -889,6 +951,8 @@ FirstOrderDubinsMppiOptimizationResult FirstOrderDubinsMppiInterface::optimizeTr
889951 std::chrono::duration<double , std::milli>(std::chrono::steady_clock::now () - start_time)
890952 .count ();
891953
954+ set_initial_engage_velocity (output);
955+
892956 result.trajectory = output;
893957 result.debug .reference_trajectory = input;
894958 result.debug .optimized_trajectory = output;
0 commit comments