41#include <moveit_msgs/srv/get_planning_scene.hpp>
44#include <rclcpp/qos.hpp>
47#if __has_include(<tf2/exceptions.hpp>)
48#include <tf2/exceptions.hpp>
50#include <tf2/exceptions.h>
52#if __has_include(<tf2/LinearMath/Transform.hpp>)
53#include <tf2/LinearMath/Transform.hpp>
55#include <tf2/LinearMath/Transform.h>
57#include <tf2_eigen/tf2_eigen.hpp>
58#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
60#include <fmt/format.h>
63#include <std_msgs/msg/string.hpp>
66using namespace std::chrono_literals;
79 const std::string& name)
85 const planning_scene::PlanningScenePtr& scene,
86 const std::string& robot_description,
const std::string& name)
93 const robot_model_loader::RobotModelLoaderPtr& rm_loader,
94 const std::string& name)
100 const planning_scene::PlanningScenePtr& scene,
101 const robot_model_loader::RobotModelLoaderPtr& rm_loader,
102 const std::string& name)
103 : monitor_name_(name)
105 , private_executor_(std::make_shared<
rclcpp::executors::SingleThreadedExecutor>())
106 , tf_buffer_(std::make_shared<
tf2_ros::Buffer>(node->get_clock()))
107 , dt_state_update_(0.0)
108 , shape_transform_cache_lookup_wait_time_(0, 0)
109 , rm_loader_(rm_loader)
110 , logger_(
moveit::getLogger(
"moveit.ros.planning_scene_monitor"))
112 std::vector<std::string> new_args = rclcpp::NodeOptions().arguments();
113 new_args.push_back(
"--ros-args");
114 new_args.push_back(
"-r");
116 new_args.push_back(std::string(
"__node:=") +
node_->get_name() +
"_private_" +
117 std::to_string(
reinterpret_cast<std::size_t
>(
this)));
118 new_args.push_back(
"--");
119 pnode_ = std::make_shared<rclcpp::Node>(
"_",
node_->get_namespace(), rclcpp::NodeOptions().arguments(new_args));
129 use_sim_time_ = node->get_parameter(
"use_sim_time").as_bool();
153 robot_model_.reset();
166 scene->setPlanningSceneDiffMsg(diff);
175 if (rm_loader_->getModel())
177 robot_model_ = rm_loader_->getModel();
183 scene_ = std::make_shared<planning_scene::PlanningScene>(rm_loader_->getModel());
191 scene_->getCollisionEnvNonConst()->setLinkPadding(it.first, it.second);
195 scene_->getCollisionEnvNonConst()->setLinkScale(it.first, it.second);
200 RCLCPP_ERROR(logger_,
"Configuration of planning scene failed");
213 scene_->setCollisionObjectUpdateCallback(
221 RCLCPP_ERROR(logger_,
"Robot model not loaded");
228 last_robot_state_update_wall_time_ = std::chrono::system_clock::now();
229 dt_state_update_ = std::chrono::duration<double>(0.03);
231 double temp_wait_time = 0.05;
235 node_->get_parameter_or(
robot_description_ +
"_planning.shape_transform_cache_lookup_wait_time", temp_wait_time,
239 shape_transform_cache_lookup_wait_time_ = rclcpp::Duration::from_seconds(temp_wait_time);
241 state_update_pending_.store(
false);
243 using std::chrono::nanoseconds;
244 state_update_timer_ =
pnode_->create_wall_timer(dt_state_update_, [
this]() {
return stateUpdateTimerCallback(); });
250 auto declare_parameter = [
this](
const std::string& param_name,
auto default_val,
251 const std::string& description) ->
auto
253 rcl_interfaces::msg::ParameterDescriptor desc;
254 desc.set__description(description);
255 return pnode_->declare_parameter(param_name, default_val, desc);
260 bool publish_planning_scene =
false;
261 bool publish_geometry_updates =
false;
262 bool publish_state_updates =
false;
263 bool publish_transform_updates =
false;
264 double publish_planning_scene_hz = 4.0;
265 if (
node_->has_parameter(
"publish_planning_scene"))
267 publish_planning_scene =
node_->get_parameter(
"publish_planning_scene").as_bool();
269 if (
node_->has_parameter(
"publish_geometry_updates"))
271 publish_geometry_updates =
node_->get_parameter(
"publish_geometry_updates").as_bool();
273 if (
node_->has_parameter(
"publish_state_updates"))
275 publish_state_updates =
node_->get_parameter(
"publish_state_updates").as_bool();
277 if (
node_->has_parameter(
"publish_transforms_updates"))
279 publish_transform_updates =
node_->get_parameter(
"publish_transforms_updates").as_bool();
281 if (
node_->has_parameter(
"publish_planning_scene_hz"))
283 publish_planning_scene_hz =
node_->get_parameter(
"publish_planning_scene_hz").as_double();
287 publish_planning_scene =
288 declare_parameter(
"publish_planning_scene", publish_planning_scene,
"Set to True to publish Planning Scenes");
289 publish_geometry_updates = declare_parameter(
"publish_geometry_updates", publish_geometry_updates,
290 "Set to True to publish geometry updates of the planning scene");
291 publish_state_updates = declare_parameter(
"publish_state_updates", publish_state_updates,
292 "Set to True to publish state updates of the planning scene");
293 publish_transform_updates = declare_parameter(
"publish_transforms_updates", publish_transform_updates,
294 "Set to True to publish transform updates of the planning scene");
295 publish_planning_scene_hz =
296 declare_parameter(
"publish_planning_scene_hz", publish_planning_scene_hz,
297 "Set the maximum frequency at which planning scene updates are published");
298 updatePublishSettings(publish_geometry_updates, publish_state_updates, publish_transform_updates,
299 publish_planning_scene, publish_planning_scene_hz);
301 catch (
const rclcpp::exceptions::InvalidParameterTypeException& e)
303 RCLCPP_ERROR_STREAM(logger_,
"Invalid parameter type in PlanningSceneMonitor: " << e.what());
304 RCLCPP_ERROR(logger_,
"Dynamic publishing parameters won't be available");
308 auto psm_parameter_set_callback = [
this](
const std::vector<rclcpp::Parameter>& parameters) ->
auto
310 auto result = rcl_interfaces::msg::SetParametersResult();
311 result.successful =
true;
313 bool publish_planning_scene =
false, publish_geometry_updates =
false, publish_state_updates =
false,
314 publish_transform_updates =
false;
315 double publish_planning_scene_hz = 4.0;
316 bool declared_params_valid =
pnode_->get_parameter(
"publish_planning_scene", publish_planning_scene) &&
317 pnode_->get_parameter(
"publish_geometry_updates", publish_geometry_updates) &&
318 pnode_->get_parameter(
"publish_state_updates", publish_state_updates) &&
319 pnode_->get_parameter(
"publish_transforms_updates", publish_transform_updates) &&
320 pnode_->get_parameter(
"publish_planning_scene_hz", publish_planning_scene_hz);
322 if (!declared_params_valid)
324 RCLCPP_ERROR(logger_,
"Initially declared parameters are invalid - failed to process update callback");
325 result.successful =
false;
329 for (
const auto& parameter : parameters)
331 const auto& name = parameter.get_name();
332 const auto& type = parameter.get_type();
335 if (!
pnode_->has_parameter(name) ||
pnode_->get_parameter(name).get_type() != type)
337 RCLCPP_ERROR(logger_,
"Invalid parameter in PlanningSceneMonitor parameter callback");
338 result.successful =
false;
343 if (name ==
"planning_scene_monitor.publish_planning_scene")
345 publish_planning_scene = parameter.as_bool();
347 else if (name ==
"planning_scene_monitor.publish_geometry_updates")
349 publish_geometry_updates = parameter.as_bool();
351 else if (name ==
"planning_scene_monitor.publish_state_updates")
353 publish_state_updates = parameter.as_bool();
355 else if (name ==
"planning_scene_monitor.publish_transforms_updates")
357 publish_transform_updates = parameter.as_bool();
359 else if (name ==
"planning_scene_monitor.publish_planning_scene_hz")
361 publish_planning_scene_hz = parameter.as_double();
365 if (result.successful)
367 updatePublishSettings(publish_geometry_updates, publish_state_updates, publish_transform_updates,
368 publish_planning_scene, publish_planning_scene_hz);
373 callback_handler_ =
pnode_->add_on_set_parameters_callback(psm_parameter_set_callback);
394 scene_->setCollisionObjectUpdateCallback(
395 [
this](
const collision_detection::World::ObjectConstPtr&
object,
403 RCLCPP_WARN(logger_,
"Diff monitoring was stopped while publishing planning scene diffs. "
404 "Stopping planning scene diff publisher");
414 if (!
scene_->getName().empty())
416 if (
scene_->getName()[
scene_->getName().length() - 1] ==
'+')
429 std::unique_ptr<std::thread> copy;
435 RCLCPP_INFO(logger_,
"Stopped publishing maintained planning scene.");
440 const std::string& planning_scene_topic)
446 RCLCPP_INFO(logger_,
"Stopping existing planning scene publisher.");
453 RCLCPP_INFO(logger_,
"Publishing maintained planning scene on '%s'", planning_scene_topic.c_str());
459 RCLCPP_WARN(logger_,
"Did not find a planning scene, so cannot publish it.");
463void PlanningSceneMonitor::scenePublishingThread()
465 RCLCPP_DEBUG(logger_,
"Started scene publishing thread ...");
469 moveit_msgs::msg::PlanningScene msg;
474 scene_->getPlanningSceneMsg(msg);
477 RCLCPP_DEBUG(logger_,
"Published the full planning scene: '%s'", msg.name.c_str());
482 moveit_msgs::msg::PlanningScene msg;
483 bool publish_msg =
false;
484 bool is_full =
false;
503 scene_->getPlanningSceneDiffMsg(msg);
506 msg.robot_state.attached_collision_objects.clear();
507 msg.robot_state.is_diff =
true;
522 scene_->setCollisionObjectUpdateCallback(
523 [
this](
const collision_detection::World::ObjectConstPtr&
object,
535 scene_->getPlanningSceneMsg(msg);
548 RCLCPP_DEBUG(logger_,
"Published full planning scene: '%s'", msg.name.c_str());
581bool sceneIsParentOf(
const planning_scene::PlanningSceneConstPtr& scene,
584 if (scene && scene.get() == possible_parent)
587 return sceneIsParentOf(scene->getParent(), possible_parent);
608 update_callback(update_type);
617 RCLCPP_FATAL_STREAM(logger_,
"requestPlanningSceneState() to self-provided service '" << service_name <<
'\'');
618 throw std::runtime_error(
"requestPlanningSceneState() to self-provided service: " + service_name);
621 auto client =
pnode_->create_client<moveit_msgs::srv::GetPlanningScene>(service_name);
622 auto srv = std::make_shared<moveit_msgs::srv::GetPlanningScene::Request>();
623 srv->components.components = srv->components.SCENE_SETTINGS | srv->components.ROBOT_STATE |
624 srv->components.ROBOT_STATE_ATTACHED_OBJECTS | srv->components.WORLD_OBJECT_NAMES |
625 srv->components.WORLD_OBJECT_GEOMETRY | srv->components.OCTOMAP |
626 srv->components.TRANSFORMS | srv->components.ALLOWED_COLLISION_MATRIX |
627 srv->components.LINK_PADDING_AND_SCALING | srv->components.OBJECT_COLORS;
630 RCLCPP_DEBUG(logger_,
"Waiting for GetPlanningScene service `%s` to exist.", service_name.c_str());
631 if (client->wait_for_service(std::chrono::seconds(5)))
633 RCLCPP_DEBUG(logger_,
"Sending service request to `%s`.", service_name.c_str());
634 auto service_result = client->async_send_request(srv);
635 const auto service_result_status = service_result.wait_for(std::chrono::seconds(5));
636 if (service_result_status == std::future_status::ready)
638 RCLCPP_DEBUG(logger_,
"Service request succeeded, applying new planning scene");
642 if (service_result_status == std::future_status::timeout)
644 RCLCPP_INFO(logger_,
"GetPlanningScene service call to %s timed out. at %s:%d", service_name.c_str(), __FILE__,
652 "Failed to call service %s, have you launched move_group or called psm.providePlanningSceneService()?",
653 service_name.c_str());
662 service_name, [
this](
const moveit_msgs::srv::GetPlanningScene::Request::SharedPtr& req,
663 const moveit_msgs::srv::GetPlanningScene::Response::SharedPtr& res) {
664 return getPlanningSceneServiceCallback(req, res);
668void PlanningSceneMonitor::getPlanningSceneServiceCallback(
669 const moveit_msgs::srv::GetPlanningScene::Request::SharedPtr& req,
670 const moveit_msgs::srv::GetPlanningScene::Response::SharedPtr& res)
672 if (req->components.components & moveit_msgs::msg::PlanningSceneComponents::TRANSFORMS)
675 moveit_msgs::msg::PlanningSceneComponents all_components;
676 all_components.components = UINT_MAX;
679 scene_->getPlanningSceneMsg(res->scene, req->components.components ? req->components : all_components);
682void PlanningSceneMonitor::updatePublishSettings(
bool publish_geom_updates,
bool publish_state_updates,
683 bool publish_transform_updates,
bool publish_planning_scene,
684 double publish_planning_scene_hz)
687 if (publish_geom_updates)
692 if (publish_state_updates)
697 if (publish_transform_updates)
702 if (publish_planning_scene)
711void PlanningSceneMonitor::newPlanningSceneCallback(
const moveit_msgs::msg::PlanningScene::ConstSharedPtr& scene)
718 bool removed =
false;
721 removed =
scene_->getWorldNonConst()->removeObject(
scene_->OCTOMAP_NS);
731 RCLCPP_WARN(logger_,
"Unable to clear octomap since no octomap monitor has been initialized");
747 std::string old_scene_name;
755 RCLCPP_DEBUG(logger_,
"scene update %f robot stamp: %f", fmod(
last_update_time_.seconds(), 10.),
757 old_scene_name =
scene_->getName();
762 if (scene.robot_state.is_diff)
773 result =
scene_->usePlanningSceneMsg(scene);
778 if (!scene.is_diff && scene.world.octomap.octomap.data.empty())
785 robot_model_ =
scene_->getRobotModel();
797 bool no_other_scene_upd = (scene.name.empty() || scene.name == old_scene_name) &&
798 scene.allowed_collision_matrix.entry_names.empty() && scene.link_padding.empty() &&
799 scene.link_scale.empty();
800 if (no_other_scene_upd)
806 if (!scene.fixed_frame_transforms.empty())
812 if (!scene.robot_state.attached_collision_objects.empty() || !scene.robot_state.is_diff)
822 const std::optional<moveit_msgs::msg::ObjectColor>& color_msg)
831 if (!
scene_->processCollisionObjectMsg(*
object))
833 if (color_msg.has_value())
834 scene_->setObjectColor(color_msg.value().id, color_msg.value().color);
837 RCLCPP_INFO(logger_,
"Published update collision object");
842 const moveit_msgs::msg::AttachedCollisionObject::ConstSharedPtr&
object)
853 if (!
scene_->processAttachedCollisionObjectMsg(*
object))
857 RCLCPP_INFO(logger_,
"Published update attached");
862 const moveit_msgs::msg::PlanningSceneWorld::ConstSharedPtr& world)
870 scene_->getWorldNonConst()->clearObjects();
871 scene_->processPlanningSceneWorldMsg(*world);
874 if (world->octomap.octomap.data.empty())
894 const std::vector<const moveit::core::LinkModel*>& links =
getRobotModel()->getLinkModelsWithCollisionGeometry();
895 auto start = std::chrono::system_clock::now();
899 std::vector<shapes::ShapeConstPtr>
shapes = link->getShapes();
900 for (std::size_t j = 0; j <
shapes.size(); ++j)
903 if (
shapes[j]->type == shapes::MESH)
905 shapes::Mesh* m =
static_cast<shapes::Mesh*
>(
shapes[j]->clone());
906 m->mergeVertices(1e-4);
915 if (!warned && ((std::chrono::system_clock::now() - start) > std::chrono::seconds(30)))
917 RCLCPP_WARN(logger_,
"It is likely there are too many vertices in collision geometry");
931 std::vector<std::pair<occupancy_map_monitor::ShapeHandle, std::size_t>>>& link_shape_handle :
934 for (std::pair<occupancy_map_monitor::ShapeHandle, std::size_t>& it : link_shape_handle.second)
949 std::vector<std::pair<occupancy_map_monitor::ShapeHandle, std::size_t>>>& attached_body_shape_handle :
952 for (std::pair<occupancy_map_monitor::ShapeHandle, std::size_t>& it : attached_body_shape_handle.second)
964 std::vector<const moveit::core::AttachedBody*> ab;
965 scene_->getCurrentState().getAttachedBodies(ab);
978 for (std::pair<
const std::string, std::vector<std::pair<occupancy_map_monitor::ShapeHandle, const Eigen::Isometry3d*>>>&
981 for (std::pair<occupancy_map_monitor::ShapeHandle, const Eigen::Isometry3d*>& it :
982 collision_body_shape_handle.second)
993 for (
const std::pair<const std::string, collision_detection::World::ObjectPtr>& it : *
scene_->getWorld())
1004 for (std::size_t i = 0; i < attached_body->
getShapes().size(); ++i)
1006 if (attached_body->
getShapes()[i]->type == shapes::PLANE || attached_body->
getShapes()[i]->type == shapes::OCTREE)
1016 RCLCPP_DEBUG(logger_,
"Excluding attached body '%s' from monitored octomap", attached_body->
getName().c_str());
1029 for (std::pair<occupancy_map_monitor::ShapeHandle, std::size_t>& shape_handle : it->second)
1031 RCLCPP_DEBUG(logger_,
"Including attached body '%s' in monitored octomap", attached_body->
getName().c_str());
1044 for (std::size_t i = 0; i < obj->shapes_.size(); ++i)
1046 if (obj->shapes_[i]->type == shapes::PLANE || obj->shapes_[i]->type == shapes::OCTREE)
1056 RCLCPP_DEBUG(logger_,
"Excluding collision object '%s' from monitored octomap", obj->id_.c_str());
1069 for (std::pair<occupancy_map_monitor::ShapeHandle, const Eigen::Isometry3d*>& shape_handle : it->second)
1071 RCLCPP_DEBUG(logger_,
"Including collision object '%s' in monitored octomap", obj->id_.c_str());
1117 if (t.nanoseconds() == 0)
1119 RCLCPP_DEBUG(logger_,
"sync robot state to: %.3fs", fmod(t.seconds(), 10.));
1131 if (state_update_pending_.load())
1138 RCLCPP_WARN(logger_,
"Failed to fetch current robot state.");
1145 auto start =
node_->get_clock()->now();
1146 auto timeout = rclcpp::Duration::from_seconds(wait_time);
1150 timeout > rclcpp::Duration(0, 0))
1154 timeout = timeout - (
node_->get_clock()->now() - start);
1160 RCLCPP_WARN(logger_,
"Maybe failed to update robot state, time diff: %.3fs",
1164 RCLCPP_DEBUG(logger_,
"sync done: robot motion: %f scene update: %f", (t -
last_robot_motion_time_).seconds(),
1201 RCLCPP_INFO(logger_,
"Starting planning scene monitor");
1203 if (!scene_topic.empty())
1206 scene_topic, rclcpp::ServicesQoS(), [
this](
const moveit_msgs::msg::PlanningScene::ConstSharedPtr& scene) {
1207 return newPlanningSceneCallback(scene);
1217 RCLCPP_INFO(logger_,
"Stopping planning scene monitor");
1230 std::vector<std::pair<occupancy_map_monitor::ShapeHandle, std::size_t>>>& link_shape_handle :
1233 if (
tf_buffer_->canTransform(target_frame, link_shape_handle.first->getName(), target_time,
1234 shape_transform_cache_lookup_wait_time_))
1236 Eigen::Isometry3d ttr = tf2::transformToEigen(
1237 tf_buffer_->lookupTransform(target_frame, link_shape_handle.first->getName(), target_time));
1238 for (std::size_t j = 0; j < link_shape_handle.second.size(); ++j)
1240 cache[link_shape_handle.second[j].first] =
1241 ttr * link_shape_handle.first->getCollisionOriginTransforms()[link_shape_handle.second[j].second];
1246 std::vector<std::pair<occupancy_map_monitor::ShapeHandle, std::size_t>>>&
1249 if (
tf_buffer_->canTransform(target_frame, attached_body_shape_handle.first->getAttachedLinkName(), target_time,
1250 shape_transform_cache_lookup_wait_time_))
1252 Eigen::Isometry3d transform = tf2::transformToEigen(
tf_buffer_->lookupTransform(
1253 target_frame, attached_body_shape_handle.first->getAttachedLinkName(), target_time));
1254 for (std::size_t k = 0; k < attached_body_shape_handle.second.size(); ++k)
1256 cache[attached_body_shape_handle.second[k].first] =
1258 attached_body_shape_handle.first->getShapePosesInLinkFrame()[attached_body_shape_handle.second[k].second];
1263 if (
tf_buffer_->canTransform(target_frame,
scene_->getPlanningFrame(), target_time,
1264 shape_transform_cache_lookup_wait_time_))
1266 Eigen::Isometry3d transform =
1267 tf2::transformToEigen(
tf_buffer_->lookupTransform(target_frame,
scene_->getPlanningFrame(), target_time));
1268 for (
const std::pair<
const std::string,
1269 std::vector<std::pair<occupancy_map_monitor::ShapeHandle, const Eigen::Isometry3d*>>>&
1272 for (
const std::pair<occupancy_map_monitor::ShapeHandle, const Eigen::Isometry3d*>& it :
1273 collision_body_shape_handle.second)
1274 cache[it.first] = transform * (*it.second);
1279 catch (tf2::TransformException& ex)
1281 rclcpp::Clock steady_clock = rclcpp::Clock();
1282#pragma GCC diagnostic push
1283#pragma GCC diagnostic ignored "-Wold-style-cast"
1284 RCLCPP_ERROR_THROTTLE(logger_, steady_clock, 1000,
"Transform error: %s", ex.what());
1285#pragma GCC diagnostic pop
1292 const std::string& planning_scene_world_topic,
1293 const bool load_octomap_monitor)
1296 RCLCPP_INFO(logger_,
"Starting world geometry update monitor for collision objects, attached objects, octomap "
1300 if (!collision_objects_topic.empty())
1303 collision_objects_topic, rclcpp::ServicesQoS(),
1305 RCLCPP_INFO(logger_,
"Listening to '%s'", collision_objects_topic.c_str());
1308 if (!planning_scene_world_topic.empty())
1311 planning_scene_world_topic, rclcpp::ServicesQoS(),
1312 [
this](
const moveit_msgs::msg::PlanningSceneWorld::ConstSharedPtr& world) {
1315 RCLCPP_INFO(logger_,
"Listening to '%s' for planning scene world geometry", planning_scene_world_topic.c_str());
1319 if (load_octomap_monitor)
1324 std::make_unique<occupancy_map_monitor::OccupancyMapMonitor>(
node_,
tf_buffer_,
scene_->getPlanningFrame());
1329 octomap_monitor_->setTransformCacheCallback([
this](
const std::string& frame,
const rclcpp::Time& stamp,
1343 RCLCPP_INFO(logger_,
"Stopping world geometry monitor");
1348 RCLCPP_INFO(logger_,
"Stopping world geometry monitor");
1356 const std::string& attached_objects_topic)
1367 [
this](
const sensor_msgs::msg::JointState::ConstSharedPtr& joint_state) {
return onStateUpdate(joint_state); });
1371 std::unique_lock<std::mutex> lock(state_update_mutex_);
1372 if (dt_state_update_.count() > 0)
1376 state_update_timer_ =
1377 pnode_->create_wall_timer(dt_state_update_, [
this]() {
return stateUpdateTimerCallback(); });
1381 if (!attached_objects_topic.empty())
1385 attached_objects_topic, rclcpp::ServicesQoS(),
1386 [
this](
const moveit_msgs::msg::AttachedCollisionObject::ConstSharedPtr& obj) {
1389 RCLCPP_INFO(logger_,
"Listening to '%s' for attached collision objects",
1394 RCLCPP_ERROR(logger_,
"Cannot monitor robot state because planning scene is not configured");
1404 if (state_update_timer_)
1405 state_update_timer_->cancel();
1406 state_update_pending_.store(
false);
1409void PlanningSceneMonitor::onStateUpdate(
const sensor_msgs::msg::JointState::ConstSharedPtr& )
1411 state_update_pending_.store(
true);
1416 if (std::chrono::system_clock::now() - last_robot_state_update_wall_time_ >= dt_state_update_)
1420void PlanningSceneMonitor::stateUpdateTimerCallback()
1424 if (state_update_pending_.load() &&
1425 std::chrono::system_clock::now() - last_robot_state_update_wall_time_ >= dt_state_update_)
1455 bool update =
false;
1456 if (hz > std::numeric_limits<double>::epsilon())
1458 std::unique_lock<std::mutex> lock(state_update_mutex_);
1459 dt_state_update_ = std::chrono::duration<double>(1.0 / hz);
1462 state_update_timer_ =
pnode_->create_wall_timer(dt_state_update_, [
this]() {
return stateUpdateTimerCallback(); });
1469 if (state_update_timer_)
1470 state_update_timer_->cancel();
1471 std::unique_lock<std::mutex> lock(state_update_mutex_);
1472 dt_state_update_ = std::chrono::duration<double>(0.0);
1473 if (state_update_pending_.load())
1476 RCLCPP_INFO(logger_,
"Updating internal planning scene state at most every %lf seconds", dt_state_update_.count());
1484 rclcpp::Time time =
node_->now();
1485 rclcpp::Clock steady_clock = rclcpp::Clock(RCL_STEADY_TIME);
1488 std::vector<std::string> missing;
1492 std::string missing_str = fmt::format(
"{}", fmt::join(missing,
", "));
1493#pragma GCC diagnostic push
1494#pragma GCC diagnostic ignored "-Wold-style-cast"
1495 RCLCPP_WARN_THROTTLE(logger_, steady_clock, 1000,
"The complete state of the robot is not yet known. Missing %s",
1496 missing_str.c_str());
1497#pragma GCC diagnostic pop
1502 if (!skip_update_if_locked)
1506 else if (!ulock.try_lock())
1514 scene_->getCurrentStateNonConst().update();
1519 std::unique_lock<std::mutex> lock(state_update_mutex_);
1520 last_robot_state_update_wall_time_ = std::chrono::system_clock::now();
1521 state_update_pending_.store(
false);
1528#pragma GCC diagnostic push
1529#pragma GCC diagnostic ignored "-Wold-style-cast"
1530 RCLCPP_ERROR_THROTTLE(logger_, steady_clock, 1000,
1531 "State monitor is not active. Unable to set the planning scene state");
1532#pragma GCC diagnostic pop
1552 RCLCPP_DEBUG(logger_,
"Maximum frequency for publishing a planning scene is now %lf Hz",
1556void PlanningSceneMonitor::getUpdatedFrameTransforms(std::vector<geometry_msgs::msg::TransformStamped>& transforms)
1558 const std::string& target =
getRobotModel()->getModelFrame();
1560 std::vector<std::string> all_frame_names;
1561 tf_buffer_->_getFrameStrings(all_frame_names);
1562 for (
const std::string& all_frame_name : all_frame_names)
1564 if (all_frame_name == target ||
getRobotModel()->hasLinkModel(all_frame_name))
1567 geometry_msgs::msg::TransformStamped f;
1570 f =
tf_buffer_->lookupTransform(target, all_frame_name, tf2::TimePointZero);
1572 catch (tf2::TransformException& ex)
1574 RCLCPP_WARN(logger_,
"Unable to transform object from frame '%s' to planning frame'%s' (%s)",
1575 all_frame_name.c_str(), target.c_str(), ex.what());
1578 f.header.frame_id = all_frame_name;
1579 f.child_frame_id = target;
1580 transforms.push_back(f);
1588 std::vector<geometry_msgs::msg::TransformStamped> transforms;
1589 getUpdatedFrameTransforms(transforms);
1592 scene_->getTransformsNonConst().setTransforms(transforms);
1617 RCLCPP_DEBUG(logger_,
"No additional default collision operations specified");
1621 RCLCPP_DEBUG(logger_,
"Reading additional default collision operations");
1665 static const std::string ROBOT_DESCRIPTION =
void setupScene(const rclcpp::Node::SharedPtr &node, const planning_scene::PlanningScenePtr &scene)
Fetch plugin name from parameter server and activate the plugin for the given scene.
std::shared_lock< std::shared_mutex > ReadLock
Represents an action that occurred on an object in the world. Several bits may be set indicating seve...
std::function< void(const ObjectConstPtr &, Action)> ObserverCallbackFn
This may be thrown during construction of objects if errors occur.
Object defining bodies that can be attached to robot links.
const std::string & getName() const
Get the name of the attached body.
const std::vector< shapes::ShapeConstPtr > & getShapes() const
Get the shapes that make up this attached body.
A link from the robot. Contains the constant transform applied to the link and its geometry.
This class maintains the representation of the environment as seen by a planning instance....
static PlanningScenePtr clone(const PlanningSceneConstPtr &scene)
Clone a planning scene. Even if the scene scene depends on a parent, the cloned scene will not.
static const std::string OCTOMAP_NS
PlanningSceneMonitor Subscribes to the topic planning_scene.
static const std::string DEFAULT_PLANNING_SCENE_TOPIC
The name of the topic used by default for receiving full planning scenes or planning scene diffs.
void lockSceneRead()
Lock the scene for reading (multiple threads can lock for reading at the same time)
void lockSceneWrite()
Lock the scene for writing (only one thread can lock for writing and no other thread can lock for rea...
void unlockSceneRead()
Unlock the scene from reading (multiple threads can lock for reading at the same time)
static const std::string DEFAULT_PLANNING_SCENE_SERVICE
The name of the service used by default for requesting full planning scene state.
void excludeAttachedBodiesFromOctree()
planning_scene::PlanningScenePtr scene_
double default_attached_padd_
default attached padding
void currentWorldObjectUpdateCallback(const collision_detection::World::ObjectConstPtr &object, collision_detection::World::Action action)
Callback for a change in the world maintained by the planning scene.
double default_robot_scale_
default robot scaling
std::unique_ptr< occupancy_map_monitor::OccupancyMapMonitor > octomap_monitor_
planning_scene::PlanningScenePtr copyPlanningScene(const moveit_msgs::msg::PlanningScene &diff=moveit_msgs::msg::PlanningScene())
Returns a copy of the current planning scene.
AttachedBodyShapeHandles attached_body_shape_handles_
std::map< std::string, double > default_robot_link_padd_
default robot link padding
static const std::string DEFAULT_ATTACHED_COLLISION_OBJECT_TOPIC
The name of the topic used by default for attached collision objects.
LinkShapeHandles link_shape_handles_
static const std::string DEFAULT_COLLISION_OBJECT_TOPIC
The name of the topic used by default for receiving collision objects in the world.
SceneUpdateType publish_update_types_
void configureDefaultPadding()
Configure the default padding.
void publishDebugInformation(bool flag)
PlanningSceneMonitor(const PlanningSceneMonitor &)=delete
PlanningSceneMonitor cannot be copy-constructed.
rclcpp::Subscription< moveit_msgs::msg::AttachedCollisionObject >::SharedPtr attached_collision_object_subscriber_
void stopPublishingPlanningScene()
Stop publishing the maintained planning scene.
void excludeAttachedBodyFromOctree(const moveit::core::AttachedBody *attached_body)
double default_object_padd_
default object padding
void addUpdateCallback(const std::function< void(SceneUpdateType)> &fn)
Add a function to be called when an update to the scene is received.
std::shared_ptr< rclcpp::Node > pnode_
bool newPlanningSceneMessage(const moveit_msgs::msg::PlanningScene &scene)
void setPlanningScenePublishingFrequency(double hz)
Set the maximum frequency at which planning scenes are being published.
bool processAttachedCollisionObjectMsg(const moveit_msgs::msg::AttachedCollisionObject::ConstSharedPtr &attached_collision_object_msg)
void includeWorldObjectInOctree(const collision_detection::World::ObjectConstPtr &obj)
rclcpp::Service< moveit_msgs::srv::GetPlanningScene >::SharedPtr get_scene_service_
void initialize(const planning_scene::PlanningScenePtr &scene)
Initialize the planning scene monitor.
void getMonitoredTopics(std::vector< std::string > &topics) const
Get the topic names that the monitor is listening to.
void triggerSceneUpdateEvent(SceneUpdateType update_type)
This function is called every time there is a change to the planning scene.
static const std::string DEFAULT_PLANNING_SCENE_WORLD_TOPIC
void newPlanningSceneWorldCallback(const moveit_msgs::msg::PlanningSceneWorld::ConstSharedPtr &world)
Callback for a new planning scene world.
planning_scene::PlanningSceneConstPtr scene_const_
rclcpp::Subscription< moveit_msgs::msg::CollisionObject >::SharedPtr collision_object_subscriber_
void includeAttachedBodyInOctree(const moveit::core::AttachedBody *attached_body)
void octomapUpdateCallback()
Callback for octomap updates.
rclcpp::Subscription< moveit_msgs::msg::PlanningScene >::SharedPtr planning_scene_subscriber_
void clearUpdateCallbacks()
Clear the functions to be called when an update to the scene is received.
void providePlanningSceneService(const std::string &service_name=DEFAULT_PLANNING_SCENE_SERVICE)
Create an optional service for getting the complete planning scene This is useful for satisfying the ...
std::shared_mutex scene_update_mutex_
if diffs are monitored, this is the pointer to the parent scene
const moveit::core::RobotModelConstPtr & getRobotModel() const
void setStateUpdateFrequency(double hz)
Update the scene using the monitored state at a specified frequency, in Hz. This function has an effe...
double publish_planning_scene_frequency_
std::shared_ptr< tf2_ros::TransformListener > tf_listener_
void stopWorldGeometryMonitor()
Stop the world geometry monitor.
void startStateMonitor(const std::string &joint_states_topic=DEFAULT_JOINT_STATES_TOPIC, const std::string &attached_objects_topic=DEFAULT_ATTACHED_COLLISION_OBJECT_TOPIC)
Start the current state monitor.
void stopStateMonitor()
Stop the state monitor.
@ UPDATE_SCENE
The entire scene was updated.
@ UPDATE_STATE
The state in the monitored scene was updated.
@ 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.
std::atomic< SceneUpdateType > new_scene_update_
std::shared_ptr< rclcpp::executors::SingleThreadedExecutor > private_executor_
void includeAttachedBodiesInOctree()
bool getShapeTransformCache(const std::string &target_frame, const rclcpp::Time &target_time, occupancy_map_monitor::ShapeTransformCache &cache) const
void startSceneMonitor(const std::string &scene_topic=DEFAULT_PLANNING_SCENE_TOPIC)
Start the scene monitor (ROS topic-based)
void startPublishingPlanningScene(SceneUpdateType event, const std::string &planning_scene_topic=MONITORED_PLANNING_SCENE_TOPIC)
Start publishing the maintained planning scene. The first message set out is a complete planning scen...
std::string robot_description_
bool processCollisionObjectMsg(const moveit_msgs::msg::CollisionObject::ConstSharedPtr &collision_object_msg, const std::optional< moveit_msgs::msg::ObjectColor > &color_msg=std::nullopt)
bool waitForCurrentRobotState(const rclcpp::Time &t, double wait_time=1.)
Wait for robot state to become more recent than time t.
std::recursive_mutex shape_handles_lock_
std::map< std::string, double > default_robot_link_scale_
default robot link scale
rclcpp::Time last_robot_motion_time_
Last time the state was updated.
void updateSceneWithCurrentState(bool skip_update_if_locked=false)
Update the scene using the monitored state. This function is automatically called when an update to t...
std::thread private_executor_thread_
void excludeWorldObjectsFromOctree()
double default_robot_padd_
default robot padding
std::string monitor_name_
The name of this scene monitor.
bool updatesScene(const planning_scene::PlanningSceneConstPtr &scene) const
Return true if the scene scene can be updated directly or indirectly by this monitor....
CurrentStateMonitorPtr current_state_monitor_
std::recursive_mutex update_lock_
lock access to update_callbacks_
void includeWorldObjectsInOctree()
CollisionBodyShapeHandles collision_body_shape_handles_
void stopSceneMonitor()
Stop the scene monitor.
void includeRobotLinksInOctree()
rclcpp::Time last_update_time_
mutex for stored scene
void excludeRobotLinksFromOctree()
bool requestPlanningSceneState(const std::string &service_name=DEFAULT_PLANNING_SCENE_SERVICE)
Request a full planning scene state using a service call Be careful not to use this in conjunction wi...
void monitorDiffs(bool flag)
By default, the maintained planning scene does not reason about diffs. When the flag passed in is tru...
static const std::string MONITORED_PLANNING_SCENE_TOPIC
void currentStateAttachedBodyUpdateCallback(moveit::core::AttachedBody *attached_body, bool just_attached)
Callback for a change for an attached object of the current state of the planning scene.
std::unique_ptr< std::thread > publish_planning_scene_
std::shared_ptr< rclcpp::Node > node_
Last time the robot has moved.
void configureCollisionMatrix(const planning_scene::PlanningScenePtr &scene)
Configure the collision matrix for a particular scene.
void startWorldGeometryMonitor(const std::string &collision_objects_topic=DEFAULT_COLLISION_OBJECT_TOPIC, const std::string &planning_scene_world_topic=DEFAULT_PLANNING_SCENE_WORLD_TOPIC, const bool load_octomap_monitor=true)
Start the OccupancyMapMonitor and listening for:
rclcpp::Publisher< moveit_msgs::msg::PlanningScene >::SharedPtr planning_scene_publisher_
static const std::string DEFAULT_JOINT_STATES_TOPIC
The name of the topic used by default for receiving joint states.
void excludeWorldObjectFromOctree(const collision_detection::World::ObjectConstPtr &obj)
const planning_scene::PlanningScenePtr & getPlanningScene()
Avoid this function! Returns an unsafe pointer to the current planning scene.
std::vector< std::function< void(SceneUpdateType)> > update_callbacks_
void updateFrameTransforms()
Update the transforms for the frames that are not part of the kinematic model using tf....
planning_scene::PlanningScenePtr parent_scene_
std::condition_variable_any new_scene_update_condition_
std::shared_ptr< tf2_ros::Buffer > tf_buffer_
void unlockSceneWrite()
Lock the scene from writing (only one thread can lock for writing and no other thread can lock for re...
rclcpp::Subscription< moveit_msgs::msg::PlanningSceneWorld >::SharedPtr planning_scene_world_subscriber_
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::function< void(AttachedBody *body, bool attached)> AttachedBodyCallback
Main namespace for MoveIt.
std::map< ShapeHandle, Eigen::Isometry3d, std::less< ShapeHandle >, Eigen::aligned_allocator< std::pair< const ShapeHandle, Eigen::Isometry3d > > > ShapeTransformCache
This namespace includes the central class for representing planning contexts.