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