38#include <boost/variant.hpp>
40#include <geometric_shapes/shape_operations.h>
41#include <rclcpp/logger.hpp>
42#include <rclcpp/logging.hpp>
43#include <tf2_eigen/tf2_eigen.hpp>
62bool jointStateToRobotStateImpl(
const sensor_msgs::msg::JointState& joint_state,
RobotState& state)
64 if (joint_state.name.size() != joint_state.position.size())
66 RCLCPP_ERROR(
getLogger(),
"Different number of names and positions in JointState message: %zu, %zu",
67 joint_state.name.size(), joint_state.position.size());
71 state.setVariableValues(joint_state);
76bool multiDofJointsToRobotState(
const sensor_msgs::msg::MultiDOFJointState& mjs,
RobotState& state,
const Transforms* tf)
78 std::size_t nj = mjs.joint_names.size();
79 if (nj != mjs.transforms.size())
81 RCLCPP_ERROR(
getLogger(),
"Different number of names, values or frames in MultiDOFJointState message.");
86 Eigen::Isometry3d inv_t;
87 bool use_inv_t =
false;
96 const Eigen::Isometry3d& t2fixed_frame = tf->getTransform(mjs.header.frame_id);
99 inv_t = t2fixed_frame.inverse();
102 catch (std::exception& ex)
104 RCLCPP_ERROR(
getLogger(),
"Caught %s", ex.what());
116 "The transform for multi-dof joints was specified in frame '%s' "
117 "but it was not possible to transform that to frame '%s'",
118 mjs.header.frame_id.c_str(), state.getRobotModel()->getModelFrame().c_str());
122 for (std::size_t i = 0; i < nj; ++i)
124 const std::string& joint_name = mjs.joint_names[i];
125 if (!state.getRobotModel()->hasJointModel(joint_name))
127 RCLCPP_WARN(
getLogger(),
"No joint matching multi-dof joint '%s'", joint_name.c_str());
131 Eigen::Isometry3d transf = tf2::transformToEigen(mjs.transforms[i]);
134 transf = transf * inv_t;
136 state.setJointPositions(joint_name, transf);
142void robotStateToMultiDofJointState(
const RobotState& state, sensor_msgs::msg::MultiDOFJointState& mjs)
144 const std::vector<const JointModel*>& js = state.getRobotModel()->getMultiDOFJointModels();
145 mjs.joint_names.clear();
146 mjs.transforms.clear();
149 geometry_msgs::msg::TransformStamped p;
150 if (state.dirtyJointTransform(joint_model))
154 joint_model->computeTransform(state.getJointPositions(joint_model), t);
155 p = tf2::eigenToTransform(t);
159 p = tf2::eigenToTransform(state.getJointTransform(joint_model));
161 mjs.joint_names.push_back(joint_model->getName());
162 mjs.transforms.push_back(p.transform);
164 mjs.header.frame_id = state.getRobotModel()->getModelFrame();
167class ShapeVisitorAddToCollisionObject :
public boost::static_visitor<void>
170 ShapeVisitorAddToCollisionObject(moveit_msgs::msg::CollisionObject* obj) : boost::static_visitor<void>(), obj_(obj)
174 void addToObject(
const shapes::ShapeMsg& sm,
const geometry_msgs::msg::Pose& pose)
177 boost::apply_visitor(*
this, sm);
180 void operator()(
const shape_msgs::msg::Plane& shape_msg)
const
182 obj_->planes.push_back(shape_msg);
183 obj_->plane_poses.push_back(*pose_);
186 void operator()(
const shape_msgs::msg::Mesh& shape_msg)
const
188 obj_->meshes.push_back(shape_msg);
189 obj_->mesh_poses.push_back(*pose_);
192 void operator()(
const shape_msgs::msg::SolidPrimitive& shape_msg)
const
194 obj_->primitives.push_back(shape_msg);
195 obj_->primitive_poses.push_back(*pose_);
199 moveit_msgs::msg::CollisionObject* obj_;
200 const geometry_msgs::msg::Pose* pose_;
203void attachedBodyToMsg(
const AttachedBody& attached_body, moveit_msgs::msg::AttachedCollisionObject& aco)
205 aco.link_name = attached_body.getAttachedLinkName();
206 aco.detach_posture = attached_body.getDetachPosture();
207 const std::set<std::string>& touch_links = attached_body.getTouchLinks();
208 aco.touch_links.clear();
209 for (
const std::string& touch_link : touch_links)
210 aco.touch_links.push_back(touch_link);
211 aco.object.header.frame_id = aco.link_name;
212 aco.object.id = attached_body.getName();
213 aco.object.pose = tf2::toMsg(attached_body.getPose());
215 aco.object.operation = moveit_msgs::msg::CollisionObject::ADD;
216 const std::vector<shapes::ShapeConstPtr>& ab_shapes = attached_body.getShapes();
217 const EigenSTL::vector_Isometry3d& shape_poses = attached_body.getShapePoses();
218 ShapeVisitorAddToCollisionObject sv(&aco.object);
219 aco.object.primitives.clear();
220 aco.object.meshes.clear();
221 aco.object.planes.clear();
222 aco.object.primitive_poses.clear();
223 aco.object.mesh_poses.clear();
224 aco.object.plane_poses.clear();
225 for (std::size_t j = 0; j < ab_shapes.size(); ++j)
228 if (shapes::constructMsgFromShape(ab_shapes[j].get(), sm))
230 geometry_msgs::msg::Pose p;
231 p = tf2::toMsg(shape_poses[j]);
232 sv.addToObject(sm, p);
235 aco.object.subframe_names.clear();
236 aco.object.subframe_poses.clear();
237 for (
const auto& frame_pair : attached_body.getSubframes())
239 aco.object.subframe_names.push_back(frame_pair.first);
240 geometry_msgs::msg::Pose pose;
241 pose = tf2::toMsg(frame_pair.second);
242 aco.object.subframe_poses.push_back(pose);
246void msgToAttachedBody(
const Transforms* tf,
const moveit_msgs::msg::AttachedCollisionObject& aco,
RobotState& state)
248 if (aco.object.operation == moveit_msgs::msg::CollisionObject::ADD)
250 if (!aco.object.primitives.empty() || !aco.object.meshes.empty() || !aco.object.planes.empty())
252 if (aco.object.primitives.size() != aco.object.primitive_poses.size())
254 RCLCPP_ERROR(
getLogger(),
"Number of primitive shapes does not match "
255 "number of poses in collision object message");
259 if (aco.object.meshes.size() != aco.object.mesh_poses.size())
261 RCLCPP_ERROR(
getLogger(),
"Number of meshes does not match number of poses in collision object message");
265 if (aco.object.planes.size() != aco.object.plane_poses.size())
267 RCLCPP_ERROR(
getLogger(),
"Number of planes does not match number of poses in collision object message");
271 if (aco.object.subframe_poses.size() != aco.object.subframe_names.size())
273 RCLCPP_ERROR(
getLogger(),
"Number of subframe poses does not match number of subframe names in message");
277 const LinkModel* lm = state.getLinkModel(aco.link_name);
280 Eigen::Isometry3d object_pose;
281 tf2::fromMsg(aco.object.pose, object_pose);
283 std::vector<shapes::ShapeConstPtr> shapes;
284 EigenSTL::vector_Isometry3d shape_poses;
285 const auto num_shapes = aco.object.primitives.size() + aco.object.meshes.size() + aco.object.planes.size();
286 shapes.reserve(num_shapes);
287 shape_poses.reserve(num_shapes);
289 auto append = [&shapes, &shape_poses](shapes::Shape* s,
const geometry_msgs::msg::Pose& pose_msg) {
292 Eigen::Isometry3d pose;
293 tf2::fromMsg(pose_msg, pose);
294 shapes.emplace_back(shapes::ShapeConstPtr(s));
295 shape_poses.emplace_back(std::move(pose));
298 for (std::size_t i = 0; i < aco.object.primitives.size(); ++i)
299 append(shapes::constructShapeFromMsg(aco.object.primitives[i]), aco.object.primitive_poses[i]);
300 for (std::size_t i = 0; i < aco.object.meshes.size(); ++i)
301 append(shapes::constructShapeFromMsg(aco.object.meshes[i]), aco.object.mesh_poses[i]);
302 for (std::size_t i = 0; i < aco.object.planes.size(); ++i)
303 append(shapes::constructShapeFromMsg(aco.object.planes[i]), aco.object.plane_poses[i]);
306 for (std::size_t i = 0; i < aco.object.subframe_poses.size(); ++i)
309 tf2::fromMsg(aco.object.subframe_poses[i], p);
310 std::string
name = aco.object.subframe_names[i];
311 subframe_poses[
name] = p;
317 bool frame_found =
false;
318 Eigen::Isometry3d world_to_header_frame;
319 world_to_header_frame = state.getFrameTransform(aco.object.header.frame_id, &frame_found);
322 if (tf && tf->canTransform(aco.object.header.frame_id))
324 world_to_header_frame = tf->getTransform(aco.object.header.frame_id);
328 world_to_header_frame.setIdentity();
330 "Cannot properly transform from frame '%s'. "
331 "The pose of the attached body may be incorrect",
332 aco.object.header.frame_id.c_str());
335 object_pose = state.getGlobalLinkTransform(lm).inverse() * world_to_header_frame * object_pose;
340 RCLCPP_ERROR(
getLogger(),
"There is no geometry to attach to link '%s' as part of attached body '%s'",
341 aco.link_name.c_str(), aco.object.id.c_str());
345 if (state.clearAttachedBody(aco.object.id))
348 "The robot state already had an object named '%s' attached to link '%s'. "
349 "The object was replaced.",
350 aco.object.id.c_str(), aco.link_name.c_str());
352 state.attachBody(aco.object.id, object_pose, shapes, shape_poses, aco.touch_links, aco.link_name,
353 aco.detach_posture, subframe_poses);
354 RCLCPP_DEBUG(
getLogger(),
"Attached object '%s' to link '%s'", aco.object.id.c_str(), aco.link_name.c_str());
360 RCLCPP_ERROR(
getLogger(),
"The attached body for link '%s' has no geometry", aco.link_name.c_str());
363 else if (aco.object.operation == moveit_msgs::msg::CollisionObject::REMOVE)
365 if (!state.clearAttachedBody(aco.object.id))
367 RCLCPP_ERROR(
getLogger(),
"The attached body '%s' can not be removed because it does not exist",
368 aco.link_name.c_str());
373 RCLCPP_ERROR(
getLogger(),
"Unknown collision object operation: %d", aco.object.operation);
377bool robotStateMsgToRobotStateHelper(
const Transforms* tf,
const moveit_msgs::msg::RobotState& robot_state,
381 const moveit_msgs::msg::RobotState& rs = robot_state;
383 if (!rs.is_diff && rs.joint_state.name.empty() && rs.multi_dof_joint_state.joint_names.empty())
385 RCLCPP_ERROR(
getLogger(),
"Found empty JointState message");
389 bool result1 = jointStateToRobotStateImpl(robot_state.joint_state, state);
390 bool result2 = multiDofJointsToRobotState(robot_state.multi_dof_joint_state, state, tf);
391 valid = result1 || result2;
393 if (valid && copy_attached_bodies)
395 if (!robot_state.is_diff)
396 state.clearAttachedBodies();
397 for (
const moveit_msgs::msg::AttachedCollisionObject& attached_collision_object :
398 robot_state.attached_collision_objects)
399 msgToAttachedBody(tf, attached_collision_object, state);
414 bool result = jointStateToRobotStateImpl(joint_state, state);
420 bool copy_attached_bodies)
422 bool result = robotStateMsgToRobotStateHelper(
nullptr, robot_state, state, copy_attached_bodies);
428 bool copy_attached_bodies)
430 bool result = robotStateMsgToRobotStateHelper(&tf, robot_state, state, copy_attached_bodies);
436 bool copy_attached_bodies)
438 robot_state.is_diff =
false;
440 robotStateToMultiDofJointState(state, robot_state.multi_dof_joint_state);
442 if (copy_attached_bodies)
444 std::vector<const AttachedBody*> attached_bodies;
451 const std::vector<const AttachedBody*>& attached_bodies,
452 std::vector<moveit_msgs::msg::AttachedCollisionObject>& attached_collision_objs)
454 attached_collision_objs.resize(attached_bodies.size());
455 for (std::size_t i = 0; i < attached_bodies.size(); ++i)
456 attachedBodyToMsg(*attached_bodies[i], attached_collision_objs[i]);
461 const std::vector<const JointModel*>& js = state.
getRobotModel()->getSingleDOFJointModels();
462 joint_state = sensor_msgs::msg::JointState();
466 joint_state.name.push_back(joint_model->getName());
467 joint_state.position.push_back(state.
getVariablePosition(joint_model->getFirstVariableIndex()));
469 joint_state.velocity.push_back(state.
getVariableVelocity(joint_model->getFirstVariableIndex()));
473 if (joint_state.velocity.size() != joint_state.position.size())
474 joint_state.velocity.clear();
476 joint_state.header.frame_id = state.
getRobotModel()->getModelFrame();
482 if (trajectory.points.empty() || point_id > trajectory.points.size() - 1)
484 RCLCPP_ERROR(
getLogger(),
"Invalid point_id");
487 if (trajectory.joint_names.empty())
489 RCLCPP_ERROR(
getLogger(),
"No joint names specified");
494 if (!trajectory.points[point_id].velocities.empty())
496 if (!trajectory.points[point_id].accelerations.empty())
498 if (!trajectory.points[point_id].effort.empty())
499 state.
setVariableEffort(trajectory.joint_names, trajectory.points[point_id].effort);
533 const std::vector<std::string>& joint_groups_ordering,
bool include_header,
534 const std::string& separator)
536 std::stringstream headers;
537 std::stringstream joints;
539 for (
const std::string& joint_group_id : joint_groups_ordering)
553 std::vector<double> group_variable_positions;
559 joints << group_variable_positions[i] << separator;
565 out << headers.str() <<
'\n';
566 out << joints.str() <<
'\n';
571 std::stringstream line_stream(line);
578 if (!std::getline(line_stream, cell, separator[0]))
Object defining bodies that can be attached to robot links.
const std::vector< std::string > & getVariableNames() const
Get the names of the variables that make up the joints included in this group. The number of returned...
unsigned int getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
A link from the robot. Contains the constant transform applied to the link and its geometry.
Representation of a robot's state. This includes position, velocity, acceleration and effort.
void setVariablePositions(const double *position)
It is assumed positions is an array containing the new positions for all variables in this state....
const std::vector< std::string > & getVariableNames() const
Get the names of the variables that make up this state, in the order they are stored in memory.
bool hasVelocities() const
By default, if velocities are never set or initialized, the state remembers that there are no velocit...
double getVariableVelocity(const std::string &variable) const
Get the velocity of a particular variable. An exception is thrown if the variable is not known.
void getAttachedBodies(std::vector< const AttachedBody * > &attached_bodies) const
Get all bodies attached to the model corresponding to this state.
void copyJointGroupPositions(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the position values of the variables that make up the group into another loca...
void setVariableVelocities(const double *velocity)
Given an array with velocity values for all variables, set those values as the velocities in this sta...
const RobotModelConstPtr & getRobotModel() const
Get the robot model this state is constructed for.
double * getVariablePositions()
Get a raw pointer to the positions of the variables stored in this state. Use carefully....
void setVariableEffort(const double *effort)
Given an array with effort values for all variables, set those values as the effort in this state.
double getVariablePosition(const std::string &variable) const
Get the position of a particular variable. An exception is thrown if the variable is not known.
void update(bool force=false)
Update all transforms.
std::size_t getVariableCount() const
Get the number of variables that make up this state.
void setVariableAccelerations(const double *acceleration)
Given an array with acceleration values for all variables, set those values as the accelerations in t...
Core components of MoveIt.
void robotStateToRobotStateMsg(const RobotState &state, moveit_msgs::msg::RobotState &robot_state, bool copy_attached_bodies=true)
Convert a MoveIt robot state to a robot state message.
bool jointTrajPointToRobotState(const trajectory_msgs::msg::JointTrajectory &trajectory, std::size_t point_id, RobotState &state)
Convert a joint trajectory point to a MoveIt robot state.
std::map< std::string, Eigen::Isometry3d, std::less< std::string >, Eigen::aligned_allocator< std::pair< const std::string, Eigen::Isometry3d > > > FixedTransformsMap
Map frame names to the transformation matrix that can transform objects from the frame name to the pl...
bool jointStateToRobotState(const sensor_msgs::msg::JointState &joint_state, RobotState &state)
Convert a joint state to a MoveIt robot state.
void attachedBodiesToAttachedCollisionObjectMsgs(const std::vector< const AttachedBody * > &attached_bodies, std::vector< moveit_msgs::msg::AttachedCollisionObject > &attached_collision_objs)
Convert AttachedBodies to AttachedCollisionObjects.
void robotStateToStream(const RobotState &state, std::ostream &out, bool include_header=true, const std::string &separator=",")
Convert a MoveIt robot state to common separated values (CSV) on a single line that is outputted to a...
void robotStateToJointStateMsg(const RobotState &state, sensor_msgs::msg::JointState &joint_state)
Convert a MoveIt robot state to a joint state message.
void streamToRobotState(RobotState &state, const std::string &line, const std::string &separator=",")
Convert a string of joint values from a file (CSV) or input source into a RobotState.
bool robotStateMsgToRobotState(const Transforms &tf, const moveit_msgs::msg::RobotState &robot_state, RobotState &state, bool copy_attached_bodies=true)
Convert a robot state msg (with accompanying extra transforms) to a MoveIt robot state.
Main namespace for MoveIt.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
std::string append(const std::string &left, const std::string &right)
rclcpp::Logger getLogger()