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  getParam(s.open_loop, "open_loop", false);
103 
104  s.base_constraints.ax_max = fabs(s.base_constraints.ax_max);
105  if (s.base_constraints.ax_min > 0.0) {
106  s.base_constraints.ax_min = -1.0 * s.base_constraints.ax_min;
107  RCLCPP_WARN(
108  logger_,
109  "Sign of the parameter ax_min is incorrect, consider setting it negative.");
110  }
111 
112  if (s.base_constraints.ay_min > 0.0) {
113  s.base_constraints.ay_min = -1.0 * s.base_constraints.ay_min;
114  RCLCPP_WARN(
115  logger_,
116  "Sign of the parameter ay_min is incorrect, consider setting it negative.");
117  }
118 
119 
120  getParam(motion_model_name, "motion_model", std::string("DiffDrive"));
121 
122  s.constraints = s.base_constraints;
123 
124  setMotionModel(motion_model_name);
125  parameters_handler_->addPostCallback([this]() {reset();});
126 
127  double controller_frequency;
128  getParentParam(controller_frequency, "controller_frequency", 0.0, ParameterType::Static);
129  setOffset(controller_frequency);
130 }
131 
132 void Optimizer::setOffset(double controller_frequency)
133 {
134  const double controller_period = 1.0 / controller_frequency;
135  constexpr double eps = 1e-6;
136 
137  if ((controller_period + eps) < settings_.model_dt) {
138  RCLCPP_WARN(
139  logger_,
140  "Controller period is less then model dt, consider setting it equal");
141  } else if (abs(controller_period - settings_.model_dt) < eps) {
142  RCLCPP_INFO(
143  logger_,
144  "Controller period is equal to model dt. Control sequence "
145  "shifting is ON");
146  settings_.shift_control_sequence = true;
147  } else {
149  "Controller period more then model dt, set it equal to model dt");
150  }
151 }
152 
153 void Optimizer::reset(bool reset_dynamic_speed_limits)
154 {
155  state_.reset(settings_.batch_size, settings_.time_steps);
156  control_sequence_.reset(settings_.time_steps);
157  control_history_[0] = {0.0f, 0.0f, 0.0f};
158  control_history_[1] = {0.0f, 0.0f, 0.0f};
159  control_history_[2] = {0.0f, 0.0f, 0.0f};
160  control_history_[3] = {0.0f, 0.0f, 0.0f};
161 
162  if (settings_.open_loop) {
163  last_command_vel_ = geometry_msgs::msg::Twist();
164  }
165 
166  if (reset_dynamic_speed_limits) {
167  settings_.constraints = settings_.base_constraints;
168  }
169 
170  costs_.setZero(settings_.batch_size);
171  generated_trajectories_.reset(settings_.batch_size, settings_.time_steps);
172 
173  noise_generator_.reset(settings_, isHolonomic());
174  motion_model_->initialize(settings_.constraints, settings_.model_dt);
175  trajectory_validator_->initialize(
176  parent_, name_ + ".TrajectoryValidator",
177  costmap_ros_, parameters_handler_, tf_buffer_, settings_);
178 
179  RCLCPP_INFO(logger_, "Optimizer reset");
180 }
181 
183 {
184  return motion_model_->isHolonomic();
185 }
186 
187 std::tuple<geometry_msgs::msg::TwistStamped, Eigen::ArrayXXf> Optimizer::evalControl(
188  const geometry_msgs::msg::PoseStamped & robot_pose,
189  const geometry_msgs::msg::Twist & robot_speed,
190  const nav_msgs::msg::Path & plan,
191  const geometry_msgs::msg::Pose & goal,
192  nav2_core::GoalChecker * goal_checker)
193 {
194  prepare(robot_pose, robot_speed, plan, goal, goal_checker);
195  Eigen::ArrayXXf optimal_trajectory;
196  bool trajectory_valid = true;
197 
198  do {
199  optimize();
200  optimal_trajectory = getOptimizedTrajectory();
201  switch (trajectory_validator_->validateTrajectory(
202  optimal_trajectory, control_sequence_, robot_pose, robot_speed, plan, goal))
203  {
204  case mppi::ValidationResult::SOFT_RESET:
205  trajectory_valid = false;
206  RCLCPP_WARN(logger_, "Soft reset triggered by trajectory validator");
207  break;
208  case mppi::ValidationResult::FAILURE:
210  "Trajectory validator failed to validate trajectory, hard reset triggered.");
211  case mppi::ValidationResult::SUCCESS:
212  default:
213  trajectory_valid = true;
214  break;
215  }
216  } while (fallback(critics_data_.fail_flag || !trajectory_valid));
217 
218  utils::savitskyGolayFilter(control_sequence_, control_history_, settings_);
219  auto control = getControlFromSequenceAsTwist(plan.header.stamp);
220 
221  last_command_vel_ = control.twist;
222 
223  if (settings_.shift_control_sequence) {
225  }
226 
227  return std::make_tuple(control, optimal_trajectory);
228 }
229 
231 {
232  for (size_t i = 0; i < settings_.iteration_count; ++i) {
234  critic_manager_.evalTrajectoriesScores(critics_data_);
236  }
237 }
238 
239 bool Optimizer::fallback(bool fail)
240 {
241  static size_t counter = 0;
242 
243  if (!fail) {
244  counter = 0;
245  return false;
246  }
247 
248  reset();
249 
250  if (++counter > settings_.retry_attempt_limit) {
251  counter = 0;
252  throw nav2_core::NoValidControl("Optimizer fail to compute path");
253  }
254 
255  return true;
256 }
257 
259  const geometry_msgs::msg::PoseStamped & robot_pose,
260  const geometry_msgs::msg::Twist & robot_speed,
261  const nav_msgs::msg::Path & plan,
262  const geometry_msgs::msg::Pose & goal,
263  nav2_core::GoalChecker * goal_checker)
264 {
265  state_.pose = robot_pose;
266  state_.speed = settings_.open_loop ? last_command_vel_ : robot_speed;
267  state_.local_path_length = nav2_util::geometry_utils::calculate_path_length(plan);
268  path_ = utils::toTensor(plan);
269  costs_.setZero();
270  goal_ = goal;
271 
272  critics_data_.fail_flag = false;
273  critics_data_.goal_checker = goal_checker;
274  critics_data_.motion_model = motion_model_;
275  critics_data_.furthest_reached_path_point.reset();
276  critics_data_.path_pts_valid.reset();
277 }
278 
280 {
281  auto size = control_sequence_.vx.size();
282  utils::shiftColumnsByOnePlace(control_sequence_.vx, -1);
283  utils::shiftColumnsByOnePlace(control_sequence_.wz, -1);
284  control_sequence_.vx(size - 1) = control_sequence_.vx(size - 2);
285  control_sequence_.wz(size - 1) = control_sequence_.wz(size - 2);
286 
287  if (isHolonomic()) {
288  utils::shiftColumnsByOnePlace(control_sequence_.vy, -1);
289  control_sequence_.vy(size - 1) = control_sequence_.vy(size - 2);
290  }
291 }
292 
294 {
295  noise_generator_.setNoisedControls(state_, control_sequence_);
296  noise_generator_.generateNextNoises();
297  updateStateVelocities(state_);
298  integrateStateVelocities(generated_trajectories_, state_);
299 }
300 
302 {
303  auto & s = settings_;
304 
305  float max_delta_vx = s.model_dt * s.constraints.ax_max;
306  float min_delta_vx = s.model_dt * s.constraints.ax_min;
307  float max_delta_vy = s.model_dt * s.constraints.ay_max;
308  float min_delta_vy = s.model_dt * s.constraints.ay_min;
309  float max_delta_wz = s.model_dt * s.constraints.az_max;
310  float vx_last = utils::clamp(s.constraints.vx_min, s.constraints.vx_max, control_sequence_.vx(0));
311  float wz_last = utils::clamp(-s.constraints.wz, s.constraints.wz, control_sequence_.wz(0));
312  control_sequence_.vx(0) = vx_last;
313  control_sequence_.wz(0) = wz_last;
314  float vy_last = 0;
315  if (isHolonomic()) {
316  vy_last = utils::clamp(-s.constraints.vy, s.constraints.vy, control_sequence_.vy(0));
317  control_sequence_.vy(0) = vy_last;
318  }
319 
320  for (unsigned int i = 1; i != control_sequence_.vx.size(); i++) {
321  float & vx_curr = control_sequence_.vx(i);
322  vx_curr = utils::clamp(s.constraints.vx_min, s.constraints.vx_max, vx_curr);
323  if(vx_last > 0) {
324  vx_curr = utils::clamp(vx_last + min_delta_vx, vx_last + max_delta_vx, vx_curr);
325  } else {
326  vx_curr = utils::clamp(vx_last - max_delta_vx, vx_last - min_delta_vx, vx_curr);
327  }
328  vx_last = vx_curr;
329 
330  float & wz_curr = control_sequence_.wz(i);
331  wz_curr = utils::clamp(-s.constraints.wz, s.constraints.wz, wz_curr);
332  wz_curr = utils::clamp(wz_last - max_delta_wz, wz_last + max_delta_wz, wz_curr);
333  wz_last = wz_curr;
334 
335  if (isHolonomic()) {
336  float & vy_curr = control_sequence_.vy(i);
337  vy_curr = utils::clamp(-s.constraints.vy, s.constraints.vy, vy_curr);
338  if(vy_last > 0) {
339  vy_curr = utils::clamp(vy_last + min_delta_vy, vy_last + max_delta_vy, vy_curr);
340  } else {
341  vy_curr = utils::clamp(vy_last - max_delta_vy, vy_last - min_delta_vy, vy_curr);
342  }
343  vy_last = vy_curr;
344  }
345  }
346 
347  motion_model_->applyConstraints(control_sequence_);
348 }
349 
351  models::State & state) const
352 {
355 }
356 
358 {
359  state.vx.col(0) = static_cast<float>(state.speed.linear.x);
360  state.wz.col(0) = static_cast<float>(state.speed.angular.z);
361 
362  if (isHolonomic()) {
363  state.vy.col(0) = static_cast<float>(state.speed.linear.y);
364  }
365 }
366 
368  models::State & state) const
369 {
370  motion_model_->predict(state);
371 }
372 
374  Eigen::Array<float, Eigen::Dynamic, 3> & trajectory,
375  const Eigen::ArrayXXf & sequence) const
376 {
377  float initial_yaw = static_cast<float>(tf2::getYaw(state_.pose.pose.orientation));
378 
379  const auto vx = sequence.col(0);
380  const auto wz = sequence.col(1);
381 
382  auto traj_x = trajectory.col(0);
383  auto traj_y = trajectory.col(1);
384  auto traj_yaws = trajectory.col(2);
385 
386  const size_t n_size = traj_yaws.size();
387  if (n_size == 0) {
388  return;
389  }
390 
391  float last_yaw = initial_yaw;
392  for(size_t i = 0; i != n_size; i++) {
393  last_yaw += wz(i) * settings_.model_dt;
394  traj_yaws(i) = last_yaw;
395  }
396 
397  Eigen::ArrayXf yaw_cos = traj_yaws.cos();
398  Eigen::ArrayXf yaw_sin = traj_yaws.sin();
399  utils::shiftColumnsByOnePlace(yaw_cos, 1);
400  utils::shiftColumnsByOnePlace(yaw_sin, 1);
401  yaw_cos(0) = cosf(initial_yaw);
402  yaw_sin(0) = sinf(initial_yaw);
403 
404  auto dx = (vx * yaw_cos).eval();
405  auto dy = (vx * yaw_sin).eval();
406 
407  if (isHolonomic()) {
408  auto vy = sequence.col(2);
409  dx = (dx - vy * yaw_sin).eval();
410  dy = (dy + vy * yaw_cos).eval();
411  }
412 
413  float last_x = state_.pose.pose.position.x;
414  float last_y = state_.pose.pose.position.y;
415  for(size_t i = 0; i != n_size; i++) {
416  last_x += dx(i) * settings_.model_dt;
417  last_y += dy(i) * settings_.model_dt;
418  traj_x(i) = last_x;
419  traj_y(i) = last_y;
420  }
421 }
422 
424  models::Trajectories & trajectories,
425  const models::State & state) const
426 {
427  auto initial_yaw = static_cast<float>(tf2::getYaw(state.pose.pose.orientation));
428  const size_t n_cols = trajectories.yaws.cols();
429 
430  Eigen::ArrayXf last_yaws = Eigen::ArrayXf::Constant(trajectories.yaws.rows(), initial_yaw);
431  for (size_t i = 0; i != n_cols; i++) {
432  last_yaws += state.wz.col(i) * settings_.model_dt;
433  trajectories.yaws.col(i) = last_yaws;
434  }
435 
436  Eigen::ArrayXXf yaw_cos = trajectories.yaws.cos();
437  Eigen::ArrayXXf yaw_sin = trajectories.yaws.sin();
438  utils::shiftColumnsByOnePlace(yaw_cos, 1);
439  utils::shiftColumnsByOnePlace(yaw_sin, 1);
440  yaw_cos.col(0) = cosf(initial_yaw);
441  yaw_sin.col(0) = sinf(initial_yaw);
442 
443  auto dx = (state.vx * yaw_cos).eval();
444  auto dy = (state.vx * yaw_sin).eval();
445 
446  if (isHolonomic()) {
447  dx -= state.vy * yaw_sin;
448  dy += state.vy * yaw_cos;
449  }
450 
451  Eigen::ArrayXf last_x = Eigen::ArrayXf::Constant(trajectories.x.rows(),
452  state.pose.pose.position.x);
453  Eigen::ArrayXf last_y = Eigen::ArrayXf::Constant(trajectories.y.rows(),
454  state.pose.pose.position.y);
455 
456  for (size_t i = 0; i != n_cols; i++) {
457  last_x += dx.col(i) * settings_.model_dt;
458  last_y += dy.col(i) * settings_.model_dt;
459  trajectories.x.col(i) = last_x;
460  trajectories.y.col(i) = last_y;
461  }
462 }
463 
465 {
466  const bool is_holo = isHolonomic();
467  Eigen::ArrayXXf sequence = Eigen::ArrayXXf(settings_.time_steps, is_holo ? 3 : 2);
468  Eigen::Array<float, Eigen::Dynamic, 3> trajectories =
469  Eigen::Array<float, Eigen::Dynamic, 3>(settings_.time_steps, 3);
470 
471  sequence.col(0) = control_sequence_.vx;
472  sequence.col(1) = control_sequence_.wz;
473 
474  if (is_holo) {
475  sequence.col(2) = control_sequence_.vy;
476  }
477 
478  integrateStateVelocities(trajectories, sequence);
479  return trajectories;
480 }
481 
483 {
484  return control_sequence_;
485 }
486 
488 {
489  const bool is_holo = isHolonomic();
490  auto & s = settings_;
491 
492  auto vx_T = control_sequence_.vx.transpose();
493  auto bounded_noises_vx = state_.cvx.rowwise() - vx_T;
494  const float gamma_vx = s.gamma / (s.sampling_std.vx * s.sampling_std.vx);
495  costs_ += (gamma_vx * (bounded_noises_vx.rowwise() * vx_T).rowwise().sum()).eval();
496 
497  if (s.sampling_std.wz > 0.0f) {
498  auto wz_T = control_sequence_.wz.transpose();
499  auto bounded_noises_wz = state_.cwz.rowwise() - wz_T;
500  const float gamma_wz = s.gamma / (s.sampling_std.wz * s.sampling_std.wz);
501  costs_ += (gamma_wz * (bounded_noises_wz.rowwise() * wz_T).rowwise().sum()).eval();
502  }
503 
504  if (is_holo) {
505  auto vy_T = control_sequence_.vy.transpose();
506  auto bounded_noises_vy = state_.cvy.rowwise() - vy_T;
507  const float gamma_vy = s.gamma / (s.sampling_std.vy * s.sampling_std.vy);
508  costs_ += (gamma_vy * (bounded_noises_vy.rowwise() * vy_T).rowwise().sum()).eval();
509  }
510 
511  auto costs_normalized = costs_ - costs_.minCoeff();
512  const float inv_temp = 1.0f / s.temperature;
513  auto softmaxes = (-inv_temp * costs_normalized).exp().eval();
514  softmaxes /= softmaxes.sum();
515 
516  auto softmax_mat = softmaxes.matrix();
517  control_sequence_.vx = state_.cvx.transpose().matrix() * softmax_mat;
518  control_sequence_.wz = state_.cwz.transpose().matrix() * softmax_mat;
519 
520  if (is_holo) {
521  control_sequence_.vy = state_.cvy.transpose().matrix() * softmax_mat;
522  }
523 
525 }
526 
527 geometry_msgs::msg::TwistStamped Optimizer::getControlFromSequenceAsTwist(
528  const builtin_interfaces::msg::Time & stamp)
529 {
530  unsigned int offset = settings_.shift_control_sequence ? 1 : 0;
531 
532  auto vx = control_sequence_.vx(offset);
533  auto wz = control_sequence_.wz(offset);
534 
535  if (isHolonomic()) {
536  auto vy = control_sequence_.vy(offset);
537  return utils::toTwistStamped(vx, vy, wz, stamp, costmap_ros_->getBaseFrameID());
538  }
539 
540  return utils::toTwistStamped(vx, wz, stamp, costmap_ros_->getBaseFrameID());
541 }
542 
543 void Optimizer::setMotionModel(const std::string & model)
544 {
545  if (model == "DiffDrive") {
546  motion_model_ = std::make_shared<DiffDriveMotionModel>();
547  } else if (model == "Omni") {
548  motion_model_ = std::make_shared<OmniMotionModel>();
549  } else if (model == "Ackermann") {
550  motion_model_ = std::make_shared<AckermannMotionModel>(parameters_handler_, name_);
551  } else {
553  std::string(
554  "Model " + model + " is not valid! Valid options are DiffDrive, Omni, "
555  "or Ackermann"));
556  }
557  motion_model_->initialize(settings_.constraints, settings_.model_dt);
558 }
559 
560 void Optimizer::setSpeedLimit(double speed_limit, bool percentage)
561 {
562  auto & s = settings_;
563  if (speed_limit == nav2_costmap_2d::NO_SPEED_LIMIT) {
564  s.constraints.vx_max = s.base_constraints.vx_max;
565  s.constraints.vx_min = s.base_constraints.vx_min;
566  s.constraints.vy = s.base_constraints.vy;
567  s.constraints.wz = s.base_constraints.wz;
568  } else {
569  if (percentage) {
570  // Speed limit is expressed in % from maximum speed of robot
571  double ratio = speed_limit / 100.0;
572  s.constraints.vx_max = s.base_constraints.vx_max * ratio;
573  s.constraints.vx_min = s.base_constraints.vx_min * ratio;
574  s.constraints.vy = s.base_constraints.vy * ratio;
575  s.constraints.wz = s.base_constraints.wz * ratio;
576  } else {
577  // Speed limit is expressed in absolute value
578  double ratio = speed_limit / s.base_constraints.vx_max;
579  s.constraints.vx_max = s.base_constraints.vx_max * ratio;
580  s.constraints.vx_min = s.base_constraints.vx_min * ratio;
581  s.constraints.vy = s.base_constraints.vy * ratio;
582  s.constraints.wz = s.base_constraints.wz * ratio;
583  }
584  }
585 }
586 
588 {
589  return generated_trajectories_;
590 }
591 
592 } // 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:350
const models::ControlSequence & getOptimalControlSequence()
Get the optimal control sequence for a cycle for visualization.
Definition: optimizer.cpp:482
void setMotionModel(const std::string &model)
Set the motion model of the vehicle platform.
Definition: optimizer.cpp:543
void setOffset(double controller_frequency)
Using control frequencies and time step size, determine if trajectory offset should be used to popula...
Definition: optimizer.cpp:132
Eigen::ArrayXXf getOptimizedTrajectory()
Get the optimal trajectory for a cycle for visualization.
Definition: optimizer.cpp:464
void reset(bool reset_dynamic_speed_limits=true)
Reset the optimization problem to initial conditions.
Definition: optimizer.cpp:153
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:258
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:187
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:423
void updateControlSequence()
Update control sequence with state controls weighted by costs using softmax function.
Definition: optimizer.cpp:487
void generateNoisedTrajectories()
updates generated trajectories with noised trajectories from the last cycle's optimal control
Definition: optimizer.cpp:293
bool fallback(bool fail)
Perform fallback behavior to try to recover from a set of trajectories in collision.
Definition: optimizer.cpp:239
bool isHolonomic() const
Whether the motion model is holonomic.
Definition: optimizer.cpp:182
models::Trajectories & getGeneratedTrajectories()
Get the trajectories generated in a cycle for visualization.
Definition: optimizer.cpp:587
void updateInitialStateVelocities(models::State &state) const
Update initial velocity in state.
Definition: optimizer.cpp:357
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:230
void setSpeedLimit(double speed_limit, bool percentage)
Set the maximum speed based on the speed limits callback.
Definition: optimizer.cpp:560
void shiftControlSequence()
Shift the optimal control sequence after processing for next iterations initial conditions after exec...
Definition: optimizer.cpp:279
void applyControlSequenceConstraints()
Apply hard vehicle constraints on control sequence.
Definition: optimizer.cpp:301
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:367
geometry_msgs::msg::TwistStamped getControlFromSequenceAsTwist(const builtin_interfaces::msg::Time &stamp)
Convert control sequence to a twist command.
Definition: optimizer.cpp:527
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.