Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
optimizer.cpp
1 // Copyright (c) 2022 Samsung Research America, @artofnothingness Alexey Budyakov
2 // Copyright (c) 2025 Open Navigation LLC
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "nav2_mppi_controller/optimizer.hpp"
17 
18 #include <limits>
19 #include <memory>
20 #include <stdexcept>
21 #include <string>
22 #include <vector>
23 #include <cmath>
24 #include <chrono>
25 
26 #include "nav2_core/controller_exceptions.hpp"
27 #include "nav2_costmap_2d/costmap_filters/filter_values.hpp"
28 #include "nav2_ros_common/node_utils.hpp"
29 
30 namespace mppi
31 {
32 
34  nav2::LifecycleNode::WeakPtr parent, const std::string & name,
35  std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros,
36  std::shared_ptr<tf2_ros::Buffer> tf_buffer,
37  ParametersHandler * param_handler)
38 {
39  parent_ = parent;
40  name_ = name;
41  costmap_ros_ = costmap_ros;
42  costmap_ = costmap_ros_->getCostmap();
43  parameters_handler_ = param_handler;
44  tf_buffer_ = tf_buffer;
45 
46  auto node = parent_.lock();
47  logger_ = node->get_logger();
48 
49  getParams();
50 
51  critic_manager_.on_configure(parent_, name_, costmap_ros_, parameters_handler_);
52  noise_generator_.initialize(settings_, isHolonomic(), name_, parameters_handler_);
53 
54  // This may throw an exception if not valid and fail initialization
55  nav2::declare_parameter_if_not_declared(
56  node, name_ + ".TrajectoryValidator.plugin",
57  rclcpp::ParameterValue("mppi::DefaultOptimalTrajectoryValidator"));
58  std::string validator_plugin_type = nav2::get_plugin_type_param(
59  node, name_ + ".TrajectoryValidator");
60  validator_loader_ = std::make_unique<pluginlib::ClassLoader<OptimalTrajectoryValidator>>(
61  "nav2_mppi_controller", "mppi::OptimalTrajectoryValidator");
62  trajectory_validator_ = validator_loader_->createUniqueInstance(validator_plugin_type);
63  trajectory_validator_->initialize(
64  parent_, name_ + ".TrajectoryValidator",
65  costmap_ros_, parameters_handler_, tf_buffer, settings_);
66  RCLCPP_INFO(logger_, "Loaded trajectory validator plugin: %s", validator_plugin_type.c_str());
67 
68  reset();
69 }
70 
72 {
73  noise_generator_.shutdown();
74 }
75 
77 {
78  std::string motion_model_name;
79 
80  auto & s = settings_;
81  auto getParam = parameters_handler_->getParamGetter(name_);
82  auto getParentParam = parameters_handler_->getParamGetter("");
83  getParam(s.model_dt, "model_dt", 0.05f);
84  getParam(s.time_steps, "time_steps", 56);
85  getParam(s.batch_size, "batch_size", 1000);
86  getParam(s.iteration_count, "iteration_count", 1);
87  getParam(s.temperature, "temperature", 0.3f);
88  getParam(s.gamma, "gamma", 0.015f);
89  getParam(s.base_constraints.vx_max, "vx_max", 0.5f);
90  getParam(s.base_constraints.vx_min, "vx_min", -0.35f);
91  getParam(s.base_constraints.vy, "vy_max", 0.5f);
92  getParam(s.base_constraints.wz, "wz_max", 1.9f);
93  getParam(s.base_constraints.ax_max, "ax_max", 3.0f);
94  getParam(s.base_constraints.ax_min, "ax_min", -3.0f);
95  getParam(s.base_constraints.ay_max, "ay_max", 3.0f);
96  getParam(s.base_constraints.ay_min, "ay_min", -3.0f);
97  getParam(s.base_constraints.az_max, "az_max", 3.5f);
98  getParam(s.sampling_std.vx, "vx_std", 0.2f);
99  getParam(s.sampling_std.vy, "vy_std", 0.2f);
100  getParam(s.sampling_std.wz, "wz_std", 0.4f);
101  getParam(s.retry_attempt_limit, "retry_attempt_limit", 1);
102 
103  s.base_constraints.ax_max = fabs(s.base_constraints.ax_max);
104  if (s.base_constraints.ax_min > 0.0) {
105  s.base_constraints.ax_min = -1.0 * s.base_constraints.ax_min;
106  RCLCPP_WARN(
107  logger_,
108  "Sign of the parameter ax_min is incorrect, consider setting it negative.");
109  }
110 
111  if (s.base_constraints.ay_min > 0.0) {
112  s.base_constraints.ay_min = -1.0 * s.base_constraints.ay_min;
113  RCLCPP_WARN(
114  logger_,
115  "Sign of the parameter ay_min is incorrect, consider setting it negative.");
116  }
117 
118 
119  getParam(motion_model_name, "motion_model", std::string("DiffDrive"));
120 
121  s.constraints = s.base_constraints;
122 
123  setMotionModel(motion_model_name);
124  parameters_handler_->addPostCallback([this]() {reset();});
125 
126  double controller_frequency;
127  getParentParam(controller_frequency, "controller_frequency", 0.0, ParameterType::Static);
128  setOffset(controller_frequency);
129 }
130 
131 void Optimizer::setOffset(double controller_frequency)
132 {
133  const double controller_period = 1.0 / controller_frequency;
134  constexpr double eps = 1e-6;
135 
136  if ((controller_period + eps) < settings_.model_dt) {
137  RCLCPP_WARN(
138  logger_,
139  "Controller period is less then model dt, consider setting it equal");
140  } else if (abs(controller_period - settings_.model_dt) < eps) {
141  RCLCPP_INFO(
142  logger_,
143  "Controller period is equal to model dt. Control sequence "
144  "shifting is ON");
145  settings_.shift_control_sequence = true;
146  } else {
148  "Controller period more then model dt, set it equal to model dt");
149  }
150 }
151 
152 void Optimizer::reset(bool reset_dynamic_speed_limits)
153 {
154  state_.reset(settings_.batch_size, settings_.time_steps);
155  control_sequence_.reset(settings_.time_steps);
156  control_history_[0] = {0.0f, 0.0f, 0.0f};
157  control_history_[1] = {0.0f, 0.0f, 0.0f};
158  control_history_[2] = {0.0f, 0.0f, 0.0f};
159  control_history_[3] = {0.0f, 0.0f, 0.0f};
160 
161  if (reset_dynamic_speed_limits) {
162  settings_.constraints = settings_.base_constraints;
163  }
164 
165  costs_.setZero(settings_.batch_size);
166  generated_trajectories_.reset(settings_.batch_size, settings_.time_steps);
167 
168  noise_generator_.reset(settings_, isHolonomic());
169  motion_model_->initialize(settings_.constraints, settings_.model_dt);
170  trajectory_validator_->initialize(
171  parent_, name_ + ".TrajectoryValidator",
172  costmap_ros_, parameters_handler_, tf_buffer_, settings_);
173 
174  RCLCPP_INFO(logger_, "Optimizer reset");
175 }
176 
178 {
179  return motion_model_->isHolonomic();
180 }
181 
182 std::tuple<geometry_msgs::msg::TwistStamped, Eigen::ArrayXXf> Optimizer::evalControl(
183  const geometry_msgs::msg::PoseStamped & robot_pose,
184  const geometry_msgs::msg::Twist & robot_speed,
185  const nav_msgs::msg::Path & plan,
186  const geometry_msgs::msg::Pose & goal,
187  nav2_core::GoalChecker * goal_checker)
188 {
189  prepare(robot_pose, robot_speed, plan, goal, goal_checker);
190  Eigen::ArrayXXf optimal_trajectory;
191  bool trajectory_valid = true;
192 
193  do {
194  optimize();
195  optimal_trajectory = getOptimizedTrajectory();
196  switch (trajectory_validator_->validateTrajectory(
197  optimal_trajectory, control_sequence_, robot_pose, robot_speed, plan, goal))
198  {
199  case mppi::ValidationResult::SOFT_RESET:
200  trajectory_valid = false;
201  RCLCPP_WARN(logger_, "Soft reset triggered by trajectory validator");
202  break;
203  case mppi::ValidationResult::FAILURE:
205  "Trajectory validator failed to validate trajectory, hard reset triggered.");
206  case mppi::ValidationResult::SUCCESS:
207  default:
208  trajectory_valid = true;
209  break;
210  }
211  } while (fallback(critics_data_.fail_flag || !trajectory_valid));
212 
213  utils::savitskyGolayFilter(control_sequence_, control_history_, settings_);
214  auto control = getControlFromSequenceAsTwist(plan.header.stamp);
215 
216  if (settings_.shift_control_sequence) {
218  }
219 
220  return std::make_tuple(control, optimal_trajectory);
221 }
222 
224 {
225  for (size_t i = 0; i < settings_.iteration_count; ++i) {
227  critic_manager_.evalTrajectoriesScores(critics_data_);
229  }
230 }
231 
232 bool Optimizer::fallback(bool fail)
233 {
234  static size_t counter = 0;
235 
236  if (!fail) {
237  counter = 0;
238  return false;
239  }
240 
241  reset();
242 
243  if (++counter > settings_.retry_attempt_limit) {
244  counter = 0;
245  throw nav2_core::NoValidControl("Optimizer fail to compute path");
246  }
247 
248  return true;
249 }
250 
252  const geometry_msgs::msg::PoseStamped & robot_pose,
253  const geometry_msgs::msg::Twist & robot_speed,
254  const nav_msgs::msg::Path & plan,
255  const geometry_msgs::msg::Pose & goal,
256  nav2_core::GoalChecker * goal_checker)
257 {
258  state_.pose = robot_pose;
259  state_.speed = robot_speed;
260  state_.local_path_length = nav2_util::geometry_utils::calculate_path_length(plan);
261  path_ = utils::toTensor(plan);
262  costs_.setZero();
263  goal_ = goal;
264 
265  critics_data_.fail_flag = false;
266  critics_data_.goal_checker = goal_checker;
267  critics_data_.motion_model = motion_model_;
268  critics_data_.furthest_reached_path_point.reset();
269  critics_data_.path_pts_valid.reset();
270 }
271 
273 {
274  auto size = control_sequence_.vx.size();
275  utils::shiftColumnsByOnePlace(control_sequence_.vx, -1);
276  utils::shiftColumnsByOnePlace(control_sequence_.wz, -1);
277  control_sequence_.vx(size - 1) = control_sequence_.vx(size - 2);
278  control_sequence_.wz(size - 1) = control_sequence_.wz(size - 2);
279 
280  if (isHolonomic()) {
281  utils::shiftColumnsByOnePlace(control_sequence_.vy, -1);
282  control_sequence_.vy(size - 1) = control_sequence_.vy(size - 2);
283  }
284 }
285 
287 {
288  noise_generator_.setNoisedControls(state_, control_sequence_);
289  noise_generator_.generateNextNoises();
290  updateStateVelocities(state_);
291  integrateStateVelocities(generated_trajectories_, state_);
292 }
293 
295 {
296  auto & s = settings_;
297 
298  float max_delta_vx = s.model_dt * s.constraints.ax_max;
299  float min_delta_vx = s.model_dt * s.constraints.ax_min;
300  float max_delta_vy = s.model_dt * s.constraints.ay_max;
301  float min_delta_vy = s.model_dt * s.constraints.ay_min;
302  float max_delta_wz = s.model_dt * s.constraints.az_max;
303  float vx_last = utils::clamp(s.constraints.vx_min, s.constraints.vx_max, control_sequence_.vx(0));
304  float wz_last = utils::clamp(-s.constraints.wz, s.constraints.wz, control_sequence_.wz(0));
305  control_sequence_.vx(0) = vx_last;
306  control_sequence_.wz(0) = wz_last;
307  float vy_last = 0;
308  if (isHolonomic()) {
309  vy_last = utils::clamp(-s.constraints.vy, s.constraints.vy, control_sequence_.vy(0));
310  control_sequence_.vy(0) = vy_last;
311  }
312 
313  for (unsigned int i = 1; i != control_sequence_.vx.size(); i++) {
314  float & vx_curr = control_sequence_.vx(i);
315  vx_curr = utils::clamp(s.constraints.vx_min, s.constraints.vx_max, vx_curr);
316  if(vx_last > 0) {
317  vx_curr = utils::clamp(vx_last + min_delta_vx, vx_last + max_delta_vx, vx_curr);
318  } else {
319  vx_curr = utils::clamp(vx_last - max_delta_vx, vx_last - min_delta_vx, vx_curr);
320  }
321  vx_last = vx_curr;
322 
323  float & wz_curr = control_sequence_.wz(i);
324  wz_curr = utils::clamp(-s.constraints.wz, s.constraints.wz, wz_curr);
325  wz_curr = utils::clamp(wz_last - max_delta_wz, wz_last + max_delta_wz, wz_curr);
326  wz_last = wz_curr;
327 
328  if (isHolonomic()) {
329  float & vy_curr = control_sequence_.vy(i);
330  vy_curr = utils::clamp(-s.constraints.vy, s.constraints.vy, vy_curr);
331  if(vy_last > 0) {
332  vy_curr = utils::clamp(vy_last + min_delta_vy, vy_last + max_delta_vy, vy_curr);
333  } else {
334  vy_curr = utils::clamp(vy_last - max_delta_vy, vy_last - min_delta_vy, vy_curr);
335  }
336  vy_last = vy_curr;
337  }
338  }
339 
340  motion_model_->applyConstraints(control_sequence_);
341 }
342 
344  models::State & state) const
345 {
348 }
349 
351  models::State & state) const
352 {
353  state.vx.col(0) = static_cast<float>(state.speed.linear.x);
354  state.wz.col(0) = static_cast<float>(state.speed.angular.z);
355 
356  if (isHolonomic()) {
357  state.vy.col(0) = static_cast<float>(state.speed.linear.y);
358  }
359 }
360 
362  models::State & state) const
363 {
364  motion_model_->predict(state);
365 }
366 
368  Eigen::Array<float, Eigen::Dynamic, 3> & trajectory,
369  const Eigen::ArrayXXf & sequence) const
370 {
371  float initial_yaw = static_cast<float>(tf2::getYaw(state_.pose.pose.orientation));
372 
373  const auto vx = sequence.col(0);
374  const auto wz = sequence.col(1);
375 
376  auto traj_x = trajectory.col(0);
377  auto traj_y = trajectory.col(1);
378  auto traj_yaws = trajectory.col(2);
379 
380  const size_t n_size = traj_yaws.size();
381  if (n_size == 0) {
382  return;
383  }
384 
385  float last_yaw = initial_yaw;
386  for(size_t i = 0; i != n_size; i++) {
387  last_yaw += wz(i) * settings_.model_dt;
388  traj_yaws(i) = last_yaw;
389  }
390 
391  Eigen::ArrayXf yaw_cos = traj_yaws.cos();
392  Eigen::ArrayXf yaw_sin = traj_yaws.sin();
393  utils::shiftColumnsByOnePlace(yaw_cos, 1);
394  utils::shiftColumnsByOnePlace(yaw_sin, 1);
395  yaw_cos(0) = cosf(initial_yaw);
396  yaw_sin(0) = sinf(initial_yaw);
397 
398  auto dx = (vx * yaw_cos).eval();
399  auto dy = (vx * yaw_sin).eval();
400 
401  if (isHolonomic()) {
402  auto vy = sequence.col(2);
403  dx = (dx - vy * yaw_sin).eval();
404  dy = (dy + vy * yaw_cos).eval();
405  }
406 
407  float last_x = state_.pose.pose.position.x;
408  float last_y = state_.pose.pose.position.y;
409  for(size_t i = 0; i != n_size; i++) {
410  last_x += dx(i) * settings_.model_dt;
411  last_y += dy(i) * settings_.model_dt;
412  traj_x(i) = last_x;
413  traj_y(i) = last_y;
414  }
415 }
416 
418  models::Trajectories & trajectories,
419  const models::State & state) const
420 {
421  auto initial_yaw = static_cast<float>(tf2::getYaw(state.pose.pose.orientation));
422  const size_t n_cols = trajectories.yaws.cols();
423 
424  Eigen::ArrayXf last_yaws = Eigen::ArrayXf::Constant(trajectories.yaws.rows(), initial_yaw);
425  for (size_t i = 0; i != n_cols; i++) {
426  last_yaws += state.wz.col(i) * settings_.model_dt;
427  trajectories.yaws.col(i) = last_yaws;
428  }
429 
430  Eigen::ArrayXXf yaw_cos = trajectories.yaws.cos();
431  Eigen::ArrayXXf yaw_sin = trajectories.yaws.sin();
432  utils::shiftColumnsByOnePlace(yaw_cos, 1);
433  utils::shiftColumnsByOnePlace(yaw_sin, 1);
434  yaw_cos.col(0) = cosf(initial_yaw);
435  yaw_sin.col(0) = sinf(initial_yaw);
436 
437  auto dx = (state.vx * yaw_cos).eval();
438  auto dy = (state.vx * yaw_sin).eval();
439 
440  if (isHolonomic()) {
441  dx -= state.vy * yaw_sin;
442  dy += state.vy * yaw_cos;
443  }
444 
445  Eigen::ArrayXf last_x = Eigen::ArrayXf::Constant(trajectories.x.rows(),
446  state.pose.pose.position.x);
447  Eigen::ArrayXf last_y = Eigen::ArrayXf::Constant(trajectories.y.rows(),
448  state.pose.pose.position.y);
449 
450  for (size_t i = 0; i != n_cols; i++) {
451  last_x += dx.col(i) * settings_.model_dt;
452  last_y += dy.col(i) * settings_.model_dt;
453  trajectories.x.col(i) = last_x;
454  trajectories.y.col(i) = last_y;
455  }
456 }
457 
459 {
460  const bool is_holo = isHolonomic();
461  Eigen::ArrayXXf sequence = Eigen::ArrayXXf(settings_.time_steps, is_holo ? 3 : 2);
462  Eigen::Array<float, Eigen::Dynamic, 3> trajectories =
463  Eigen::Array<float, Eigen::Dynamic, 3>(settings_.time_steps, 3);
464 
465  sequence.col(0) = control_sequence_.vx;
466  sequence.col(1) = control_sequence_.wz;
467 
468  if (is_holo) {
469  sequence.col(2) = control_sequence_.vy;
470  }
471 
472  integrateStateVelocities(trajectories, sequence);
473  return trajectories;
474 }
475 
477 {
478  return control_sequence_;
479 }
480 
482 {
483  const bool is_holo = isHolonomic();
484  auto & s = settings_;
485 
486  auto vx_T = control_sequence_.vx.transpose();
487  auto bounded_noises_vx = state_.cvx.rowwise() - vx_T;
488  const float gamma_vx = s.gamma / (s.sampling_std.vx * s.sampling_std.vx);
489  costs_ += (gamma_vx * (bounded_noises_vx.rowwise() * vx_T).rowwise().sum()).eval();
490 
491  if (s.sampling_std.wz > 0.0f) {
492  auto wz_T = control_sequence_.wz.transpose();
493  auto bounded_noises_wz = state_.cwz.rowwise() - wz_T;
494  const float gamma_wz = s.gamma / (s.sampling_std.wz * s.sampling_std.wz);
495  costs_ += (gamma_wz * (bounded_noises_wz.rowwise() * wz_T).rowwise().sum()).eval();
496  }
497 
498  if (is_holo) {
499  auto vy_T = control_sequence_.vy.transpose();
500  auto bounded_noises_vy = state_.cvy.rowwise() - vy_T;
501  const float gamma_vy = s.gamma / (s.sampling_std.vy * s.sampling_std.vy);
502  costs_ += (gamma_vy * (bounded_noises_vy.rowwise() * vy_T).rowwise().sum()).eval();
503  }
504 
505  auto costs_normalized = costs_ - costs_.minCoeff();
506  const float inv_temp = 1.0f / s.temperature;
507  auto softmaxes = (-inv_temp * costs_normalized).exp().eval();
508  softmaxes /= softmaxes.sum();
509 
510  auto softmax_mat = softmaxes.matrix();
511  control_sequence_.vx = state_.cvx.transpose().matrix() * softmax_mat;
512  control_sequence_.wz = state_.cwz.transpose().matrix() * softmax_mat;
513 
514  if (is_holo) {
515  control_sequence_.vy = state_.cvy.transpose().matrix() * softmax_mat;
516  }
517 
519 }
520 
521 geometry_msgs::msg::TwistStamped Optimizer::getControlFromSequenceAsTwist(
522  const builtin_interfaces::msg::Time & stamp)
523 {
524  unsigned int offset = settings_.shift_control_sequence ? 1 : 0;
525 
526  auto vx = control_sequence_.vx(offset);
527  auto wz = control_sequence_.wz(offset);
528 
529  if (isHolonomic()) {
530  auto vy = control_sequence_.vy(offset);
531  return utils::toTwistStamped(vx, vy, wz, stamp, costmap_ros_->getBaseFrameID());
532  }
533 
534  return utils::toTwistStamped(vx, wz, stamp, costmap_ros_->getBaseFrameID());
535 }
536 
537 void Optimizer::setMotionModel(const std::string & model)
538 {
539  if (model == "DiffDrive") {
540  motion_model_ = std::make_shared<DiffDriveMotionModel>();
541  } else if (model == "Omni") {
542  motion_model_ = std::make_shared<OmniMotionModel>();
543  } else if (model == "Ackermann") {
544  motion_model_ = std::make_shared<AckermannMotionModel>(parameters_handler_, name_);
545  } else {
547  std::string(
548  "Model " + model + " is not valid! Valid options are DiffDrive, Omni, "
549  "or Ackermann"));
550  }
551  motion_model_->initialize(settings_.constraints, settings_.model_dt);
552 }
553 
554 void Optimizer::setSpeedLimit(double speed_limit, bool percentage)
555 {
556  auto & s = settings_;
557  if (speed_limit == nav2_costmap_2d::NO_SPEED_LIMIT) {
558  s.constraints.vx_max = s.base_constraints.vx_max;
559  s.constraints.vx_min = s.base_constraints.vx_min;
560  s.constraints.vy = s.base_constraints.vy;
561  s.constraints.wz = s.base_constraints.wz;
562  } else {
563  if (percentage) {
564  // Speed limit is expressed in % from maximum speed of robot
565  double ratio = speed_limit / 100.0;
566  s.constraints.vx_max = s.base_constraints.vx_max * ratio;
567  s.constraints.vx_min = s.base_constraints.vx_min * ratio;
568  s.constraints.vy = s.base_constraints.vy * ratio;
569  s.constraints.wz = s.base_constraints.wz * ratio;
570  } else {
571  // Speed limit is expressed in absolute value
572  double ratio = speed_limit / s.base_constraints.vx_max;
573  s.constraints.vx_max = s.base_constraints.vx_max * ratio;
574  s.constraints.vx_min = s.base_constraints.vx_min * ratio;
575  s.constraints.vy = s.base_constraints.vy * ratio;
576  s.constraints.wz = s.base_constraints.wz * ratio;
577  }
578  }
579 }
580 
582 {
583  return generated_trajectories_;
584 }
585 
586 } // namespace mppi
void on_configure(nav2::LifecycleNode::WeakPtr parent, const std::string &name, std::shared_ptr< nav2_costmap_2d::Costmap2DROS >, ParametersHandler *)
Configure critic manager on bringup and load plugins.
void evalTrajectoriesScores(CriticData &data) const
Score trajectories by the set of loaded critic functions.
void reset(mppi::models::OptimizerSettings &settings, bool is_holonomic)
Reset noise generator with settings and model types.
void initialize(mppi::models::OptimizerSettings &settings, bool is_holonomic, const std::string &name, ParametersHandler *param_handler)
Initialize noise generator with settings and model types.
void setNoisedControls(models::State &state, const models::ControlSequence &control_sequence)
set noised control_sequence to state controls
void shutdown()
Shutdown noise generator thread.
void generateNextNoises()
Signal to the noise thread the controller is ready to generate a new noised control for the next iter...
void updateStateVelocities(models::State &state) const
Update velocities in state.
Definition: optimizer.cpp:343
const models::ControlSequence & getOptimalControlSequence()
Get the optimal control sequence for a cycle for visualization.
Definition: optimizer.cpp:476
void setMotionModel(const std::string &model)
Set the motion model of the vehicle platform.
Definition: optimizer.cpp:537
void setOffset(double controller_frequency)
Using control frequencies and time step size, determine if trajectory offset should be used to popula...
Definition: optimizer.cpp:131
Eigen::ArrayXXf getOptimizedTrajectory()
Get the optimal trajectory for a cycle for visualization.
Definition: optimizer.cpp:458
void reset(bool reset_dynamic_speed_limits=true)
Reset the optimization problem to initial conditions.
Definition: optimizer.cpp:152
rclcpp::Logger logger_
Caution, keep references.
Definition: optimizer.hpp:290
void prepare(const geometry_msgs::msg::PoseStamped &robot_pose, const geometry_msgs::msg::Twist &robot_speed, const nav_msgs::msg::Path &plan, const geometry_msgs::msg::Pose &goal, nav2_core::GoalChecker *goal_checker)
Prepare state information on new request for trajectory rollouts.
Definition: optimizer.cpp:251
std::tuple< geometry_msgs::msg::TwistStamped, Eigen::ArrayXXf > evalControl(const geometry_msgs::msg::PoseStamped &robot_pose, const geometry_msgs::msg::Twist &robot_speed, const nav_msgs::msg::Path &plan, const geometry_msgs::msg::Pose &goal, nav2_core::GoalChecker *goal_checker)
Compute control using MPPI algorithm.
Definition: optimizer.cpp:182
void initialize(nav2::LifecycleNode::WeakPtr parent, const std::string &name, std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmap_ros, std::shared_ptr< tf2_ros::Buffer > tf_buffer, ParametersHandler *dynamic_parameters_handler)
Initializes optimizer on startup.
Definition: optimizer.cpp:33
void integrateStateVelocities(models::Trajectories &trajectories, const models::State &state) const
Rollout velocities in state to poses.
Definition: optimizer.cpp:417
void updateControlSequence()
Update control sequence with state controls weighted by costs using softmax function.
Definition: optimizer.cpp:481
void generateNoisedTrajectories()
updates generated trajectories with noised trajectories from the last cycle's optimal control
Definition: optimizer.cpp:286
bool fallback(bool fail)
Perform fallback behavior to try to recover from a set of trajectories in collision.
Definition: optimizer.cpp:232
bool isHolonomic() const
Whether the motion model is holonomic.
Definition: optimizer.cpp:177
models::Trajectories & getGeneratedTrajectories()
Get the trajectories generated in a cycle for visualization.
Definition: optimizer.cpp:581
void updateInitialStateVelocities(models::State &state) const
Update initial velocity in state.
Definition: optimizer.cpp:350
void shutdown()
Shutdown for optimizer at process end.
Definition: optimizer.cpp:71
void optimize()
Main function to generate, score, and return trajectories.
Definition: optimizer.cpp:223
void setSpeedLimit(double speed_limit, bool percentage)
Set the maximum speed based on the speed limits callback.
Definition: optimizer.cpp:554
void shiftControlSequence()
Shift the optimal control sequence after processing for next iterations initial conditions after exec...
Definition: optimizer.cpp:272
void applyControlSequenceConstraints()
Apply hard vehicle constraints on control sequence.
Definition: optimizer.cpp:294
void getParams()
Obtain the main controller's parameters.
Definition: optimizer.cpp:76
void propagateStateVelocitiesFromInitials(models::State &state) const
predict velocities in state using model for time horizon equal to timesteps
Definition: optimizer.cpp:361
geometry_msgs::msg::TwistStamped getControlFromSequenceAsTwist(const builtin_interfaces::msg::Time &stamp)
Convert control sequence to a twist command.
Definition: optimizer.cpp:521
Handles getting parameters and dynamic parameter changes.
void addPostCallback(T &&callback)
Set a callback to process after parameter changes.
auto getParamGetter(const std::string &ns)
Get an object to retrieve parameters.
Function-object for checking whether a goal has been reached.
A control sequence over time (e.g. trajectory)
State information: velocities, controls, poses, speed.
Definition: state.hpp:32
void reset(unsigned int batch_size, unsigned int time_steps)
Reset state data.
Definition: state.hpp:48
Candidate Trajectories.
void reset(unsigned int batch_size, unsigned int time_steps)
Reset state data.