29 #include <boost/serialization/access.hpp>
30 #include <boost/serialization/array.hpp>
31 #include <boost/serialization/shared_ptr.hpp>
32 #include <boost/serialization/nvp.hpp>
33 #include <unordered_map>
36 #include <console_bridge/console.h>
39 #include <boost/algorithm/string/classification.hpp>
40 #include <boost/algorithm/string/split.hpp>
41 #include <yaml-cpp/yaml.h>
63 const std::string& filename,
68 std::string xml_string;
69 std::fstream xml_file(filename.c_str(), std::fstream::in);
70 if (xml_file.is_open() && resource)
72 while (xml_file.good())
75 std::getline(xml_file, line);
76 xml_string += (line +
"\n");
81 initString(scene_graph, xml_string, *resource);
85 std::throw_with_nested(std::runtime_error(
"SRDF: Failed to parse file '" + filename +
"'!"));
90 std::throw_with_nested(std::runtime_error(
"SRDF: Failed to open file '" + filename +
"'!"));
95 const std::string& xmlstring,
98 tinyxml2::XMLDocument xml_doc;
99 int status = xml_doc.Parse(xmlstring.c_str());
100 if (status != tinyxml2::XML_SUCCESS)
101 std::throw_with_nested(std::runtime_error(
"SRDF: Failed to create XMLDocument from xml string!"));
105 const tinyxml2::XMLElement* srdf_xml = xml_doc.FirstChildElement(
"robot");
106 if (srdf_xml ==
nullptr)
107 std::throw_with_nested(std::runtime_error(
"SRDF: Missing 'robot' element in the xml file!"));
109 if (srdf_xml ==
nullptr || std::strncmp(srdf_xml->Name(),
"robot", 5) != 0)
110 std::throw_with_nested(std::runtime_error(
"SRDF: Missing 'robot' element in the xml file!"));
114 if (status != tinyxml2::XML_SUCCESS)
115 std::throw_with_nested(std::runtime_error(
"SRDF: Missing or failed to parse attribute 'name'!"));
118 CONSOLE_BRIDGE_logError(
"Semantic description is not specified for the same robot as the URDF");
120 std::string version_string;
122 if (status != tinyxml2::XML_NO_ATTRIBUTE && status != tinyxml2::XML_SUCCESS)
124 std::throw_with_nested(std::runtime_error(
"SRDF: Failed to parse attribute 'version'!"));
126 else if (status != tinyxml2::XML_NO_ATTRIBUTE)
128 std::vector<std::string> tokens;
129 boost::split(tokens, version_string, boost::is_any_of(
"."), boost::token_compress_on);
131 std::throw_with_nested(std::runtime_error(
"SRDF: Failed to parse attribute 'version'!"));
135 if (tokens.size() == 3)
142 CONSOLE_BRIDGE_logDebug(
"SRDF Parser: The version number warning can be suppressed by adding the attribute: "
149 std::tuple<GroupNames, ChainGroups, JointGroups, LinkGroups> groups_info;
156 std::throw_with_nested(std::runtime_error(
"SRDF: Error parsing srdf groups for robot '" +
name +
"'!"));
171 std::throw_with_nested(std::runtime_error(
"SRDF: Error parsing srdf groups states for robot '" +
name +
"'!"));
180 std::throw_with_nested(
181 std::runtime_error(
"SRDF: Error parsing srdf groups tool center points for robot '" +
name +
"'!"));
186 for (
const tinyxml2::XMLElement* xml_element = srdf_xml->FirstChildElement(
"kinematics_plugin_config");
187 xml_element !=
nullptr;
188 xml_element = xml_element->NextSiblingElement(
"kinematics_plugin_config"))
196 std::throw_with_nested(
197 std::runtime_error(
"SRDF: Error parsing srdf kinematics plugin config for robot '" +
name +
"'!"));
202 for (
const tinyxml2::XMLElement* xml_element = srdf_xml->FirstChildElement(
"calibration_config");
203 xml_element !=
nullptr;
204 xml_element = xml_element->NextSiblingElement(
"calibration_config"))
212 std::throw_with_nested(std::runtime_error(
"SRDF: Error parsing srdf calibration config for robot '" +
name +
"'!"));
221 std::throw_with_nested(
222 std::runtime_error(
"SRDF: Error parsing srdf disabled collisions for robot '" +
name +
"'!"));
231 std::throw_with_nested(
232 std::runtime_error(
"SRDF: Error parsing srdf collision margin data for robot '" +
name +
"'!"));
237 for (
const tinyxml2::XMLElement* xml_element = srdf_xml->FirstChildElement(
"contact_managers_plugin_config");
238 xml_element !=
nullptr;
239 xml_element = xml_element->NextSiblingElement(
"contact_managers_plugin_config"))
248 std::throw_with_nested(
249 std::runtime_error(
"SRDF: Error parsing srdf contact managers plugin config for robot '" +
name +
"'!"));
255 tinyxml2::XMLDocument doc;
256 tinyxml2::XMLElement* xml_root = doc.NewElement(
"robot");
257 xml_root->SetAttribute(
"name",
name.c_str());
258 xml_root->SetAttribute(
260 (std::to_string(
version[0]) +
"." + std::to_string(
version[1]) +
"." + std::to_string(
version[2])).c_str());
264 tinyxml2::XMLElement* xml_group = doc.NewElement(
"group");
265 xml_group->SetAttribute(
"name", chain.first.c_str());
266 for (
const auto& pair : chain.second)
268 tinyxml2::XMLElement* xml_pair = doc.NewElement(
"chain");
269 xml_pair->SetAttribute(
"base_link", pair.first.c_str());
270 xml_pair->SetAttribute(
"tip_link", pair.second.c_str());
271 xml_group->InsertEndChild(xml_pair);
273 xml_root->InsertEndChild(xml_group);
278 tinyxml2::XMLElement* xml_group = doc.NewElement(
"group");
279 xml_group->SetAttribute(
"name", joint.first.c_str());
280 for (
const auto& joint_name : joint.second)
282 tinyxml2::XMLElement* xml_joint = doc.NewElement(
"joint");
283 xml_joint->SetAttribute(
"name", joint_name.c_str());
284 xml_group->InsertEndChild(xml_joint);
286 xml_root->InsertEndChild(xml_group);
291 tinyxml2::XMLElement* xml_group = doc.NewElement(
"group");
292 xml_group->SetAttribute(
"name", link.first.c_str());
293 for (
const auto& link_name : link.second)
295 tinyxml2::XMLElement* xml_link = doc.NewElement(
"link");
296 xml_link->SetAttribute(
"name", link_name.c_str());
297 xml_group->InsertEndChild(xml_link);
299 xml_root->InsertEndChild(xml_group);
304 for (
const auto& joint_state : group_state.second)
306 tinyxml2::XMLElement* xml_group_state = doc.NewElement(
"group_state");
307 xml_group_state->SetAttribute(
"name", joint_state.first.c_str());
308 xml_group_state->SetAttribute(
"group", group_state.first.c_str());
310 for (
const auto& joint : joint_state.second)
312 tinyxml2::XMLElement* xml_joint = doc.NewElement(
"joint");
313 xml_joint->SetAttribute(
"name", joint.first.c_str());
314 xml_joint->SetAttribute(
"value", joint.second);
315 xml_group_state->InsertEndChild(xml_joint);
317 xml_root->InsertEndChild(xml_group_state);
321 Eigen::IOFormat eigen_format(Eigen::StreamPrecision, Eigen::DontAlignCols,
" ",
" ");
324 tinyxml2::XMLElement* xml_group_tcps = doc.NewElement(
"group_tcps");
325 xml_group_tcps->SetAttribute(
"group", group_tcp.first.c_str());
327 for (
const auto& tcp : group_tcp.second)
329 tinyxml2::XMLElement* xml_tcp = doc.NewElement(
"tcp");
330 xml_tcp->SetAttribute(
"name", tcp.first.c_str());
332 std::stringstream xyz_string;
333 xyz_string << tcp.second.translation().format(eigen_format);
334 xml_tcp->SetAttribute(
"xyz", xyz_string.str().c_str());
336 std::stringstream wxyz_string;
337 Eigen::Quaterniond q(tcp.second.linear());
338 wxyz_string << Eigen::Vector4d(q.w(), q.x(), q.y(), q.z()).format(eigen_format);
340 xml_tcp->SetAttribute(
"wxyz", wxyz_string.str().c_str());
341 xml_group_tcps->InsertEndChild(xml_tcp);
343 xml_root->InsertEndChild(xml_group_tcps);
348 std::filesystem::path p(file_path);
349 std::ofstream fout(p.parent_path().append(
"kinematics_plugin_config.yaml").string());
353 tinyxml2::XMLElement* xml_kin_plugin_entry = doc.NewElement(
"kinematics_plugin_config");
354 xml_kin_plugin_entry->SetAttribute(
"filename",
"kinematics_plugin_config.yaml");
355 xml_root->InsertEndChild(xml_kin_plugin_entry);
360 std::filesystem::path p(file_path);
361 std::ofstream fout(p.parent_path().append(
"contact_managers_plugin_config.yaml").string());
365 tinyxml2::XMLElement* xml_kin_plugin_entry = doc.NewElement(
"contact_managers_plugin_config");
366 xml_kin_plugin_entry->SetAttribute(
"filename",
"contact_managers_plugin_config.yaml");
367 xml_root->InsertEndChild(xml_kin_plugin_entry);
372 std::filesystem::path p(file_path);
373 std::ofstream fout(p.parent_path().append(
"calibration_config.yaml").string());
377 tinyxml2::XMLElement* xml_cal_info_entry = doc.NewElement(
"calibration_config");
378 xml_cal_info_entry->SetAttribute(
"filename",
"calibration_config.yaml");
379 xml_root->InsertEndChild(xml_cal_info_entry);
385 for (
const auto& key : acm_keys)
387 tinyxml2::XMLElement* xml_acm_entry = doc.NewElement(
"disable_collisions");
388 xml_acm_entry->SetAttribute(
"link1", key.get().first.c_str());
389 xml_acm_entry->SetAttribute(
"link2", key.get().second.c_str());
390 xml_acm_entry->SetAttribute(
"reason", allowed_collision_entries.at(key.get()).c_str());
391 xml_root->InsertEndChild(xml_acm_entry);
396 tinyxml2::XMLElement* xml_cm_entry = doc.NewElement(
"collision_margins");
400 tinyxml2::XMLElement* xml_cm_pair_entry = doc.NewElement(
"pair_margin");
401 xml_cm_pair_entry->SetAttribute(
"link1", entry.first.first.c_str());
402 xml_cm_pair_entry->SetAttribute(
"link2", entry.first.second.c_str());
403 xml_cm_pair_entry->SetAttribute(
"margin", entry.second);
404 xml_cm_entry->InsertEndChild(xml_cm_pair_entry);
406 xml_root->InsertEndChild(xml_cm_entry);
410 doc.InsertFirstChild(xml_root);
411 int status = doc.SaveFile(file_path.c_str());
412 if (status != tinyxml2::XML_SUCCESS)
415 CONSOLE_BRIDGE_logError(
"Failed to save SRDF XML File: %s", file_path.c_str());
437 equal &= tesseract_common::isIdenticalArray<int, 3>(
version, rhs.
version);
448 template <
class Archive>
451 ar& BOOST_SERIALIZATION_NVP(
name);
452 ar& BOOST_SERIALIZATION_NVP(
version);
455 ar& BOOST_SERIALIZATION_NVP(
acm);