Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00027
00029
00030 #ifndef JOINT_TRAJECTORY_CONTROLLER_INIT_JOINT_TRAJECTORY_H
00031 #define JOINT_TRAJECTORY_CONTROLLER_INIT_JOINT_TRAJECTORY_H
00032
00033
00034 #include <algorithm>
00035 #include <iomanip>
00036 #include <sstream>
00037 #include <stdexcept>
00038 #include <vector>
00039
00040
00041 #include <boost/shared_ptr.hpp>
00042
00043
00044 #include <control_msgs/FollowJointTrajectoryAction.h>
00045 #include <trajectory_msgs/JointTrajectoryPoint.h>
00046
00047
00048 #include <realtime_tools/realtime_server_goal_handle.h>
00049
00050
00051 #include <joint_trajectory_controller/joint_trajectory_msg_utils.h>
00052 #include <joint_trajectory_controller/joint_trajectory_segment.h>
00053
00054 namespace joint_trajectory_controller
00055 {
00056
00057 namespace internal
00058 {
00064 template <class T>
00065 inline std::vector<unsigned int> permutation(const T& t1, const T& t2)
00066 {
00067 typedef unsigned int SizeType;
00068
00069
00070 if (t1.size() != t2.size()) {return std::vector<SizeType>();}
00071
00072 std::vector<SizeType> permutation_vector(t1.size());
00073 for (typename T::const_iterator t1_it = t1.begin(); t1_it != t1.end(); ++t1_it)
00074 {
00075 typename T::const_iterator t2_it = std::find(t2.begin(), t2.end(), *t1_it);
00076 if (t2.end() == t2_it) {return std::vector<SizeType>();}
00077 else
00078 {
00079 const SizeType t1_dist = std::distance(t1.begin(), t1_it);
00080 const SizeType t2_dist = std::distance(t2.begin(), t2_it);
00081 permutation_vector[t1_dist] = t2_dist;
00082 }
00083 }
00084 return permutation_vector;
00085 }
00086
00087 }
00088
00093 template <class Trajectory>
00094 struct InitJointTrajectoryOptions
00095 {
00096 typedef realtime_tools::RealtimeServerGoalHandle<control_msgs::FollowJointTrajectoryAction> RealtimeGoalHandle;
00097 typedef boost::shared_ptr<RealtimeGoalHandle> RealtimeGoalHandlePtr;
00098 typedef typename Trajectory::value_type::Scalar Scalar;
00099
00100 InitJointTrajectoryOptions()
00101 : current_trajectory(0),
00102 joint_names(0),
00103 angle_wraparound(0),
00104 rt_goal_handle(),
00105 default_tolerances(0),
00106 other_time_base(0)
00107 {}
00108
00109 Trajectory* current_trajectory;
00110 std::vector<std::string>* joint_names;
00111 std::vector<bool>* angle_wraparound;
00112 RealtimeGoalHandlePtr rt_goal_handle;
00113 SegmentTolerances<Scalar>* default_tolerances;
00114 ros::Time* other_time_base;
00115 };
00116
00180
00181 template <class Trajectory>
00182 Trajectory initJointTrajectory(const trajectory_msgs::JointTrajectory& msg,
00183 const ros::Time& time,
00184 const InitJointTrajectoryOptions<Trajectory>& options =
00185 InitJointTrajectoryOptions<Trajectory>())
00186 {
00187 typedef typename Trajectory::value_type Segment;
00188 typedef typename Segment::Scalar Scalar;
00189
00190 const unsigned int n_joints = msg.joint_names.size();
00191
00192 const ros::Time msg_start_time = internal::startTime(msg, time);
00193
00194 ROS_DEBUG_STREAM("Figuring out new trajectory starting at time "
00195 << std::fixed << std::setprecision(3) << msg_start_time.toSec());
00196
00197
00198 if (msg.points.empty())
00199 {
00200 ROS_DEBUG("Trajectory message contains empty trajectory. Nothing to convert.");
00201 return Trajectory();
00202 }
00203
00204
00205 if (!isTimeStrictlyIncreasing(msg))
00206 {
00207 ROS_ERROR("Trajectory message contains waypoints that are not strictly increasing in time.");
00208 return Trajectory();
00209 }
00210
00211
00212 const bool has_current_trajectory = options.current_trajectory && !options.current_trajectory->empty();
00213 const bool has_joint_names = options.joint_names && !options.joint_names->empty();
00214 const bool has_angle_wraparound = options.angle_wraparound && !options.angle_wraparound->empty();
00215 const bool has_rt_goal_handle = options.rt_goal_handle;
00216 const bool has_other_time_base = options.other_time_base;
00217 const bool has_default_tolerances = options.default_tolerances;
00218
00219 if (!has_current_trajectory && has_angle_wraparound)
00220 {
00221 ROS_WARN("Vector specifying whether joints wrap around will not be used because no current trajectory was given.");
00222 }
00223
00224
00225
00226 ros::Time o_time;
00227 ros::Time o_msg_start_time;
00228 if (has_other_time_base)
00229 {
00230 ros::Duration msg_start_duration = msg_start_time - time;
00231 o_time = *options.other_time_base;
00232 o_msg_start_time = o_time + msg_start_duration;
00233 ROS_DEBUG_STREAM("Using alternate time base. In it, the new trajectory starts at time "
00234 << std::fixed << std::setprecision(3) << o_msg_start_time.toSec());
00235 }
00236 else
00237 {
00238 o_time = time;
00239 o_msg_start_time = msg_start_time;
00240 }
00241
00242
00243
00244 const std::vector<std::string> joint_names = has_joint_names ? *(options.joint_names) : msg.joint_names;
00245
00246 std::vector<unsigned int> permutation_vector = internal::permutation(joint_names, msg.joint_names);
00247
00248 if (permutation_vector.empty())
00249 {
00250 ROS_ERROR("Cannot create trajectory from message. It does not contain the expected joints.");
00251 return Trajectory();
00252 }
00253
00254
00255 SegmentTolerances<Scalar> tolerances = has_default_tolerances ?
00256 *(options.default_tolerances) : SegmentTolerances<Scalar>(n_joints);
00257
00258 if (has_rt_goal_handle && options.rt_goal_handle->gh_.getGoal())
00259 {
00260 updateSegmentTolerances<Scalar>(*(options.rt_goal_handle->gh_.getGoal()), joint_names, tolerances);
00261 }
00262
00263
00264
00265
00266 std::vector<trajectory_msgs::JointTrajectoryPoint>::const_iterator
00267 it = findPoint(msg, time);
00268 if (it == msg.points.end())
00269 {
00270 it = msg.points.begin();
00271 }
00272 else
00273 {
00274 ++it;
00275 if (it == msg.points.end())
00276 {
00277 ros::Duration last_point_dur = time - (msg_start_time + (--it)->time_from_start);
00278 ROS_WARN_STREAM("Dropping all " << msg.points.size() <<
00279 " trajectory point(s), as they occur before the current time.\n" <<
00280 "Last point is " << std::fixed << std::setprecision(3) << last_point_dur.toSec() <<
00281 "s in the past.");
00282 return Trajectory();
00283 }
00284 else
00285 {
00286 ros::Duration next_point_dur = msg_start_time + it->time_from_start - time;
00287 ROS_WARN_STREAM("Dropping first " << std::distance(msg.points.begin(), it) <<
00288 " trajectory point(s) out of " << msg.points.size() <<
00289 ", as they occur before the current time.\n" <<
00290 "First valid point will be reached in " << std::fixed << std::setprecision(3) <<
00291 next_point_dur.toSec() << "s.");
00292 }
00293 }
00294
00295
00296
00297
00298 Trajectory result_traj;
00299
00300
00301 std::vector<Scalar> position_offset(n_joints, 0.0);
00302
00303
00304 if (has_current_trajectory)
00305 {
00306 const Trajectory& curr_traj = *(options.current_trajectory);
00307
00308
00309 const typename Segment::Time last_curr_time = std::max(o_msg_start_time.toSec(), o_time.toSec());
00310 typename Segment::State last_curr_state;
00311 sample(curr_traj, last_curr_time, last_curr_state);
00312
00313
00314 const typename Segment::Time first_new_time = o_msg_start_time.toSec() + (it->time_from_start).toSec();
00315 typename Segment::State first_new_state(*it, permutation_vector);
00316
00317
00318 if (has_angle_wraparound)
00319 {
00320 position_offset = wraparoundOffset(last_curr_state.position,
00321 first_new_state.position,
00322 *(options.angle_wraparound));
00323 if (position_offset.empty())
00324 {
00325 ROS_ERROR("Cannot create trajectory from message. "
00326 "Vector specifying whether joints wrap around has an invalid size.");
00327 return Trajectory();
00328 }
00329 }
00330
00331
00332 first_new_state = typename Segment::State(*it, permutation_vector, position_offset);
00333
00334
00335 {
00336 typedef typename Trajectory::const_iterator TrajIter;
00337 TrajIter first = findSegment(curr_traj, o_time.toSec());
00338 TrajIter last = findSegment(curr_traj, last_curr_time);
00339 if (first == curr_traj.end() || last == curr_traj.end())
00340 {
00341 ROS_ERROR("Unexpected error: Could not find segments in current trajectory. Please contact the package maintainer.");
00342 return Trajectory();
00343 }
00344 result_traj.insert(result_traj.begin(), first, ++last);
00345 }
00346
00347
00348 Segment bridge_seg(last_curr_time, last_curr_state,
00349 first_new_time, first_new_state);
00350 bridge_seg.setGoalHandle(options.rt_goal_handle);
00351 if (has_rt_goal_handle) {bridge_seg.setTolerances(tolerances);}
00352 result_traj.push_back(bridge_seg);
00353 }
00354
00355
00356 const unsigned int num_old_segments = result_traj.size() -1;
00357 const unsigned int num_new_segments = std::distance(it, msg.points.end()) -1;
00358
00359
00360
00361
00362 while (std::distance(it, msg.points.end()) >= 2)
00363 {
00364 std::vector<trajectory_msgs::JointTrajectoryPoint>::const_iterator next_it = it; ++next_it;
00365 Segment segment(o_msg_start_time, *it, *next_it, permutation_vector, position_offset);
00366 segment.setGoalHandle(options.rt_goal_handle);
00367 if (has_rt_goal_handle) {segment.setTolerances(tolerances);}
00368 result_traj.push_back(segment);
00369 ++it;
00370 }
00371
00372
00373 std::stringstream log_str;
00374 log_str << "Trajectory has " << result_traj.size() << " segments";
00375 if (has_current_trajectory)
00376 {
00377 log_str << ":";
00378 log_str << "\n- " << num_old_segments << " segment(s) will still be executed from previous trajectory.";
00379 log_str << "\n- 1 segment added for transitioning between the current trajectory and first point of the input message.";
00380 if (num_new_segments > 0) {log_str << "\n- " << num_new_segments << " new segments (" << (num_new_segments + 1) <<
00381 " points) taken from the input trajectory.";}
00382 }
00383 else {log_str << ".";}
00384 ROS_DEBUG_STREAM(log_str.str());
00385
00386 return result_traj;
00387 }
00388
00389 }
00390
00391 #endif // header guard