moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
trajectory_generator_lin.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2018 Pilz GmbH & Co. KG
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 Pilz GmbH & Co. KG 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
36
38
39#include <cassert>
40#include <sstream>
41#include <time.h>
43#include <kdl/path_line.hpp>
44#include <kdl/trajectory_segment.hpp>
45#include <kdl/utilities/error.h>
46// TODO: Remove conditional include when released to all active distros.
47#if __has_include(<tf2/convert.hpp>)
48#include <tf2/convert.hpp>
49#else
50#include <tf2/convert.h>
51#endif
52#include <rclcpp/logger.hpp>
53#include <rclcpp/logging.hpp>
54#include <tf2_eigen/tf2_eigen.hpp>
55#include <tf2_eigen_kdl/tf2_eigen_kdl.hpp>
56#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
58
60{
61namespace
62{
63rclcpp::Logger getLogger()
64{
65 return moveit::getLogger("moveit.planners.pilz.trajectory_generator.lin");
66}
67} // namespace
68TrajectoryGeneratorLIN::TrajectoryGeneratorLIN(const moveit::core::RobotModelConstPtr& robot_model,
69 const LimitsContainer& planner_limits, const std::string& /*group_name*/)
70 : TrajectoryGenerator::TrajectoryGenerator(robot_model, planner_limits)
71{
73}
74
75void TrajectoryGeneratorLIN::extractMotionPlanInfo(const planning_scene::PlanningSceneConstPtr& scene,
78{
79 RCLCPP_DEBUG(getLogger(), "Extract necessary information from motion plan request.");
80
81 info.group_name = req.group_name;
82 moveit::core::RobotState robot_state = scene->getCurrentState();
83
84 // goal given in joint space
85 if (!req.goal_constraints.front().joint_constraints.empty())
86 {
87 info.link_name = getSolverTipFrame(robot_model_->getJointModelGroup(req.group_name));
88
89 if (req.goal_constraints.front().joint_constraints.size() !=
90 robot_model_->getJointModelGroup(req.group_name)->getActiveJointModelNames().size())
91 {
92 std::ostringstream os;
93 os << "Number of joints in goal does not match number of joints of group "
94 "(Number joints goal: "
95 << req.goal_constraints.front().joint_constraints.size() << " | Number of joints of group: "
96 << robot_model_->getJointModelGroup(req.group_name)->getActiveJointModelNames().size() << ')';
97 throw JointNumberMismatch(os.str());
98 }
99
100 for (const auto& joint_item : req.goal_constraints.front().joint_constraints)
101 {
102 info.goal_joint_position[joint_item.joint_name] = joint_item.position;
103 }
104
105 computeLinkFK(robot_state, info.link_name, info.goal_joint_position, info.goal_pose);
106 }
107 // goal given in Cartesian space
108 else
109 {
110 std::string frame_id;
111
112 info.link_name = req.goal_constraints.front().position_constraints.front().link_name;
113 if (req.goal_constraints.front().position_constraints.front().header.frame_id.empty() ||
114 req.goal_constraints.front().orientation_constraints.front().header.frame_id.empty())
115 {
116 RCLCPP_WARN(getLogger(), "Frame id is not set in position/orientation constraints of "
117 "goal. Use model frame as default");
118 frame_id = robot_model_->getModelFrame();
119 }
120 else
121 {
122 frame_id = req.goal_constraints.front().position_constraints.front().header.frame_id;
123 }
124
125 // goal pose with optional offset wrt. the planning frame
126 info.goal_pose = scene->getFrameTransform(frame_id) * getConstraintPose(req.goal_constraints.front());
127 frame_id = robot_model_->getModelFrame();
128
129 // check goal pose ik before Cartesian motion plan starts
130 std::map<std::string, double> ik_solution;
131 if (!computePoseIK(scene, info.group_name, info.link_name, info.goal_pose, frame_id, info.start_joint_position,
132 ik_solution))
133 {
134 std::ostringstream os;
135 os << "Failed to compute inverse kinematics for link: " << info.link_name << " of goal pose";
136 throw LinInverseForGoalIncalculable(os.str());
137 }
138 }
139
140 // Ignored return value because at this point the function should always
141 // return 'true'.
142 computeLinkFK(robot_state, info.link_name, info.start_joint_position, info.start_pose);
143}
144
145void TrajectoryGeneratorLIN::plan(const planning_scene::PlanningSceneConstPtr& scene,
146 const planning_interface::MotionPlanRequest& req, const MotionPlanInfo& plan_info,
147 double sampling_time, trajectory_msgs::msg::JointTrajectory& joint_trajectory)
148{
149 // create Cartesian path for lin
150 std::unique_ptr<KDL::Path> path(setPathLIN(plan_info.start_pose, plan_info.goal_pose));
151
152 // create velocity profile
153 std::unique_ptr<KDL::VelocityProfile> vp(
154 cartesianTrapVelocityProfile(req.max_velocity_scaling_factor, req.max_acceleration_scaling_factor, path));
155
156 // combine path and velocity profile into Cartesian trajectory
157 // with the third parameter set to false, KDL::Trajectory_Segment does not
158 // take
159 // the ownship of Path and Velocity Profile
160 KDL::Trajectory_Segment cart_trajectory(path.get(), vp.get(), false);
161
162 moveit_msgs::msg::MoveItErrorCodes error_code;
163 // sample the Cartesian trajectory and compute joint trajectory using inverse
164 // kinematics
165 if (!generateJointTrajectory(scene, planner_limits_.getJointLimitContainer(), cart_trajectory, plan_info.group_name,
166 plan_info.link_name, plan_info.start_joint_position, sampling_time, joint_trajectory,
167 error_code))
168 {
169 std::ostringstream os;
170 os << "Failed to generate valid joint trajectory from the Cartesian path";
171 throw LinTrajectoryConversionFailure(os.str(), error_code.val);
172 }
173}
174
175std::unique_ptr<KDL::Path> TrajectoryGeneratorLIN::setPathLIN(const Eigen::Affine3d& start_pose,
176 const Eigen::Affine3d& goal_pose) const
177{
178 RCLCPP_DEBUG(getLogger(), "Set Cartesian path for LIN command.");
179
180 KDL::Frame kdl_start_pose, kdl_goal_pose;
181 tf2::transformEigenToKDL(start_pose, kdl_start_pose);
182 tf2::transformEigenToKDL(goal_pose, kdl_goal_pose);
183 double eqradius =
185 KDL::RotationalInterpolation* rot_interpo = new KDL::RotationalInterpolation_SingleAxis();
186
187 return std::unique_ptr<KDL::Path>(
188 std::make_unique<KDL::Path_Line>(kdl_start_pose, kdl_goal_pose, rot_interpo, eqradius, true));
189}
190
191} // namespace pilz_industrial_motion_planner
Representation of a robot's state. This includes position, velocity, acceleration and effort.
This class combines CartesianLimit and JointLimits into on single class.
void printCartesianLimits() const
Prints the cartesian limits set by user. Default values for limits are 0.0.
const cartesian_limits::Params & getCartesianLimits() const
Return the cartesian limits.
const JointLimitsContainer & getJointLimitContainer() const
Obtain the Joint Limits from the container.
TrajectoryGeneratorLIN(const moveit::core::RobotModelConstPtr &robot_model, const pilz_industrial_motion_planner::LimitsContainer &planner_limits, const std::string &group_name)
Constructor of LIN Trajectory Generator.
This class is used to extract needed information from motion plan request.
const moveit::core::RobotModelConstPtr robot_model_
const pilz_industrial_motion_planner::LimitsContainer planner_limits_
std::unique_ptr< KDL::VelocityProfile > cartesianTrapVelocityProfile(double max_velocity_scaling_factor, double max_acceleration_scaling_factor, const std::unique_ptr< KDL::Path > &path) const
build cartesian velocity profile for the path
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:79
bool computeLinkFK(moveit::core::RobotState &robot_state, const std::string &link_name, const std::map< std::string, double > &joint_state, Eigen::Isometry3d &pose)
compute the pose of a link at a given robot state
bool generateJointTrajectory(const planning_scene::PlanningSceneConstPtr &scene, const JointLimitsContainer &joint_limits, const KDL::Trajectory &trajectory, const std::string &group_name, const std::string &link_name, const std::map< std::string, double > &initial_joint_position, double sampling_time, trajectory_msgs::msg::JointTrajectory &joint_trajectory, moveit_msgs::msg::MoveItErrorCodes &error_code, bool check_self_collision=false)
Generate joint trajectory from a KDL Cartesian trajectory.
bool computePoseIK(const planning_scene::PlanningSceneConstPtr &scene, const std::string &group_name, const std::string &link_name, const Eigen::Isometry3d &pose, const std::string &frame_id, const std::map< std::string, double > &seed, std::map< std::string, double > &solution, bool check_self_collision=true, const double timeout=0.0)
compute the inverse kinematics of a given pose, also check robot self collision
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest
Eigen::Isometry3d getConstraintPose(const geometry_msgs::msg::Point &position, const geometry_msgs::msg::Quaternion &orientation, const geometry_msgs::msg::Vector3 &offset)
Adapt goal pose, defined by position+orientation, to consider offset.