trajectory_generator_ptp.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Pilz GmbH & Co. KG
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13 
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
19 #include "ros/ros.h"
22 
23 #include <iostream>
24 #include <sstream>
25 
26 namespace pilz {
27 
28 TrajectoryGeneratorPTP::TrajectoryGeneratorPTP(const robot_model::RobotModelConstPtr& robot_model,
29  const LimitsContainer &planner_limits)
30  :TrajectoryGenerator::TrajectoryGenerator(robot_model, planner_limits)
31 {
32 
34  {
35  throw TrajectoryGeneratorInvalidLimitsException("joint limit not set");
36  }
37 
39 
40  // collect most strict joint limits for each group in robot model
41  for(const auto& jmg : robot_model->getJointModelGroups())
42  {
43  pilz_extensions::JointLimit most_strict_limit = joint_limits_.getCommonLimit(jmg->getActiveJointModelNames());
44 
45  if(!most_strict_limit.has_velocity_limits)
46  {
47  ROS_ERROR_STREAM("velocity limit not set for group " << jmg->getName());
48  throw TrajectoryGeneratorInvalidLimitsException("velocity limit not set for group " + jmg->getName());
49  }
50  if(!most_strict_limit.has_acceleration_limits)
51  {
52  ROS_ERROR_STREAM("acceleration limit not set for group " << jmg->getName());
53  throw TrajectoryGeneratorInvalidLimitsException("acceleration limit not set for group " + jmg->getName());
54  }
55  if(!most_strict_limit.has_deceleration_limits)
56  {
57  ROS_ERROR_STREAM("deceleration limit not set for group " << jmg->getName());
58  throw TrajectoryGeneratorInvalidLimitsException("deceleration limit not set for group " + jmg->getName());
59  }
60 
61  most_strict_limits_.insert(std::pair<std::string, pilz_extensions::JointLimit>(jmg->getName(), most_strict_limit));
62  }
63 
64  ROS_INFO("Initialized Point-to-Point Trajectory Generator.");
65 }
66 
67 void TrajectoryGeneratorPTP::planPTP(const std::map<std::string, double>& start_pos,
68  const std::map<std::string, double>& goal_pos,
69  trajectory_msgs::JointTrajectory &joint_trajectory,
70  const std::string &group_name,
71  const double &velocity_scaling_factor,
72  const double &acceleration_scaling_factor,
73  const double &sampling_time)
74 {
75  // initialize joint names
76  for(const auto& item : goal_pos)
77  {
78  joint_trajectory.joint_names.push_back(item.first);
79  }
80 
81  // check if goal already reached
82  bool goal_reached = true;
83  for(auto const& goal: goal_pos)
84  {
85  if(fabs(start_pos.at(goal.first) - goal.second) >= MIN_MOVEMENT )
86  {
87  goal_reached = false;
88  break;
89  }
90  }
91  if(goal_reached)
92  {
93  ROS_INFO_STREAM("Goal already reached, set one goal point explicitly.");
94  if(joint_trajectory.points.empty())
95  {
96  trajectory_msgs::JointTrajectoryPoint point;
97  point.time_from_start = ros::Duration(sampling_time);
98  for(const std::string & joint_name : joint_trajectory.joint_names)
99  {
100  point.positions.push_back(start_pos.at(joint_name));
101  point.velocities.push_back(0);
102  point.accelerations.push_back(0);
103  }
104  joint_trajectory.points.push_back(point);
105  }
106  return;
107  }
108 
109  // compute the fastest trajectory and choose the slowest joint as leading axis
110  std::string leading_axis = joint_trajectory.joint_names.front();
111  double max_duration = -1.0;
112 
113  std::map<std::string, VelocityProfile_ATrap> velocity_profile;
114  for(const auto& joint_name : joint_trajectory.joint_names)
115  {
116  // create vecocity profile if necessary
117  velocity_profile.insert(std::make_pair(
118  joint_name,
120  velocity_scaling_factor * most_strict_limits_.at(group_name).max_velocity,
121  acceleration_scaling_factor * most_strict_limits_.at(group_name).max_acceleration,
122  acceleration_scaling_factor * most_strict_limits_.at(group_name).max_deceleration)));
123 
124  velocity_profile.at(joint_name).SetProfile(start_pos.at(joint_name), goal_pos.at(joint_name));
125  if(velocity_profile.at(joint_name).Duration() > max_duration)
126  {
127  max_duration = velocity_profile.at(joint_name).Duration();
128  leading_axis = joint_name;
129  }
130  }
131 
132  // Full Synchronization
133  // This should only work if all axes have same max_vel, max_acc, max_dec values
134  // reset the velocity profile for other joints
135  double acc_time = velocity_profile.at(leading_axis).FirstPhaseDuration();
136  double const_time = velocity_profile.at(leading_axis).SecondPhaseDuration();
137  double dec_time = velocity_profile.at(leading_axis).ThirdPhaseDuration();
138 
139  for(const auto& joint_name : joint_trajectory.joint_names)
140  {
141  if(joint_name != leading_axis)
142  {
143  // make full synchronization
144  // causes the program to terminate if acc_time<=0 or dec_time<=0 (should be prevented by goal_reached block above)
145  // by using the most strict limit, the following should always return true
146  if (!velocity_profile.at(joint_name).setProfileAllDurations(start_pos.at(joint_name), goal_pos.at(joint_name),
147  acc_time,const_time,dec_time))
148  // LCOV_EXCL_START
149  {
150  std::stringstream error_str;
151  error_str << "TrajectoryGeneratorPTP::planPTP(): Can not synchronize velocity profile of axis " << joint_name
152  << " with leading axis " << leading_axis;
153  throw PtpVelocityProfileSyncFailed(error_str.str());
154  }
155  // LCOV_EXCL_STOP
156  }
157  }
158 
159  // first generate the time samples
160  std::vector<double> time_samples;
161  for(double t_sample=0.0; t_sample<max_duration; t_sample+=sampling_time)
162  {
163  time_samples.push_back(t_sample);
164  }
165  // add last time
166  time_samples.push_back(max_duration);
167 
168  // construct joint trajectory point
169  for(double time_stamp : time_samples)
170  {
171  trajectory_msgs::JointTrajectoryPoint point;
172  point.time_from_start = ros::Duration(time_stamp);
173  for(std::string & joint_name : joint_trajectory.joint_names)
174  {
175  point.positions.push_back(velocity_profile.at(joint_name).Pos(time_stamp));
176  point.velocities.push_back(velocity_profile.at(joint_name).Vel(time_stamp));
177  point.accelerations.push_back(velocity_profile.at(joint_name).Acc(time_stamp));
178  }
179  joint_trajectory.points.push_back(point);
180  }
181 
182  // Set last point velocity and acceleration to zero
183  std::fill(joint_trajectory.points.back().velocities.begin(),
184  joint_trajectory.points.back().velocities.end(),
185  0.0);
186  std::fill(joint_trajectory.points.back().accelerations.begin(),
187  joint_trajectory.points.back().accelerations.end(),
188  0.0);
189 }
190 
191 
193  MotionPlanInfo& info) const
194 {
195  info.group_name = req.group_name;
196 
197  // extract start state information
198  info.start_joint_position.clear();
199  for(std::size_t i=0; i<req.start_state.joint_state.name.size(); ++i)
200  {
201  info.start_joint_position[req.start_state.joint_state.name[i]] = req.start_state.joint_state.position[i];
202  }
203 
204  // extract goal
205  info.goal_joint_position.clear();
206  if(!req.goal_constraints.at(0).joint_constraints.empty())
207  {
208  for(const auto& joint_constraint : req.goal_constraints.at(0).joint_constraints)
209  {
210  info.goal_joint_position[joint_constraint.joint_name] = joint_constraint.position;
211  }
212  }
213  // slove the ik
214  else
215  {
216  geometry_msgs::Point p = req.goal_constraints.at(0).position_constraints.at(0).
217  constraint_region.primitive_poses.at(0).position;
218  p.x -= req.goal_constraints.at(0).position_constraints.at(0).target_point_offset.x;
219  p.y -= req.goal_constraints.at(0).position_constraints.at(0).target_point_offset.y;
220  p.z -= req.goal_constraints.at(0).position_constraints.at(0).target_point_offset.z;
221 
222  geometry_msgs::Pose pose;
223  pose.position = p;
224  pose.orientation = req.goal_constraints.at(0).orientation_constraints.at(0).orientation;
225  Eigen::Affine3d pose_eigen;
226  normalizeQuaternion(pose.orientation);
227  tf::poseMsgToEigen(pose,pose_eigen);
229  req.group_name,
230  req.goal_constraints.at(0).position_constraints.at(0).link_name,
231  pose_eigen,
232  robot_model_->getModelFrame(),
234  info.goal_joint_position))
235  {
236  throw PtpNoIkSolutionForGoalPose("No IK solution for goal pose");
237  }
238  }
239 }
240 
242  const MotionPlanInfo& plan_info,
243  const double& sampling_time,
244  trajectory_msgs::JointTrajectory& joint_trajectory)
245 {
246  // plan the ptp trajectory
247  planPTP(plan_info.start_joint_position, plan_info.goal_joint_position, joint_trajectory, plan_info.group_name,
248  req.max_velocity_scaling_factor, req.max_acceleration_scaling_factor, sampling_time);
249 }
250 
251 } // namespace pilz
std::map< std::string, double > start_joint_position
std::map< std::string, double > goal_joint_position
Base class of trajectory generators.
bool computePoseIK(const robot_model::RobotModelConstPtr &robot_model, const std::string &group_name, const std::string &link_name, const Eigen::Affine3d &pose, const std::string &frame_id, const std::map< std::string, double > &seed, std::map< std::string, double > &solution, bool check_self_collision=true, int max_attempt=10, const double timeout=0.1)
compute the inverse kinematics of a given pose, also check robot self collision
std::map< std::string, pilz_extensions::JointLimit > most_strict_limits_
virtual void plan(const planning_interface::MotionPlanRequest &req, const MotionPlanInfo &plan_info, const double &sampling_time, trajectory_msgs::JointTrajectory &joint_trajectory) override
void poseMsgToEigen(const geometry_msgs::Pose &m, Eigen::Affine3d &e)
void planPTP(const std::map< std::string, double > &start_pos, const std::map< std::string, double > &goal_pos, trajectory_msgs::JointTrajectory &joint_trajectory, const std::string &group_name, const double &velocity_scaling_factor, const double &acceleration_scaling_factor, const double &sampling_time)
plan ptp joint trajectory with zero start velocity
TrajectoryGeneratorPTP(const robot_model::RobotModelConstPtr &robot_model, const pilz::LimitsContainer &planner_limits)
Constructor of PTP Trajectory Generator.
pilz::JointLimitsContainer joint_limits_
const robot_model::RobotModelConstPtr robot_model_
const pilz::LimitsContainer planner_limits_
#define ROS_INFO(...)
const JointLimitsContainer & getJointLimitContainer() const
Obtain the Joint Limits from the container.
This class combines CartesianLimit and JointLimits into on single class.
virtual void extractMotionPlanInfo(const planning_interface::MotionPlanRequest &req, MotionPlanInfo &info) const override
Extract needed information from a motion plan request in order to simplify further usages...
pilz_extensions::JointLimit getCommonLimit() const
Returns joint limit fusion of all(position, velocity, acceleration, deceleration) limits for all join...
moveit_msgs::MotionPlanRequest MotionPlanRequest
#define ROS_INFO_STREAM(args)
This class is used to extract needed information from motion plan request.
#define ROS_ERROR_STREAM(args)
void normalizeQuaternion(geometry_msgs::Quaternion &quat)
A PTP Trajectory Generator of Asymmetric Trapezoidal Velocity Profile. Differences to VelocityProfile...
bool hasJointLimits() const
Return if this LimitsContainer has defined joint limits.


pilz_trajectory_generation
Author(s):
autogenerated on Mon Apr 6 2020 03:17:33