joint_trajectory_interface.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  * Copyright (c) 2013, 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 #include <algorithm>
00033 #include "motoman_driver/industrial_robot_client/joint_trajectory_interface.h"
00034 #include "motoman_driver/industrial_robot_client/motoman_utils.h"
00035 #include "simple_message/joint_traj_pt.h"
00036 #include "industrial_utils/param_utils.h"
00037 #include <vector>
00038 #include <map>
00039 #include <string>
00040 
00041 using industrial_utils::param::getJointNames;
00042 using industrial_robot_client::motoman_utils::getJointGroups;
00043 using industrial::simple_message::SimpleMessage;
00044 namespace SpecialSeqValues = industrial::joint_traj_pt::SpecialSeqValues;
00045 typedef industrial::joint_traj_pt::JointTrajPt rbt_JointTrajPt;
00046 typedef trajectory_msgs::JointTrajectoryPoint  ros_JointTrajPt;
00047 typedef motoman_msgs::DynamicJointsGroup ros_dynamicPoint;
00048 
00049 namespace industrial_robot_client
00050 {
00051 namespace joint_trajectory_interface
00052 {
00053 
00054 #define ROS_ERROR_RETURN(rtn,...) do {ROS_ERROR(__VA_ARGS__); return(rtn);} while(0)
00055 
00056 bool JointTrajectoryInterface::init(std::string default_ip, int default_port, bool version_0)
00057 {
00058   std::string ip;
00059   int port;
00060 
00061   // override IP/port with ROS params, if available
00062   ros::param::param<std::string>("robot_ip_address", ip, default_ip);
00063   ros::param::param<int>("~port", port, default_port);
00064 
00065   // check for valid parameter values
00066   if (ip.empty())
00067   {
00068     ROS_ERROR("No valid robot IP address found.  Please set ROS 'robot_ip_address' param");
00069     return false;
00070   }
00071   if (port <= 0)
00072   {
00073     ROS_ERROR("No valid robot TCP port found.  Please set ROS '~port' param");
00074     return false;
00075   }
00076 
00077   char* ip_addr = strdup(ip.c_str());  // connection.init() requires "char*", not "const char*"
00078   ROS_INFO("Joint Trajectory Interface connecting to IP address: '%s:%d'", ip_addr, port);
00079   default_tcp_connection_.init(ip_addr, port);
00080   free(ip_addr);
00081 
00082   return init(&default_tcp_connection_);
00083 }
00084 
00085 bool JointTrajectoryInterface::init(SmplMsgConnection* connection)
00086 {
00087   std::map<int, RobotGroup> robot_groups;
00088   if(getJointGroups("topic_list", robot_groups))
00089   {
00090     this->version_0_ = false;
00091     return init(connection, robot_groups);
00092   }
00093   else
00094   {
00095     this->version_0_ = true;
00096     std::vector<std::string> joint_names;
00097     if (!getJointNames("controller_joint_names", "robot_description", joint_names))
00098     {
00099       ROS_WARN("Unable to read 'controller_joint_names' param.  Using standard 6-DOF joint names.");
00100     }
00101     return init(connection, joint_names);
00102   }
00103   return false;
00104 }
00105 
00106 bool JointTrajectoryInterface::init(SmplMsgConnection* connection, const std::vector<std::string> &joint_names,
00107                                     const std::map<std::string, double> &velocity_limits)
00108 {
00109   this->connection_ = connection;
00110   this->all_joint_names_ = joint_names;
00111   this->joint_vel_limits_ = velocity_limits;
00112   connection_->makeConnect();
00113 
00114   // try to read velocity limits from URDF, if none specified
00115   if (joint_vel_limits_.empty()
00116       && !industrial_utils::param::getJointVelocityLimits("robot_description", joint_vel_limits_))
00117     ROS_WARN("Unable to read velocity limits from 'robot_description' param.  Velocity validation disabled.");
00118 
00119 
00120   this->srv_stop_motion_ = this->node_.advertiseService(
00121                              "stop_motion", &JointTrajectoryInterface::stopMotionCB, this);
00122   this->srv_joint_trajectory_ = this->node_.advertiseService(
00123                                   "joint_path_command", &JointTrajectoryInterface::jointTrajectoryCB, this);
00124   this->sub_joint_trajectory_ = this->node_.subscribe(
00125                                   "joint_path_command", 0, &JointTrajectoryInterface::jointTrajectoryCB, this);
00126   this->sub_cur_pos_ = this->node_.subscribe(
00127                          "joint_states", 1, &JointTrajectoryInterface::jointStateCB, this);
00128 
00129   return true;
00130 }
00131 
00132 bool JointTrajectoryInterface::init(
00133   SmplMsgConnection* connection, const std::map<int, RobotGroup> &robot_groups,
00134   const std::map<std::string, double> &velocity_limits)
00135 {
00136   this->connection_ = connection;
00137   this->robot_groups_ = robot_groups;
00138   this->joint_vel_limits_ = velocity_limits;
00139   connection_->makeConnect();
00140 
00141   // try to read velocity limits from URDF, if none specified
00142   if (joint_vel_limits_.empty()
00143       && !industrial_utils::param::getJointVelocityLimits(
00144         "robot_description", joint_vel_limits_))
00145     ROS_WARN("Unable to read velocity limits from 'robot_description' param.  Velocity validation disabled.");
00146 
00147   // General server and subscriber for compounded trajectories
00148   this->srv_joint_trajectory_ = this->node_.advertiseService(
00149                                   "joint_path_command", &JointTrajectoryInterface::jointTrajectoryExCB, this);
00150   this->sub_joint_trajectory_ = this->node_.subscribe(
00151                                   "joint_path_command", 0, &JointTrajectoryInterface::jointTrajectoryExCB, this);
00152   this->srv_stop_motion_ = this->node_.advertiseService(
00153                              "stop_motion", &JointTrajectoryInterface::stopMotionCB, this);
00154 
00155   for (it_type iterator = this->robot_groups_.begin(); iterator != this->robot_groups_.end(); iterator++)
00156   {
00157     std::string name_str, ns_str;
00158     int robot_id = iterator->first;
00159     name_str = iterator->second.get_name();
00160     ns_str = iterator->second.get_ns();
00161 
00162     ros::ServiceServer srv_joint_trajectory;
00163     ros::ServiceServer srv_stop_motion;
00164     ros::Subscriber sub_joint_trajectory;
00165 
00166     srv_stop_motion = this->node_.advertiseService(
00167                         ns_str + "/" + name_str + "/stop_motion",
00168                         &JointTrajectoryInterface::stopMotionCB, this);
00169     srv_joint_trajectory = this->node_.advertiseService(
00170                              ns_str + "/" + name_str + "/joint_path_command",
00171                              &JointTrajectoryInterface::jointTrajectoryExCB, this);
00172     sub_joint_trajectory = this->node_.subscribe(
00173                              ns_str + "/" + name_str + "/joint_path_command", 0,
00174                              &JointTrajectoryInterface::jointTrajectoryExCB, this);
00175 
00176     this->srv_stops_[robot_id] = srv_stop_motion;
00177     this->srv_joints_[robot_id] = srv_joint_trajectory;
00178     this->sub_joint_trajectories_[robot_id] = sub_joint_trajectory;
00179 
00180     this->sub_cur_pos_ = this->node_.subscribe<sensor_msgs::JointState>(
00181                            ns_str + "/" + name_str + "/joint_states", 1,
00182                            boost::bind(&JointTrajectoryInterface::jointStateCB, this, _1, robot_id));
00183 
00184     this->sub_cur_positions_[robot_id] = this->sub_cur_pos_;
00185   }
00186 
00187 
00188   return true;
00189 }
00190 
00191 JointTrajectoryInterface::~JointTrajectoryInterface()
00192 {
00193   trajectoryStop();
00194   this->sub_joint_trajectory_.shutdown();
00195 }
00196 
00197 bool JointTrajectoryInterface::jointTrajectoryExCB(
00198   motoman_msgs::CmdJointTrajectoryEx::Request &req,
00199   motoman_msgs::CmdJointTrajectoryEx::Response &res)
00200 {
00201   motoman_msgs::DynamicJointTrajectoryPtr traj_ptr(
00202     new motoman_msgs::DynamicJointTrajectory);
00203   *traj_ptr = req.trajectory;  // copy message data
00204   this->jointTrajectoryExCB(traj_ptr);
00205 
00206   // no success/fail result from jointTrajectoryCB.  Assume success.
00207   res.code.val = industrial_msgs::ServiceReturnCode::SUCCESS;
00208 
00209   return true;  // always return true.  To distinguish between call-failed and service-unavailable.
00210 }
00211 
00212 
00213 bool JointTrajectoryInterface::jointTrajectoryCB(
00214   industrial_msgs::CmdJointTrajectory::Request &req,
00215   industrial_msgs::CmdJointTrajectory::Response &res)
00216 {
00217   trajectory_msgs::JointTrajectoryPtr traj_ptr(
00218     new trajectory_msgs::JointTrajectory);
00219   *traj_ptr = req.trajectory;  // copy message data
00220   this->jointTrajectoryCB(traj_ptr);
00221 
00222   res.code.val = industrial_msgs::ServiceReturnCode::SUCCESS;
00223 
00224   return true;  // always return true.  To distinguish between call-failed and service-unavailable.
00225 }
00226 
00227 void JointTrajectoryInterface::jointTrajectoryExCB(
00228   const motoman_msgs::DynamicJointTrajectoryConstPtr &msg)
00229 {
00230   ROS_INFO("Receiving joint trajectory message Dynamic");
00231 
00232   // check for STOP command
00233   if (msg->points.empty())
00234   {
00235     ROS_INFO("Empty trajectory received, canceling current trajectory");
00236     trajectoryStop();
00237     return;
00238   }
00239 
00240   // convert trajectory into robot-format
00241   std::vector<SimpleMessage> robot_msgs;
00242   if (!trajectory_to_msgs(msg, &robot_msgs))
00243     return;
00244 
00245   // send command messages to robot
00246   send_to_robot(robot_msgs);
00247 }
00248 
00249 
00250 void JointTrajectoryInterface::jointTrajectoryCB(
00251   const trajectory_msgs::JointTrajectoryConstPtr &msg)
00252 {
00253   ROS_INFO("Receiving joint trajectory message");
00254 
00255   // check for STOP command
00256   if (msg->points.empty())
00257   {
00258     ROS_INFO("Empty trajectory received, canceling current trajectory");
00259     trajectoryStop();
00260     return;
00261   }
00262 
00263   // convert trajectory into robot-format
00264   std::vector<SimpleMessage> robot_msgs;
00265   if (!trajectory_to_msgs(msg, &robot_msgs))
00266     return;
00267 
00268   // send command messages to robot
00269   send_to_robot(robot_msgs);
00270 }
00271 
00272 bool JointTrajectoryInterface::trajectory_to_msgs(
00273   const motoman_msgs::DynamicJointTrajectoryConstPtr& traj,
00274   std::vector<SimpleMessage>* msgs)
00275 {
00276   msgs->clear();
00277 
00278   std::vector<double>::iterator it;
00279 
00280   if (traj->points[0].num_groups == 1)
00281   {
00282     // check for valid trajectory
00283     if (!is_valid(*traj))
00284     {
00285       return false;
00286     }
00287 
00288     for (size_t i = 0; i < traj->points.size(); ++i)
00289     {
00290       SimpleMessage msg;
00291       ros_dynamicPoint rbt_pt, xform_pt;
00292 
00293 
00294       if (!select(traj->joint_names, traj->points[i].groups[0],
00295                   robot_groups_[traj->points[i].groups[0].group_number].get_joint_names(),
00296                   &rbt_pt))
00297         return false;
00298 
00299       // transform point data (e.g. for joint-coupling)
00300       if (!transform(rbt_pt, &xform_pt))
00301         return false;
00302 
00303       // convert trajectory point to ROS message
00304       if (!create_message(i, xform_pt, &msg))
00305         return false;
00306 
00307       msgs->push_back(msg);
00308     }
00309   }
00310   // TODO(thiagodefreitas) : get MAX_NUM_GROUPS for the FS100 controller
00311   else if (traj->points[0].num_groups <= 4)
00312   {
00313     for (size_t i = 0; i < traj->points.size(); ++i)
00314     {
00315       SimpleMessage msg;
00316       create_message_ex(i, traj->points[i], &msg);
00317       msgs->push_back(msg);
00318     }
00319   }
00320   return true;
00321 }
00322 
00323 bool JointTrajectoryInterface::trajectory_to_msgs(
00324   const trajectory_msgs::JointTrajectoryConstPtr& traj,
00325   std::vector<SimpleMessage>* msgs)
00326 {
00327   msgs->clear();
00328 
00329   // check for valid trajectory
00330   if (!is_valid(*traj))
00331     return false;
00332 
00333   for (size_t i = 0; i < traj->points.size(); ++i)
00334   {
00335     SimpleMessage msg;
00336     ros_JointTrajPt rbt_pt, xform_pt;
00337 
00338     // select / reorder joints for sending to robot
00339     if (!select(traj->joint_names, traj->points[i],
00340                 this->all_joint_names_, &rbt_pt))
00341       return false;
00342 
00343     // transform point data (e.g. for joint-coupling)
00344     if (!transform(rbt_pt, &xform_pt))
00345       return false;
00346 
00347     // convert trajectory point to ROS message
00348     if (!create_message(i, xform_pt, &msg))
00349       return false;
00350 
00351     msgs->push_back(msg);
00352   }
00353 
00354   return true;
00355 }
00356 
00357 bool JointTrajectoryInterface::select(
00358   const std::vector<std::string>& ros_joint_names,
00359   const ros_dynamicPoint& ros_pt,
00360   const std::vector<std::string>& rbt_joint_names, ros_dynamicPoint* rbt_pt)
00361 {
00362   ROS_ASSERT(ros_joint_names.size() == ros_pt.positions.size());
00363   // initialize rbt_pt
00364   *rbt_pt = ros_pt;
00365   rbt_pt->positions.clear();
00366   rbt_pt->velocities.clear();
00367   rbt_pt->accelerations.clear();
00368 
00369   for (size_t rbt_idx = 0; rbt_idx < rbt_joint_names.size(); ++rbt_idx)
00370   {
00371     bool is_empty = rbt_joint_names[rbt_idx].empty();
00372 
00373     // find matching ROS element
00374     size_t ros_idx = std::find(ros_joint_names.begin(),
00375                                ros_joint_names.end(),
00376                                rbt_joint_names[rbt_idx]) - ros_joint_names.begin();
00377     bool is_found = ros_idx < ros_joint_names.size();
00378 
00379 
00380     // error-chk: required robot joint not found in ROS joint-list
00381     if (!is_empty && !is_found)
00382     {
00383       ROS_ERROR("Expected joint (%s) not found in JointTrajectory.Aborting command.",
00384                 rbt_joint_names[rbt_idx].c_str());
00385       return false;
00386     }
00387 
00388     if (is_empty)
00389     {
00390       if (!ros_pt.positions.empty()) rbt_pt->positions.push_back(default_joint_pos_);
00391       if (!ros_pt.velocities.empty()) rbt_pt->velocities.push_back(-1);
00392       if (!ros_pt.accelerations.empty()) rbt_pt->accelerations.push_back(-1);
00393     }
00394     else
00395     {
00396       if (!ros_pt.positions.empty())
00397         rbt_pt->positions.push_back(ros_pt.positions[ros_idx]);
00398       if (!ros_pt.velocities.empty())
00399         rbt_pt->velocities.push_back(ros_pt.velocities[ros_idx]);
00400       if (!ros_pt.accelerations.empty())
00401         rbt_pt->accelerations.push_back(ros_pt.accelerations[ros_idx]);
00402     }
00403   }
00404   return true;
00405 }
00406 
00407 
00408 bool JointTrajectoryInterface::select(
00409   const std::vector<std::string>& ros_joint_names,
00410   const ros_JointTrajPt& ros_pt, const std::vector<std::string>& rbt_joint_names,
00411   ros_JointTrajPt* rbt_pt)
00412 {
00413   ROS_ASSERT(ros_joint_names.size() == ros_pt.positions.size());
00414   // initialize rbt_pt
00415   *rbt_pt = ros_pt;
00416   rbt_pt->positions.clear();
00417   rbt_pt->velocities.clear();
00418   rbt_pt->accelerations.clear();
00419 
00420   for (size_t rbt_idx = 0; rbt_idx < rbt_joint_names.size(); ++rbt_idx)
00421   {
00422     bool is_empty = rbt_joint_names[rbt_idx].empty();
00423 
00424     // find matching ROS element
00425     size_t ros_idx = std::find(ros_joint_names.begin(), ros_joint_names.end(),
00426                                rbt_joint_names[rbt_idx]) - ros_joint_names.begin();
00427     bool is_found = ros_idx < ros_joint_names.size();
00428 
00429     // error-chk: required robot joint not found in ROS joint-list
00430     if (!is_empty && !is_found)
00431     {
00432       ROS_ERROR("Expected joint (%s) not found in JointTrajectory.  Aborting command.",
00433                 rbt_joint_names[rbt_idx].c_str());
00434       return false;
00435     }
00436 
00437     if (is_empty)
00438     {
00439       if (!ros_pt.positions.empty()) rbt_pt->positions.push_back(default_joint_pos_);
00440       if (!ros_pt.velocities.empty()) rbt_pt->velocities.push_back(-1);
00441       if (!ros_pt.accelerations.empty()) rbt_pt->accelerations.push_back(-1);
00442     }
00443     else
00444     {
00445       if (!ros_pt.positions.empty()) rbt_pt->positions.push_back(ros_pt.positions[ros_idx]);
00446       if (!ros_pt.velocities.empty()) rbt_pt->velocities.push_back(ros_pt.velocities[ros_idx]);
00447       if (!ros_pt.accelerations.empty()) rbt_pt->accelerations.push_back(ros_pt.accelerations[ros_idx]);
00448     }
00449   }
00450   return true;
00451 }
00452 
00453 // default velocity calculation computes the %-of-max-velocity for the "critical joint" (closest to velocity-limit)
00454 // such that 0.2 = 20% of maximum joint speed.
00455 //
00456 // NOTE: this calculation uses the maximum joint speeds from the URDF file, which may differ from those defined on
00457 // the physical robot.  These differences could lead to different actual movement velocities than intended.
00458 // Behavior should be verified on a physical robot if movement velocity is critical.
00459 bool JointTrajectoryInterface::calc_velocity(
00460   const trajectory_msgs::JointTrajectoryPoint& pt, double* rbt_velocity)
00461 {
00462   std::vector<double> vel_ratios;
00463 
00464   ROS_ASSERT(all_joint_names_.size() == pt.positions.size());
00465 
00466   // check for empty velocities in ROS topic
00467   if (pt.velocities.empty())
00468   {
00469     ROS_WARN("Joint velocities unspecified.  Using default/safe speed.");
00470     *rbt_velocity = default_vel_ratio_;
00471     return true;
00472   }
00473 
00474   for (size_t i = 0; i < all_joint_names_.size(); ++i)
00475   {
00476     const std::string &jnt_name = all_joint_names_[i];
00477 
00478     // update vel_ratios
00479     if (jnt_name.empty())                             // ignore "dummy joints" in velocity calcs
00480       vel_ratios.push_back(-1);
00481     else if (joint_vel_limits_.count(jnt_name) == 0)  // no velocity limit specified for this joint
00482       vel_ratios.push_back(-1);
00483     else
00484       vel_ratios.push_back(fabs(pt.velocities[i] / joint_vel_limits_[jnt_name]));    // calculate expected duration for this joint
00485   }
00486 
00487   // find largest velocity-ratio (closest to max joint-speed)
00488   int max_idx = std::max_element(vel_ratios.begin(), vel_ratios.end()) - vel_ratios.begin();
00489 
00490   if (vel_ratios[max_idx] > 0)
00491     *rbt_velocity = vel_ratios[max_idx];
00492   else
00493   {
00494     ROS_WARN_ONCE("Joint velocity-limits unspecified.  Using default velocity-ratio.");
00495     *rbt_velocity = default_vel_ratio_;
00496   }
00497 
00498   if ((*rbt_velocity < 0) || (*rbt_velocity > 1))
00499   {
00500     ROS_WARN("computed velocity (%.1f %%) is out-of-range.  Clipping to [0-100%%]", *rbt_velocity * 100);
00501     *rbt_velocity = std::min(1.0, std::max(0.0, *rbt_velocity));  // clip to [0,1]
00502   }
00503 
00504   return true;
00505 }
00506 
00507 bool JointTrajectoryInterface::calc_velocity(const motoman_msgs::DynamicJointsGroup& pt, double* rbt_velocity)
00508 {
00509   std::vector<double> vel_ratios;
00510 
00511   // check for empty velocities in ROS topic
00512   if (pt.velocities.empty())
00513   {
00514     ROS_WARN("Joint velocities unspecified.  Using default/safe speed.");
00515     *rbt_velocity = default_vel_ratio_;
00516     return true;
00517   }
00518 
00519   robot_groups_[pt.group_number].get_joint_names();
00520   for (size_t i = 0; i < robot_groups_[pt.group_number].get_joint_names().size(); ++i)
00521   {
00522     const std::string &jnt_name = robot_groups_[pt.group_number].get_joint_names()[i];
00523 
00524     // update vel_ratios
00525     if (jnt_name.empty())                             // ignore "dummy joints" in velocity calcs
00526       vel_ratios.push_back(-1);
00527     else if (joint_vel_limits_.count(jnt_name) == 0)  // no velocity limit specified for this joint
00528       vel_ratios.push_back(-1);
00529     else
00530       vel_ratios.push_back(fabs(pt.velocities[i] / joint_vel_limits_[jnt_name]));    // calculate expected duration for this joint
00531   }
00532 
00533   // find largest velocity-ratio (closest to max joint-speed)
00534   int max_idx = std::max_element(vel_ratios.begin(), vel_ratios.end()) - vel_ratios.begin();
00535 
00536   if (vel_ratios[max_idx] > 0)
00537     *rbt_velocity = vel_ratios[max_idx];
00538   else
00539   {
00540     ROS_WARN_ONCE("Joint velocity-limits unspecified.  Using default velocity-ratio.");
00541     *rbt_velocity = default_vel_ratio_;
00542   }
00543 
00544   if ((*rbt_velocity < 0) || (*rbt_velocity > 1))
00545   {
00546     ROS_WARN("computed velocity (%.1f %%) is out-of-range.  Clipping to [0-100%%]", *rbt_velocity * 100);
00547     *rbt_velocity = std::min(1.0, std::max(0.0, *rbt_velocity));  // clip to [0,1]
00548   }
00549 
00550   return true;
00551 }
00552 
00553 bool JointTrajectoryInterface::calc_duration
00554 (const trajectory_msgs::JointTrajectoryPoint& pt, double* rbt_duration)
00555 {
00556   std::vector<double> durations;
00557   double this_time = pt.time_from_start.toSec();
00558   static double last_time = 0;
00559 
00560   if (this_time <= last_time)  // earlier time => new trajectory.  Move slowly to first point.
00561     *rbt_duration = default_duration_;
00562   else
00563     *rbt_duration = this_time - last_time;
00564 
00565   last_time = this_time;
00566 
00567   return true;
00568 }
00569 
00570 bool JointTrajectoryInterface::calc_duration(
00571   const motoman_msgs::DynamicJointsGroup& pt, double* rbt_duration)
00572 {
00573   std::vector<double> durations;
00574   double this_time = pt.time_from_start.toSec();
00575   static double last_time = 0;
00576 
00577   if (this_time <= last_time)  // earlier time => new trajectory.  Move slowly to first point.
00578     *rbt_duration = default_duration_;
00579   else
00580     *rbt_duration = this_time - last_time;
00581 
00582   last_time = this_time;
00583 
00584   return true;
00585 }
00586 
00587 bool JointTrajectoryInterface::create_message(
00588   int seq, const motoman_msgs::DynamicJointsGroup &pt, SimpleMessage *msg)
00589 {
00590   industrial::joint_data::JointData pos;
00591 
00592   for (size_t i = 0; i < pt.positions.size(); ++i)
00593   {
00594     pos.setJoint(i, pt.positions[i]);
00595   }
00596 
00597   // calculate velocity & duration
00598   double velocity, duration;
00599   if (!calc_velocity(pt, &velocity) || !calc_duration(pt, &duration))
00600     return false;
00601 
00602   rbt_JointTrajPt msg_data;
00603   msg_data.init(seq, pos, velocity, duration);
00604 
00605   JointTrajPtMessage jtp_msg;
00606   jtp_msg.init(msg_data);
00607 
00608   return jtp_msg.toTopic(*msg);  // assume "topic" COMM_TYPE for now
00609 }
00610 
00611 bool JointTrajectoryInterface::create_message_ex(
00612   int seq, const motoman_msgs::DynamicJointPoint &pt, SimpleMessage *msg)
00613 {
00614   return true;
00615 }
00616 
00617 bool JointTrajectoryInterface::create_message(
00618   int seq, const trajectory_msgs::JointTrajectoryPoint &pt, SimpleMessage *msg)
00619 {
00620   industrial::joint_data::JointData pos;
00621   ROS_ASSERT(pt.positions.size() <= (unsigned int)pos.getMaxNumJoints());
00622 
00623   for (size_t i = 0; i < pt.positions.size(); ++i)
00624     pos.setJoint(i, pt.positions[i]);
00625 
00626   // calculate velocity & duration
00627   double velocity, duration;
00628   if (!calc_velocity(pt, &velocity) || !calc_duration(pt, &duration))
00629     return false;
00630 
00631   rbt_JointTrajPt msg_data;
00632   msg_data.init(seq, pos, velocity, duration);
00633 
00634   JointTrajPtMessage jtp_msg;
00635   jtp_msg.init(msg_data);
00636 
00637   return jtp_msg.toTopic(*msg);  // assume "topic" COMM_TYPE for now
00638 }
00639 
00640 void JointTrajectoryInterface::trajectoryStop()
00641 {
00642   JointTrajPtMessage jMsg;
00643   SimpleMessage msg, reply;
00644 
00645   ROS_INFO("Joint trajectory handler: entering stopping state");
00646   jMsg.setSequence(SpecialSeqValues::STOP_TRAJECTORY);
00647   jMsg.toRequest(msg);
00648   ROS_DEBUG("Sending stop command");
00649   this->connection_->sendAndReceiveMsg(msg, reply);
00650 }
00651 
00652 bool JointTrajectoryInterface::stopMotionCB(
00653   industrial_msgs::StopMotion::Request &req,
00654   industrial_msgs::StopMotion::Response &res)
00655 {
00656   trajectoryStop();
00657 
00658   // no success/fail result from trajectoryStop.  Assume success.
00659   res.code.val = industrial_msgs::ServiceReturnCode::SUCCESS;
00660 
00661   return true;  // always return true.  To distinguish between call-failed and service-unavailable.
00662 }
00663 
00664 bool JointTrajectoryInterface::is_valid(const trajectory_msgs::JointTrajectory &traj)
00665 {
00666   for (int i = 0; i < traj.points.size(); ++i)
00667   {
00668     const trajectory_msgs::JointTrajectoryPoint &pt = traj.points[i];
00669 
00670     // check for non-empty positions
00671     if (pt.positions.empty())
00672       ROS_ERROR_RETURN(false, "Validation failed: Missing position data for trajectory pt %d", i);
00673 
00674     // check for joint velocity limits
00675     for (int j = 0; j < pt.velocities.size(); ++j)
00676     {
00677       std::map<std::string, double>::iterator max_vel = joint_vel_limits_.find(traj.joint_names[j]);
00678       if (max_vel == joint_vel_limits_.end()) continue;  // no velocity-checking if limit not defined
00679 
00680       if (std::abs(pt.velocities[j]) > max_vel->second)
00681         ROS_ERROR_RETURN(false, "Validation failed: Max velocity exceeded for trajectory pt %d, joint '%s'", i, traj.joint_names[j].c_str());
00682     }
00683 
00684     // check for valid timestamp
00685     if ((i > 0) && (pt.time_from_start.toSec() == 0))
00686       ROS_ERROR_RETURN(false, "Validation failed: Missing valid timestamp data for trajectory pt %d", i);
00687   }
00688 
00689   return true;
00690 }
00691 
00692 bool JointTrajectoryInterface::is_valid(const motoman_msgs::DynamicJointTrajectory &traj)
00693 {
00694   for (int i = 0; i < traj.points.size(); ++i)
00695   {
00696     for (int gr = 0; gr < traj.points[i].num_groups; gr++)
00697     {
00698       const motoman_msgs::DynamicJointsGroup &pt = traj.points[i].groups[gr];
00699 
00700       // check for non-empty positions
00701       if (pt.positions.empty())
00702         ROS_ERROR_RETURN(false, "Validation failed: Missing position data for trajectory pt %d", i);
00703       // check for joint velocity limits
00704       for (int j = 0; j < pt.velocities.size(); ++j)
00705       {
00706         std::map<std::string, double>::iterator max_vel = joint_vel_limits_.find(traj.joint_names[j]);
00707         if (max_vel == joint_vel_limits_.end()) continue;  // no velocity-checking if limit not defined
00708 
00709         if (std::abs(pt.velocities[j]) > max_vel->second)
00710           ROS_ERROR_RETURN(false, "Validation failed: Max velocity exceeded for trajectory pt %d, joint '%s'", i, traj.joint_names[j].c_str());
00711       }
00712 
00713       // check for valid timestamp
00714       if ((i > 0) && (pt.time_from_start.toSec() == 0))
00715         ROS_ERROR_RETURN(false, "Validation failed: Missing valid timestamp data for trajectory pt %d", i);
00716     }
00717   }
00718   return true;
00719 }
00720 
00721 // copy robot JointState into local cache
00722 void JointTrajectoryInterface::jointStateCB(
00723   const sensor_msgs::JointStateConstPtr &msg)
00724 {
00725   this->cur_joint_pos_ = *msg;
00726 }
00727 
00728 void JointTrajectoryInterface::jointStateCB(
00729   const sensor_msgs::JointStateConstPtr &msg, int robot_id)
00730 {
00731   this->cur_joint_pos_map_[robot_id] = *msg;
00732 }
00733 
00734 }  // namespace joint_trajectory_interface
00735 }   // namespace industrial_robot_client
00736 


motoman_driver
Author(s): Jeremy Zoss (Southwest Research Institute)
autogenerated on Sat Jun 8 2019 19:06:57