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 #include <sstream>
00029 #include <string>
00030 #include <vector>
00031 #include <XmlRpcValue.h>
00032
00033 #include <dynamixel_hardware_interface/dynamixel_const.h>
00034 #include <dynamixel_hardware_interface/dynamixel_io.h>
00035
00036 #include <dynamixel_hardware_interface/single_joint_controller.h>
00037 #include <dynamixel_hardware_interface/multi_joint_controller.h>
00038 #include <dynamixel_hardware_interface/joint_trajectory_action_controller.h>
00039 #include <dynamixel_hardware_interface/JointState.h>
00040
00041 #include <ros/ros.h>
00042 #include <pluginlib/class_list_macros.h>
00043 #include <trajectory_msgs/JointTrajectory.h>
00044 #include <control_msgs/FollowJointTrajectoryAction.h>
00045
00046 PLUGINLIB_DECLARE_CLASS(dynamixel_hardware_interface,
00047 JointTrajectoryActionController,
00048 controller::JointTrajectoryActionController,
00049 controller::MultiJointController)
00050
00051 namespace controller
00052 {
00053
00054 JointTrajectoryActionController::JointTrajectoryActionController()
00055 {
00056 terminate_ = false;
00057 }
00058
00059 JointTrajectoryActionController::~JointTrajectoryActionController()
00060 {
00061 }
00062
00063 bool JointTrajectoryActionController::initialize(std::string name, std::vector<SingleJointController*> deps)
00064 {
00065 if (!MultiJointController::initialize(name, deps)) { return false; }
00066
00067 update_rate_ = 1000;
00068 state_update_rate_ = 50;
00069
00070 std::string prefix = "joint_trajectory_action_node/constraints/";
00071
00072 c_nh_.param<double>(prefix + "goal_time", goal_time_constraint_, 0.0);
00073 c_nh_.param<double>(prefix + "stopped_velocity_tolerance", stopped_velocity_tolerance_, 0.01);
00074 c_nh_.param<double>("joint_trajectory_action_node/min_velocity", min_velocity_, 0.1);
00075
00076 goal_constraints_.resize(num_joints_);
00077 trajectory_constraints_.resize(num_joints_);
00078
00079 for (size_t i = 0; i < num_joints_; ++i)
00080 {
00081 c_nh_.param<double>(prefix + joint_names_[i] + "/goal", goal_constraints_[i], -1.0);
00082 c_nh_.param<double>(prefix + joint_names_[i] + "/trajectory", trajectory_constraints_[i], -1.0);
00083 }
00084
00085 msg_.joint_names = joint_names_;
00086 msg_.desired.positions.resize(num_joints_);
00087 msg_.desired.velocities.resize(num_joints_);
00088 msg_.desired.accelerations.resize(num_joints_);
00089 msg_.actual.positions.resize(num_joints_);
00090 msg_.actual.velocities.resize(num_joints_);
00091 msg_.actual.accelerations.resize(num_joints_);
00092 msg_.error.positions.resize(num_joints_);
00093 msg_.error.velocities.resize(num_joints_);
00094 msg_.error.accelerations.resize(num_joints_);
00095
00096 return true;
00097 }
00098
00099 void JointTrajectoryActionController::start()
00100 {
00101 command_sub_ = c_nh_.subscribe("command", 50, &JointTrajectoryActionController::processCommand, this);
00102 state_pub_ = c_nh_.advertise<control_msgs::FollowJointTrajectoryFeedback>("state", 50);
00103
00104 action_server_.reset(new FJTAS(c_nh_, "follow_joint_trajectory",
00105 boost::bind(&JointTrajectoryActionController::processFollowTrajectory, this, _1),
00106 false));
00107 action_server_->start();
00108 feedback_thread_ = new boost::thread(boost::bind(&JointTrajectoryActionController::updateState, this));
00109 }
00110
00111 void JointTrajectoryActionController::stop()
00112 {
00113 {
00114 boost::mutex::scoped_lock terminate_lock(terminate_mutex_);
00115 terminate_ = true;
00116 }
00117
00118 feedback_thread_->join();
00119 delete feedback_thread_;
00120
00121 command_sub_.shutdown();
00122 state_pub_.shutdown();
00123 action_server_->shutdown();
00124 }
00125
00126 void JointTrajectoryActionController::processCommand(const trajectory_msgs::JointTrajectoryConstPtr& msg)
00127 {
00128 if (action_server_->isActive()) { action_server_->setPreempted(); }
00129
00130 while (action_server_->isActive())
00131 {
00132 ros::Duration(0.01).sleep();
00133 }
00134
00135 processTrajectory(*msg, false);
00136 }
00137
00138 void JointTrajectoryActionController::processFollowTrajectory(const control_msgs::FollowJointTrajectoryGoalConstPtr& goal)
00139 {
00140 processTrajectory(goal->trajectory, true);
00141 }
00142
00143 void JointTrajectoryActionController::updateState()
00144 {
00145 ros::Rate rate(state_update_rate_);
00146
00147 while (nh_.ok())
00148 {
00149 {
00150 boost::mutex::scoped_lock terminate_lock(terminate_mutex_);
00151 if (terminate_) { break; }
00152 }
00153
00154 msg_.header.stamp = ros::Time::now();
00155
00156 for (size_t j = 0; j < joint_names_.size(); ++j)
00157 {
00158 const dynamixel_hardware_interface::JointState* state = joint_states_[joint_names_[j]];
00159 msg_.desired.positions[j] = state->target_position;
00160 msg_.desired.velocities[j] = std::abs(state->target_velocity);
00161 msg_.actual.positions[j] = state->position;
00162 msg_.actual.velocities[j] = std::abs(state->velocity);
00163 msg_.error.positions[j] = msg_.actual.positions[j] - msg_.desired.positions[j];
00164 msg_.error.velocities[j] = msg_.actual.velocities[j] - msg_.desired.velocities[j];
00165 }
00166
00167 state_pub_.publish(msg_);
00168 rate.sleep();
00169 }
00170 }
00171
00172 void JointTrajectoryActionController::processTrajectory(const trajectory_msgs::JointTrajectory& traj, bool is_action)
00173 {
00174 control_msgs::FollowJointTrajectoryResult res;
00175 std::string error_msg;
00176
00177 int num_points = traj.points.size();
00178
00179 ROS_DEBUG("Received trajectory with %d points", num_points);
00180
00181
00182 std::vector<int> lookup(num_joints_, -1);
00183
00184 for (size_t j = 0; j < num_joints_; ++j)
00185 {
00186 for (size_t k = 0; k < traj.joint_names.size(); ++k)
00187 {
00188 if (traj.joint_names[k] == joint_names_[j])
00189 {
00190 lookup[j] = k;
00191 break;
00192 }
00193 }
00194
00195 if (lookup[j] == -1)
00196 {
00197 res.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_JOINTS;
00198 error_msg = "Unable to locate joint " + joint_names_[j] + " in the commanded trajectory";
00199 ROS_ERROR("%s", error_msg.c_str());
00200 if (is_action) { action_server_->setAborted(res, error_msg.c_str()); }
00201 return;
00202 }
00203 }
00204
00205 std::vector<double> durations;
00206 durations.resize(num_points);
00207
00208
00209 durations[0] = traj.points[0].time_from_start.toSec();
00210 double trajectory_duration = durations[0];
00211
00212 for (int i = 1; i < num_points; ++i)
00213 {
00214 durations[i] = (traj.points[i].time_from_start - traj.points[i-1].time_from_start).toSec();
00215 trajectory_duration += durations[i];
00216
00217
00218 }
00219
00220 if (traj.points[0].positions.empty())
00221 {
00222 res.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
00223 error_msg = "First point of trajectory has no positions";
00224 ROS_ERROR("%s", error_msg.c_str());
00225 if (is_action) { action_server_->setAborted(res, error_msg); }
00226 return;
00227 }
00228
00229 std::vector<Segment> trajectory;
00230 ros::Time time = ros::Time::now() + ros::Duration(0.01);
00231
00232 for (int i = 0; i < num_points; ++i)
00233 {
00234 const trajectory_msgs::JointTrajectoryPoint point = traj.points[i];
00235 Segment seg;
00236
00237 if (traj.header.stamp == ros::Time(0.0))
00238 {
00239 seg.start_time = (time + point.time_from_start).toSec() - durations[i];
00240 }
00241 else
00242 {
00243 seg.start_time = (traj.header.stamp + point.time_from_start).toSec() - durations[i];
00244 }
00245
00246 seg.duration = durations[i];
00247
00248
00249 if (!point.velocities.empty() && point.velocities.size() != num_joints_)
00250 {
00251 res.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
00252 error_msg = "Command point " + boost::lexical_cast<std::string>(i) + " has " + boost::lexical_cast<std::string>(point.velocities.size()) + " elements for the velocities";
00253 ROS_ERROR("%s", error_msg.c_str());
00254 if (is_action) { action_server_->setAborted(res, error_msg); }
00255 return;
00256 }
00257
00258 if (!point.positions.empty() && point.positions.size() != num_joints_)
00259 {
00260 res.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
00261 error_msg = "Command point " + boost::lexical_cast<std::string>(i) + " has " + boost::lexical_cast<std::string>(point.positions.size()) + " elements for the positions";
00262 ROS_ERROR("%s", error_msg.c_str());
00263 if (is_action) { action_server_->setAborted(res, error_msg); }
00264 return;
00265 }
00266
00267 seg.velocities.resize(num_joints_);
00268 seg.positions.resize(num_joints_);
00269
00270 for (size_t j = 0; j < num_joints_; ++j)
00271 {
00272 seg.velocities[j] = point.velocities[lookup[j]];
00273 seg.positions[j] = point.positions[lookup[j]];
00274 }
00275
00276 trajectory.push_back(seg);
00277 }
00278
00279 ROS_INFO("Trajectory start requested at %.3lf, waiting...", traj.header.stamp.toSec());
00280 ros::Time::sleepUntil(traj.header.stamp);
00281
00282 ros::Time end_time = traj.header.stamp + ros::Duration(trajectory_duration);
00283 std::vector<ros::Time> seg_end_times(num_points, ros::Time(0.0));
00284
00285 for (int i = 0; i < num_points; ++i)
00286 {
00287 seg_end_times[i] = ros::Time(trajectory[i].start_time + durations[i]);
00288 }
00289
00290 ROS_INFO("Trajectory start time is %.3lf, end time is %.3lf, total duration is %.3lf", time.toSec(), end_time.toSec(), trajectory_duration);
00291
00292 trajectory_ = trajectory;
00293 ros::Time traj_start_time = ros::Time::now();
00294 ros::Rate rate(update_rate_);
00295
00296 for (int seg = 0; seg < num_points; ++seg)
00297 {
00298 ROS_DEBUG("Processing segment %d", seg);
00299
00300
00301 if (durations[seg] == 0.0)
00302 {
00303 ROS_DEBUG("Skipping segment %d becuase duration is 0", seg);
00304 continue;
00305 }
00306
00307 std::map<std::string, std::vector<std::vector<int> > > multi_packet;
00308
00309 std::map<std::string, std::vector<std::string> >::const_iterator pjit;
00310 std::vector<std::string>::const_iterator jit;
00311
00312 for (pjit = port_to_joints_.begin(); pjit != port_to_joints_.end(); ++pjit)
00313 {
00314 std::vector<std::vector<int> > vals;
00315
00316 for (jit = pjit->second.begin(); jit != pjit->second.end(); ++jit)
00317 {
00318 std::string joint = *jit;
00319 int j = joint_to_idx_[joint];
00320
00321 double start_position = joint_states_[joint]->position;
00322 if (seg != 0) { start_position = trajectory[seg-1].positions[j]; }
00323
00324 double desired_position = trajectory[seg].positions[j];
00325 double desired_velocity = std::max<double>(min_velocity_, std::abs(desired_position - start_position) / durations[seg]);
00326
00327 ROS_DEBUG("\tstart_position: %f, duration: %f", start_position, durations[seg]);
00328 ROS_DEBUG("\tport: %s, joint: %s, dpos: %f, dvel: %f", pjit->first.c_str(), joint.c_str(), desired_position, desired_velocity);
00329
00330 std::vector<std::vector<int> > mvcs = joint_to_controller_[joint]->getRawMotorCommands(desired_position, desired_velocity);
00331 for (size_t i = 0; i < mvcs.size(); ++i)
00332 {
00333 vals.push_back(mvcs[i]);
00334 }
00335
00336 multi_packet[pjit->first] = vals;
00337 }
00338 }
00339
00340 std::map<std::string, std::vector<std::vector<int> > >::const_iterator mpit;
00341 for (mpit = multi_packet.begin(); mpit != multi_packet.end(); ++mpit)
00342 {
00343 port_to_io_[mpit->first]->setMultiPositionVelocity(mpit->second);
00344 }
00345
00346 while (time < seg_end_times[seg])
00347 {
00348
00349 if (is_action && action_server_->isPreemptRequested())
00350 {
00351 res.error_code = control_msgs::FollowJointTrajectoryResult::SUCCESSFUL;
00352 error_msg = "New trajectory received. Aborting old trajectory.";
00353
00354 std::map<std::string, std::vector<std::vector<int> > > multi_packet;
00355
00356 std::map<std::string, std::vector<std::string> >::const_iterator pjit;
00357 std::vector<std::string>::const_iterator jit;
00358
00359 for (pjit = port_to_joints_.begin(); pjit != port_to_joints_.end(); ++pjit)
00360 {
00361 std::vector<std::vector<int> > vals;
00362
00363 for (jit = pjit->second.begin(); jit != pjit->second.end(); ++jit)
00364 {
00365 std::string joint = *jit;
00366
00367 double desired_position = joint_states_[joint]->position;
00368 double desired_velocity = joint_states_[joint]->velocity;
00369
00370 std::vector<std::vector<int> > mvcs = joint_to_controller_[joint]->getRawMotorCommands(desired_position, desired_velocity);
00371 for (size_t i = 0; i < mvcs.size(); ++i)
00372 {
00373 vals.push_back(mvcs[i]);
00374 }
00375
00376 multi_packet[pjit->first] = vals;
00377 }
00378 }
00379
00380 std::map<std::string, std::vector<std::vector<int> > >::const_iterator mpit;
00381 for (mpit = multi_packet.begin(); mpit != multi_packet.end(); ++mpit)
00382 {
00383 port_to_io_[mpit->first]->setMultiPositionVelocity(mpit->second);
00384 }
00385
00386 action_server_->setPreempted(res, error_msg);
00387 ROS_WARN("%s", error_msg.c_str());
00388 return;
00389 }
00390
00391 rate.sleep();
00392 time = ros::Time::now();
00393 }
00394
00395
00396 for (size_t j = 0; j < joint_names_.size(); ++j)
00397 {
00398 if (trajectory_constraints_[j] > 0.0 && msg_.error.positions[j] > trajectory_constraints_[j])
00399 {
00400 res.error_code = control_msgs::FollowJointTrajectoryResult::PATH_TOLERANCE_VIOLATED;
00401 error_msg = "Unsatisfied position constraint for " + joint_names_[j] +
00402 " trajectory point " + boost::lexical_cast<std::string>(seg) +
00403 ", " + boost::lexical_cast<std::string>(msg_.error.positions[j]) +
00404 " is larger than " + boost::lexical_cast<std::string>(trajectory_constraints_[j]);
00405 ROS_ERROR("%s", error_msg.c_str());
00406 if (is_action) { action_server_->setAborted(res, error_msg); }
00407 return;
00408 }
00409 }
00410 }
00411
00412
00413 ros::Duration(goal_time_constraint_).sleep();
00414
00415 for (size_t i = 0; i < num_joints_; ++i)
00416 {
00417 if (goal_constraints_[i] > 0 && std::abs(msg_.error.positions[i]) > goal_constraints_[i])
00418 {
00419 res.error_code = control_msgs::FollowJointTrajectoryResult::GOAL_TOLERANCE_VIOLATED;
00420 error_msg = "Aborting because " + joint_names_[i] +
00421 " joint wound up outside the goal constraints, " +
00422 boost::lexical_cast<std::string>(msg_.error.positions[i]) +
00423 " is larger than " + boost::lexical_cast<std::string>(goal_constraints_[i]);
00424 ROS_ERROR("%s", error_msg.c_str());
00425 if (is_action) { action_server_->setAborted(res, error_msg); }
00426 return;
00427 }
00428 }
00429
00430 res.error_code = control_msgs::FollowJointTrajectoryResult::SUCCESSFUL;
00431 error_msg = "Trajectory execution successfully completed";
00432 ROS_INFO("%s", error_msg.c_str());
00433 action_server_->setSucceeded(res, error_msg);
00434 }
00435
00436 }