moveit2
The MoveIt Motion Planning Framework for ROS 2.
plan_execution.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ioan Sucan */
36 
42 #include <boost/algorithm/string/join.hpp>
43 #include <rclcpp/logger.hpp>
44 #include <rclcpp/logging.hpp>
45 #include <rclcpp/node.hpp>
46 #include <rclcpp/parameter_value.hpp>
47 #include <rclcpp/rate.hpp>
48 #include <rclcpp/utilities.hpp>
49 
50 // #include <dynamic_reconfigure/server.h>
51 // #include <moveit_ros_planning/PlanExecutionDynamicReconfigureConfig.h>
52 
53 namespace plan_execution
54 {
55 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_ros.plan_execution");
56 
57 // class PlanExecution::DynamicReconfigureImpl
58 // {
59 // public:
60 // DynamicReconfigureImpl(PlanExecution* owner)
61 // : owner_(owner) //, dynamic_reconfigure_server_(ros::NodeHandle("~/plan_execution"))
62 // {
63 // // dynamic_reconfigure_server_.setCallback(
64 // // [this](const auto& config, uint32_t level) { dynamicReconfigureCallback(config, level); });
65 // }
66 //
67 // private:
68 // // void dynamicReconfigureCallback(const PlanExecutionDynamicReconfigureConfig& config, uint32_t level)
69 // // {
70 // // owner_->setMaxReplanAttempts(config.max_replan_attempts);
71 // // owner_->setTrajectoryStateRecordingFrequency(config.record_trajectory_state_frequency);
72 // // }
73 //
74 // PlanExecution* owner_;
75 // // dynamic_reconfigure::Server<PlanExecutionDynamicReconfigureConfig> dynamic_reconfigure_server_;
76 // };
77 } // namespace plan_execution
78 
80  const rclcpp::Node::SharedPtr& node, const planning_scene_monitor::PlanningSceneMonitorPtr& planning_scene_monitor,
81  const trajectory_execution_manager::TrajectoryExecutionManagerPtr& trajectory_execution)
82  : node_(node), planning_scene_monitor_(planning_scene_monitor), trajectory_execution_manager_(trajectory_execution)
83 {
84  if (!trajectory_execution_manager_)
85  trajectory_execution_manager_ = std::make_shared<trajectory_execution_manager::TrajectoryExecutionManager>(
86  node_, planning_scene_monitor_->getRobotModel(), planning_scene_monitor_->getStateMonitor());
87 
88  default_max_replan_attempts_ = 5;
89 
90  new_scene_update_ = false;
91 
92  // we want to be notified when new information is available
93  planning_scene_monitor_->addUpdateCallback(
95  planningSceneUpdatedCallback(update_type);
96  });
97 
98  // start the dynamic-reconfigure server
99  // reconfigure_impl_ = new DynamicReconfigureImpl(this);
100 }
101 
103 {
104  // delete reconfigure_impl_;
105 }
106 
108 {
109  preempt_.request();
110 }
111 
112 std::string plan_execution::PlanExecution::getErrorCodeString(const moveit_msgs::msg::MoveItErrorCodes& error_code)
113 {
114  if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
115  return "Success";
116  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::INVALID_GROUP_NAME)
117  return "Invalid group name";
118  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::PLANNING_FAILED)
119  return "Planning failed.";
120  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::INVALID_MOTION_PLAN)
121  return "Invalid motion plan";
122  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA)
123  return "Unable to acquire sensor data";
124  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE)
125  return "Motion plan invalidated by environment change";
126  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::CONTROL_FAILED)
127  return "Controller failed during execution";
128  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::TIMED_OUT)
129  return "Timeout reached";
130  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::PREEMPTED)
131  return "Preempted";
132  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::INVALID_GOAL_CONSTRAINTS)
133  return "Invalid goal constraints";
134  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::INVALID_OBJECT_NAME)
135  return "Invalid object name";
136  else if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::FAILURE)
137  return "Catastrophic failure";
138  return "Unknown event";
139 }
140 
142 {
143  plan.planning_scene_monitor_ = planning_scene_monitor_;
144  plan.planning_scene_ = planning_scene_monitor_->getPlanningScene();
145  planAndExecuteHelper(plan, opt);
146 }
147 
149  const moveit_msgs::msg::PlanningScene& scene_diff,
150  const Options& opt)
151 {
152  if (moveit::core::isEmpty(scene_diff))
153  planAndExecute(plan, opt);
154  else
155  {
156  plan.planning_scene_monitor_ = planning_scene_monitor_;
157  {
158  planning_scene_monitor::LockedPlanningSceneRO lscene(planning_scene_monitor_); // lock the scene so that it does
159  // not modify the world
160  // representation while diff() is
161  // called
162  plan.planning_scene_ = lscene->diff(scene_diff);
163  }
164  planAndExecuteHelper(plan, opt);
165  }
166 }
167 
168 void plan_execution::PlanExecution::planAndExecuteHelper(ExecutableMotionPlan& plan, const Options& opt)
169 {
170  // perform initial configuration steps & various checks
171  preempt_.checkAndClear(); // clear any previous preempt_ request
172 
173  bool preempt_requested = false;
174 
175  // run the actual motion plan & execution
176  unsigned int max_replan_attempts =
177  opt.replan_ ? (opt.replan_attempts_ > 0 ? opt.replan_attempts_ : default_max_replan_attempts_) : 1;
178  unsigned int replan_attempts = 0;
179  bool previously_solved = false;
180 
181  // run a planning loop for at most the maximum replanning attempts;
182  // re-planning is executed only in case of known types of failures (e.g., environment changed)
183  do
184  {
185  replan_attempts++;
186  RCLCPP_INFO(LOGGER, "Planning attempt %u of at most %u", replan_attempts, max_replan_attempts);
187 
188  if (opt.before_plan_callback_)
189  opt.before_plan_callback_();
190 
191  new_scene_update_ = false; // we clear any scene updates to be evaluated because we are about to compute a new
192  // plan, which should consider most recent updates already
193 
194  // if we never had a solved plan, or there is no specified way of fixing plans, just call the planner; otherwise,
195  // try to repair the plan we previously had;
196  bool solved =
197  (!previously_solved || !opt.repair_plan_callback_) ?
198  opt.plan_callback_(plan) :
199  opt.repair_plan_callback_(plan, trajectory_execution_manager_->getCurrentExpectedTrajectoryIndex());
200 
201  preempt_requested = preempt_.checkAndClear();
202  if (preempt_requested)
203  break;
204 
205  // if planning fails in a manner that is not recoverable, we exit the loop,
206  // otherwise, we attempt to continue, if replanning attempts are left
207  if (plan.error_code_.val == moveit_msgs::msg::MoveItErrorCodes::PLANNING_FAILED ||
208  plan.error_code_.val == moveit_msgs::msg::MoveItErrorCodes::INVALID_MOTION_PLAN ||
209  plan.error_code_.val == moveit_msgs::msg::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA)
210  {
211  if (plan.error_code_.val == moveit_msgs::msg::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA &&
212  opt.replan_delay_ > 0.0)
213  {
214  auto replan_delay_seconds = std::chrono::duration<double>(opt.replan_delay_);
215  rclcpp::sleep_for(std::chrono::duration_cast<std::chrono::nanoseconds>(replan_delay_seconds));
216  }
217  continue;
218  }
219 
220  // abort if no plan was found
221  if (solved)
222  previously_solved = true;
223  else
224  break;
225 
226  if (plan.error_code_.val == moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
227  {
228  if (opt.before_execution_callback_)
229  opt.before_execution_callback_();
230 
231  preempt_requested = preempt_.checkAndClear();
232  if (preempt_requested)
233  break;
234 
235  // execute the trajectory, and monitor its execution
236  plan.error_code_ = executeAndMonitor(plan, false);
237  }
238 
239  if (plan.error_code_.val == moveit_msgs::msg::MoveItErrorCodes::PREEMPTED)
240  preempt_requested = true;
241 
242  // if execution succeeded or failed in a manner that we do not consider recoverable, we exit the loop (with failure)
243  if (plan.error_code_.val != moveit_msgs::msg::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE)
244  break;
245  else
246  {
247  // otherwise, we wait (if needed)
248  if (opt.replan_delay_ > 0.0)
249  {
250  RCLCPP_INFO(LOGGER, "Waiting for a %lf seconds before attempting a new plan ...", opt.replan_delay_);
251  auto replan_delay_seconds = std::chrono::duration<double>(opt.replan_delay_);
252  rclcpp::sleep_for(std::chrono::duration_cast<std::chrono::nanoseconds>(replan_delay_seconds));
253  RCLCPP_INFO(node_->get_logger(), "Done waiting");
254  }
255  }
256 
257  preempt_requested = preempt_.checkAndClear();
258  if (preempt_requested)
259  break;
260 
261  } while (replan_attempts < max_replan_attempts);
262 
263  if (preempt_requested)
264  {
265  RCLCPP_DEBUG(LOGGER, "PlanExecution was preempted");
266  plan.error_code_.val = moveit_msgs::msg::MoveItErrorCodes::PREEMPTED;
267  }
268 
269  if (opt.done_callback_)
270  opt.done_callback_();
271 
272  if (plan.error_code_.val == moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
273  {
274  RCLCPP_DEBUG(LOGGER, "PlanExecution finished successfully.");
275  }
276  else
277  {
278  RCLCPP_DEBUG(LOGGER, "PlanExecution terminating with error code %d - '%s'", plan.error_code_.val,
279  getErrorCodeString(plan.error_code_).c_str());
280  }
281 }
282 
283 bool plan_execution::PlanExecution::isRemainingPathValid(const ExecutableMotionPlan& plan,
284  const std::pair<int, int>& path_segment)
285 {
286  if (path_segment.first >= 0 &&
287  plan.plan_components_[path_segment.first].trajectory_monitoring_) // If path_segment.second <= 0, the function
288  // will fallback to check the entire trajectory
289  {
290  planning_scene_monitor::LockedPlanningSceneRO lscene(plan.planning_scene_monitor_); // lock the scene so that it
291  // does not modify the world
292  // representation while
293  // isStateValid() is called
294  const robot_trajectory::RobotTrajectory& t = *plan.plan_components_[path_segment.first].trajectory_;
296  plan.plan_components_[path_segment.first].allowed_collision_matrix_.get();
297  std::size_t wpc = t.getWayPointCount();
299  req.group_name = t.getGroupName();
300  for (std::size_t i = std::max(path_segment.second - 1, 0); i < wpc; ++i)
301  {
303  if (acm)
304  plan.planning_scene_->checkCollisionUnpadded(req, res, t.getWayPoint(i), *acm);
305  else
306  plan.planning_scene_->checkCollisionUnpadded(req, res, t.getWayPoint(i));
307 
308  if (res.collision || !plan.planning_scene_->isStateFeasible(t.getWayPoint(i), false))
309  {
310  RCLCPP_INFO(LOGGER, "Trajectory component '%s' is invalid for waypoint %ld out of %ld",
311  plan.plan_components_[path_segment.first].description_.c_str(), i, wpc);
312 
313  // call the same functions again, in verbose mode, to show what issues have been detected
314  plan.planning_scene_->isStateFeasible(t.getWayPoint(i), true);
315  req.verbose = true;
316  res.clear();
317  if (acm)
318  plan.planning_scene_->checkCollisionUnpadded(req, res, t.getWayPoint(i), *acm);
319  else
320  plan.planning_scene_->checkCollisionUnpadded(req, res, t.getWayPoint(i));
321  return false;
322  }
323  }
324  }
325  return true;
326 }
327 
329  bool reset_preempted)
330 {
331  if (reset_preempted)
332  preempt_.checkAndClear();
333 
334  if (!plan.planning_scene_monitor_)
335  plan.planning_scene_monitor_ = planning_scene_monitor_;
336  if (!plan.planning_scene_)
337  plan.planning_scene_ = planning_scene_monitor_->getPlanningScene();
338 
339  moveit_msgs::msg::MoveItErrorCodes result;
340 
341  // try to execute the trajectory
342  execution_complete_ = true;
343 
344  if (!trajectory_execution_manager_)
345  {
346  RCLCPP_ERROR(LOGGER, "No trajectory execution manager");
347  result.val = moveit_msgs::msg::MoveItErrorCodes::CONTROL_FAILED;
348  return result;
349  }
350 
351  if (plan.plan_components_.empty())
352  {
353  result.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
354  return result;
355  }
356 
357  execution_complete_ = false;
358 
359  // push the trajectories we have slated for execution to the trajectory execution manager
360  int prev = -1;
361  for (std::size_t i = 0; i < plan.plan_components_.size(); ++i)
362  {
363  // \todo should this be in trajectory_execution ? Maybe. Then that will have to use kinematic_trajectory too;
364  // splitting trajectories for controllers becomes interesting: tied to groups instead of joints. this could cause
365  // some problems
366  // in the meantime we do a hack:
367 
368  bool unwound = false;
369  for (std::size_t j = 0; j < i; ++j)
370  // if we ran unwind on a path for the same group
371  if (plan.plan_components_[j].trajectory_ &&
372  plan.plan_components_[j].trajectory_->getGroup() == plan.plan_components_[i].trajectory_->getGroup() &&
373  !plan.plan_components_[j].trajectory_->empty())
374  {
375  plan.plan_components_[i].trajectory_->unwind(plan.plan_components_[j].trajectory_->getLastWayPoint());
376  unwound = true;
377  break;
378  }
379 
380  if (!unwound)
381  {
382  // unwind the path to execute based on the current state of the system
383  if (prev < 0)
384  plan.plan_components_[i].trajectory_->unwind(
385  plan.planning_scene_monitor_ && plan.planning_scene_monitor_->getStateMonitor() ?
386  *plan.planning_scene_monitor_->getStateMonitor()->getCurrentState() :
387  plan.planning_scene_->getCurrentState());
388  else
389  plan.plan_components_[i].trajectory_->unwind(plan.plan_components_[prev].trajectory_->getLastWayPoint());
390  }
391 
392  if (plan.plan_components_[i].trajectory_ && !plan.plan_components_[i].trajectory_->empty())
393  prev = i;
394 
395  // convert to message, pass along
396  moveit_msgs::msg::RobotTrajectory msg;
397  plan.plan_components_[i].trajectory_->getRobotTrajectoryMsg(msg);
398  if (!trajectory_execution_manager_->push(msg, plan.plan_components_[i].controller_names_))
399  {
400  RCLCPP_ERROR(LOGGER, "Apparently trajectory initialization failed");
401  execution_complete_ = true;
402  result.val = moveit_msgs::msg::MoveItErrorCodes::CONTROL_FAILED;
403  return result;
404  }
405  }
406 
407  if (!trajectory_monitor_ && planning_scene_monitor_->getStateMonitor())
408  {
409  // Pass current value of reconfigurable parameter plan_execution/record_trajectory_state_frequency
410  double sampling_frequency = 0.0;
411  node_->get_parameter_or("plan_execution.record_trajectory_state_frequency", sampling_frequency, 0.0);
412  trajectory_monitor_ = std::make_shared<planning_scene_monitor::TrajectoryMonitor>(
413  planning_scene_monitor_->getStateMonitor(), sampling_frequency);
414  }
415 
416  // start recording trajectory states
417  if (trajectory_monitor_)
418  trajectory_monitor_->startTrajectoryMonitor();
419 
420  // start a trajectory execution thread
421  trajectory_execution_manager_->execute(
422  [this](const moveit_controller_manager::ExecutionStatus& status) { doneWithTrajectoryExecution(status); },
423  [this, &plan](std::size_t index) { successfulTrajectorySegmentExecution(plan, index); });
424  // wait for path to be done, while checking that the path does not become invalid
425  rclcpp::WallRate r(100);
426  path_became_invalid_ = false;
427  bool preempt_requested = false;
428 
429  while (rclcpp::ok() && !execution_complete_ && !path_became_invalid_)
430  {
431  r.sleep();
432  // check the path if there was an environment update in the meantime
433  if (new_scene_update_)
434  {
435  new_scene_update_ = false;
436  std::pair<int, int> current_index = trajectory_execution_manager_->getCurrentExpectedTrajectoryIndex();
437  if (!isRemainingPathValid(plan, current_index))
438  {
439  RCLCPP_INFO(LOGGER, "Trajectory component '%s' is invalid after scene update",
440  plan.plan_components_[current_index.first].description_.c_str());
441  path_became_invalid_ = true;
442  break;
443  }
444  }
445 
446  preempt_requested = preempt_.checkAndClear();
447  if (preempt_requested)
448  break;
449  }
450 
451  // stop execution if needed
452  if (preempt_requested)
453  {
454  RCLCPP_INFO(LOGGER, "Stopping execution due to preempt request");
455  trajectory_execution_manager_->stopExecution();
456  }
457  else if (path_became_invalid_)
458  {
459  RCLCPP_INFO(LOGGER, "Stopping execution because the path to execute became invalid"
460  "(probably the environment changed)");
461  trajectory_execution_manager_->stopExecution();
462  }
463  else if (!execution_complete_)
464  {
465  RCLCPP_WARN(LOGGER, "Stopping execution due to unknown reason."
466  "Possibly the node is about to shut down.");
467  trajectory_execution_manager_->stopExecution();
468  }
469 
470  // stop recording trajectory states
471  if (trajectory_monitor_)
472  {
473  trajectory_monitor_->stopTrajectoryMonitor();
474  plan.executed_trajectory_ =
475  std::make_shared<robot_trajectory::RobotTrajectory>(planning_scene_monitor_->getRobotModel(), "");
476  trajectory_monitor_->swapTrajectory(*plan.executed_trajectory_);
477  }
478 
479  // decide return value
480  if (path_became_invalid_)
481  result.val = moveit_msgs::msg::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE;
482  else
483  {
484  if (preempt_requested)
485  {
486  result.val = moveit_msgs::msg::MoveItErrorCodes::PREEMPTED;
487  }
488  else
489  {
490  if (trajectory_execution_manager_->getLastExecutionStatus() ==
492  result.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
493  else if (trajectory_execution_manager_->getLastExecutionStatus() ==
495  result.val = moveit_msgs::msg::MoveItErrorCodes::TIMED_OUT;
496  else
497  result.val = moveit_msgs::msg::MoveItErrorCodes::CONTROL_FAILED;
498  }
499  }
500  return result;
501 }
502 
503 void plan_execution::PlanExecution::planningSceneUpdatedCallback(
505 {
508  new_scene_update_ = true;
509 }
510 
511 void plan_execution::PlanExecution::doneWithTrajectoryExecution(
513 {
514  execution_complete_ = true;
515 }
516 
517 void plan_execution::PlanExecution::successfulTrajectorySegmentExecution(const ExecutableMotionPlan& plan,
518  std::size_t index)
519 {
520  if (plan.plan_components_.empty())
521  {
522  RCLCPP_WARN(LOGGER, "Length of provided motion plan is zero.");
523  return;
524  }
525 
526  // if any side-effects are associated to the trajectory part that just completed, execute them
527  RCLCPP_DEBUG(LOGGER, "Completed '%s'", plan.plan_components_[index].description_.c_str());
528  if (plan.plan_components_[index].effect_on_success_)
529  if (!plan.plan_components_[index].effect_on_success_(&plan))
530  {
531  // execution of side-effect failed
532  RCLCPP_ERROR(LOGGER, "Execution of path-completion side-effect failed. Preempting.");
533  preempt_.request();
534  return;
535  }
536 
537  // if there is a next trajectory, check it for validity, before we start execution
538  ++index;
539  if (index < plan.plan_components_.size() && plan.plan_components_[index].trajectory_ &&
540  !plan.plan_components_[index].trajectory_->empty())
541  {
542  std::pair<int, int> next_index(static_cast<int>(index), 0);
543  if (!isRemainingPathValid(plan, next_index))
544  {
545  RCLCPP_INFO(LOGGER, "Upcoming trajectory component '%s' is invalid",
546  plan.plan_components_[next_index.first].description_.c_str());
547  path_became_invalid_ = true;
548  }
549  }
550 }
Definition of a structure for the allowed collision matrix. All elements in the collision world are r...
void planAndExecute(ExecutableMotionPlan &plan, const Options &opt)
std::string getErrorCodeString(const moveit_msgs::msg::MoveItErrorCodes &error_code)
PlanExecution(const rclcpp::Node::SharedPtr &node, const planning_scene_monitor::PlanningSceneMonitorPtr &planning_scene_monitor, const trajectory_execution_manager::TrajectoryExecutionManagerPtr &trajectory_execution)
moveit_msgs::msg::MoveItErrorCodes executeAndMonitor(ExecutableMotionPlan &plan, bool reset_preempted=true)
Execute and monitor a previously created plan.
This is a convenience class for obtaining access to an instance of a locked PlanningScene.
@ UPDATE_GEOMETRY
The geometry of the scene was updated. This includes receiving new octomaps, collision objects,...
@ UPDATE_TRANSFORMS
The maintained set of fixed transforms in the monitored scene was updated.
Maintain a sequence of waypoints and the time durations between these waypoints.
const std::string & getGroupName() const
const moveit::core::RobotState & getWayPoint(std::size_t index) const
bool isEmpty(const moveit_msgs::msg::PlanningScene &msg)
Check if a message includes any information about a planning scene, or whether it is empty.
This namespace includes functionality specific to the execution and monitoring of motion plans.
Definition: plan.py:1
r
Definition: plan.py:56
const rclcpp::Logger LOGGER
Definition: async_test.h:31
Representation of a collision checking request.
std::string group_name
The group name to check collisions for (optional; if empty, assume the complete robot)
bool verbose
Flag indicating whether information about detected collisions should be reported.
Representation of a collision checking result.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void clear()
Clear a previously stored result.
bool collision
True if collision was found, false otherwise.
A generic representation on what a computed motion plan looks like.