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  path_ = utils::toTensor(plan);
261  costs_.setZero();
262  goal_ = goal;
263 
264  critics_data_.fail_flag = false;
265  critics_data_.goal_checker = goal_checker;
266  critics_data_.motion_model = motion_model_;
267  critics_data_.furthest_reached_path_point.reset();
268  critics_data_.path_pts_valid.reset();
269 }
270 
272 {
273  auto size = control_sequence_.vx.size();
274  utils::shiftColumnsByOnePlace(control_sequence_.vx, -1);
275  utils::shiftColumnsByOnePlace(control_sequence_.wz, -1);
276  control_sequence_.vx(size - 1) = control_sequence_.vx(size - 2);
277  control_sequence_.wz(size - 1) = control_sequence_.wz(size - 2);
278 
279  if (isHolonomic()) {
280  utils::shiftColumnsByOnePlace(control_sequence_.vy, -1);
281  control_sequence_.vy(size - 1) = control_sequence_.vy(size - 2);
282  }
283 }
284 
286 {
287  noise_generator_.setNoisedControls(state_, control_sequence_);
288  noise_generator_.generateNextNoises();
289  updateStateVelocities(state_);
290  integrateStateVelocities(generated_trajectories_, state_);
291 }
292 
294 {
295  auto & s = settings_;
296 
297  float max_delta_vx = s.model_dt * s.constraints.ax_max;
298  float min_delta_vx = s.model_dt * s.constraints.ax_min;
299  float max_delta_vy = s.model_dt * s.constraints.ay_max;
300  float min_delta_vy = s.model_dt * s.constraints.ay_min;
301  float max_delta_wz = s.model_dt * s.constraints.az_max;
302  float vx_last = utils::clamp(s.constraints.vx_min, s.constraints.vx_max, control_sequence_.vx(0));
303  float wz_last = utils::clamp(-s.constraints.wz, s.constraints.wz, control_sequence_.wz(0));
304  control_sequence_.vx(0) = vx_last;
305  control_sequence_.wz(0) = wz_last;
306  float vy_last = 0;
307  if (isHolonomic()) {
308  vy_last = utils::clamp(-s.constraints.vy, s.constraints.vy, control_sequence_.vy(0));
309  control_sequence_.vy(0) = vy_last;
310  }
311 
312  for (unsigned int i = 1; i != control_sequence_.vx.size(); i++) {
313  float & vx_curr = control_sequence_.vx(i);
314  vx_curr = utils::clamp(s.constraints.vx_min, s.constraints.vx_max, vx_curr);
315  if(vx_last > 0) {
316  vx_curr = utils::clamp(vx_last + min_delta_vx, vx_last + max_delta_vx, vx_curr);
317  } else {
318  vx_curr = utils::clamp(vx_last - max_delta_vx, vx_last - min_delta_vx, vx_curr);
319  }
320  vx_last = vx_curr;
321 
322  float & wz_curr = control_sequence_.wz(i);
323  wz_curr = utils::clamp(-s.constraints.wz, s.constraints.wz, wz_curr);
324  wz_curr = utils::clamp(wz_last - max_delta_wz, wz_last + max_delta_wz, wz_curr);
325  wz_last = wz_curr;
326 
327  if (isHolonomic()) {
328  float & vy_curr = control_sequence_.vy(i);
329  vy_curr = utils::clamp(-s.constraints.vy, s.constraints.vy, vy_curr);
330  if(vy_last > 0) {
331  vy_curr = utils::clamp(vy_last + min_delta_vy, vy_last + max_delta_vy, vy_curr);
332  } else {
333  vy_curr = utils::clamp(vy_last - max_delta_vy, vy_last - min_delta_vy, vy_curr);
334  }
335  vy_last = vy_curr;
336  }
337  }
338 
339  motion_model_->applyConstraints(control_sequence_);
340 }
341 
343  models::State & state) const
344 {
347 }
348 
350  models::State & state) const
351 {
352  state.vx.col(0) = static_cast<float>(state.speed.linear.x);
353  state.wz.col(0) = static_cast<float>(state.speed.angular.z);
354 
355  if (isHolonomic()) {
356  state.vy.col(0) = static_cast<float>(state.speed.linear.y);
357  }
358 }
359 
361  models::State & state) const
362 {
363  motion_model_->predict(state);
364 }
365 
367  Eigen::Array<float, Eigen::Dynamic, 3> & trajectory,
368  const Eigen::ArrayXXf & sequence) const
369 {
370  float initial_yaw = static_cast<float>(tf2::getYaw(state_.pose.pose.orientation));
371 
372  const auto vx = sequence.col(0);
373  const auto wz = sequence.col(1);
374 
375  auto traj_x = trajectory.col(0);
376  auto traj_y = trajectory.col(1);
377  auto traj_yaws = trajectory.col(2);
378 
379  const size_t n_size = traj_yaws.size();
380  if (n_size == 0) {
381  return;
382  }
383 
384  float last_yaw = initial_yaw;
385  for(size_t i = 0; i != n_size; i++) {
386  last_yaw += wz(i) * settings_.model_dt;
387  traj_yaws(i) = last_yaw;
388  }
389 
390  Eigen::ArrayXf yaw_cos = traj_yaws.cos();
391  Eigen::ArrayXf yaw_sin = traj_yaws.sin();
392  utils::shiftColumnsByOnePlace(yaw_cos, 1);
393  utils::shiftColumnsByOnePlace(yaw_sin, 1);
394  yaw_cos(0) = cosf(initial_yaw);
395  yaw_sin(0) = sinf(initial_yaw);
396 
397  auto dx = (vx * yaw_cos).eval();
398  auto dy = (vx * yaw_sin).eval();
399 
400  if (isHolonomic()) {
401  auto vy = sequence.col(2);
402  dx = (dx - vy * yaw_sin).eval();
403  dy = (dy + vy * yaw_cos).eval();
404  }
405 
406  float last_x = state_.pose.pose.position.x;
407  float last_y = state_.pose.pose.position.y;
408  for(size_t i = 0; i != n_size; i++) {
409  last_x += dx(i) * settings_.model_dt;
410  last_y += dy(i) * settings_.model_dt;
411  traj_x(i) = last_x;
412  traj_y(i) = last_y;
413  }
414 }
415 
417  models::Trajectories & trajectories,
418  const models::State & state) const
419 {
420  auto initial_yaw = static_cast<float>(tf2::getYaw(state.pose.pose.orientation));
421  const size_t n_cols = trajectories.yaws.cols();
422 
423  Eigen::ArrayXf last_yaws = Eigen::ArrayXf::Constant(trajectories.yaws.rows(), initial_yaw);
424  for (size_t i = 0; i != n_cols; i++) {
425  last_yaws += state.wz.col(i) * settings_.model_dt;
426  trajectories.yaws.col(i) = last_yaws;
427  }
428 
429  Eigen::ArrayXXf yaw_cos = trajectories.yaws.cos();
430  Eigen::ArrayXXf yaw_sin = trajectories.yaws.sin();
431  utils::shiftColumnsByOnePlace(yaw_cos, 1);
432  utils::shiftColumnsByOnePlace(yaw_sin, 1);
433  yaw_cos.col(0) = cosf(initial_yaw);
434  yaw_sin.col(0) = sinf(initial_yaw);
435 
436  auto dx = (state.vx * yaw_cos).eval();
437  auto dy = (state.vx * yaw_sin).eval();
438 
439  if (isHolonomic()) {
440  dx -= state.vy * yaw_sin;
441  dy += state.vy * yaw_cos;
442  }
443 
444  Eigen::ArrayXf last_x = Eigen::ArrayXf::Constant(trajectories.x.rows(),
445  state.pose.pose.position.x);
446  Eigen::ArrayXf last_y = Eigen::ArrayXf::Constant(trajectories.y.rows(),
447  state.pose.pose.position.y);
448 
449  for (size_t i = 0; i != n_cols; i++) {
450  last_x += dx.col(i) * settings_.model_dt;
451  last_y += dy.col(i) * settings_.model_dt;
452  trajectories.x.col(i) = last_x;
453  trajectories.y.col(i) = last_y;
454  }
455 }
456 
458 {
459  const bool is_holo = isHolonomic();
460  Eigen::ArrayXXf sequence = Eigen::ArrayXXf(settings_.time_steps, is_holo ? 3 : 2);
461  Eigen::Array<float, Eigen::Dynamic, 3> trajectories =
462  Eigen::Array<float, Eigen::Dynamic, 3>(settings_.time_steps, 3);
463 
464  sequence.col(0) = control_sequence_.vx;
465  sequence.col(1) = control_sequence_.wz;
466 
467  if (is_holo) {
468  sequence.col(2) = control_sequence_.vy;
469  }
470 
471  integrateStateVelocities(trajectories, sequence);
472  return trajectories;
473 }
474 
476 {
477  return control_sequence_;
478 }
479 
481 {
482  const bool is_holo = isHolonomic();
483  auto & s = settings_;
484 
485  auto vx_T = control_sequence_.vx.transpose();
486  auto bounded_noises_vx = state_.cvx.rowwise() - vx_T;
487  const float gamma_vx = s.gamma / (s.sampling_std.vx * s.sampling_std.vx);
488  costs_ += (gamma_vx * (bounded_noises_vx.rowwise() * vx_T).rowwise().sum()).eval();
489 
490  if (s.sampling_std.wz > 0.0f) {
491  auto wz_T = control_sequence_.wz.transpose();
492  auto bounded_noises_wz = state_.cwz.rowwise() - wz_T;
493  const float gamma_wz = s.gamma / (s.sampling_std.wz * s.sampling_std.wz);
494  costs_ += (gamma_wz * (bounded_noises_wz.rowwise() * wz_T).rowwise().sum()).eval();
495  }
496 
497  if (is_holo) {
498  auto vy_T = control_sequence_.vy.transpose();
499  auto bounded_noises_vy = state_.cvy.rowwise() - vy_T;
500  const float gamma_vy = s.gamma / (s.sampling_std.vy * s.sampling_std.vy);
501  costs_ += (gamma_vy * (bounded_noises_vy.rowwise() * vy_T).rowwise().sum()).eval();
502  }
503 
504  auto costs_normalized = costs_ - costs_.minCoeff();
505  const float inv_temp = 1.0f / s.temperature;
506  auto softmaxes = (-inv_temp * costs_normalized).exp().eval();
507  softmaxes /= softmaxes.sum();
508 
509  auto softmax_mat = softmaxes.matrix();
510  control_sequence_.vx = state_.cvx.transpose().matrix() * softmax_mat;
511  control_sequence_.wz = state_.cwz.transpose().matrix() * softmax_mat;
512 
513  if (is_holo) {
514  control_sequence_.vy = state_.cvy.transpose().matrix() * softmax_mat;
515  }
516 
518 }
519 
520 geometry_msgs::msg::TwistStamped Optimizer::getControlFromSequenceAsTwist(
521  const builtin_interfaces::msg::Time & stamp)
522 {
523  unsigned int offset = settings_.shift_control_sequence ? 1 : 0;
524 
525  auto vx = control_sequence_.vx(offset);
526  auto wz = control_sequence_.wz(offset);
527 
528  if (isHolonomic()) {
529  auto vy = control_sequence_.vy(offset);
530  return utils::toTwistStamped(vx, vy, wz, stamp, costmap_ros_->getBaseFrameID());
531  }
532 
533  return utils::toTwistStamped(vx, wz, stamp, costmap_ros_->getBaseFrameID());
534 }
535 
536 void Optimizer::setMotionModel(const std::string & model)
537 {
538  if (model == "DiffDrive") {
539  motion_model_ = std::make_shared<DiffDriveMotionModel>();
540  } else if (model == "Omni") {
541  motion_model_ = std::make_shared<OmniMotionModel>();
542  } else if (model == "Ackermann") {
543  motion_model_ = std::make_shared<AckermannMotionModel>(parameters_handler_, name_);
544  } else {
546  std::string(
547  "Model " + model + " is not valid! Valid options are DiffDrive, Omni, "
548  "or Ackermann"));
549  }
550  motion_model_->initialize(settings_.constraints, settings_.model_dt);
551 }
552 
553 void Optimizer::setSpeedLimit(double speed_limit, bool percentage)
554 {
555  auto & s = settings_;
556  if (speed_limit == nav2_costmap_2d::NO_SPEED_LIMIT) {
557  s.constraints.vx_max = s.base_constraints.vx_max;
558  s.constraints.vx_min = s.base_constraints.vx_min;
559  s.constraints.vy = s.base_constraints.vy;
560  s.constraints.wz = s.base_constraints.wz;
561  } else {
562  if (percentage) {
563  // Speed limit is expressed in % from maximum speed of robot
564  double ratio = speed_limit / 100.0;
565  s.constraints.vx_max = s.base_constraints.vx_max * ratio;
566  s.constraints.vx_min = s.base_constraints.vx_min * ratio;
567  s.constraints.vy = s.base_constraints.vy * ratio;
568  s.constraints.wz = s.base_constraints.wz * ratio;
569  } else {
570  // Speed limit is expressed in absolute value
571  double ratio = speed_limit / s.base_constraints.vx_max;
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  }
577  }
578 }
579 
581 {
582  return generated_trajectories_;
583 }
584 
585 } // 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:342
const models::ControlSequence & getOptimalControlSequence()
Get the optimal control sequence for a cycle for visualization.
Definition: optimizer.cpp:475
void setMotionModel(const std::string &model)
Set the motion model of the vehicle platform.
Definition: optimizer.cpp:536
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:457
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:289
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:416
void updateControlSequence()
Update control sequence with state controls weighted by costs using softmax function.
Definition: optimizer.cpp:480
void generateNoisedTrajectories()
updates generated trajectories with noised trajectories from the last cycle's optimal control
Definition: optimizer.cpp:285
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:580
void updateInitialStateVelocities(models::State &state) const
Update initial velocity in state.
Definition: optimizer.cpp:349
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:553
void shiftControlSequence()
Shift the optimal control sequence after processing for next iterations initial conditions after exec...
Definition: optimizer.cpp:271
void applyControlSequenceConstraints()
Apply hard vehicle constraints on control sequence.
Definition: optimizer.cpp:293
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:360
geometry_msgs::msg::TwistStamped getControlFromSequenceAsTwist(const builtin_interfaces::msg::Time &stamp)
Convert control sequence to a twist command.
Definition: optimizer.cpp:520
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:47
Candidate Trajectories.
void reset(unsigned int batch_size, unsigned int time_steps)
Reset state data.