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
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <set>
00042 #include <angles/angles.h>
00043 #include <pr2_base_trajectory_action/pr2_base_trajectory_action_controller.h>
00044 #include <geometry_msgs/Twist.h>
00045
00046 namespace pr2_base_trajectory_action {
00047
00048 Controller::Controller()
00049 : nh_(""), pnh_("~")
00050 {
00051 pnh_.param("update_frequency", frequency_, 40.0);
00052 pnh_.param("stopped_velocity_tolerance", stopped_velocity_tolerance_, 0.01);
00053 pnh_.param("goal_threshold", goal_threshold_, 0.01);
00054 pnh_.param("goal_time_constraint", goal_time_constraint_, 0.0);
00055
00056 pnh_.param<std::string>("linear_x_joint_name", joints_.x.name, "base_link_x");
00057 pnh_.param<std::string>("linear_y_joint_name", joints_.y.name, "base_link_y");
00058 pnh_.param<std::string>("rotational_z_joint_name", joints_.yaw.name, "base_link_pan");
00059 pnh_.param(joints_.x.name + "/max_velocity", joints_.x.max_velocity, 0.2);
00060 pnh_.param(joints_.y.name + "/max_velocity", joints_.y.max_velocity, 0.2);
00061 pnh_.param(joints_.yaw.name + "/max_velocity", joints_.yaw.max_velocity, 0.2);
00062
00063 cmd_vel_pub_ = nh_.advertise<geometry_msgs::Twist>("command", 10);
00064 odom_sub_ = nh_.subscribe<nav_msgs::Odometry>("odom", 1,
00065 boost::bind(&Controller::odomCallback, this, _1));
00066
00067 update_timer_ = nh_.createTimer(ros::Duration(1.0 / frequency_),
00068 boost::bind(&Controller::update, this, _1));
00069
00070 as_.reset(new Server(nh_,
00071 "follow_joint_trajectory",
00072 boost::bind(&Controller::goalCallback, this, _1),
00073 boost::bind(&Controller::cancelCallback, this, _1),
00074 false));
00075 as_->start();
00076 }
00077
00078 Controller::~Controller()
00079 {}
00080
00081 void Controller::goalCallback(GoalHandle gh)
00082 {
00083 boost::mutex::scoped_lock lock(mutex_);
00084
00085 ROS_DEBUG("new goal arrived");
00086
00087
00088 std::set<std::string> names;
00089 for (int i = 0; i < 3; ++i)
00090 names.insert(joints_[i].name);
00091 std::set<std::string> goal_joint_set(gh.getGoal()->trajectory.joint_names.begin(),
00092 gh.getGoal()->trajectory.joint_names.end());
00093 if (names != goal_joint_set) {
00094 ROS_ERROR("Joints on incoming goal don't match our joints");
00095 gh.setRejected();
00096 return;
00097 }
00098
00099
00100 if (active_goal_)
00101 {
00102 ROS_DEBUG("canceled active goal");
00103 active_goal_->setCanceled();
00104 }
00105
00106
00107 if (!gh.getGoal()->trajectory.points.empty())
00108 {
00109 int pos_size = gh.getGoal()->trajectory.points[0].positions.size();
00110 if (pos_size != gh.getGoal()->trajectory.points[0].velocities.size())
00111 {
00112 ROS_ERROR("size of points and velocities must be the same");
00113 gh.setRejected();
00114 return;
00115 }
00116 else if (!gh.getGoal()->trajectory.points[0].accelerations.empty() &&
00117 pos_size != gh.getGoal()->trajectory.points[0].accelerations.size())
00118 {
00119 ROS_ERROR("size of acclerations must be the same as points or 0");
00120 gh.setRejected();
00121 return;
00122 }
00123 }
00124
00125 gh.setAccepted();
00126 active_goal_.reset(new GoalHandle(gh));
00127
00128 ROS_DEBUG("goal accepted");
00129
00130 if (gh.getGoal()->trajectory.points.empty())
00131 {
00132 clearTrajectory();
00133 return;
00134 }
00135
00136
00137 setTrajectory(share_member(gh.getGoal(), gh.getGoal()->trajectory), active_goal_);
00138 }
00139
00140 void Controller::cancelCallback(GoalHandle gh)
00141 {
00142 boost::mutex::scoped_lock lock(mutex_);
00143 if (active_goal_ && *active_goal_ == gh)
00144 {
00145 trajectory_msgs::JointTrajectory::Ptr empty(new trajectory_msgs::JointTrajectory);
00146 boost::shared_ptr<GoalHandle> empty_gh = boost::shared_ptr<GoalHandle>((GoalHandle*)NULL);
00147 empty->joint_names.resize(3);
00148 for (int i = 0; i < 3; ++i)
00149 empty->joint_names[i] = joints_[i].name;
00150 setTrajectory(empty, empty_gh);
00151 active_goal_->setCanceled();
00152 active_goal_ = boost::shared_ptr<GoalHandle>((GoalHandle*)NULL);
00153 }
00154 }
00155
00156 void Controller::odomCallback(const nav_msgs::Odometry::ConstPtr & msg)
00157 {
00158 joints_.real_latest_time = msg->header.stamp;
00159 joints_.x.position = msg->pose.pose.position.x;
00160 joints_.y.position = msg->pose.pose.position.y;
00161 joints_.yaw.position = 2.0 * atan2(msg->pose.pose.orientation.z,
00162 msg->pose.pose.orientation.w);
00163
00164
00165 joints_.x.velocity = msg->twist.twist.linear.x;
00166 joints_.y.velocity = msg->twist.twist.linear.y;
00167 joints_.yaw.velocity = msg->twist.twist.angular.z;
00168 }
00169
00170 void Controller::update(const ros::TimerEvent& e)
00171 {
00172 if (!active_goal_) return;
00173 if (active_traj_->size() <= 0)
00174 {
00175 ROS_ERROR("No segments in active trajectory");
00176 return;
00177 }
00178
00179 ros::Time now = e.current_real, last = e.last_real;
00180 ros::Duration dt = now - last;
00181
00182 BaseMotion next_motion;
00183 active_traj_->motionAtTime(now.toSec(), next_motion);
00184
00185 BaseMotion desired_motion, error_motion;
00186 active_traj_->motionAtTime(joints_.real_latest_time.toSec(), desired_motion);
00187 error_motion.x.position = desired_motion.x.position - joints_.x.position;
00188 error_motion.y.position = desired_motion.y.position - joints_.y.position;
00189 error_motion.yaw.position = angles::shortest_angular_distance(joints_.yaw.position,
00190 desired_motion.yaw.position);
00191 for(int i = 0; i < 3; ++i)
00192 joints_[i].commanded_effort = error_motion[i].position * 1.0;
00193
00194
00195 setFeedback(now, desired_motion, error_motion);
00196 ROS_DEBUG_STREAM("desired: " << desired_motion);
00197 ROS_DEBUG_STREAM("actual: x: " << joints_.x.position <<
00198 ", y: " << joints_.y.position <<
00199 ", th: " << joints_.yaw.position);
00200 ROS_DEBUG_STREAM("error: " << error_motion);
00201
00202
00203 boost::shared_ptr<GoalHandle> gh;
00204 bool has_goal = active_traj_->goalAtTime(now.toSec(), gh);
00205 if (has_goal && gh == active_goal_)
00206 {
00207 ros::Time end_time(active_traj_->endTime());
00208 ROS_DEBUG_STREAM("time: " << now.toSec() << " -> end: " << end_time.toSec());
00209
00210 if(now > end_time) {
00211 ROS_DEBUG_STREAM("current time exceeded goal end time");
00212 bool inside_goal_constraints = true;
00213 for (size_t i = 0; i < 3 && inside_goal_constraints; ++i)
00214 {
00215 if (fabs(next_motion[i].velocity) < 1e-6)
00216 {
00217 if (fabs(joints_[i].velocity) > stopped_velocity_tolerance_)
00218 {
00219 ROS_WARN_STREAM("velocity of joint " << joints_[i].name << ": " << joints_[i].velocity << " > stopped_velocity_tolerance: " << stopped_velocity_tolerance_);
00220 inside_goal_constraints = false;
00221 } else if (fabs(error_motion[i].position) > goal_threshold_) {
00222 ROS_WARN_STREAM("error of joint " << joints_[i].name << ": " << error_motion[i].position << " > goal_threshold: " << goal_threshold_);
00223 inside_goal_constraints = false;
00224 }
00225 }
00226 }
00227 if (inside_goal_constraints)
00228 {
00229 active_goal_->setSucceeded();
00230 active_goal_ = boost::shared_ptr<GoalHandle>((GoalHandle*)NULL);
00231 ROS_DEBUG_STREAM("set succeeded");
00232 } else if (now >= end_time + ros::Duration(goal_time_constraint_)) {
00233 active_goal_->setAborted();
00234 active_goal_ = boost::shared_ptr<GoalHandle>((GoalHandle*)NULL);
00235 ROS_DEBUG_STREAM("set aborted");
00236 }
00237 }
00238
00239
00240 for (size_t i = 0; i < 3; ++i)
00241 {
00242 joints_[i].commanded_velocity = desired_motion[i].velocity + (use_pid ? joints_[i].commanded_effort : 0);
00243 if (joints_[i].max_velocity < fabs(joints_[i].commanded_velocity))
00244 {
00245 joints_[i].commanded_velocity *= joints_[i].max_velocity / fabs(joints_[i].commanded_velocity);
00246 ROS_WARN_STREAM("joint " << joints_[i].name << " violates its velocity limit");
00247 }
00248 }
00249
00250
00251
00252 cmd_vel_msg_.reset(new geometry_msgs::Twist);
00253 double vx = joints_.x.commanded_velocity;
00254 double vy = joints_.y.commanded_velocity;
00255 double th = joints_.yaw.position;
00256 ROS_DEBUG_STREAM("vx: " << vx << ", vy: " << vy << ", th: " << th);
00257 cmd_vel_msg_->linear.x = vx * cos(th) + vy * sin(th);
00258 cmd_vel_msg_->linear.y = vy * cos(th) - vx * sin(th);
00259 cmd_vel_msg_->angular.z = joints_.yaw.commanded_velocity;
00260 ROS_DEBUG_STREAM("cmd_vel x: " << cmd_vel_msg_->linear.x <<
00261 " ,y: " << cmd_vel_msg_->linear.y <<
00262 " ,th: " << cmd_vel_msg_->angular.z);
00263 cmd_vel_pub_.publish(*cmd_vel_msg_);
00264 }
00265 }
00266
00267 void Controller::setFeedback(const ros::Time &stamp, const BaseMotion &desired, const BaseMotion &error)
00268 {
00269 if (!active_goal_) return;
00270 control_msgs::FollowJointTrajectoryFeedback msg;
00271 msg.header.stamp = stamp;
00272 for (int i = 0; i < 3; ++i) {
00273 msg.joint_names.push_back(joints_[i].name);
00274 msg.desired.positions.push_back(desired[i].position);
00275 msg.desired.velocities.push_back(desired[i].velocity);
00276 msg.actual.positions.push_back(joints_[i].position);
00277 msg.actual.velocities.push_back(joints_[i].velocity);
00278 msg.error.positions.push_back(error[i].position);
00279 msg.error.velocities.push_back(error[i].velocity);
00280 }
00281 active_goal_->publishFeedback(msg);
00282 }
00283
00284 void Controller::setTrajectory(const trajectory_msgs::JointTrajectory::ConstPtr &msg,
00285 boost::shared_ptr<GoalHandle> &gh)
00286 {
00287 ROS_DEBUG("set trajectory");
00288 if (!active_traj_) clearTrajectory();
00289 ros::Time now = ros::Time::now();
00290 double msg_start_time = 0.0;
00291 if (msg->header.stamp == ros::Time(0.0))
00292 msg_start_time = now.toSec();
00293 else msg_start_time = msg->header.stamp.toSec();
00294 Trajectory::ConstPtr prev_traj = active_traj_;
00295 Trajectory::Ptr new_traj(new Trajectory(1));
00296 new_traj->segments[0].start_time = ros::Time::now().toSec() - 0.001;
00297 new_traj->segments[0].duration = 0.0;
00298 for (int i = 0; i < 3; ++i)
00299 new_traj->segments[0].splines[i].coefficients[0] = joints_[i].position;
00300 ROS_DEBUG("set prev trajectory");
00301
00302
00303 int from_seg = -1, to_seg = -1;
00304 while (from_seg + 1 < prev_traj->size() &&
00305 prev_traj->segments[from_seg + 1].start_time <= now.toSec())
00306 ++from_seg;
00307 while (to_seg + 1 < prev_traj->size() &&
00308 prev_traj->segments[to_seg + 1].start_time < msg_start_time)
00309 ++to_seg;
00310 if (to_seg < from_seg) from_seg = to_seg;
00311
00312 ROS_DEBUG_STREAM("use prev traj from " << from_seg << ", to " << to_seg);
00313
00314 for (int i = std::max(from_seg, 0); i <= to_seg; ++i) {
00315 new_traj->segments.push_back(prev_traj->segments[i]);
00316 }
00317 if (new_traj->size() == 0)
00318 new_traj->segments.push_back(prev_traj->segments[prev_traj->size() - 1]);
00319
00320
00321 int joint_idx_x = findIndex(msg->joint_names, joints_.x.name);
00322 int joint_idx_y = findIndex(msg->joint_names, joints_.y.name);
00323 int joint_idx_yaw = findIndex(msg->joint_names, joints_.yaw.name);
00324
00325 ROS_DEBUG_STREAM("look up x: " << joint_idx_x << ", y: " << joint_idx_y << ", yaw: " << joint_idx_yaw);
00326
00327
00328 Trajectory::Segment last_seg = new_traj->segments[new_traj->size() - 1];
00329 BaseMotion prev_motion;
00330 last_seg.sample(msg_start_time, prev_motion);
00331 double dist = angles::shortest_angular_distance(prev_motion.yaw.position,
00332 msg->points[0].positions[joint_idx_yaw]);
00333 double yaw_align = prev_motion.yaw.position + dist - msg->points[0].positions[joint_idx_yaw];
00334
00335 ROS_DEBUG_STREAM("yaw_align: " << yaw_align);
00336
00337
00338 for (size_t i = 0; i < msg->points.size(); ++i)
00339 {
00340 Trajectory::Segment s;
00341 s.duration = msg->points[i].time_from_start.toSec();
00342 if (i != 0) s.duration -= msg->points[i-1].time_from_start.toSec();
00343 s.start_time = msg_start_time + msg->points[i].time_from_start.toSec() - s.duration;
00344 s.gh = gh;
00345
00346 ROS_DEBUG_STREAM("s.start_time: " << s.start_time << ", s.duration: " << s.duration);
00347
00348 if (prev_motion.hasAcceleration() && msg->points[i].accelerations.size() > 0) {
00349 Motion mx(msg->points[i].positions[joint_idx_x],
00350 msg->points[i].velocities[joint_idx_x],
00351 msg->points[i].accelerations[joint_idx_x]);
00352 QuinticSpline spx(prev_motion.x, mx, s.duration);
00353 s.splines[0] = spx;
00354
00355 Motion my(msg->points[i].positions[joint_idx_y],
00356 msg->points[i].velocities[joint_idx_y],
00357 msg->points[i].accelerations[joint_idx_y]);
00358 QuinticSpline spy(prev_motion.y, my, s.duration);
00359 s.splines[1] = spy;
00360
00361 Motion myaw(msg->points[i].positions[joint_idx_yaw] + yaw_align,
00362 msg->points[i].velocities[joint_idx_yaw],
00363 msg->points[i].accelerations[joint_idx_yaw]);
00364 QuinticSpline spyaw(prev_motion.yaw, myaw, s.duration);
00365 s.splines[2] = spyaw;
00366 new_traj->segments.push_back(s);
00367 prev_motion.x = mx;
00368 prev_motion.y = my;
00369 prev_motion.yaw = myaw;
00370 } else if (prev_motion.hasVelocity() && msg->points[i].velocities.size() > 0) {
00371 ROS_DEBUG_THROTTLE(1.0, "velocity only");
00372 Motion mx(msg->points[i].positions[joint_idx_x],
00373 msg->points[i].velocities[joint_idx_x]);
00374 CubicSpline spx(prev_motion.x, mx, s.duration);
00375 s.splines[0] = spx;
00376
00377 Motion my(msg->points[i].positions[joint_idx_y],
00378 msg->points[i].velocities[joint_idx_y]);
00379 CubicSpline spy(prev_motion.y, my, s.duration);
00380 s.splines[1] = spy;
00381
00382 Motion myaw(msg->points[i].positions[joint_idx_yaw] + yaw_align,
00383 msg->points[i].velocities[joint_idx_yaw]);
00384 CubicSpline spyaw(prev_motion.yaw, myaw, s.duration);
00385 s.splines[2] = spyaw;
00386 new_traj->segments.push_back(s);
00387 prev_motion.x = mx;
00388 prev_motion.y = my;
00389 prev_motion.yaw = myaw;
00390 } else {
00391 ROS_DEBUG_THROTTLE(1.0, "position only");
00392 Motion mx(msg->points[i].positions[joint_idx_x]);
00393 Line spx(prev_motion.x, mx, s.duration);
00394 s.splines[0] = spx;
00395
00396 Motion my(msg->points[i].positions[joint_idx_y]);
00397 Line spy(prev_motion.y, my, s.duration);
00398 s.splines[1] = spy;
00399
00400 Motion myaw(msg->points[i].positions[joint_idx_yaw] + yaw_align);
00401 Line spyaw(prev_motion.yaw, myaw, s.duration);
00402 s.splines[2] = spyaw;
00403 new_traj->segments.push_back(s);
00404 prev_motion.x = mx;
00405 prev_motion.y = my;
00406 prev_motion.yaw = myaw;
00407 }
00408
00409
00410 ROS_DEBUG_STREAM("start time: " << s.start_time << ", duration: " << s.duration);
00411 for (int j = 0; j < 3; ++j) {
00412 ROS_DEBUG_STREAM(" spline " << j << ":");
00413 for (int k = 0; k < 6; ++k)
00414 ROS_DEBUG_STREAM(" " << k << ": " << s.splines[j].coefficients[k]);
00415 }
00416 }
00417
00418
00419 active_traj_ = new_traj;
00420 ROS_DEBUG_STREAM("new active trajectory is set");
00421 }
00422
00423 void Controller::clearTrajectory()
00424 {
00425 active_traj_.reset(new Trajectory(1));
00426 active_traj_->segments[0].start_time = ros::Time::now().toSec() - 0.001;
00427 active_traj_->segments[0].duration = 0.0;
00428 for (int i = 0; i < 3; ++i)
00429 active_traj_->segments[0].splines[i].coefficients[0] = joints_[i].position;
00430 ROS_DEBUG("clear trajectory");
00431 }
00432 }