moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
srv_kinematics_plugin.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2014, JSK, The University of Tokyo.
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 JSK, The University of Tokyo 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: Dave Coleman, Masaki Murooka */
36
37#include <moveit_msgs/srv/get_position_ik.hpp>
39#include <class_loader/class_loader.hpp>
41#include <iterator>
43
44// Eigen
45#include <Eigen/Core>
46#include <Eigen/Geometry>
47
48// register SRVKinematics as a KinematicsBase implementation
50
52{
53namespace
54{
55rclcpp::Logger getLogger()
56{
57 return moveit::getLogger("moveit.kinematics.srv_kinematics_plugin");
58}
59} // namespace
60
64
65bool SrvKinematicsPlugin::initialize(const rclcpp::Node::SharedPtr& node, const moveit::core::RobotModel& robot_model,
66 const std::string& group_name, const std::string& base_frame,
67 const std::vector<std::string>& tip_frames, double search_discretization)
68{
69 node_ = node;
70 bool debug = false;
71
72 RCLCPP_INFO(getLogger(), "SrvKinematicsPlugin initializing");
73
74 // Get Solver Parameters
75 std::string kinematics_param_prefix = "robot_description_kinematics." + group_name;
76 param_listener_ = std::make_shared<srv_kinematics::ParamListener>(node, kinematics_param_prefix);
77 params_ = param_listener_->get_params();
78
79 storeValues(robot_model, group_name, base_frame, tip_frames, search_discretization);
80 joint_model_group_ = robot_model_->getJointModelGroup(group_name);
81 if (!joint_model_group_)
82 return false;
83
84 if (debug)
85 {
86 std::cout << "Joint Model Variable Names: ------------------------------------------- \n ";
87 const std::vector<std::string> jm_names = joint_model_group_->getVariableNames();
88 std::copy(jm_names.begin(), jm_names.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
89 std::cout << '\n';
90 }
91
92 // Get the dimension of the planning group
93 dimension_ = joint_model_group_->getVariableCount();
94 RCLCPP_INFO_STREAM(getLogger(), "Dimension planning group '"
95 << group_name << "': " << dimension_
96 << ". Active Joints Models: " << joint_model_group_->getActiveJointModels().size()
97 << ". Mimic Joint Models: " << joint_model_group_->getMimicJointModels().size());
98
99 // Copy joint names
100 for (std::size_t i = 0; i < joint_model_group_->getJointModels().size(); ++i)
101 {
102 ik_group_info_.joint_names.push_back(joint_model_group_->getJointModelNames()[i]);
103 }
104
105 if (debug)
106 {
107 RCLCPP_ERROR(getLogger(), "tip links available:");
108 std::copy(tip_frames_.begin(), tip_frames_.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
109 }
110
111 // Make sure all the tip links are in the link_names vector
112 for (const std::string& tip_frame : tip_frames_)
113 {
114 if (!joint_model_group_->hasLinkModel(tip_frame))
115 {
116 RCLCPP_ERROR(getLogger(), "Could not find tip name '%s' in joint group '%s'", tip_frame.c_str(),
117 group_name.c_str());
118 return false;
119 }
120 ik_group_info_.link_names.push_back(tip_frame);
121 }
122
123 // Setup the joint state groups that we need
124 robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
125 robot_state_->setToDefaultValues();
126
127 // Create the ROS2 service client
128 RCLCPP_DEBUG(getLogger(), "IK Service client topic : %s", params_.kinematics_solver_service_name.c_str());
129 ik_service_client_ = node_->create_client<moveit_msgs::srv::GetPositionIK>(params_.kinematics_solver_service_name);
130
131 if (!ik_service_client_->wait_for_service(std::chrono::seconds(1)))
132 { // wait 0.1 seconds, blocking
133 RCLCPP_WARN_STREAM(getLogger(),
134 "Unable to connect to ROS service client with name: " << ik_service_client_->get_service_name());
135 }
136 else
137 {
138 RCLCPP_INFO_STREAM(getLogger(),
139 "Service client started with ROS service name: " << ik_service_client_->get_service_name());
140 }
141
142 active_ = true;
143 RCLCPP_DEBUG(getLogger(), "ROS service-based kinematics solver initialized");
144 return true;
145}
146
147bool SrvKinematicsPlugin::setRedundantJoints(const std::vector<unsigned int>& redundant_joints)
148{
149 if (num_possible_redundant_joints_ < 0)
150 {
151 RCLCPP_ERROR(getLogger(), "This group cannot have redundant joints");
152 return false;
153 }
154 if (int(redundant_joints.size()) > num_possible_redundant_joints_)
155 {
156 RCLCPP_ERROR(getLogger(), "This group can only have %d redundant joints", num_possible_redundant_joints_);
157 return false;
158 }
159
160 return true;
161}
162
163bool SrvKinematicsPlugin::isRedundantJoint(unsigned int index) const
164{
165 for (unsigned int redundant_joint_indice : redundant_joint_indices_)
166 {
167 if (redundant_joint_indice == index)
168 return true;
169 }
170 return false;
171}
172
173int SrvKinematicsPlugin::getJointIndex(const std::string& name) const
174{
175 for (unsigned int i = 0; i < ik_group_info_.joint_names.size(); ++i)
176 {
177 if (ik_group_info_.joint_names[i] == name)
178 return i;
179 }
180 return -1;
181}
182
183bool SrvKinematicsPlugin::timedOut(const rclcpp::Time& start_time, double duration) const
184{
185 return ((node_->now() - start_time).seconds() >= duration);
186}
187
188bool SrvKinematicsPlugin::getPositionIK(const geometry_msgs::msg::Pose& ik_pose,
189 const std::vector<double>& ik_seed_state, std::vector<double>& solution,
190 moveit_msgs::msg::MoveItErrorCodes& error_code,
191 const kinematics::KinematicsQueryOptions& options) const
192{
193 std::vector<double> consistency_limits;
194
195 return searchPositionIK(ik_pose, ik_seed_state, default_timeout_, consistency_limits, solution, IKCallbackFn(),
196 error_code, options);
197}
198
199bool SrvKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
200 const std::vector<double>& ik_seed_state, double timeout,
201 std::vector<double>& solution,
202 moveit_msgs::msg::MoveItErrorCodes& error_code,
203 const kinematics::KinematicsQueryOptions& options) const
204{
205 std::vector<double> consistency_limits;
206
207 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, IKCallbackFn(), error_code,
208 options);
209}
210
211bool SrvKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
212 const std::vector<double>& ik_seed_state, double timeout,
213 const std::vector<double>& consistency_limits, std::vector<double>& solution,
214 moveit_msgs::msg::MoveItErrorCodes& error_code,
215 const kinematics::KinematicsQueryOptions& options) const
216{
217 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, IKCallbackFn(), error_code,
218 options);
219}
220
221bool SrvKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
222 const std::vector<double>& ik_seed_state, double timeout,
223 std::vector<double>& solution, const IKCallbackFn& solution_callback,
224 moveit_msgs::msg::MoveItErrorCodes& error_code,
225 const kinematics::KinematicsQueryOptions& options) const
226{
227 std::vector<double> consistency_limits;
228 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, solution_callback, error_code,
229 options);
230}
231
232bool SrvKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
233 const std::vector<double>& ik_seed_state, double timeout,
234 const std::vector<double>& consistency_limits, std::vector<double>& solution,
235 const IKCallbackFn& solution_callback,
236 moveit_msgs::msg::MoveItErrorCodes& error_code,
237 const kinematics::KinematicsQueryOptions& options) const
238{
239 // Convert single pose into a vector of one pose
240 std::vector<geometry_msgs::msg::Pose> ik_poses;
241 ik_poses.push_back(ik_pose);
242
243 return searchPositionIK(ik_poses, ik_seed_state, timeout, consistency_limits, solution, solution_callback, error_code,
244 options);
245}
246
247bool SrvKinematicsPlugin::searchPositionIK(const std::vector<geometry_msgs::msg::Pose>& ik_poses,
248 const std::vector<double>& ik_seed_state, double /*timeout*/,
249 const std::vector<double>& /*consistency_limits*/,
250 std::vector<double>& solution, const IKCallbackFn& solution_callback,
251 moveit_msgs::msg::MoveItErrorCodes& error_code,
252 const kinematics::KinematicsQueryOptions& /*options*/,
253 const moveit::core::RobotState* /*context_state*/) const
254{
255 // Check if active
256 if (!active_)
257 {
258 RCLCPP_ERROR(getLogger(), "kinematics not active");
259 error_code.val = error_code.NO_IK_SOLUTION;
260 return false;
261 }
262
263 // Check if seed state correct
264 if (ik_seed_state.size() != dimension_)
265 {
266 RCLCPP_ERROR_STREAM(getLogger(),
267 "Seed state must have size " << dimension_ << " instead of size " << ik_seed_state.size());
268 error_code.val = error_code.NO_IK_SOLUTION;
269 return false;
270 }
271
272 // Check that we have the same number of poses as tips
273 if (tip_frames_.size() != ik_poses.size())
274 {
275 RCLCPP_ERROR_STREAM(getLogger(), "Mismatched number of pose requests (" << ik_poses.size() << ") to tip frames ("
276 << tip_frames_.size()
277 << ") in searchPositionIK");
278 error_code.val = error_code.NO_IK_SOLUTION;
279 return false;
280 }
281
282 // Create the service message
283 auto ik_srv = std::make_shared<moveit_msgs::srv::GetPositionIK::Request>();
284 ik_srv->ik_request.avoid_collisions = true;
285 ik_srv->ik_request.group_name = getGroupName();
286
287 // Copy seed state into virtual robot state and convert into moveit_msg
288 robot_state_->setJointGroupPositions(joint_model_group_, ik_seed_state);
289 moveit::core::robotStateToRobotStateMsg(*robot_state_, ik_srv->ik_request.robot_state);
290
291 // Load the poses into the request in difference places depending if there is more than one or not
292 geometry_msgs::msg::PoseStamped ik_pose_st;
293 ik_pose_st.header.frame_id = base_frame_;
294 if (tip_frames_.size() > 1)
295 {
296 // Load into vector of poses
297 for (std::size_t i = 0; i < tip_frames_.size(); ++i)
298 {
299 ik_pose_st.pose = ik_poses[i];
300 ik_srv->ik_request.pose_stamped_vector.push_back(ik_pose_st);
301 ik_srv->ik_request.ik_link_names.push_back(tip_frames_[i]);
302 }
303 }
304 else
305 {
306 ik_pose_st.pose = ik_poses[0];
307
308 // Load into single pose value
309 ik_srv->ik_request.pose_stamped = ik_pose_st;
310 ik_srv->ik_request.ik_link_name = getTipFrames()[0];
311 }
312
313 RCLCPP_DEBUG(getLogger(), "Calling service: %s", ik_service_client_->get_service_name());
314 auto result_future = ik_service_client_->async_send_request(ik_srv);
315 const auto& response = result_future.get();
316 if (rclcpp::spin_until_future_complete(node_, result_future) == rclcpp::FutureReturnCode::SUCCESS)
317 {
318 // Check error code
319 error_code.val = response->error_code.val;
320 if (error_code.val != error_code.SUCCESS)
321 {
322 // TODO (JafarAbdi) Print the entire message for ROS2?
323 // RCLCPP_DEBUG("srv", "An IK that satisfies the constraints and is collision free could not be found."
324 // << "\nRequest was: \n"
325 // << ik_srv.request.ik_request << "\nResponse was: \n"
326 // << ik_srv.response.solution);
327 switch (error_code.val)
328 {
329 case moveit_msgs::msg::MoveItErrorCodes::FAILURE:
330 RCLCPP_ERROR(getLogger(), "Service failed with with error code: FAILURE");
331 break;
332 case moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION:
333 RCLCPP_DEBUG(getLogger(), "Service failed with with error code: NO IK SOLUTION");
334 break;
335 default:
336 RCLCPP_DEBUG_STREAM(getLogger(), "Service failed with with error code: " << error_code.val);
337 }
338 return false;
339 }
340 }
341 else
342 {
343 RCLCPP_DEBUG_STREAM(getLogger(),
344 "Service call failed to connect to service: " << ik_service_client_->get_service_name());
345 error_code.val = error_code.FAILURE;
346 return false;
347 }
348 // Convert the robot state message to our robot_state representation
349 if (!moveit::core::robotStateMsgToRobotState(response->solution, *robot_state_))
350 {
351 RCLCPP_ERROR(getLogger(), "An error occurred converting received robot state message into internal robot state.");
352 error_code.val = error_code.FAILURE;
353 return false;
354 }
355
356 // Get just the joints we are concerned about in our planning group
357 robot_state_->copyJointGroupPositions(joint_model_group_, solution);
358
359 // Run the solution callback (i.e. collision checker) if available
360 if (solution_callback)
361 {
362 RCLCPP_DEBUG(getLogger(), "Calling solution callback on IK solution");
363
364 // hack: should use all poses, not just the 0th
365 solution_callback(ik_poses[0], solution, error_code);
366
367 if (error_code.val != error_code.SUCCESS)
368 {
369 switch (error_code.val)
370 {
371 case moveit_msgs::msg::MoveItErrorCodes::FAILURE:
372 RCLCPP_ERROR(getLogger(), "IK solution callback failed with with error code: FAILURE");
373 break;
374 case moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION:
375 RCLCPP_ERROR(getLogger(), "IK solution callback failed with with error code: "
376 "NO IK SOLUTION");
377 break;
378 default:
379 RCLCPP_ERROR_STREAM(getLogger(), "IK solution callback failed with with error code: " << error_code.val);
380 }
381 return false;
382 }
383 }
384
385 RCLCPP_INFO(getLogger(), "IK Solver Succeeded!");
386 return true;
387}
388
389bool SrvKinematicsPlugin::getPositionFK(const std::vector<std::string>& link_names,
390 const std::vector<double>& joint_angles,
391 std::vector<geometry_msgs::msg::Pose>& poses) const
392{
393 if (!active_)
394 {
395 RCLCPP_ERROR(getLogger(), "kinematics not active");
396 return false;
397 }
398 poses.resize(link_names.size());
399 if (joint_angles.size() != dimension_)
400 {
401 RCLCPP_ERROR(getLogger(), "Joint angles vector must have size: %d", dimension_);
402 return false;
403 }
404
405 RCLCPP_ERROR(getLogger(), "Forward kinematics not implemented");
406
407 return false;
408}
409
410const std::vector<std::string>& SrvKinematicsPlugin::getJointNames() const
411{
412 return ik_group_info_.joint_names;
413}
414
415const std::vector<std::string>& SrvKinematicsPlugin::getLinkNames() const
416{
417 return ik_group_info_.link_names;
418}
419
420const std::vector<std::string>& SrvKinematicsPlugin::getVariableNames() const
421{
422 return joint_model_group_->getVariableNames();
423}
424
425} // namespace srv_kinematics_plugin
Provides an interface for kinematics solvers.
void storeValues(const moveit::core::RobotModel &robot_model, const std::string &group_name, const std::string &base_frame, const std::vector< std::string > &tip_frames, double search_discretization)
std::vector< unsigned int > redundant_joint_indices_
virtual const std::string & getGroupName() const
Return the name of the group that the solver is operating on.
std::vector< std::string > tip_frames_
std::function< void(const geometry_msgs::msg::Pose &, const std::vector< double > &, moveit_msgs::msg::MoveItErrorCodes &)> IKCallbackFn
Signature for a callback to validate an IK solution. Typically used for collision checking.
virtual const std::vector< std::string > & getTipFrames() const
Return the names of the tip frames of the kinematic tree on which the solver is operating....
moveit::core::RobotModelConstPtr robot_model_
const std::vector< const JointModel * > & getMimicJointModels() const
Get the mimic joints that are part of this group.
const std::vector< std::string > & getJointModelNames() const
Get the names of the joints in this group. These are the names of the joints returned by getJointMode...
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...
const std::vector< const JointModel * > & getActiveJointModels() const
Get the active joints in this group (that have controllable DOF). This does not include mimic joints.
bool hasLinkModel(const std::string &link) const
Check if a link is part of this group.
unsigned int getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
const std::vector< const JointModel * > & getJointModels() const
Get all the joints in this group (including fixed and mimic joints).
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
Definition robot_model.h:76
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition robot_state.h:90
Specific implementation of kinematics using ROS service calls to communicate with external IK solvers...
bool setRedundantJoints(const std::vector< unsigned int > &redundant_joint_indices) override
Set a set of redundant joints for the kinematics solver to use. This can fail, depending on the IK so...
const std::vector< std::string > & getJointNames() const override
Return all the joint names in the order they are used internally.
bool searchPositionIK(const geometry_msgs::msg::Pose &ik_pose, const std::vector< double > &ik_seed_state, double timeout, std::vector< double > &solution, moveit_msgs::msg::MoveItErrorCodes &error_code, const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions()) const override
Given a desired pose of the end-effector, search for the joint angles required to reach it....
bool getPositionIK(const geometry_msgs::msg::Pose &ik_pose, const std::vector< double > &ik_seed_state, std::vector< double > &solution, moveit_msgs::msg::MoveItErrorCodes &error_code, const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions()) const override
Given a desired pose of the end-effector, compute the joint angles to reach it.
const std::vector< std::string > & getVariableNames() const
Return all the variable names in the order they are represented internally.
const std::vector< std::string > & getLinkNames() const override
Return all the link names in the order they are represented internally.
bool getPositionFK(const std::vector< std::string > &link_names, const std::vector< double > &joint_angles, std::vector< geometry_msgs::msg::Pose > &poses) const override
Given a set of joint angles and a set of links, compute their pose.
bool initialize(const rclcpp::Node::SharedPtr &node, const moveit::core::RobotModel &robot_model, const std::string &group_name, const std::string &base_name, const std::vector< std::string > &tip_frames, double search_discretization) override
Initialization function for the kinematics, for use with kinematic chain IK solvers.
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 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.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:79
CLASS_LOADER_REGISTER_CLASS(default_planning_request_adapters::ResolveConstraintFrames, planning_interface::PlanningRequestAdapter)
A set of options for the kinematics solver.