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