pr2_base_trajectory_action_controller.cpp
Go to the documentation of this file.
00001 // -*- mode: c++ -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2016, JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/o2r other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the JSK Lab nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *********************************************************************/
00035 
00036 /*
00037  * pr2_base_trajectory_action_controller.cpp
00038  * Author: Yuki Furuta <furushchev@jsk.imi.i.u-tokyo.ac.jp>
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                          /* auto_start = */ 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     // check joint names
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     // send cancel to current active goal
00100     if (active_goal_)
00101     {
00102       ROS_DEBUG("canceled active goal");
00103       active_goal_->setCanceled();
00104     }
00105 
00106     // validate points
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     { // stop
00132       clearTrajectory();
00133       return;
00134     }
00135 
00136     // set new trajectory
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     // for feedback msg
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     // calc error
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; // P gain: 1.0
00193 
00194     // publish feedback
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     // check if goal reached
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       // check if new commands violates the max velocity
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       // publish command velocity
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   } // function update
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     // first, append previous trajectory to new traecjtory
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     // look up table
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     // calc rotational align from previous trajectory
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     // calc spline from trajectory
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       // debugging
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     // commit new active trajectory
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 } // namespace


pr2_base_trajectory_action
Author(s): saito, Yuki Furuta
autogenerated on Sat Jul 1 2017 02:43:02