44#include <boost/algorithm/string/join.hpp>
45#include <rclcpp/logger.hpp>
46#include <rclcpp/logging.hpp>
47#include <rclcpp/node.hpp>
48#include <rclcpp/parameter_value.hpp>
49#include <rclcpp/rate.hpp>
50#include <rclcpp/utilities.hpp>
82 const rclcpp::Node::SharedPtr& node,
const planning_scene_monitor::PlanningSceneMonitorPtr&
planning_scene_monitor,
83 const trajectory_execution_manager::TrajectoryExecutionManagerPtr& trajectory_execution)
86 , trajectory_execution_manager_(trajectory_execution)
89 if (!trajectory_execution_manager_)
91 trajectory_execution_manager_ = std::make_shared<trajectory_execution_manager::TrajectoryExecutionManager>(
92 node_, planning_scene_monitor_->getRobotModel(), planning_scene_monitor_->getStateMonitor());
95 default_max_replan_attempts_ = 5;
97 new_scene_update_ =
false;
100 planning_scene_monitor_->addUpdateCallback(
102 planningSceneUpdatedCallback(update_type);
121 plan.planning_scene_monitor = planning_scene_monitor_;
122 plan.planning_scene = planning_scene_monitor_->getPlanningScene();
123 planAndExecuteHelper(plan, opt);
127 const moveit_msgs::msg::PlanningScene& scene_diff,
136 plan.planning_scene_monitor = planning_scene_monitor_;
142 plan.planning_scene = lscene->diff(scene_diff);
144 planAndExecuteHelper(plan, opt);
148void plan_execution::PlanExecution::planAndExecuteHelper(
ExecutableMotionPlan& plan,
const Options& opt)
151 preempt_.checkAndClear();
153 bool preempt_requested =
false;
156 unsigned int max_replan_attempts =
157 opt.replan ? (opt.replan_attemps > 0 ? opt.replan_attemps : default_max_replan_attempts_) : 1;
158 unsigned int replan_attempts = 0;
159 bool previously_solved =
false;
166 RCLCPP_INFO(logger_,
"Planning attempt %u of at most %u", replan_attempts, max_replan_attempts);
168 if (opt.before_plan_callback_)
169 opt.before_plan_callback_();
171 new_scene_update_ =
false;
177 (!previously_solved || !opt.repair_plan_callback_) ?
178 opt.plan_callback(plan) :
179 opt.repair_plan_callback_(plan, trajectory_execution_manager_->getCurrentExpectedTrajectoryIndex());
181 preempt_requested = preempt_.checkAndClear();
182 if (preempt_requested)
187 if (plan.
error_code.val == moveit_msgs::msg::MoveItErrorCodes::PLANNING_FAILED ||
188 plan.
error_code.val == moveit_msgs::msg::MoveItErrorCodes::INVALID_MOTION_PLAN ||
189 plan.
error_code.val == moveit_msgs::msg::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA)
191 if (plan.
error_code.val == moveit_msgs::msg::MoveItErrorCodes::UNABLE_TO_AQUIRE_SENSOR_DATA &&
192 opt.replan_delay > 0.0)
194 auto replan_delay_seconds = std::chrono::duration<double>(opt.replan_delay);
195 rclcpp::sleep_for(std::chrono::duration_cast<std::chrono::nanoseconds>(replan_delay_seconds));
203 previously_solved =
true;
210 if (
plan.
error_code.val == moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
212 if (opt.before_execution_callback_)
213 opt.before_execution_callback_();
215 preempt_requested = preempt_.checkAndClear();
216 if (preempt_requested)
223 if (
plan.
error_code.val == moveit_msgs::msg::MoveItErrorCodes::PREEMPTED)
224 preempt_requested =
true;
227 if (
plan.
error_code.val != moveit_msgs::msg::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE)
234 if (opt.replan_delay > 0.0)
236 RCLCPP_INFO(logger_,
"Waiting for a %lf seconds before attempting a new plan ...", opt.replan_delay);
237 auto replan_delay_seconds = std::chrono::duration<double>(opt.replan_delay);
238 rclcpp::sleep_for(std::chrono::duration_cast<std::chrono::nanoseconds>(replan_delay_seconds));
239 RCLCPP_INFO(logger_,
"Done waiting");
243 preempt_requested = preempt_.checkAndClear();
244 if (preempt_requested)
247 }
while (replan_attempts < max_replan_attempts);
249 if (preempt_requested)
251 RCLCPP_DEBUG(logger_,
"PlanExecution was preempted");
252 plan.
error_code.val = moveit_msgs::msg::MoveItErrorCodes::PREEMPTED;
255 if (opt.done_callback_)
256 opt.done_callback_();
258 if (
plan.
error_code.val == moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
260 RCLCPP_DEBUG(logger_,
"PlanExecution finished successfully.");
264 RCLCPP_DEBUG(logger_,
"PlanExecution terminating with error code %d - '%s'",
plan.
error_code.val,
270 const std::pair<int, int>& path_segment)
272 if (path_segment.first >= 0 &&
273 plan.plan_components[path_segment.first].trajectory_monitoring)
276 planning_scene_monitor::LockedPlanningSceneRO lscene(
plan.planning_scene_monitor);
280 const robot_trajectory::RobotTrajectory& t = *
plan.plan_components[path_segment.first].
trajectory;
281 const collision_detection::AllowedCollisionMatrix* acm =
282 plan.plan_components[path_segment.first].allowed_collision_matrix.get();
284 collision_detection::CollisionRequest req;
287 moveit::core::RobotState start_state =
plan.planning_scene->getCurrentState();
288 std::map<std::string, const moveit::core::AttachedBody*> current_attached_objects, waypoint_attached_objects;
290 if (plan_components_attached_objects_.size() >
static_cast<size_t>(path_segment.first))
291 waypoint_attached_objects = plan_components_attached_objects_[path_segment.first];
292 moveit::core::RobotState waypoint_state(start_state);
293 for (std::size_t i = std::max(path_segment.second - 1, 0); i < wpc; ++i)
295 collision_detection::CollisionResult res;
296 waypoint_attached_objects.clear();
298 if (plan_components_attached_objects_[path_segment.first].empty())
300 waypoint_state.getAttachedBodies(waypoint_attached_objects);
304 for (
const auto& [name,
object] : waypoint_attached_objects)
306 if (current_attached_objects.find(name) == current_attached_objects.end())
308 RCLCPP_DEBUG(logger_,
"Attached object '%s' is not in the current scene. Removing it.",
name.c_str());
309 waypoint_state.clearAttachedBody(name);
314 for (
const auto& [name,
object] : current_attached_objects)
316 if (waypoint_attached_objects.find(name) == waypoint_attached_objects.end())
318 RCLCPP_DEBUG(logger_,
"Attached object '%s' is not in the robot state. Adding it.",
name.c_str());
319 waypoint_state.attachBody(std::make_unique<moveit::core::AttachedBody>(*
object));
325 plan.planning_scene->checkCollision(req, res, waypoint_state, *acm);
329 plan.planning_scene->checkCollision(req, res, waypoint_state);
332 if (res.
collision || !
plan.planning_scene->isStateFeasible(waypoint_state,
false))
334 RCLCPP_INFO(logger_,
"Trajectory component '%s' is invalid for waypoint %ld out of %ld",
335 plan.plan_components[path_segment.first].description.c_str(), i, wpc);
338 plan.planning_scene->isStateFeasible(waypoint_state,
true);
343 plan.planning_scene->checkCollision(req, res, waypoint_state, *acm);
347 plan.planning_scene->checkCollision(req, res, waypoint_state);
357 bool reset_preempted)
360 preempt_.checkAndClear();
362 if (!plan.planning_scene_monitor)
363 plan.planning_scene_monitor = planning_scene_monitor_;
364 if (!plan.planning_scene)
365 plan.planning_scene = planning_scene_monitor_->getPlanningScene();
367 moveit_msgs::msg::MoveItErrorCodes result;
370 execution_complete_ =
true;
372 if (!trajectory_execution_manager_)
374 RCLCPP_ERROR(logger_,
"No trajectory execution manager");
375 result.val = moveit_msgs::msg::MoveItErrorCodes::CONTROL_FAILED;
379 if (plan.plan_components.empty())
381 result.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
385 execution_complete_ =
false;
389 for (
size_t component_idx = 0; component_idx < plan.plan_components.size(); ++component_idx)
396 bool unwound =
false;
397 for (
int prev_component = component_idx - 1; prev_component >= 0; --prev_component)
401 if (plan.plan_components.at(prev_component).
trajectory &&
402 plan.plan_components.at(prev_component).
trajectory->getGroup() ==
403 plan.plan_components.at(prev_component).
trajectory->getGroup() &&
404 !plan.plan_components.at(prev_component).
trajectory->empty())
406 plan.plan_components.at(component_idx)
419 plan.plan_components[component_idx].
trajectory->unwind(
420 plan.planning_scene_monitor && plan.planning_scene_monitor->getStateMonitor() ?
421 *plan.planning_scene_monitor->getStateMonitor()->getCurrentState() :
422 plan.planning_scene->getCurrentState());
426 plan.plan_components[component_idx].
trajectory->unwind(plan.plan_components[prev].
trajectory->getLastWayPoint());
430 if (plan.plan_components[component_idx].
trajectory && !plan.plan_components[component_idx].
trajectory->empty())
431 prev = component_idx;
434 moveit_msgs::msg::RobotTrajectory msg;
435 plan.plan_components[component_idx].
trajectory->getRobotTrajectoryMsg(msg);
436 if (!trajectory_execution_manager_->push(msg, plan.plan_components[component_idx].controller_name))
438 RCLCPP_ERROR(logger_,
"Apparently trajectory initialization failed");
439 execution_complete_ =
true;
440 result.val = moveit_msgs::msg::MoveItErrorCodes::CONTROL_FAILED;
445 if (!trajectory_monitor_ && planning_scene_monitor_->getStateMonitor())
448 double sampling_frequency = 0.0;
449 node_->get_parameter_or(
"plan_execution.record_trajectory_state_frequency", sampling_frequency, 0.0);
450 trajectory_monitor_ = std::make_shared<planning_scene_monitor::TrajectoryMonitor>(
451 planning_scene_monitor_->getStateMonitor(), sampling_frequency);
455 if (trajectory_monitor_)
456 trajectory_monitor_->startTrajectoryMonitor();
459 trajectory_execution_manager_->execute(
461 [
this, &plan](std::size_t index) { successfulTrajectorySegmentExecution(plan, index); });
463 rclcpp::WallRate r(100);
464 path_became_invalid_ =
false;
465 bool preempt_requested =
false;
470 plan_components_attached_objects_.clear();
471 plan_components_attached_objects_.reserve(plan.plan_components.size());
472 for (
const auto& component : plan.plan_components)
474 const auto& trajectory = component.trajectory;
475 std::map<std::string, const moveit::core::AttachedBody*> trajectory_attached_objects;
476 if (trajectory && trajectory->getWayPointCount() > 0)
478 std::map<std::string, const moveit::core::AttachedBody*> attached_objects;
479 trajectory->getWayPoint(0).getAttachedBodies(trajectory_attached_objects);
480 for (std::size_t i = 1; i < trajectory->getWayPointCount(); ++i)
482 trajectory->getWayPoint(i).getAttachedBodies(attached_objects);
483 if (attached_objects != trajectory_attached_objects)
485 trajectory_attached_objects.clear();
490 if (!trajectory_attached_objects.empty())
491 plan_components_attached_objects_.push_back(trajectory_attached_objects);
494 while (rclcpp::ok() && !execution_complete_ && !path_became_invalid_)
498 if (new_scene_update_)
500 new_scene_update_ =
false;
501 std::pair<int, int> current_index = trajectory_execution_manager_->getCurrentExpectedTrajectoryIndex();
502 if (!isRemainingPathValid(plan, current_index))
504 RCLCPP_INFO(logger_,
"Trajectory component '%s' is invalid after scene update",
505 plan.plan_components[current_index.first].description.c_str());
506 path_became_invalid_ =
true;
511 preempt_requested = preempt_.checkAndClear();
512 if (preempt_requested)
517 if (preempt_requested)
519 RCLCPP_INFO(logger_,
"Stopping execution due to preempt request");
520 trajectory_execution_manager_->stopExecution();
522 else if (path_became_invalid_)
524 RCLCPP_INFO(logger_,
"Stopping execution because the path to execute became invalid"
525 "(probably the environment changed)");
526 trajectory_execution_manager_->stopExecution();
528 else if (!execution_complete_)
530 RCLCPP_WARN(logger_,
"Stopping execution due to unknown reason."
531 "Possibly the node is about to shut down.");
532 trajectory_execution_manager_->stopExecution();
536 if (trajectory_monitor_)
538 trajectory_monitor_->stopTrajectoryMonitor();
539 plan.executed_trajectory =
540 std::make_shared<robot_trajectory::RobotTrajectory>(planning_scene_monitor_->getRobotModel(),
"");
541 trajectory_monitor_->swapTrajectory(*plan.executed_trajectory);
545 if (path_became_invalid_)
547 result.val = moveit_msgs::msg::MoveItErrorCodes::MOTION_PLAN_INVALIDATED_BY_ENVIRONMENT_CHANGE;
551 if (preempt_requested)
553 result.val = moveit_msgs::msg::MoveItErrorCodes::PREEMPTED;
557 if (trajectory_execution_manager_->getLastExecutionStatus() ==
560 result.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
562 else if (trajectory_execution_manager_->getLastExecutionStatus() ==
565 result.val = moveit_msgs::msg::MoveItErrorCodes::TIMED_OUT;
569 result.val = moveit_msgs::msg::MoveItErrorCodes::CONTROL_FAILED;
576void plan_execution::PlanExecution::planningSceneUpdatedCallback(
581 new_scene_update_ =
true;
584void plan_execution::PlanExecution::doneWithTrajectoryExecution(
587 execution_complete_ =
true;
590void plan_execution::PlanExecution::successfulTrajectorySegmentExecution(
const ExecutableMotionPlan& plan,
593 if (
plan.plan_components.empty())
595 RCLCPP_WARN(logger_,
"Length of provided motion plan is zero.");
600 RCLCPP_DEBUG(logger_,
"Completed '%s'",
plan.plan_components[index].description.c_str());
601 if (
plan.plan_components[index].effect_on_success)
603 if (!
plan.plan_components[index].effect_on_success(&plan))
606 RCLCPP_ERROR(logger_,
"Execution of path-completion side-effect failed. Preempting.");
617 std::pair<int, int> next_index(
static_cast<int>(index), 0);
618 if (!isRemainingPathValid(plan, next_index))
620 RCLCPP_INFO(logger_,
"Upcoming trajectory component '%s' is invalid",
621 plan.plan_components[next_index.first].description.c_str());
622 path_became_invalid_ =
true;
void getAttachedBodies(std::vector< const AttachedBody * > &attached_bodies) const
Get all bodies attached to the model corresponding to this state.
void planAndExecute(ExecutableMotionPlan &plan, const Options &opt)
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.
const std::string & getGroupName() const
std::size_t getWayPointCount() 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.
std::string errorCodeToString(const MoveItErrorCode &error_code)
Convenience function to translated error message into string.
planning_interface::MotionPlanResponse plan(std::shared_ptr< moveit_cpp::PlanningComponent > &planning_component, std::shared_ptr< moveit_cpp::PlanningComponent::PlanRequestParameters > &single_plan_parameters, std::shared_ptr< moveit_cpp::PlanningComponent::MultiPipelinePlanRequestParameters > &multi_plan_parameters, std::shared_ptr< planning_scene::PlanningScene > &planning_scene, std::optional< const moveit::planning_pipeline_interfaces::SolutionSelectionFunction > solution_selection_function, std::optional< moveit::planning_pipeline_interfaces::StoppingCriterionFunction > stopping_criterion_callback)
Main namespace for MoveIt.
This namespace includes functionality specific to the execution and monitoring of motion plans.
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.
bool pad_environment_collisions
If true, use padded collision environment.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void clear()
Clear a previously stored result.
bool collision
True if collision was found, false otherwise.
The reported execution status.
A generic representation on what a computed motion plan looks like.
moveit::core::MoveItErrorCode error_code
robot_trajectory::RobotTrajectoryPtr trajectory
rclcpp::Logger getLogger()