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{
72 planner_limits_.printCartesianLimits();
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 // set pilz cartesian limits for each item
151 // create Cartesian path for lin
152 std::unique_ptr<KDL::Path> path(setPathLIN(plan_info.start_pose, plan_info.goal_pose));
153 // create velocity profile
154 std::unique_ptr<KDL::VelocityProfile> vp(
155 cartesianTrapVelocityProfile(req.max_velocity_scaling_factor, req.max_acceleration_scaling_factor, path));
156
157 // combine path and velocity profile into Cartesian trajectory
158 // with the third parameter set to false, KDL::Trajectory_Segment does not
159 // take
160 // the ownship of Path and Velocity Profile
161 KDL::Trajectory_Segment cart_trajectory(path.get(), vp.get(), false);
162
163 moveit_msgs::msg::MoveItErrorCodes error_code;
164 // sample the Cartesian trajectory and compute joint trajectory using inverse
165 // kinematics
166 if (!generateJointTrajectory(scene, planner_limits_.getJointLimitContainer(), cart_trajectory, plan_info.group_name,
167 plan_info.link_name, plan_info.start_joint_position, sampling_time, joint_trajectory,
168 error_code))
169 {
170 std::ostringstream os;
171 os << "Failed to generate valid joint trajectory from the Cartesian path";
172 throw LinTrajectoryConversionFailure(os.str(), error_code.val);
173 }
174}
175
176std::unique_ptr<KDL::Path> TrajectoryGeneratorLIN::setPathLIN(const Eigen::Affine3d& start_pose,
177 const Eigen::Affine3d& goal_pose) const
178{
179 RCLCPP_DEBUG(getLogger(), "Set Cartesian path for LIN command.");
180
181 KDL::Frame kdl_start_pose, kdl_goal_pose;
182 tf2::transformEigenToKDL(start_pose, kdl_start_pose);
183 tf2::transformEigenToKDL(goal_pose, kdl_goal_pose);
184 double eqradius = max_cartesian_speed_ / planner_limits_.getCartesianLimits().max_rot_vel;
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.
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_
TrajectoryGenerator(const moveit::core::RobotModelConstPtr &robot_model, const pilz_industrial_motion_planner::LimitsContainer &planner_limits)
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
void setMaxCartesianSpeed(const moveit_msgs::msg::MotionPlanRequest &req)
Set the max cartesian speed from motion request.
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.