39 #include <geometric_shapes/shape_operations.h>
40 #include <rclcpp/logger.hpp>
41 #include <rclcpp/logging.hpp>
42 #include <tf2_eigen/tf2_eigen.hpp>
56 static const rclcpp::Logger
LOGGER = rclcpp::get_logger(
"moveit_robot_state.conversions");
58 static bool _jointStateToRobotState(
const sensor_msgs::msg::JointState& joint_state, RobotState& state)
60 if (joint_state.name.size() != joint_state.position.size())
62 RCLCPP_ERROR(LOGGER,
"Different number of names and positions in JointState message: %zu, %zu",
63 joint_state.name.size(), joint_state.position.size());
67 state.setVariableValues(joint_state);
72 static bool _multiDOFJointsToRobotState(
const sensor_msgs::msg::MultiDOFJointState& mjs, RobotState& state,
75 std::size_t nj = mjs.joint_names.size();
76 if (nj != mjs.transforms.size())
78 RCLCPP_ERROR(LOGGER,
"Different number of names, values or frames in MultiDOFJointState message.");
83 Eigen::Isometry3d inv_t;
84 bool use_inv_t =
false;
92 const Eigen::Isometry3d& t2fixed_frame = tf->getTransform(mjs.header.frame_id);
95 inv_t = t2fixed_frame.inverse();
98 catch (std::exception& ex)
100 RCLCPP_ERROR(LOGGER,
"Caught %s", ex.what());
108 "The transform for multi-dof joints was specified in frame '%s' "
109 "but it was not possible to transform that to frame '%s'",
110 mjs.header.frame_id.c_str(), state.getRobotModel()->getModelFrame().c_str());
113 for (std::size_t i = 0; i < nj; ++i)
115 const std::string& joint_name = mjs.joint_names[i];
116 if (!state.getRobotModel()->hasJointModel(joint_name))
118 RCLCPP_WARN(LOGGER,
"No joint matching multi-dof joint '%s'", joint_name.c_str());
122 Eigen::Isometry3d transf = tf2::transformToEigen(mjs.transforms[i]);
125 transf = transf * inv_t;
127 state.setJointPositions(joint_name, transf);
133 static inline void _robotStateToMultiDOFJointState(
const RobotState& state, sensor_msgs::msg::MultiDOFJointState& mjs)
135 const std::vector<const JointModel*>& js = state.getRobotModel()->getMultiDOFJointModels();
136 mjs.joint_names.clear();
137 mjs.transforms.clear();
138 for (
const JointModel* joint_model : js)
140 geometry_msgs::msg::TransformStamped
p;
141 if (state.dirtyJointTransform(joint_model))
145 joint_model->computeTransform(state.getJointPositions(joint_model), t);
146 p = tf2::eigenToTransform(t);
149 p = tf2::eigenToTransform(state.getJointTransform(joint_model));
150 mjs.joint_names.push_back(joint_model->getName());
151 mjs.transforms.push_back(
p.transform);
153 mjs.header.frame_id = state.getRobotModel()->getModelFrame();
156 class ShapeVisitorAddToCollisionObject :
public boost::static_visitor<void>
159 ShapeVisitorAddToCollisionObject(moveit_msgs::msg::CollisionObject* obj) :
boost::static_visitor<void>(), obj_(obj)
163 void addToObject(
const shapes::ShapeMsg& sm,
const geometry_msgs::msg::Pose& pose)
166 boost::apply_visitor(*
this, sm);
169 void operator()(
const shape_msgs::msg::Plane& shape_msg)
const
171 obj_->planes.push_back(shape_msg);
172 obj_->plane_poses.push_back(*pose_);
175 void operator()(
const shape_msgs::msg::Mesh& shape_msg)
const
177 obj_->meshes.push_back(shape_msg);
178 obj_->mesh_poses.push_back(*pose_);
181 void operator()(
const shape_msgs::msg::SolidPrimitive& shape_msg)
const
183 obj_->primitives.push_back(shape_msg);
184 obj_->primitive_poses.push_back(*pose_);
188 moveit_msgs::msg::CollisionObject* obj_;
189 const geometry_msgs::msg::Pose* pose_;
192 static void _attachedBodyToMsg(
const AttachedBody& attached_body, moveit_msgs::msg::AttachedCollisionObject& aco)
194 aco.link_name = attached_body.getAttachedLinkName();
195 aco.detach_posture = attached_body.getDetachPosture();
196 const std::set<std::string>& touch_links = attached_body.getTouchLinks();
197 aco.touch_links.clear();
198 for (
const std::string& touch_link : touch_links)
199 aco.touch_links.push_back(touch_link);
200 aco.object.header.frame_id = aco.link_name;
201 aco.object.id = attached_body.getName();
202 aco.object.pose = tf2::toMsg(attached_body.getPose());
204 aco.object.operation = moveit_msgs::msg::CollisionObject::ADD;
205 const std::vector<shapes::ShapeConstPtr>& ab_shapes = attached_body.getShapes();
206 const EigenSTL::vector_Isometry3d& shape_poses = attached_body.getShapePoses();
207 ShapeVisitorAddToCollisionObject sv(&aco.object);
208 aco.object.primitives.clear();
209 aco.object.meshes.clear();
210 aco.object.planes.clear();
211 aco.object.primitive_poses.clear();
212 aco.object.mesh_poses.clear();
213 aco.object.plane_poses.clear();
214 for (std::size_t j = 0; j < ab_shapes.size(); ++j)
217 if (shapes::constructMsgFromShape(ab_shapes[j].get(), sm))
219 geometry_msgs::msg::Pose
p;
220 p = tf2::toMsg(shape_poses[j]);
221 sv.addToObject(sm,
p);
224 aco.object.subframe_names.clear();
225 aco.object.subframe_poses.clear();
226 for (
const auto& frame_pair : attached_body.getSubframes())
228 aco.object.subframe_names.push_back(frame_pair.first);
229 geometry_msgs::msg::Pose pose;
230 pose = tf2::toMsg(frame_pair.second);
231 aco.object.subframe_poses.push_back(pose);
235 static void _msgToAttachedBody(
const Transforms* tf,
const moveit_msgs::msg::AttachedCollisionObject& aco,
238 if (aco.object.operation == moveit_msgs::msg::CollisionObject::ADD)
240 if (!aco.object.primitives.empty() || !aco.object.meshes.empty() || !aco.object.planes.empty())
242 if (aco.object.primitives.size() != aco.object.primitive_poses.size())
244 RCLCPP_ERROR(LOGGER,
"Number of primitive shapes does not match "
245 "number of poses in collision object message");
249 if (aco.object.meshes.size() != aco.object.mesh_poses.size())
251 RCLCPP_ERROR(LOGGER,
"Number of meshes does not match number of poses in collision object message");
255 if (aco.object.planes.size() != aco.object.plane_poses.size())
257 RCLCPP_ERROR(LOGGER,
"Number of planes does not match number of poses in collision object message");
261 if (aco.object.subframe_poses.size() != aco.object.subframe_names.size())
263 RCLCPP_ERROR(LOGGER,
"Number of subframe poses does not match number of subframe names in message");
267 const LinkModel* lm = state.getLinkModel(aco.link_name);
270 Eigen::Isometry3d object_pose;
271 tf2::fromMsg(aco.object.pose, object_pose);
273 std::vector<shapes::ShapeConstPtr>
shapes;
274 EigenSTL::vector_Isometry3d shape_poses;
275 const auto num_shapes = aco.object.primitives.size() + aco.object.meshes.size() + aco.object.planes.size();
276 shapes.reserve(num_shapes);
277 shape_poses.reserve(num_shapes);
279 auto append = [&
shapes, &shape_poses](shapes::Shape* s,
const geometry_msgs::msg::Pose& pose_msg) {
282 Eigen::Isometry3d pose;
283 tf2::fromMsg(pose_msg, pose);
284 shapes.emplace_back(shapes::ShapeConstPtr(s));
285 shape_poses.emplace_back(std::move(pose));
288 for (std::size_t i = 0; i < aco.object.primitives.size(); ++i)
289 append(shapes::constructShapeFromMsg(aco.object.primitives[i]), aco.object.primitive_poses[i]);
290 for (std::size_t i = 0; i < aco.object.meshes.size(); ++i)
291 append(shapes::constructShapeFromMsg(aco.object.meshes[i]), aco.object.mesh_poses[i]);
292 for (std::size_t i = 0; i < aco.object.planes.size(); ++i)
293 append(shapes::constructShapeFromMsg(aco.object.planes[i]), aco.object.plane_poses[i]);
296 for (std::size_t i = 0; i < aco.object.subframe_poses.size(); ++i)
299 tf2::fromMsg(aco.object.subframe_poses[i],
p);
300 std::string
name = aco.object.subframe_names[i];
301 subframe_poses[
name] =
p;
307 bool frame_found =
false;
308 Eigen::Isometry3d world_to_header_frame;
309 world_to_header_frame = state.getFrameTransform(aco.object.header.frame_id, &frame_found);
312 if (tf && tf->canTransform(aco.object.header.frame_id))
313 world_to_header_frame = tf->getTransform(aco.object.header.frame_id);
316 world_to_header_frame.setIdentity();
318 "Cannot properly transform from frame '%s'. "
319 "The pose of the attached body may be incorrect",
320 aco.object.header.frame_id.c_str());
323 object_pose = state.getGlobalLinkTransform(lm).inverse() * world_to_header_frame * object_pose;
328 RCLCPP_ERROR(LOGGER,
"There is no geometry to attach to link '%s' as part of attached body '%s'",
329 aco.link_name.c_str(), aco.object.id.c_str());
333 if (state.clearAttachedBody(aco.object.id))
335 "The robot state already had an object named '%s' attached to link '%s'. "
336 "The object was replaced.",
337 aco.object.id.c_str(), aco.link_name.c_str());
338 state.attachBody(aco.object.id, object_pose,
shapes, shape_poses, aco.touch_links, aco.link_name,
339 aco.detach_posture, subframe_poses);
340 RCLCPP_DEBUG(LOGGER,
"Attached object '%s' to link '%s'", aco.object.id.c_str(), aco.link_name.c_str());
345 RCLCPP_ERROR(LOGGER,
"The attached body for link '%s' has no geometry", aco.link_name.c_str());
347 else if (aco.object.operation == moveit_msgs::msg::CollisionObject::REMOVE)
349 if (!state.clearAttachedBody(aco.object.id))
350 RCLCPP_ERROR(LOGGER,
"The attached body '%s' can not be removed because it does not exist", aco.link_name.c_str());
353 RCLCPP_ERROR(LOGGER,
"Unknown collision object operation: %d", aco.object.operation);
356 static bool _robotStateMsgToRobotStateHelper(
const Transforms* tf,
const moveit_msgs::msg::RobotState& robot_state,
357 RobotState& state,
bool copy_attached_bodies)
360 const moveit_msgs::msg::RobotState& rs = robot_state;
362 if (!rs.is_diff && rs.joint_state.name.empty() && rs.multi_dof_joint_state.joint_names.empty())
364 RCLCPP_ERROR(LOGGER,
"Found empty JointState message");
368 bool result1 = _jointStateToRobotState(robot_state.joint_state, state);
369 bool result2 = _multiDOFJointsToRobotState(robot_state.multi_dof_joint_state, state, tf);
370 valid = result1 || result2;
372 if (valid && copy_attached_bodies)
374 if (!robot_state.is_diff)
375 state.clearAttachedBodies();
376 for (
const moveit_msgs::msg::AttachedCollisionObject& attached_collision_object :
377 robot_state.attached_collision_objects)
378 _msgToAttachedBody(tf, attached_collision_object, state);
393 bool result = _jointStateToRobotState(joint_state, state);
399 bool copy_attached_bodies)
401 bool result = _robotStateMsgToRobotStateHelper(
nullptr, robot_state, state, copy_attached_bodies);
407 bool copy_attached_bodies)
409 bool result = _robotStateMsgToRobotStateHelper(&tf, robot_state, state, copy_attached_bodies);
415 bool copy_attached_bodies)
417 robot_state.is_diff =
false;
419 _robotStateToMultiDOFJointState(state, robot_state.multi_dof_joint_state);
421 if (copy_attached_bodies)
423 std::vector<const AttachedBody*> attached_bodies;
430 const std::vector<const AttachedBody*>& attached_bodies,
431 std::vector<moveit_msgs::msg::AttachedCollisionObject>& attached_collision_objs)
433 attached_collision_objs.resize(attached_bodies.size());
434 for (std::size_t i = 0; i < attached_bodies.size(); ++i)
435 _attachedBodyToMsg(*attached_bodies[i], attached_collision_objs[i]);
440 const std::vector<const JointModel*>& js = state.
getRobotModel()->getSingleDOFJointModels();
441 joint_state = sensor_msgs::msg::JointState();
445 joint_state.name.push_back(joint_model->getName());
446 joint_state.position.push_back(state.
getVariablePosition(joint_model->getFirstVariableIndex()));
448 joint_state.velocity.push_back(state.
getVariableVelocity(joint_model->getFirstVariableIndex()));
452 if (joint_state.velocity.size() != joint_state.position.size())
453 joint_state.velocity.clear();
455 joint_state.header.frame_id = state.
getRobotModel()->getModelFrame();
461 if (trajectory.points.empty() || point_id > trajectory.points.size() - 1)
463 RCLCPP_ERROR(LOGGER,
"Invalid point_id");
466 if (trajectory.joint_names.empty())
468 RCLCPP_ERROR(LOGGER,
"No joint names specified");
473 if (!trajectory.points[point_id].velocities.empty())
475 if (!trajectory.points[point_id].accelerations.empty())
477 if (!trajectory.points[point_id].effort.empty())
478 state.
setVariableEffort(trajectory.joint_names, trajectory.points[point_id].effort);
512 const std::vector<std::string>& joint_groups_ordering,
bool include_header,
513 const std::string& separator)
515 std::stringstream headers;
516 std::stringstream joints;
518 for (
const std::string& joint_group_id : joint_groups_ordering)
532 std::vector<double> group_variable_positions;
538 joints << group_variable_positions[i] << separator;
544 out << headers.str() <<
'\n';
545 out << joints.str() <<
'\n';
550 std::stringstream line_stream(line);
557 if (!std::getline(line_stream, cell, separator[0]))
558 RCLCPP_ERROR(LOGGER,
"Missing variable %s", state.
getVariableNames()[i].c_str());
unsigned int getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
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...
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
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....
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...
const RobotModelConstPtr & getRobotModel() const
Get the robot model this state is constructed for.
void setVariableVelocities(const double *velocity)
Given an array with velocity values for all variables, set those values as the velocities in this sta...
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...
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.
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.
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...
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...
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.
std::string append(const std::string &left, const std::string &right)
const rclcpp::Logger LOGGER