joint_trajectory_action.cpp
Go to the documentation of this file.
00001 /*
00002 * Software License Agreement (BSD License)
00003 *
00004 * Copyright (c) 2011, Southwest Research Institute
00005 * All rights reserved.
00006 *
00007 * Redistribution and use in source and binary forms, with or without
00008 * modification, are permitted provided that the following conditions are met:
00009 *
00010 *       * Redistributions of source code must retain the above copyright
00011 *       notice, this list of conditions and the following disclaimer.
00012 *       * Redistributions in binary form must reproduce the above copyright
00013 *       notice, this list of conditions and the following disclaimer in the
00014 *       documentation and/or other materials provided with the distribution.
00015 *       * Neither the name of the Southwest Research Institute, nor the names
00016 *       of its contributors may be used to endorse or promote products derived
00017 *       from this software without specific prior written permission.
00018 *
00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00023 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00024 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00025 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00026 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00027 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00029 * POSSIBILITY OF SUCH DAMAGE.
00030 */
00031 
00032 
00033 #include <ros/ros.h>
00034 #include <actionlib/server/action_server.h>
00035 
00036 #include <trajectory_msgs/JointTrajectory.h>
00037 #include <control_msgs/FollowJointTrajectoryAction.h>
00038 #include <control_msgs/FollowJointTrajectoryFeedback.h>
00039 
00040 const double DEFAULT_GOAL_THRESHOLD = 0.01;
00041 
00042 class JointTrajectoryExecuter
00043 {
00044 private:
00045   typedef actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction> JTAS;
00046   typedef JTAS::GoalHandle GoalHandle;
00047 public:
00048   JointTrajectoryExecuter(ros::NodeHandle &n) :
00049     node_(n),
00050     action_server_(node_, "joint_trajectory_action",
00051                    boost::bind(&JointTrajectoryExecuter::goalCB, this, _1),
00052                    boost::bind(&JointTrajectoryExecuter::cancelCB, this, _1),
00053                    false),
00054     has_active_goal_(false)
00055   {
00056     using namespace XmlRpc;
00057     ros::NodeHandle pn("~");
00058 
00059     joint_names_.push_back("joint_s");
00060     joint_names_.push_back("joint_l");
00061     joint_names_.push_back("joint_e");
00062     joint_names_.push_back("joint_u");
00063     joint_names_.push_back("joint_r");
00064     joint_names_.push_back("joint_b");
00065     joint_names_.push_back("joint_t");
00066 
00067     pn.param("constraints/goal_time", goal_time_constraint_, 0.0);
00068 
00069     // Gets the constraints for each joint.
00070     for (size_t i = 0; i < joint_names_.size(); ++i)
00071     {
00072       std::string ns = std::string("constraints/") + joint_names_[i];
00073       double g, t;
00074       pn.param(ns + "/goal", g, DEFAULT_GOAL_THRESHOLD);
00075       pn.param(ns + "/trajectory", t, -1.0);
00076       goal_constraints_[joint_names_[i]] = g;
00077       trajectory_constraints_[joint_names_[i]] = t;
00078     }
00079     pn.param("constraints/stopped_velocity_tolerance", stopped_velocity_tolerance_, 0.01);
00080 
00081 
00082     pub_controller_command_ =
00083       node_.advertise<trajectory_msgs::JointTrajectory>("command", 1);
00084     sub_controller_state_ =
00085       node_.subscribe("feedback_states", 1, &JointTrajectoryExecuter::controllerStateCB, this);
00086     
00087     action_server_.start();
00088   }
00089 
00090   ~JointTrajectoryExecuter()
00091   {
00092    pub_controller_command_.shutdown();
00093     sub_controller_state_.shutdown();
00094     watchdog_timer_.stop();
00095   }
00096 
00097   bool withinGoalConstraints(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg,
00098                              const std::map<std::string, double>& constraints,
00099                              const trajectory_msgs::JointTrajectory& traj) {
00100     ROS_DEBUG("Checking goal contraints");
00101     int last = traj.points.size() - 1;
00102     for (size_t i = 0; i < msg->joint_names.size(); ++i)
00103     {
00104       double abs_error = fabs(msg->actual.positions[i]-traj.points[last].positions[i]);
00105       double goal_constraint = constraints.at(msg->joint_names[i]);
00106       if (goal_constraint >= 0 && abs_error > goal_constraint)
00107       {
00108         ROS_DEBUG("Bad constraint: %f, abs_errs: %f", goal_constraint, abs_error);
00109         return false;
00110       }
00111       ROS_DEBUG("Checking constraint: %f, abs_errs: %f", goal_constraint, abs_error);
00112     }
00113     return true;
00114   }
00115 
00116 private:
00117 
00118   static bool setsEqual(const std::vector<std::string> &a, const std::vector<std::string> &b)
00119   {
00120     if (a.size() != b.size())
00121       return false;
00122 
00123     for (size_t i = 0; i < a.size(); ++i)
00124     {
00125       if (count(b.begin(), b.end(), a[i]) != 1)
00126         return false;
00127     }
00128     for (size_t i = 0; i < b.size(); ++i)
00129     {
00130       if (count(a.begin(), a.end(), b[i]) != 1)
00131         return false;
00132     }
00133 
00134     return true;
00135   }
00136 
00137   void watchdog(const ros::TimerEvent &e)
00138   {
00139     ros::Time now = ros::Time::now();
00140 
00141     // Aborts the active goal if the controller does not appear to be active.
00142     if (has_active_goal_)
00143     {
00144       bool should_abort = false;
00145       if (!last_controller_state_)
00146       {
00147         should_abort = true;
00148         ROS_WARN("Aborting goal because we have never heard a controller state message.");
00149       }
00150       else if ((now - last_controller_state_->header.stamp) > ros::Duration(5.0))
00151       {
00152         should_abort = true;
00153         ROS_WARN("Aborting goal because we haven't heard from the controller in %.3lf seconds",
00154                  (now - last_controller_state_->header.stamp).toSec());
00155       }
00156 
00157       if (should_abort)
00158       {
00159         // Stops the controller.
00160         trajectory_msgs::JointTrajectory empty;
00161         empty.joint_names = joint_names_;
00162         pub_controller_command_.publish(empty);
00163 
00164         // Marks the current goal as aborted.
00165         active_goal_.setAborted();
00166         has_active_goal_ = false;
00167       }
00168     }
00169   }
00170 
00171   void goalCB(GoalHandle gh)
00172   {
00173     // Ensures that the joints in the goal match the joints we are commanding.
00174     ROS_DEBUG("Received goal: goalCB");
00175     if (!setsEqual(joint_names_, gh.getGoal()->trajectory.joint_names))
00176     {
00177       ROS_ERROR("Joints on incoming goal don't match our joints");
00178       gh.setRejected();
00179       return;
00180     }
00181 
00182     // Cancels the currently active goal.
00183     if (has_active_goal_)
00184     {
00185       ROS_DEBUG("Received new goal, canceling current goal");
00186       // Stops the controller.
00187       trajectory_msgs::JointTrajectory empty;
00188       empty.joint_names = joint_names_;
00189       pub_controller_command_.publish(empty);
00190 
00191       // Marks the current goal as canceled.
00192       active_goal_.setCanceled();
00193       has_active_goal_ = false;
00194     }
00195 
00196     // Sends the trajectory along to the controller
00197     if(withinGoalConstraints(last_controller_state_,
00198                              goal_constraints_,
00199                              gh.getGoal()->trajectory)) {
00200       ROS_INFO_STREAM("Already within goal constraints");
00201       gh.setAccepted();
00202       gh.setSucceeded();
00203     } else {
00204       gh.setAccepted();
00205       active_goal_ = gh;
00206       has_active_goal_ = true;
00207 
00208       ROS_INFO("Publishing trajectory");
00209 
00210       current_traj_ = active_goal_.getGoal()->trajectory;
00211       pub_controller_command_.publish(current_traj_);
00212     }
00213   }
00214 
00215   void cancelCB(GoalHandle gh)
00216   {
00217     ROS_DEBUG("Received action cancel request");
00218     if (active_goal_ == gh)
00219     {
00220       // Stops the controller.
00221       trajectory_msgs::JointTrajectory empty;
00222       empty.joint_names = joint_names_;
00223       pub_controller_command_.publish(empty);
00224 
00225       // Marks the current goal as canceled.
00226       active_goal_.setCanceled();
00227       has_active_goal_ = false;
00228     }
00229   }
00230 
00231 
00232   ros::NodeHandle node_;
00233   JTAS action_server_;
00234   ros::Publisher pub_controller_command_;
00235   ros::Subscriber sub_controller_state_;
00236   ros::Timer watchdog_timer_;
00237 
00238   bool has_active_goal_;
00239   GoalHandle active_goal_;
00240   trajectory_msgs::JointTrajectory current_traj_;
00241 
00242 
00243   std::vector<std::string> joint_names_;
00244   std::map<std::string,double> goal_constraints_;
00245   std::map<std::string,double> trajectory_constraints_;
00246   double goal_time_constraint_;
00247   double stopped_velocity_tolerance_;
00248 
00249   control_msgs::FollowJointTrajectoryFeedbackConstPtr last_controller_state_;
00250 
00251   void controllerStateCB(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg)
00252   {
00253     //ROS_DEBUG("Checking controller state feedback");
00254     last_controller_state_ = msg;
00255     ros::Time now = ros::Time::now();
00256 
00257     if (!has_active_goal_)
00258     {
00259       //ROS_DEBUG("No active goal, ignoring feedback");
00260       return;
00261     }
00262     if (current_traj_.points.empty())
00263     {
00264       ROS_DEBUG("Current trajecotry is empty, ignoring feedback");
00265       return;
00266     }
00267     /* NOT CONCERNED ABOUT TRAJECTORY TIMING AT THIS POINT
00268     if (now < current_traj_.header.stamp + current_traj_.points[0].time_from_start)
00269       return;
00270     */
00271 
00272     if (!setsEqual(joint_names_, msg->joint_names))
00273     {
00274       ROS_ERROR("Joint names from the controller don't match our joint names.");
00275       return;
00276     }
00277 
00278     // Checking for goal constraints
00279     // Checks that we have ended inside the goal constraints
00280 
00281     ROS_DEBUG("Checking goal contraints");
00282     if(withinGoalConstraints(msg, 
00283                              goal_constraints_,
00284                              current_traj_)) {
00285       ROS_INFO("Inside goal contraints, return success for action");
00286       active_goal_.setSucceeded();
00287       has_active_goal_ = false;
00288     }
00289     // Verifies that the controller has stayed within the trajectory constraints.
00290     /*  DISABLING THIS MORE COMPLICATED GOAL CHECKING AND ERROR DETECTION
00291 
00292 
00293     int last = current_traj_.points.size() - 1;
00294     ros::Time end_time = current_traj_.header.stamp + current_traj_.points[last].time_from_start;
00295     if (now < end_time)
00296     {
00297       // Checks that the controller is inside the trajectory constraints.
00298       for (size_t i = 0; i < msg->joint_names.size(); ++i)
00299       {
00300         double abs_error = fabs(msg->error.positions[i]);
00301         double constraint = trajectory_constraints_[msg->joint_names[i]];
00302         if (constraint >= 0 && abs_error > constraint)
00303         {
00304           // Stops the controller.
00305           trajectory_msgs::JointTrajectory empty;
00306           empty.joint_names = joint_names_;
00307           pub_controller_command_.publish(empty);
00308 
00309           active_goal_.setAborted();
00310           has_active_goal_ = false;
00311           ROS_WARN("Aborting because we would up outside the trajectory constraints");
00312           return;
00313         }
00314       }
00315     }
00316     else
00317     {
00318       // Checks that we have ended inside the goal constraints
00319       bool inside_goal_constraints = true;
00320       for (size_t i = 0; i < msg->joint_names.size() && inside_goal_constraints; ++i)
00321       {
00322         double abs_error = fabs(msg->error.positions[i]);
00323         double goal_constraint = goal_constraints_[msg->joint_names[i]];
00324         if (goal_constraint >= 0 && abs_error > goal_constraint)
00325           inside_goal_constraints = false;
00326 
00327         // It's important to be stopped if that's desired.
00328         if (fabs(msg->desired.velocities[i]) < 1e-6)
00329         {
00330           if (fabs(msg->actual.velocities[i]) > stopped_velocity_tolerance_)
00331             inside_goal_constraints = false;
00332         }
00333       }
00334 
00335       if (inside_goal_constraints)
00336       {
00337         active_goal_.setSucceeded();
00338         has_active_goal_ = false;
00339       }
00340       else if (now < end_time + ros::Duration(goal_time_constraint_))
00341       {
00342         // Still have some time left to make it.
00343       }
00344       else
00345       {
00346         ROS_WARN("Aborting because we wound up outside the goal constraints");
00347         active_goal_.setAborted();
00348         has_active_goal_ = false;
00349       }
00350 
00351     }
00352     */
00353   }
00354 };
00355 
00356 
00357 int main(int argc, char** argv)
00358 {
00359   ros::init(argc, argv, "joint_trajectory_action_node");
00360   ros::NodeHandle node;//("~");
00361   JointTrajectoryExecuter jte(node);
00362 
00363   ros::spin();
00364 
00365   return 0;
00366 }
00367 
00368 
00369 
00370 


dx100
Author(s): Shaun Edwards (Southwest Research Institute)
autogenerated on Thu Jan 2 2014 11:29:36