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 #include <ros/ros.h>
00033 #include <actionlib/server/action_server.h>
00034 
00035 #include <trajectory_msgs/JointTrajectory.h>
00036 #include <control_msgs/FollowJointTrajectoryAction.h>
00037 #include <control_msgs/FollowJointTrajectoryFeedback.h>
00038 #include <industrial_msgs/RobotStatus.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), action_server_(node_, "joint_trajectory_action",
00050                                boost::bind(&JointTrajectoryExecuter::goalCB, this, _1),
00051                                boost::bind(&JointTrajectoryExecuter::cancelCB, this, _1), false), has_active_goal_(
00052           false)
00053   {
00054     using namespace XmlRpc;
00055     ros::NodeHandle pn("~");
00056 
00057     joint_names_.push_back("joint_s");
00058     joint_names_.push_back("joint_l");
00059     joint_names_.push_back("joint_e");
00060     joint_names_.push_back("joint_u");
00061     joint_names_.push_back("joint_r");
00062     joint_names_.push_back("joint_b");
00063     joint_names_.push_back("joint_t");
00064 
00065     pn.param("constraints/goal_time", goal_time_constraint_, 0.0);
00066 
00067     
00068     for (size_t i = 0; i < joint_names_.size(); ++i)
00069     {
00070       std::string ns = std::string("constraints/") + joint_names_[i];
00071       double g, t;
00072       pn.param(ns + "/goal", g, DEFAULT_GOAL_THRESHOLD);
00073       pn.param(ns + "/trajectory", t, -1.0);
00074       goal_constraints_[joint_names_[i]] = g;
00075       trajectory_constraints_[joint_names_[i]] = t;
00076     }
00077     pn.param("constraints/stopped_velocity_tolerance", stopped_velocity_tolerance_, 0.01);
00078 
00079     pub_controller_command_ = node_.advertise<trajectory_msgs::JointTrajectory>("command", 1);
00080     sub_controller_state_ = node_.subscribe("feedback_states", 1, &JointTrajectoryExecuter::controllerStateCB, this);
00081     sub_robot_status_ = node_.subscribe("robot_status", 1, &JointTrajectoryExecuter::robotStatusCB, this);
00082 
00083     action_server_.start();
00084   }
00085 
00086   ~JointTrajectoryExecuter()
00087   {
00088     pub_controller_command_.shutdown();
00089     sub_controller_state_.shutdown();
00090     watchdog_timer_.stop();
00091   }
00092 
00093   void robotStatusCB(const industrial_msgs::RobotStatusConstPtr &msg)
00094   {
00095     last_robot_status_ = *msg;  
00096   }
00097 
00098   bool withinGoalConstraints(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg,
00099                              const std::map<std::string, double>& constraints,
00100                              const trajectory_msgs::JointTrajectory& traj)
00101   {
00102     ROS_DEBUG("Checking goal contraints");
00103     int last = traj.points.size() - 1;
00104     for (size_t i = 0; i < msg->joint_names.size(); ++i)
00105     {
00106       double abs_error = fabs(msg->actual.positions[i] - traj.points[last].positions[i]);
00107       double goal_constraint = constraints.at(msg->joint_names[i]);
00108       if (goal_constraint >= 0 && abs_error > goal_constraint)
00109       {
00110         ROS_DEBUG("Bad constraint: %f, abs_errs: %f", goal_constraint, abs_error);
00111         return false;
00112       }
00113       ROS_DEBUG("Checking constraint: %f, abs_errs: %f", goal_constraint, abs_error);
00114     }
00115     return true;
00116   }
00117 
00118 private:
00119 
00120   static bool setsEqual(const std::vector<std::string> &a, const std::vector<std::string> &b)
00121   {
00122     if (a.size() != b.size())
00123       return false;
00124 
00125     for (size_t i = 0; i < a.size(); ++i)
00126     {
00127       if (count(b.begin(), b.end(), a[i]) != 1)
00128         return false;
00129     }
00130     for (size_t i = 0; i < b.size(); ++i)
00131     {
00132       if (count(a.begin(), a.end(), b[i]) != 1)
00133         return false;
00134     }
00135 
00136     return true;
00137   }
00138 
00139   void watchdog(const ros::TimerEvent &e)
00140   {
00141     ros::Time now = ros::Time::now();
00142 
00143     
00144     if (has_active_goal_)
00145     {
00146       bool should_abort = false;
00147       if (!last_controller_state_)
00148       {
00149         should_abort = true;
00150         ROS_WARN("Aborting goal because we have never heard a controller state message.");
00151       }
00152       else if ((now - last_controller_state_->header.stamp) > ros::Duration(5.0))
00153       {
00154         should_abort = true;
00155         ROS_WARN(
00156             "Aborting goal because we haven't heard from the controller in %.3lf seconds", (now - last_controller_state_->header.stamp).toSec());
00157       }
00158 
00159       if (should_abort)
00160       {
00161         
00162         trajectory_msgs::JointTrajectory empty;
00163         empty.joint_names = joint_names_;
00164         pub_controller_command_.publish(empty);
00165 
00166         
00167         active_goal_.setAborted();
00168         has_active_goal_ = false;
00169       }
00170     }
00171   }
00172 
00173   void goalCB(GoalHandle gh)
00174   {
00175     
00176     ROS_DEBUG("Received goal: goalCB");
00177     if (!setsEqual(joint_names_, gh.getGoal()->trajectory.joint_names))
00178     {
00179       ROS_ERROR("Joints on incoming goal don't match our joints");
00180       gh.setRejected();
00181       return;
00182     }
00183 
00184     
00185     if (has_active_goal_)
00186     {
00187       ROS_DEBUG("Received new goal, canceling current goal");
00188       
00189       trajectory_msgs::JointTrajectory empty;
00190       empty.joint_names = joint_names_;
00191       pub_controller_command_.publish(empty);
00192 
00193       
00194       active_goal_.setCanceled();
00195       has_active_goal_ = false;
00196     }
00197 
00198     
00199     if (withinGoalConstraints(last_controller_state_, goal_constraints_, gh.getGoal()->trajectory))
00200     {
00201       ROS_INFO_STREAM("Already within goal constraints");
00202       gh.setAccepted();
00203       gh.setSucceeded();
00204     }
00205     else
00206     {
00207       gh.setAccepted();
00208       active_goal_ = gh;
00209       has_active_goal_ = true;
00210 
00211       ROS_INFO("Publishing trajectory");
00212 
00213       current_traj_ = active_goal_.getGoal()->trajectory;
00214       pub_controller_command_.publish(current_traj_);
00215     }
00216   }
00217 
00218   void cancelCB(GoalHandle gh)
00219   {
00220     ROS_DEBUG("Received action cancel request");
00221     if (active_goal_ == gh)
00222     {
00223       
00224       trajectory_msgs::JointTrajectory empty;
00225       empty.joint_names = joint_names_;
00226       pub_controller_command_.publish(empty);
00227 
00228       
00229       active_goal_.setCanceled();
00230       has_active_goal_ = false;
00231     }
00232   }
00233 
00234   ros::NodeHandle node_;
00235   JTAS action_server_;
00236   ros::Publisher pub_controller_command_;
00237   ros::Subscriber sub_controller_state_;
00238   ros::Subscriber sub_robot_status_;
00239   ros::Timer watchdog_timer_;
00240 
00241   bool has_active_goal_;
00242   GoalHandle active_goal_;
00243   trajectory_msgs::JointTrajectory current_traj_;
00244 
00245   std::vector<std::string> joint_names_;
00246   std::map<std::string, double> goal_constraints_;
00247   std::map<std::string, double> trajectory_constraints_;
00248   double goal_time_constraint_;
00249   double stopped_velocity_tolerance_;
00250 
00251   control_msgs::FollowJointTrajectoryFeedbackConstPtr last_controller_state_;
00252   industrial_msgs::RobotStatus last_robot_status_;
00253 
00254   void controllerStateCB(const control_msgs::FollowJointTrajectoryFeedbackConstPtr &msg)
00255   {
00256     
00257     last_controller_state_ = msg;
00258     ros::Time now = ros::Time::now();
00259 
00260     if (!has_active_goal_)
00261     {
00262       
00263       return;
00264     }
00265     if (current_traj_.points.empty())
00266     {
00267       ROS_DEBUG("Current trajectory is empty, ignoring feedback");
00268       return;
00269     }
00270     
00271 
00272 
00273 
00274 
00275     if (!setsEqual(joint_names_, msg->joint_names))
00276     {
00277       ROS_ERROR("Joint names from the controller don't match our joint names.");
00278       return;
00279     }
00280 
00281     
00282     
00283 
00284     ROS_DEBUG("Checking goal constraints");
00285     if (withinGoalConstraints(msg, goal_constraints_, current_traj_))
00286     {
00287       
00288       
00289       
00290       
00291       if (last_robot_status_.in_motion.val == industrial_msgs::TriState::FALSE)
00292       {
00293         ROS_INFO("Inside goal constraints, stopped moving, return success for action");
00294         active_goal_.setSucceeded();
00295         has_active_goal_ = false;
00296       }
00297       else if (last_robot_status_.in_motion.val == industrial_msgs::TriState::UNKNOWN)
00298       {
00299         ROS_INFO("Inside goal constraints, return success for action");
00300         ROS_WARN("Robot status: in motion unknown, the robot driver node and controller code should be updated");
00301         active_goal_.setSucceeded();
00302         has_active_goal_ = false;
00303       }
00304       else
00305       {
00306         ROS_DEBUG("Within goal constraints but robot is still moving");
00307       }
00308     }
00309     
00310     
00311 
00312 
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324 
00325 
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00338 
00339 
00340 
00341 
00342 
00343 
00344 
00345 
00346 
00347 
00348 
00349 
00350 
00351 
00352 
00353 
00354 
00355 
00356 
00357 
00358 
00359 
00360 
00361 
00362 
00363 
00364 
00365 
00366 
00367 
00368 
00369 
00370 
00371 
00372 
00373   }
00374 };
00375 
00376 int main(int argc, char** argv)
00377 {
00378   ros::init(argc, argv, "joint_trajectory_action_node");
00379   ros::NodeHandle node; 
00380   JointTrajectoryExecuter jte(node);
00381 
00382   ros::spin();
00383 
00384   return 0;
00385 }
00386