Robowflex  v0.1
Making MoveIt Easy
robowflex_dart/src/robot.cpp
Go to the documentation of this file.
1 /* Author: Zachary Kingston */
2 
3 #include <tinyxml2.h>
4 
5 #include <dart/dynamics/BodyNode.hpp>
6 #include <dart/dynamics/DegreeOfFreedom.hpp>
7 #include <dart/dynamics/Joint.hpp>
8 
9 #include <robowflex_library/io.h>
10 #include <robowflex_library/log.h>
12 #include <robowflex_library/tf.h>
13 
14 #include <robowflex_dart/acm.h>
15 #include <robowflex_dart/io.h>
16 #include <robowflex_dart/robot.h>
17 
18 using namespace robowflex::darts;
19 
20 ///
21 /// Robot
22 ///
23 
24 Robot::Robot(const std::string &name) : Structure(name)
25 {
26 }
27 
29 {
30  std::ofstream urdf_file;
31  std::string urdf_filename = robowflex::IO::createTempFile(urdf_file);
32 
33  std::ofstream srdf_file;
34  std::string srdf_filename = robowflex::IO::createTempFile(srdf_file);
35 
36  urdf_file << robot->getURDFString();
37  urdf_file.close();
38 
39  srdf_file << robot->getSRDFString();
40  srdf_file.close();
41 
42  loadURDF(urdf_filename);
43  loadSRDF(srdf_filename);
44 
45  robowflex::IO::deleteFile(urdf_filename);
46  robowflex::IO::deleteFile(srdf_filename);
47 }
48 
49 Robot::Robot(const std::string &name, const ScenePtr &scene) : Structure(name, scene)
50 {
51 }
52 
53 RobotPtr Robot::cloneRobot(const std::string &newName) const
54 {
55  auto robot = std::make_shared<Robot>(newName);
56  robot->setSkeleton(skeleton_->cloneSkeleton(newName));
57 
58  for (const auto &pair : acm_->getDisabledPairsConst())
59  robot->getACM()->disableCollision(pair.first, pair.second);
60 
61  robot->setGroups(groups_);
62  robot->setNamedGroupStates(group_states_);
63 
64  return robot;
65 }
66 
67 bool Robot::loadURDF(const std::string &urdf)
68 {
69  return IO::loadURDF(*this, urdf);
70 }
71 
72 bool Robot::addNameToGroup(const std::string &group, const std::string &name)
73 {
74  if (not isGroup(group))
75  {
76  RBX_DEBUG("Adding joint %1% to group %2%.", name, group);
78  return true;
79  }
80 
81  auto &names = getGroupJointNames(group);
82 
83  for (const auto &item : names)
84  if (item == name)
85  return false;
86 
87  RBX_DEBUG("Adding joint %1% to group %2%.", name, group);
88  names.emplace_back(name);
89  return true;
90 }
91 
92 bool Robot::addJointToGroup(const std::string &group, const std::string &joint_name)
93 {
94  const auto &joint = skeleton_->getJoint(joint_name);
95  if (not joint)
96  {
97  RBX_ERROR("Joint %1% not in skeleton.", joint_name);
98  return false;
99  }
100 
101  if (joint->getNumDofs() > 0)
102  addNameToGroup(group, joint_name);
103 
104  processGroup(group);
105  return true;
106 }
107 
108 bool Robot::addLinkToGroup(const std::string &group, const std::string &link_name)
109 {
110  const auto &node = skeleton_->getBodyNode(link_name);
111  if (not node)
112  {
113  RBX_ERROR("Link %1% not in skeleton.", link_name);
114  return false;
115  }
116 
117  const auto &joint = node->getParentJoint();
118  if (not joint)
119  {
120  RBX_ERROR("Link %1% has no parent joint", link_name);
121  return false;
122  }
123 
124  if (joint->getName() == "rootJoint")
125  return false;
126 
127  // Only include mobile joints
128  if (joint->getNumDofs() > 0)
129  addNameToGroup(group, joint->getName());
130 
131  processGroup(group);
132  return true;
133 }
134 
135 bool Robot::addChainToGroup(const std::string &group, const std::string &tip, const std::string &base)
136 {
137  auto *node = skeleton_->getBodyNode(tip);
138  if (not node)
139  {
140  RBX_ERROR("Tip link %1% not in skeleton.", tip);
141  return false;
142  }
143 
145  while (node and node->getName() != base)
146  {
147  const auto &joint = node->getParentJoint();
148  if (not joint)
149  {
150  RBX_ERROR("Link %1% has no parent joint", node->getName());
151  return false;
152  }
153 
154  if (joint->getNumDofs() > 0)
155  names.emplace_back(joint->getName());
156 
157  node = joint->getParentBodyNode();
158  }
159 
160  if (not node)
161  {
162  RBX_ERROR("Base link %1% not parent of tip link %2%", base, tip);
163  return false;
164  }
165 
166  for (const auto &name : names)
167  addNameToGroup(group, name);
168 
169  processGroup(group);
170  return true;
171 }
172 
173 bool Robot::addGroupToGroup(const std::string &group, const std::string &other)
174 {
175  if (not isGroup(other))
176  {
177  RBX_ERROR("Group %1% does not exist", other);
178  return false;
179  }
180 
181  for (const auto &name : getGroupJointNamesConst(other))
182  addNameToGroup(group, name);
183 
184  processGroup(group);
185  return true;
186 }
187 
188 bool Robot::loadSRDF(const std::string &srdf)
189 {
190  const auto &file = IO::getPackageFile(srdf);
191  if (file.empty())
192  {
193  RBX_ERROR("File %1% cannot be found!", srdf);
194  return false;
195  }
196 
197  tinyxml2::XMLDocument doc;
198  doc.LoadFile(file.c_str());
199 
200  tinyxml2::XMLElement *root = doc.FirstChildElement();
201  if (not root)
202  {
203  RBX_ERROR("No child element in SRDF");
204  return false;
205  }
206 
207  // parse virtual joints
208  tinyxml2::XMLElement *vj = root->FirstChildElement("virtual_joint");
209  while (vj != nullptr)
210  {
211  std::string name = vj->Attribute("name");
212  std::string type = vj->Attribute("type");
213  std::string parent = vj->Attribute("parent_frame");
214  std::string child = vj->Attribute("child_link");
215 
216  dart::dynamics::BodyNode *pnode = nullptr;
217  if (parent != "world")
218  {
219  pnode = skeleton_->getBodyNode(parent);
220  if (not pnode)
221  RBX_ERROR("Couldn't find %s for virtual joint!", parent);
222  }
223 
224  auto *cnode = skeleton_->getBodyNode(child);
225  if (cnode)
226  {
227  if (type == "floating")
228  {
229  dart::dynamics::FreeJoint::Properties joint;
230  joint.mName = name;
231 
232  cnode->moveTo<dart::dynamics::FreeJoint>(pnode, joint);
233  }
234  }
235 
236  vj = vj->NextSiblingElement("virtual_joint");
237  }
238 
239  // Parse groups
240  tinyxml2::XMLElement *group = root->FirstChildElement("group");
241  while (group != nullptr)
242  {
243  const auto &group_name = group->Attribute("name");
244 
245  tinyxml2::XMLElement *joints = group->FirstChildElement("joint");
246  while (joints != nullptr)
247  {
248  const auto &joint_name = joints->Attribute("name");
249  addJointToGroup(group_name, joint_name);
250 
251  joints = joints->NextSiblingElement("joint");
252  }
253 
254  tinyxml2::XMLElement *links = group->FirstChildElement("link");
255  while (links != nullptr)
256  {
257  const auto &link_name = links->Attribute("name");
258  addLinkToGroup(group_name, link_name);
259 
260  links = links->NextSiblingElement("link");
261  }
262 
263  tinyxml2::XMLElement *chains = group->FirstChildElement("chain");
264  while (chains != nullptr)
265  {
266  const auto &base_link = chains->Attribute("base_link");
267  const auto &tip_link = chains->Attribute("tip_link");
268  addChainToGroup(group_name, tip_link, base_link);
269 
270  chains = chains->NextSiblingElement("chain");
271  }
272 
273  tinyxml2::XMLElement *groups = group->FirstChildElement("group");
274  while (groups != nullptr)
275  {
276  const auto &other_name = groups->Attribute("name");
277  addGroupToGroup(group_name, other_name);
278 
279  groups = groups->NextSiblingElement("group");
280  }
281 
282  group = group->NextSiblingElement("group");
283  }
284 
285  // Parse allowed collisions
286  tinyxml2::XMLElement *dc = root->FirstChildElement("disable_collisions");
287  while (dc != nullptr)
288  {
289  const auto &l1 = dc->Attribute("link1");
290  const auto &l2 = dc->Attribute("link2");
291 
292  acm_->disableCollision(l1, l2);
293 
294  dc = dc->NextSiblingElement("disable_collisions");
295  }
296 
297  // Parse named group states
298  tinyxml2::XMLElement *gs = root->FirstChildElement("group_state");
299  while (gs != nullptr)
300  {
301  const auto &group = gs->Attribute("group");
302  const auto &name = gs->Attribute("name");
303 
304  Eigen::VectorXd state = Eigen::VectorXd::Zero(getNumDofsGroup(group));
305 
306  tinyxml2::XMLElement *js = gs->FirstChildElement("joint");
307  while (js != nullptr)
308  {
309  const auto &value = js->Attribute("value");
310  const auto &jname = js->Attribute("name");
311 
312  auto values = robowflex::IO::tokenize<double>(value, " ");
313  auto joint = getGroupJoint(group, jname);
314  if (joint.second != nullptr)
315  {
316  for (std::size_t i = 0; i < values.size(); ++i)
317  state[joint.first + i] = values[i];
318  }
319 
320  js = js->NextSiblingElement("joint");
321  }
322 
323  setNamedGroupState(group, name, state);
324  gs = gs->NextSiblingElement("group_state");
325  }
326 
327  return true;
328 }
329 
330 bool Robot::isGroup(const std::string &name) const
331 {
332  return groups_.find(name) != groups_.end();
333 }
334 
335 void Robot::setGroups(const GroupsMap &newGroups)
336 {
337  groups_ = newGroups;
338  for (const auto &pair : groups_)
339  processGroup(pair.first);
340 }
341 
343 {
344  return groups_;
345 }
346 
348 {
349  return groups_.find(group)->second;
350 }
351 
353 {
354  return groups_.find(group)->second;
355 }
356 
358 {
360  for (const auto &dof : groups_.find(group)->second)
361  joints.emplace_back(skeleton_->getJoint(dof));
362 
363  return joints;
364 }
365 
367  const std::string &joint) const
368 {
369  std::size_t i = 0;
370  for (const auto &dof : getGroupJoints(group))
371  {
372  if (dof->getName() == joint)
373  return {i, dof};
374 
375  i += dof->getNumDofs();
376  }
377 
378  return {0, nullptr};
379 }
380 
382 {
383  return group_indices_.find(group)->second;
384 }
385 
387 {
388  return getGroupIndices(group).size();
389 }
390 
391 void Robot::getGroupState(const std::string &group, Eigen::Ref<Eigen::VectorXd> q) const
392 {
393  q = skeleton_->getPositions(getGroupIndices(group));
394 }
395 
396 void Robot::setGroupState(const std::string &group, const Eigen::Ref<const Eigen::VectorXd> &q)
397 {
398  skeleton_->setPositions(getGroupIndices(group), q);
399 }
400 
402 {
403  group_states_ = states;
404 }
405 
407 {
408  return group_states_;
409 }
410 
412 {
414  for (const auto &group : group_states_)
415  {
416  for (const auto &state : group.second)
417  names.emplace_back(state.first);
418  }
419 
420  return names;
421 }
422 
423 bool Robot::getNamedGroupState(const std::string &group, const std::string &name,
424  Eigen::Ref<Eigen::VectorXd> q) const
425 {
426  auto gsit = group_states_.find(group);
427  if (gsit != group_states_.end())
428  {
429  auto it = gsit->second.find(name);
430  if (it != gsit->second.end())
431  {
432  q = it->second;
433  return true;
434  }
435 
436  return false;
437  }
438 
439  return false;
440 }
441 
442 void Robot::setNamedGroupState(const std::string &group, const std::string &name,
443  const Eigen::Ref<const Eigen::VectorXd> &q)
444 {
445  auto gsit = group_states_.find(group);
446  if (gsit == group_states_.end())
447  {
448  bool r;
450  }
451 
452  auto &names = gsit->second;
453 
454  auto it = names.find(name);
455  if (it == names.end())
456  {
457  bool r;
458  std::tie(it, r) = names.emplace(name, q);
459  }
460  else
461  it->second = q;
462 }
463 
464 void Robot::setStateFromMoveItMsg(const moveit_msgs::RobotState &msg)
465 {
466  for (std::size_t i = 0; i < msg.joint_state.name.size(); ++i)
467  setJoint(msg.joint_state.name[i], msg.joint_state.position[i]);
468 
469  for (std::size_t i = 0; i < msg.multi_dof_joint_state.joint_names.size(); ++i)
470  {
471  auto *joint = skeleton_->getJoint(msg.multi_dof_joint_state.joint_names[i]);
472  auto *j = static_cast<dart::dynamics::FreeJoint *>(joint);
473 
474  auto tfmsg = msg.multi_dof_joint_state.transforms[i];
475 
476  Eigen::Isometry3d tf;
477  tf.translation() = TF::vectorMsgToEigen(tfmsg.translation);
478  tf.linear() = TF::quaternionMsgToEigen(tfmsg.rotation).toRotationMatrix();
479 
480  j->setRelativeTransform(tf);
481  }
482 }
483 
484 void Robot::setMoveItMsgFromState(moveit_msgs::RobotState &msg) const
485 {
486  msg = moveit_msgs::RobotState();
487 
488  for (std::size_t i = 0; i < skeleton_->getNumJoints(); ++i)
489  {
490  auto *joint = skeleton_->getJoint(i);
491 
492  // ignore fixed joints
493  if (joint->getNumDofs() == 0)
494  continue;
495 
496  auto *j = dynamic_cast<dart::dynamics::FreeJoint *>(joint);
497  if (j)
498  {
499  msg.multi_dof_joint_state.joint_names.push_back(joint->getName());
500 
501  auto tf = joint->getRelativeTransform();
502  geometry_msgs::Transform tfmsg;
503  tfmsg.translation = TF::vectorEigenToMsg(tf.translation());
504  tfmsg.rotation = TF::quaternionEigenToMsg(TF::getPoseRotation(tf));
505 
506  msg.multi_dof_joint_state.transforms.push_back(tfmsg);
507  }
508  else
509  {
510  msg.joint_state.name.push_back(joint->getName());
511  msg.joint_state.position.push_back(joint->getPositions()[0]);
512  }
513  }
514 }
515 
516 void Robot::setStateFromMoveItState(const robot_state::RobotState &state)
517 {
518  moveit_msgs::RobotState msg;
521 }
522 
523 void Robot::setMoveItStateFromState(robot_state::RobotState &state) const
524 {
525  moveit_msgs::RobotState msg;
528 }
529 
531 {
532  if (not robot_)
533  return;
534 
535  setMoveItStateFromState(*robot_->getScratchState()); // copy current state
536  robot_->getScratchState()->setJointGroupPositions(jmg, joints); // set only JMG state
537  setStateFromMoveItState(*robot_->getScratchState()); // copy back
538 }
539 
540 void Robot::setStateFromMoveItJMG(const std::string &jmg, const Eigen::Ref<const Eigen::VectorXd> &vec)
541 {
542  if (not robot_)
543  return;
544 
545  setMoveItStateFromState(*robot_->getScratchState()); // copy current state
546  robot_->getScratchState()->setJointGroupPositions(jmg, vec.data()); // set only JMG state
547  setStateFromMoveItState(*robot_->getScratchState()); // copy back
548 }
549 
551 {
552  if (not robot_)
553  return;
554 
555  setMoveItStateFromState(*robot_->getScratchState()); // copy current state
556  robot_->getScratchState()->copyJointGroupPositions(jmg, joints); // copy JMG state
557 }
558 
559 void Robot::setMoveItJMGFromState(const std::string &jmg, Eigen::Ref<Eigen::VectorXd> vec) const
560 {
561  if (not robot_)
562  return;
563 
564  setMoveItStateFromState(*robot_->getScratchState()); // copy current state
565  robot_->getScratchState()->copyJointGroupPositions(jmg, vec.data()); // copy JMG state
566 }
567 
569 {
570  std::vector<std::size_t> indices;
571 
572  auto joints = getGroupJoints(group);
573  for (const auto &joint : joints)
574  {
575  for (std::size_t i = 0; i < joint->getNumDofs(); ++i)
576  indices.emplace_back(joint->getDof(i)->getIndexInSkeleton());
577  }
578 
579  auto it = group_indices_.find(group);
580  if (it == group_indices_.end())
581  group_indices_.emplace(group, indices);
582  else
583  it->second = indices;
584 }
585 
587  const std::string &srdf)
588 {
589  auto robot = std::make_shared<Robot>(name);
590  robot->loadURDF(urdf);
591  robot->loadSRDF(srdf);
592 
593  return robot;
594 }
A shared pointer wrapper for robowflex::Robot.
A shared pointer wrapper for robowflex::Scene.
void setStateFromMoveItState(const robot_state::RobotState &state)
Set the current state of this robot from a MoveIt robot state.
std::size_t getNumDofsGroup(const std::string &group) const
Gets the number of DoFs controlled by a group.
const std::vector< std::string > & getGroupJointNamesConst(const std::string &group) const
Get the joint names in a group.
const GroupsMap & getGroups() const
Get the groups currently in the robot. A map of group name to a list of all joints in the group.
const std::vector< std::size_t > & getGroupIndices(const std::string &group) const
Get the indices of joints corresponding to a group.
bool addGroupToGroup(const std::string &group, const std::string &other)
Add all the joints in another group to this group.
void setGroupState(const std::string &group, const Eigen::Ref< const Eigen::VectorXd > &q)
Set the current state of the joints of a group.
void setGroups(const GroupsMap &newGroups)
Get the groups currently in the robot. A map of group name to a list of all joints in the group.
Robot(const std::string &name)
Construct an empty robot.
const NamedStatesMap & getNamedGroupStates() const
Get the named states map.
void setStateFromMoveItJMG(const std::string &jmg, const std::vector< double > &joints)
Set the state using a MoveIt Joint Group.
void setMoveItStateFromState(robot_state::RobotState &state) const
Set a MoveIt robot state from the current state of this robot.
bool getNamedGroupState(const std::string &group, const std::string &name, Eigen::Ref< Eigen::VectorXd > q) const
Get the configuration of a named group state.
void setNamedGroupState(const std::string &group, const std::string &name, const Eigen::Ref< const Eigen::VectorXd > &q)
Set or create a named group state.
bool addJointToGroup(const std::string &group, const std::string &joint_name)
Add a joint to a group.
void setMoveItMsgFromState(moveit_msgs::RobotState &msg) const
Set a MoveIt message from the current state of this robot.
bool loadSRDF(const std::string &srdf)
Load a SRDF into this robot.
std::map< std::string, std::vector< std::size_t > > group_indices_
Indices of group joints.
void getGroupState(const std::string &group, Eigen::Ref< Eigen::VectorXd > q) const
Get the current state of the joints of a group.
bool isGroup(const std::string &name) const
Checks if a group exists.
bool addChainToGroup(const std::string &group, const std::string &tip, const std::string &base)
Add all the joints between two frames in a chain to a group.
robowflex::RobotPtr robot_
Robowflex robot.
bool addNameToGroup(const std::string &group, const std::string &name)
Adds a name to the group.
void setNamedGroupStates(const NamedStatesMap &states)
Set the named states map.
void setStateFromMoveItMsg(const moveit_msgs::RobotState &msg)
Set the current state of this robot from a MoveIt message.
RobotPtr cloneRobot(const std::string &newName) const
Clone this robot with a new name.
std::pair< std::size_t, dart::dynamics::Joint * > getGroupJoint(const std::string &group, const std::string &joint) const
Get a joint in a group along with its index in the group.
void processGroup(const std::string &group)
Process the members of a group to generate the set of indices.
std::vector< std::string > & getGroupJointNames(const std::string &group)
Get the joint names in a group.
std::map< std::string, std::map< std::string, Eigen::VectorXd > > group_states_
std::vector< dart::dynamics::Joint * > getGroupJoints(const std::string &group) const
Get the joints for a group.
void setMoveItJMGFromState(const std::string &jmg, std::vector< double > &joints) const
Set a MoveIt Joint Group state from the current state of the robot.
bool loadURDF(const std::string &urdf)
Load a URDF into this robot.
std::map< std::string, std::vector< std::string > > groups_
Map of group names to joint names.
bool addLinkToGroup(const std::string &group, const std::string &link_name)
Add a the parent joint of a link to a group.
Wrapper class for a dart::dynamics::Skeleton.
Definition: structure.h:53
void setJoint(const std::string &name, double value)
Set the value of a 1-DoF joint in the structure.
Definition: structure.cpp:254
ACMPtr acm_
ACM for structure.
Definition: structure.h:262
dart::dynamics::SkeletonPtr skeleton_
Underlying skeleton.
Definition: structure.h:261
T close(T... args)
T data(T... args)
T emplace_back(T... args)
T emplace(T... args)
T end(T... args)
T find(T... args)
#define RBX_ERROR(fmt,...)
Output a error logging message.
Definition: log.h:102
#define RBX_DEBUG(fmt,...)
Output a debug logging message.
Definition: log.h:126
bool robotStateMsgToRobotState(const Transforms &tf, const moveit_msgs::RobotState &robot_state, RobotState &state, bool copy_attached_bodies=true)
void robotStateToRobotStateMsg(const RobotState &state, moveit_msgs::RobotState &robot_state, bool copy_attached_bodies=true)
Functions for loading and animating robots in Blender.
void deleteFile(const std::string &file)
Deletes a file.
std::string createTempFile(std::ofstream &out)
Creates a temporary file and opens an output stream.
geometry_msgs::Vector3 vectorEigenToMsg(const Eigen::Vector3d &vector)
Converts an Eigen::Vector3d to a vector message.
Definition: tf.cpp:104
Eigen::Vector3d vectorMsgToEigen(const geometry_msgs::Vector3 &msg)
Converts a vector message to an Eigen::Vector3d.
Definition: tf.cpp:94
Eigen::Quaterniond quaternionMsgToEigen(const geometry_msgs::Quaternion &msg)
Converts a quaternion message to Eigen::Quaterniond.
Definition: tf.cpp:135
geometry_msgs::Quaternion quaternionEigenToMsg(const Eigen::Quaterniond &quaternion)
Converts an Eigen::Quaterniond to a quaternion message.
Definition: tf.cpp:140
Eigen::Quaterniond getPoseRotation(const RobotPose &pose)
Get the rotational component of a robot pose.
Definition: tf.cpp:69
std::string getPackageFile(const std::string &uri)
Get the filename for a package URI using Dart's lookup.
bool loadURDF(Robot &robot, const std::string &urdf)
Loads a URDF at urdf into a robot.
DART-based robot modeling and planning.
Definition: acm.h:16
RobotPtr loadMoveItRobot(const std::string &name, const std::string &urdf, const std::string &srdf)
Load a robot from a URDF and SRDF (i.e., a MoveIt enabled robot).
Functions for loading and animating scenes in Blender.
T size(T... args)
T tie(T... args)