moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
get_group_urdf_capability.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2024, PickNik Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of PickNik Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Sebastian Jahr */
36
38
42#include <urdf_parser/urdf_parser.h>
43
44namespace move_group
45{
46
47namespace
48{
49rclcpp::Logger getLogger()
50{
51 return moveit::getLogger("moveit.ros.move_group.get_urdf_service");
52}
53const auto JOINT_ELEMENT_CLOSING = std::string("</joint>");
54const auto LINK_ELEMENT_CLOSING = std::string("</link>");
55const auto ROBOT_ELEMENT_CLOSING = std::string("</robot>");
56const auto GENERAL_ELEMENT_CLOSING = std::string("/>");
57} // namespace
58
62
64{
65 get_urdf_service_ = context_->moveit_cpp_->getNode()->create_service<moveit_msgs::srv::GetGroupUrdf>(
66 GET_URDF_SERVICE_NAME,
67 [this](const std::shared_ptr<moveit_msgs::srv::GetGroupUrdf::Request>& req,
68 const std::shared_ptr<moveit_msgs::srv::GetGroupUrdf::Response>& res) {
69 res->error_code.source = std::string("GetUrdfService");
70 const auto subgroup = context_->moveit_cpp_->getRobotModel()->getJointModelGroup(req->group_name);
71 // Check if group exists in loaded robot model
72 if (!subgroup)
73 {
74 const auto error_string = std::string("Cannot create URDF because planning group '") + req->group_name +
75 std::string("' does not exist");
76 RCLCPP_ERROR(getLogger(), "%s", error_string.c_str());
77 res->error_code.message = error_string;
78 res->error_code.val = moveit_msgs::msg::MoveItErrorCodes::FAILURE;
79 return;
80 }
81
82 std::string full_urdf_string =
83 context_->moveit_cpp_->getPlanningSceneMonitor()->getRobotModelLoader()->getRDFLoader()->getURDFString();
84
85 // Check if robot description string is empty
86 if (full_urdf_string.empty())
87 {
88 const auto error_string = std::string("Couldn't get the robot description string from MoveItCpp");
89 RCLCPP_ERROR(getLogger(), "%s", error_string.c_str());
90 res->error_code.message = error_string;
91 res->error_code.val = moveit_msgs::msg::MoveItErrorCodes::FAILURE;
92 return;
93 }
94
95 // Create subgroup urdf
96 // Create header
97 res->urdf_string = std::string("<?xml version=\"1.0\" ?><robot name=\"") + req->group_name +
98 std::string("\" xmlns:xacro=\"http://ros.org/wiki/xacro\">");
99
100 // Create links
101 auto link_names = subgroup->getLinkModelNames();
102 // Remove duplicates
103 std::sort(link_names.begin(), link_names.end());
104 link_names.erase(std::unique(link_names.begin(), link_names.end()), link_names.end());
105
106 for (const auto& link_name : link_names)
107 {
108 const auto start = full_urdf_string.find("<link name=\"" + link_name + "\"");
109 auto substring = full_urdf_string.substr(start, full_urdf_string.size() - start);
110
111 // Link elements can be closed either by "/>" or "</link>" so we need to consider both cases
112 auto const substring_without_opening = substring.substr(1, substring.size() - 2);
113 auto const general_opening_pos_a = substring_without_opening.find('<');
114 auto const link_closing_pos_b = substring.find(GENERAL_ELEMENT_CLOSING);
115 // Case "/>"
116 if (link_closing_pos_b < general_opening_pos_a)
117 {
118 res->urdf_string += substring.substr(0, link_closing_pos_b + GENERAL_ELEMENT_CLOSING.size());
119 }
120 // Case </link>
121 else
122 {
123 res->urdf_string += substring.substr(0, substring.find(LINK_ELEMENT_CLOSING) + LINK_ELEMENT_CLOSING.size());
124 }
125 }
126
127 // Create joints
128 auto joint_names = subgroup->getJointModelNames();
129 // Remove duplicates
130 std::sort(joint_names.begin(), joint_names.end());
131 joint_names.erase(std::unique(joint_names.begin(), joint_names.end()), joint_names.end());
132 for (const auto& joint_name : joint_names)
133 {
134 const auto start = full_urdf_string.find("<joint name=\"" + joint_name + "\" type");
135 auto substring = full_urdf_string.substr(start, full_urdf_string.size() - start);
136 res->urdf_string += substring.substr(0, substring.find(JOINT_ELEMENT_CLOSING) + JOINT_ELEMENT_CLOSING.size());
137
138 // If parent link model is not part of the joint group, add it
139 const auto parent_link_element = subgroup->getJointModel(joint_name)->getParentLinkModel()->getName();
140 if (std::find(link_names.begin(), link_names.end(), parent_link_element) == link_names.end())
141 {
142 auto const base_link_element = "<link name=\"" + parent_link_element + "\"/>";
143 res->urdf_string += base_link_element;
144 link_names.push_back(parent_link_element);
145 }
146 }
147
148 // Add closing
149 res->urdf_string += ROBOT_ELEMENT_CLOSING;
150
151 // Validate urdf file
152 if (!urdf::parseURDF(res->urdf_string))
153 {
154 const std::string error_string = std::string("Failed to create valid urdf");
155 RCLCPP_ERROR(getLogger(), "%s", error_string.c_str());
156 res->error_code.message = error_string;
157 res->error_code.val = moveit_msgs::msg::MoveItErrorCodes::FAILURE;
158 return;
159 }
160 res->error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
161 } // End of callback function
162 );
163}
164} // namespace move_group
165
166#include <pluginlib/class_list_macros.hpp>
167
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
Move group capability to create an URDF string for a joint model group.
void initialize() override
Initializes service when plugin is loaded.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:79