joint.cpp
Go to the documentation of this file.
1 
29 #include <stdexcept>
30 
31 #include <boost/algorithm/string.hpp>
32 #include <Eigen/Geometry>
33 #include <tesseract_common/utils.h>
34 #include <tinyxml2.h>
36 
40 #include <tesseract_urdf/joint.h>
41 #include <tesseract_urdf/limits.h>
42 #include <tesseract_urdf/mimic.h>
43 #include <tesseract_urdf/origin.h>
45 
46 namespace tesseract_urdf
47 {
48 tesseract_scene_graph::Joint::Ptr parseJoint(const tinyxml2::XMLElement* xml_element)
49 {
50  // get joint name
51  std::string joint_name;
52  if (tesseract_common::QueryStringAttribute(xml_element, "name", joint_name) != tinyxml2::XML_SUCCESS)
53  std::throw_with_nested(std::runtime_error("Joint: Missing or failed parsing attribute 'name'!"));
54 
55  // create joint
56  auto j = std::make_shared<tesseract_scene_graph::Joint>(joint_name);
57 
58  // get joint origin
59  const tinyxml2::XMLElement* origin = xml_element->FirstChildElement("origin");
60  if (origin != nullptr)
61  {
62  try
63  {
64  j->parent_to_joint_origin_transform = parseOrigin(origin);
65  }
66  catch (...)
67  {
68  std::throw_with_nested(
69  std::runtime_error("Joint: Error parsing 'origin' element for joint '" + joint_name + "'!"));
70  }
71  }
72 
73  // get parent link
74  const tinyxml2::XMLElement* parent = xml_element->FirstChildElement("parent");
75  if (parent == nullptr)
76  std::throw_with_nested(std::runtime_error("Joint: Missing element 'parent' for joint '" + joint_name + "'!"));
77 
78  if (tesseract_common::QueryStringAttribute(parent, "link", j->parent_link_name) != tinyxml2::XML_SUCCESS)
79  std::throw_with_nested(
80  std::runtime_error("Joint: Failed parsing element 'parent' attribute 'link' for joint '" + joint_name + "'!"));
81 
82  // get child link
83  const tinyxml2::XMLElement* child = xml_element->FirstChildElement("child");
84  if (child == nullptr)
85  std::throw_with_nested(std::runtime_error("Joint: Missing element 'child' for joint '" + joint_name + "'!"));
86 
87  if (tesseract_common::QueryStringAttribute(child, "link", j->child_link_name) != tinyxml2::XML_SUCCESS)
88  std::throw_with_nested(
89  std::runtime_error("Joint: Failed parsing element 'child' attribute 'link' for joint '" + joint_name + "'!"));
90 
91  // get joint type
92  std::string joint_type;
93  if (tesseract_common::QueryStringAttribute(xml_element, "type", joint_type) != tinyxml2::XML_SUCCESS)
94  std::throw_with_nested(std::runtime_error("Joint: Missing element 'type' for joint '" + joint_name + "'!"));
95 
96  if (joint_type == "planar")
98  else if (joint_type == "floating")
100  else if (joint_type == "revolute")
102  else if (joint_type == "continuous")
104  else if (joint_type == "prismatic")
106  else if (joint_type == "fixed")
108  else
109  std::throw_with_nested(
110  std::runtime_error("Joint: Invalid joint type '" + joint_type + "' for joint '" + joint_name + "'!"));
111 
112  // get joint axis
114  {
115  const tinyxml2::XMLElement* axis = xml_element->FirstChildElement("axis");
116  if (axis == nullptr)
117  {
118  j->axis = Eigen::Vector3d(1.0, 0.0, 0.0);
119  }
120  else
121  {
122  std::string axis_str;
123  if (tesseract_common::QueryStringAttribute(axis, "xyz", axis_str) != tinyxml2::XML_SUCCESS)
124  std::throw_with_nested(
125  std::runtime_error("Joint: Failed parsing element 'axis' attribute 'xyz' for joint '" + joint_name + "'!"));
126 
127  std::vector<std::string> tokens;
128  boost::split(tokens, axis_str, boost::is_any_of(" "), boost::token_compress_on);
129  if (tokens.size() != 3 || !tesseract_common::isNumeric(tokens))
130  std::throw_with_nested(std::runtime_error("Joint: Failed parsing element 'axis' attribute 'xyz' string for "
131  "joint '" +
132  joint_name + "'!"));
133 
134  double ax{ 0 }, ay{ 0 }, az{ 0 };
135  // No need to check return values because the tokens are verified above
139 
140  j->axis = Eigen::Vector3d(ax, ay, az);
141  }
142  }
143 
144  // get joint limits
147  {
148  const tinyxml2::XMLElement* limits = xml_element->FirstChildElement("limit");
149  if (limits == nullptr && j->type != tesseract_scene_graph::JointType::CONTINUOUS)
150  std::throw_with_nested(std::runtime_error("Joint: Missing element 'limits' for joint '" + joint_name + "'!"));
151 
152  if (limits == nullptr && j->type == tesseract_scene_graph::JointType::CONTINUOUS)
153  {
154  j->limits = std::make_shared<tesseract_scene_graph::JointLimits>();
155  }
156  else
157  {
158  try
159  {
160  j->limits = parseLimits(limits);
161  }
162  catch (...)
163  {
164  std::throw_with_nested(
165  std::runtime_error("Joint: Failed parsing element 'limits' for joint '" + joint_name + "'!"));
166  }
167  }
168  }
169 
170  // get joint safety if exists
171  const tinyxml2::XMLElement* safety = xml_element->FirstChildElement("safety_controller");
172  if (safety != nullptr)
173  {
174  try
175  {
176  j->safety = parseSafetyController(safety);
177  }
178  catch (...)
179  {
180  std::throw_with_nested(
181  std::runtime_error("Joint: Failed parsing element 'safety_controller' for joint '" + joint_name + "'!"));
182  }
183  }
184 
185  // get joint calibration if exists
186  const tinyxml2::XMLElement* calibration = xml_element->FirstChildElement("calibration");
187  if (calibration != nullptr)
188  {
189  try
190  {
191  j->calibration = parseCalibration(calibration);
192  }
193  catch (...)
194  {
195  std::throw_with_nested(
196  std::runtime_error("Joint: Failed parsing element 'calibration' for joint '" + joint_name + "'!"));
197  }
198  }
199 
200  // get mimic joint if exists
201  const tinyxml2::XMLElement* mimic = xml_element->FirstChildElement("mimic");
202  if (mimic != nullptr)
203  {
204  try
205  {
206  j->mimic = parseMimic(mimic);
207  }
208  catch (...)
209  {
210  std::throw_with_nested(
211  std::runtime_error("Joint: Failed parsing element 'mimic' for joint '" + joint_name + "'!"));
212  }
213  }
214 
215  // get dynamics if exists
216  const tinyxml2::XMLElement* dynamics = xml_element->FirstChildElement("dynamics");
217  if (dynamics != nullptr)
218  {
219  try
220  {
221  j->dynamics = parseDynamics(dynamics);
222  }
223  catch (...)
224  {
225  std::throw_with_nested(
226  std::runtime_error("Joint: Failed parsing element 'dynamics' for joint '" + joint_name + "'!"));
227  }
228  }
229 
230  return j;
231 }
232 
233 tinyxml2::XMLElement* writeJoint(const std::shared_ptr<const tesseract_scene_graph::Joint>& joint,
234  tinyxml2::XMLDocument& doc)
235 {
236  if (joint == nullptr)
237  std::throw_with_nested(std::runtime_error("Joint is nullptr and cannot be converted to XML"));
238  tinyxml2::XMLElement* xml_element = doc.NewElement(JOINT_ELEMENT_NAME.data());
239 
240  // Set the joint name
241  xml_element->SetAttribute("name", joint->getName().c_str());
242 
243  // Set joint origin
244  if (!joint->parent_to_joint_origin_transform.matrix().isIdentity(std::numeric_limits<double>::epsilon()))
245  {
246  tinyxml2::XMLElement* xml_origin = writeOrigin(joint->parent_to_joint_origin_transform, doc);
247  xml_element->InsertEndChild(xml_origin);
248  }
249 
250  // Set parent link
251  tinyxml2::XMLElement* xml_parent = doc.NewElement("parent");
252  xml_parent->SetAttribute("link", joint->parent_link_name.c_str());
253  xml_element->InsertEndChild(xml_parent);
254 
255  // Set child link
256  tinyxml2::XMLElement* xml_child = doc.NewElement("child");
257  xml_child->SetAttribute("link", joint->child_link_name.c_str());
258  xml_element->InsertEndChild(xml_child);
259 
260  // Set joint type
261  if (joint->type == tesseract_scene_graph::JointType::PLANAR)
262  xml_element->SetAttribute("type", "planar");
263  else if (joint->type == tesseract_scene_graph::JointType::FLOATING)
264  xml_element->SetAttribute("type", "floating");
265  else if (joint->type == tesseract_scene_graph::JointType::REVOLUTE)
266  xml_element->SetAttribute("type", "revolute");
267  else if (joint->type == tesseract_scene_graph::JointType::CONTINUOUS)
268  xml_element->SetAttribute("type", "continuous");
269  else if (joint->type == tesseract_scene_graph::JointType::PRISMATIC)
270  xml_element->SetAttribute("type", "prismatic");
271  else if (joint->type == tesseract_scene_graph::JointType::FIXED)
272  xml_element->SetAttribute("type", "fixed");
273  else
274  std::throw_with_nested(std::runtime_error("Joint: Invalid joint type for joint '" + joint->getName() + "'!"));
275 
276  // Set joint axis
277  if (joint->type != tesseract_scene_graph::JointType::FLOATING &&
279  {
280  tinyxml2::XMLElement* xml_axis = doc.NewElement("axis");
281  Eigen::IOFormat eigen_format(Eigen::StreamPrecision, Eigen::DontAlignCols, " ", " ");
282  std::stringstream axis_str;
283  axis_str << joint->axis.format(eigen_format);
284  xml_axis->SetAttribute("xyz", axis_str.str().c_str());
285  xml_element->InsertEndChild(xml_axis);
286  }
287 
288  // Set joint limits
289  // For Revolute or Prismatic, we need nonzero upper or lower
290  if (joint->type == tesseract_scene_graph::JointType::REVOLUTE ||
292  {
293  if (joint->limits == nullptr)
294  std::throw_with_nested(std::runtime_error("Joint: Missing limits for joint '" + joint->getName() + "'!"));
295  if (tesseract_common::almostEqualRelativeAndAbs(joint->limits->lower, 0.0) &&
296  tesseract_common::almostEqualRelativeAndAbs(joint->limits->upper, 0.0))
297  std::throw_with_nested(std::runtime_error("Upper/Lower limits for `" + joint->getName() + "` are both zero!"));
298 
299  tinyxml2::XMLElement* xml_limits = writeLimits(joint->limits, doc);
300  xml_element->InsertEndChild(xml_limits);
301  }
302  // For continuous, we just need something. If e/v/a are all zero, don't bother writing.
304  {
305  if (joint->limits != nullptr && (!tesseract_common::almostEqualRelativeAndAbs(joint->limits->effort, 0.0) ||
306  !tesseract_common::almostEqualRelativeAndAbs(joint->limits->velocity, 0.0) ||
307  !tesseract_common::almostEqualRelativeAndAbs(joint->limits->acceleration, 0.0) ||
308  !tesseract_common::almostEqualRelativeAndAbs(joint->limits->jerk, 0.0)))
309  {
310  tinyxml2::XMLElement* xml_limits = writeLimits(joint->limits, doc);
311  xml_element->InsertEndChild(xml_limits);
312  }
313  }
314 
315  // Set joint safety if it exists
316  if (joint->safety != nullptr)
317  {
318  tinyxml2::XMLElement* xml_safety = writeSafetyController(joint->safety, doc);
319  xml_element->InsertEndChild(xml_safety);
320  }
321 
322  // Set joint calibration if it exists
323  if (joint->calibration != nullptr)
324  {
325  tinyxml2::XMLElement* xml_calibration = writeCalibration(joint->calibration, doc);
326  xml_element->InsertEndChild(xml_calibration);
327  }
328 
329  // Set mimic joint it it exists
330  if (joint->mimic != nullptr)
331  {
332  tinyxml2::XMLElement* xml_mimic = writeMimic(joint->mimic, doc);
333  xml_element->InsertEndChild(xml_mimic);
334  }
335 
336  // Set dynamics if exists
337  if (joint->dynamics != nullptr)
338  {
339  tinyxml2::XMLElement* xml_dynamics = writeDynamics(joint->dynamics, doc);
340  xml_element->InsertEndChild(xml_dynamics);
341  }
342 
343  return xml_element;
344 }
345 
346 } // namespace tesseract_urdf
tesseract_scene_graph::JointType::REVOLUTE
@ REVOLUTE
tesseract_urdf::JOINT_ELEMENT_NAME
static constexpr std::string_view JOINT_ELEMENT_NAME
Definition: joint.h:45
tesseract_scene_graph::JointType::FLOATING
@ FLOATING
utils.h
tesseract_urdf::parseSafetyController
std::shared_ptr< tesseract_scene_graph::JointSafety > parseSafetyController(const tinyxml2::XMLElement *xml_element)
Parse xml element safety_controller.
Definition: safety_controller.cpp:41
tesseract_urdf::writeLimits
tinyxml2::XMLElement * writeLimits(const std::shared_ptr< const tesseract_scene_graph::JointLimits > &limits, tinyxml2::XMLDocument &doc)
Definition: limits.cpp:74
safety_controller.h
Parse safety_controller from xml string.
tesseract_common::almostEqualRelativeAndAbs
bool almostEqualRelativeAndAbs(const Eigen::Ref< const Eigen::VectorXd > &v1, const Eigen::Ref< const Eigen::VectorXd > &v2, const Eigen::Ref< const Eigen::VectorXd > &max_diff, const Eigen::Ref< const Eigen::VectorXd > &max_rel_diff)
joint.h
tesseract_urdf::parseOrigin
Eigen::Isometry3d parseOrigin(const tinyxml2::XMLElement *xml_element)
Parse xml element origin.
Definition: origin.cpp:42
origin.h
Parse origin from xml string.
TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#define TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
dynamics.h
Parse dynamics from xml string.
tesseract_urdf::parseDynamics
std::shared_ptr< tesseract_scene_graph::JointDynamics > parseDynamics(const tinyxml2::XMLElement *xml_element)
Parse a xml dynamics element.
Definition: dynamics.cpp:41
joint.h
Parse joint from xml string.
tesseract_scene_graph::JointType::PLANAR
@ PLANAR
limits.h
Parse limits from xml string.
tesseract_urdf::writeSafetyController
tinyxml2::XMLElement * writeSafetyController(const std::shared_ptr< const tesseract_scene_graph::JointSafety > &safety, tinyxml2::XMLDocument &doc)
Definition: safety_controller.cpp:76
tesseract_urdf::parseCalibration
std::shared_ptr< tesseract_scene_graph::JointCalibration > parseCalibration(const tinyxml2::XMLElement *xml_element)
Parse a xml calibration element.
Definition: calibration.cpp:41
tesseract_scene_graph::JointType::PRISMATIC
@ PRISMATIC
tesseract_urdf::parseMimic
std::shared_ptr< tesseract_scene_graph::JointMimic > parseMimic(const tinyxml2::XMLElement *xml_element)
Parse xml element mimic.
Definition: mimic.cpp:42
tesseract_urdf::parseLimits
std::shared_ptr< tesseract_scene_graph::JointLimits > parseLimits(const tinyxml2::XMLElement *xml_element)
Parse xml element limits.
Definition: limits.cpp:41
tesseract_common::QueryStringAttribute
int QueryStringAttribute(const tinyxml2::XMLElement *xml_element, const char *name, std::string &value)
TESSERACT_COMMON_IGNORE_WARNINGS_POP
tesseract_urdf::parseJoint
std::shared_ptr< tesseract_scene_graph::Joint > parseJoint(const tinyxml2::XMLElement *xml_element)
Parse xml element joint.
Definition: joint.cpp:48
tesseract_scene_graph::JointType::CONTINUOUS
@ CONTINUOUS
tesseract_urdf::writeDynamics
tinyxml2::XMLElement * writeDynamics(const std::shared_ptr< const tesseract_scene_graph::JointDynamics > &dynamics, tinyxml2::XMLDocument &doc)
Definition: dynamics.cpp:66
tesseract_urdf::writeOrigin
tinyxml2::XMLElement * writeOrigin(const Eigen::Isometry3d &origin, tinyxml2::XMLDocument &doc)
Definition: origin.cpp:129
tesseract_common::isNumeric
bool isNumeric(const std::string &s)
tesseract_scene_graph::Joint::Ptr
std::shared_ptr< Joint > Ptr
tesseract_common::toNumeric< double >
template bool toNumeric< double >(const std::string &, double &)
tesseract_urdf::writeMimic
tinyxml2::XMLElement * writeMimic(const std::shared_ptr< const tesseract_scene_graph::JointMimic > &mimic, tinyxml2::XMLDocument &doc)
Definition: mimic.cpp:66
tesseract_urdf::writeJoint
tinyxml2::XMLElement * writeJoint(const std::shared_ptr< const tesseract_scene_graph::Joint > &joint, tinyxml2::XMLDocument &doc)
Definition: joint.cpp:233
macros.h
tesseract_urdf
Definition: box.h:43
calibration.h
Parse calibration from xml string.
tesseract_urdf::writeCalibration
tinyxml2::XMLElement * writeCalibration(const std::shared_ptr< const tesseract_scene_graph::JointCalibration > &calibration, tinyxml2::XMLDocument &doc)
Definition: calibration.cpp:66
mimic.h
Parse mimic from xml string.
tesseract_scene_graph::JointType::FIXED
@ FIXED


tesseract_urdf
Author(s): Levi Armstrong
autogenerated on Thu Apr 24 2025 03:10:44