ur_ros_wrapper.cpp
Go to the documentation of this file.
00001 /*
00002  * ur_driver.cpp
00003  *
00004  * Copyright 2015 Thomas Timm Andersen
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  *     http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 
00019 #include "ur_modern_driver/ur_driver.h"
00020 #include "ur_modern_driver/ur_hardware_interface.h"
00021 #include "ur_modern_driver/do_output.h"
00022 #include <string.h>
00023 #include <vector>
00024 #include <mutex>
00025 #include <condition_variable>
00026 #include <thread>
00027 #include <algorithm>
00028 #include <cmath>
00029 #include <chrono>
00030 #include <time.h>
00031 
00032 #include "ros/ros.h"
00033 #include <ros/console.h>
00034 #include "sensor_msgs/JointState.h"
00035 #include "geometry_msgs/WrenchStamped.h"
00036 #include "geometry_msgs/PoseStamped.h"
00037 #include "control_msgs/FollowJointTrajectoryAction.h"
00038 #include "actionlib/server/action_server.h"
00039 #include "actionlib/server/server_goal_handle.h"
00040 #include "trajectory_msgs/JointTrajectoryPoint.h"
00041 #include "ur_msgs/SetIO.h"
00042 #include "ur_msgs/SetPayload.h"
00043 #include "ur_msgs/SetPayloadRequest.h"
00044 #include "ur_msgs/SetPayloadResponse.h"
00045 #include "ur_msgs/SetIORequest.h"
00046 #include "ur_msgs/SetIOResponse.h"
00047 #include "ur_msgs/IOStates.h"
00048 #include "ur_msgs/Digital.h"
00049 #include "ur_msgs/Analog.h"
00050 #include "std_msgs/String.h"
00051 #include <controller_manager/controller_manager.h>
00052 #include <realtime_tools/realtime_publisher.h>
00053 
00055 #include <tf/tf.h>
00056 #include <tf/transform_broadcaster.h>
00057 
00058 class RosWrapper {
00059 protected:
00060         UrDriver robot_;
00061         std::condition_variable rt_msg_cond_;
00062         std::condition_variable msg_cond_;
00063         ros::NodeHandle nh_;
00064         actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction> as_;
00065         actionlib::ServerGoalHandle<control_msgs::FollowJointTrajectoryAction> goal_handle_;
00066         bool has_goal_;
00067         control_msgs::FollowJointTrajectoryFeedback feedback_;
00068         control_msgs::FollowJointTrajectoryResult result_;
00069         ros::Subscriber speed_sub_;
00070         ros::Subscriber urscript_sub_;
00071         ros::ServiceServer io_srv_;
00072         ros::ServiceServer payload_srv_;
00073         std::thread* rt_publish_thread_;
00074         std::thread* mb_publish_thread_;
00075         double io_flag_delay_;
00076         double max_velocity_;
00077         std::vector<double> joint_offsets_;
00078     std::string base_frame_;
00079     std::string tool_frame_;
00080         bool use_ros_control_;
00081         std::thread* ros_control_thread_;
00082         boost::shared_ptr<ros_control_ur::UrHardwareInterface> hardware_interface_;
00083         boost::shared_ptr<controller_manager::ControllerManager> controller_manager_;
00084 
00085 public:
00086         RosWrapper(std::string host, int reverse_port) :
00087                         as_(nh_, "follow_joint_trajectory",
00088                                         boost::bind(&RosWrapper::goalCB, this, _1),
00089                                         boost::bind(&RosWrapper::cancelCB, this, _1), false), robot_(
00090                                         rt_msg_cond_, msg_cond_, host, reverse_port, 0.03, 300), io_flag_delay_(0.05), joint_offsets_(
00091                                         6, 0.0) {
00092 
00093                 std::string joint_prefix = "";
00094                 std::vector<std::string> joint_names;
00095                 char buf[256];
00096 
00097                 if (ros::param::get("~prefix", joint_prefix)) {
00098                     if (joint_prefix.length() > 0) {
00099                         sprintf(buf, "Setting prefix to %s", joint_prefix.c_str());
00100                         print_info(buf);
00101                 }       
00102         }
00103                 joint_names.push_back(joint_prefix + "shoulder_pan_joint");
00104                 joint_names.push_back(joint_prefix + "shoulder_lift_joint");
00105                 joint_names.push_back(joint_prefix + "elbow_joint");
00106                 joint_names.push_back(joint_prefix + "wrist_1_joint");
00107                 joint_names.push_back(joint_prefix + "wrist_2_joint");
00108                 joint_names.push_back(joint_prefix + "wrist_3_joint");
00109                 robot_.setJointNames(joint_names);
00110 
00111                 use_ros_control_ = false;
00112                 ros::param::get("~use_ros_control", use_ros_control_);
00113 
00114                 if (use_ros_control_) {
00115                         hardware_interface_.reset(
00116                                         new ros_control_ur::UrHardwareInterface(nh_, &robot_));
00117                         controller_manager_.reset(
00118                                         new controller_manager::ControllerManager(
00119                                                         hardware_interface_.get(), nh_));
00120                         double max_vel_change = 0.12; // equivalent of an acceleration of 15 rad/sec^2
00121                         if (ros::param::get("~max_acceleration", max_vel_change)) {
00122                                 max_vel_change = max_vel_change / 125;
00123                         }
00124                         sprintf(buf, "Max acceleration set to: %f [rad/secĀ²]",
00125                                         max_vel_change * 125);
00126                         print_debug(buf);
00127                         hardware_interface_->setMaxVelChange(max_vel_change);
00128                 }
00129                 //Using a very high value in order to not limit execution of trajectories being sent from MoveIt!
00130                 max_velocity_ = 10.;
00131                 if (ros::param::get("~max_velocity", max_velocity_)) {
00132                         sprintf(buf, "Max velocity accepted by ur_driver: %f [rad/s]",
00133                                         max_velocity_);
00134                         print_debug(buf);
00135                 }
00136 
00137                 //Bounds for SetPayload service
00138                 //Using a very conservative value as it should be set through the parameter server
00139                 double min_payload = 0.;
00140                 double max_payload = 1.;
00141                 if (ros::param::get("~min_payload", min_payload)) {
00142                         sprintf(buf, "Min payload set to: %f [kg]", min_payload);
00143                         print_debug(buf);
00144                 }
00145                 if (ros::param::get("~max_payload", max_payload)) {
00146                         sprintf(buf, "Max payload set to: %f [kg]", max_payload);
00147                         print_debug(buf);
00148                 }
00149                 robot_.setMinPayload(min_payload);
00150                 robot_.setMaxPayload(max_payload);
00151                 sprintf(buf, "Bounds for set_payload service calls: [%f, %f]",
00152                                 min_payload, max_payload);
00153                 print_debug(buf);
00154 
00155                 double servoj_time = 0.008;
00156                 if (ros::param::get("~servoj_time", servoj_time)) {
00157                         sprintf(buf, "Servoj_time set to: %f [sec]", servoj_time);
00158                         print_debug(buf);
00159                 }
00160                 robot_.setServojTime(servoj_time);
00161 
00162                 double servoj_lookahead_time = 0.03;
00163                 if (ros::param::get("~servoj_lookahead_time", servoj_lookahead_time)) {
00164                         sprintf(buf, "Servoj_lookahead_time set to: %f [sec]", servoj_lookahead_time);
00165                         print_debug(buf);
00166                 }
00167                 robot_.setServojLookahead(servoj_lookahead_time);
00168 
00169                 double servoj_gain = 300.;
00170                 if (ros::param::get("~servoj_gain", servoj_gain)) {
00171                         sprintf(buf, "Servoj_gain set to: %f [sec]", servoj_gain);
00172                         print_debug(buf);
00173                 }
00174                 robot_.setServojGain(servoj_gain);
00175 
00176         //Base and tool frames
00177         base_frame_ = joint_prefix + "base_link";
00178         tool_frame_ =  joint_prefix + "tool0_controller";
00179         if (ros::param::get("~base_frame", base_frame_)) {
00180             sprintf(buf, "Base frame set to: %s", base_frame_.c_str());
00181             print_debug(buf);
00182         }
00183         if (ros::param::get("~tool_frame", tool_frame_)) {
00184             sprintf(buf, "Tool frame set to: %s", tool_frame_.c_str());
00185             print_debug(buf);
00186         }
00187 
00188                 if (robot_.start()) {
00189                         if (use_ros_control_) {
00190                                 ros_control_thread_ = new std::thread(
00191                                                 boost::bind(&RosWrapper::rosControlLoop, this));
00192                                 print_debug(
00193                                                 "The control thread for this driver has been started");
00194                         } else {
00195                                 //start actionserver
00196                                 has_goal_ = false;
00197                                 as_.start();
00198 
00199                                 //subscribe to the data topic of interest
00200                                 rt_publish_thread_ = new std::thread(
00201                                                 boost::bind(&RosWrapper::publishRTMsg, this));
00202                                 print_debug(
00203                                                 "The action server for this driver has been started");
00204                         }
00205                         mb_publish_thread_ = new std::thread(
00206                                         boost::bind(&RosWrapper::publishMbMsg, this));
00207                         speed_sub_ = nh_.subscribe("ur_driver/joint_speed", 1,
00208                                         &RosWrapper::speedInterface, this);
00209                         urscript_sub_ = nh_.subscribe("ur_driver/URScript", 1,
00210                                         &RosWrapper::urscriptInterface, this);
00211 
00212                         io_srv_ = nh_.advertiseService("ur_driver/set_io",
00213                                         &RosWrapper::setIO, this);
00214                         payload_srv_ = nh_.advertiseService("ur_driver/set_payload",
00215                                         &RosWrapper::setPayload, this);
00216                 }
00217         }
00218 
00219         void halt() {
00220                 robot_.halt();
00221                 rt_publish_thread_->join();
00222 
00223         }
00224 private:
00225         void trajThread(std::vector<double> timestamps,
00226                         std::vector<std::vector<double> > positions,
00227                         std::vector<std::vector<double> > velocities) {
00228 
00229                 robot_.doTraj(timestamps, positions, velocities);
00230                 if (has_goal_) {
00231                         result_.error_code = result_.SUCCESSFUL;
00232                         goal_handle_.setSucceeded(result_);
00233                         has_goal_ = false;
00234                 }
00235         }
00236         void goalCB(
00237                         actionlib::ServerGoalHandle<
00238                                         control_msgs::FollowJointTrajectoryAction> gh) {
00239                 std::string buf;
00240                 print_info("on_goal");
00241                 if (!robot_.sec_interface_->robot_state_->isReady()) {
00242                         result_.error_code = -100; //nothing is defined for this...?
00243 
00244                         if (!robot_.sec_interface_->robot_state_->isPowerOnRobot()) {
00245                                 result_.error_string =
00246                                                 "Cannot accept new trajectories: Robot arm is not powered on";
00247                                 gh.setRejected(result_, result_.error_string);
00248                                 print_error(result_.error_string);
00249                                 return;
00250                         }
00251                         if (!robot_.sec_interface_->robot_state_->isRealRobotEnabled()) {
00252                                 result_.error_string =
00253                                                 "Cannot accept new trajectories: Robot is not enabled";
00254                                 gh.setRejected(result_, result_.error_string);
00255                                 print_error(result_.error_string);
00256                                 return;
00257                         }
00258                         result_.error_string =
00259                                         "Cannot accept new trajectories. (Debug: Robot mode is "
00260                                                         + std::to_string(
00261                                                                         robot_.sec_interface_->robot_state_->getRobotMode())
00262                                                         + ")";
00263                         gh.setRejected(result_, result_.error_string);
00264                         print_error(result_.error_string);
00265                         return;
00266                 }
00267                 if (robot_.sec_interface_->robot_state_->isEmergencyStopped()) {
00268                         result_.error_code = -100; //nothing is defined for this...?
00269                         result_.error_string =
00270                                         "Cannot accept new trajectories: Robot is emergency stopped";
00271                         gh.setRejected(result_, result_.error_string);
00272                         print_error(result_.error_string);
00273                         return;
00274                 }
00275                 if (robot_.sec_interface_->robot_state_->isProtectiveStopped()) {
00276                         result_.error_code = -100; //nothing is defined for this...?
00277                         result_.error_string =
00278                                         "Cannot accept new trajectories: Robot is protective stopped";
00279                         gh.setRejected(result_, result_.error_string);
00280                         print_error(result_.error_string);
00281                         return;
00282                 }
00283 
00284                 actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction>::Goal goal =
00285                                 *gh.getGoal(); //make a copy that we can modify
00286                 if (has_goal_) {
00287                         print_warning(
00288                                         "Received new goal while still executing previous trajectory. Canceling previous trajectory");
00289                         has_goal_ = false;
00290                         robot_.stopTraj();
00291                         result_.error_code = -100; //nothing is defined for this...?
00292                         result_.error_string = "Received another trajectory";
00293                         goal_handle_.setAborted(result_, result_.error_string);
00294                         std::this_thread::sleep_for(std::chrono::milliseconds(250));
00295                 }
00296                 goal_handle_ = gh;
00297                 if (!validateJointNames()) {
00298                         std::string outp_joint_names = "";
00299                         for (unsigned int i = 0; i < goal.trajectory.joint_names.size();
00300                                         i++) {
00301                                 outp_joint_names += goal.trajectory.joint_names[i] + " ";
00302                         }
00303                         result_.error_code = result_.INVALID_JOINTS;
00304                         result_.error_string =
00305                                         "Received a goal with incorrect joint names: "
00306                                                         + outp_joint_names;
00307                         gh.setRejected(result_, result_.error_string);
00308                         print_error(result_.error_string);
00309                         return;
00310                 }
00311                 if (!has_positions()) {
00312                         result_.error_code = result_.INVALID_GOAL;
00313                         result_.error_string = "Received a goal without positions";
00314                         gh.setRejected(result_, result_.error_string);
00315                         print_error(result_.error_string);
00316                         return;
00317                 }
00318         
00319                 if (!has_velocities()) {
00320                         result_.error_code = result_.INVALID_GOAL;
00321                         result_.error_string = "Received a goal without velocities";
00322                         gh.setRejected(result_, result_.error_string);
00323                         print_error(result_.error_string);
00324                         return;
00325                 }
00326 
00327                 if (!traj_is_finite()) {
00328                         result_.error_string = "Received a goal with infinities or NaNs";
00329                         result_.error_code = result_.INVALID_GOAL;
00330                         gh.setRejected(result_, result_.error_string);
00331                         print_error(result_.error_string);
00332                         return;
00333                 }
00334 
00335                 if (!has_limited_velocities()) {
00336                         result_.error_code = result_.INVALID_GOAL;
00337                         result_.error_string =
00338                                         "Received a goal with velocities that are higher than "
00339                                                         + std::to_string(max_velocity_);
00340                         gh.setRejected(result_, result_.error_string);
00341                         print_error(result_.error_string);
00342                         return;
00343                 }
00344 
00345                 reorder_traj_joints(goal.trajectory);
00346                 
00347                 if (!start_positions_match(goal.trajectory, 0.01)) {
00348                         result_.error_code = result_.INVALID_GOAL;
00349                         result_.error_string = "Goal start doesn't match current pose";
00350                         gh.setRejected(result_, result_.error_string);
00351                         print_error(result_.error_string);
00352                         return;
00353                 }
00354 
00355                 std::vector<double> timestamps;
00356                 std::vector<std::vector<double> > positions, velocities;
00357                 if (goal.trajectory.points[0].time_from_start.toSec() != 0.) {
00358                         print_warning(
00359                                         "Trajectory's first point should be the current position, with time_from_start set to 0.0 - Inserting point in malformed trajectory");
00360                         timestamps.push_back(0.0);
00361                         positions.push_back(
00362                                         robot_.rt_interface_->robot_state_->getQActual());
00363                         velocities.push_back(
00364                                         robot_.rt_interface_->robot_state_->getQdActual());
00365                 }
00366                 for (unsigned int i = 0; i < goal.trajectory.points.size(); i++) {
00367                         timestamps.push_back(
00368                                         goal.trajectory.points[i].time_from_start.toSec());
00369                         positions.push_back(goal.trajectory.points[i].positions);
00370                         velocities.push_back(goal.trajectory.points[i].velocities);
00371 
00372                 }
00373 
00374                 goal_handle_.setAccepted();
00375                 has_goal_ = true;
00376                 std::thread(&RosWrapper::trajThread, this, timestamps, positions,
00377                                 velocities).detach();
00378         }
00379 
00380         void cancelCB(
00381                         actionlib::ServerGoalHandle<
00382                                         control_msgs::FollowJointTrajectoryAction> gh) {
00383                 // set the action state to preempted
00384                 print_info("on_cancel");
00385                 if (has_goal_) {
00386                         if (gh == goal_handle_) {
00387                                 robot_.stopTraj();
00388                                 has_goal_ = false;
00389                         }
00390                 }
00391                 result_.error_code = -100; //nothing is defined for this...?
00392                 result_.error_string = "Goal cancelled by client";
00393                 gh.setCanceled(result_);
00394         }
00395 
00396         bool setIO(ur_msgs::SetIORequest& req, ur_msgs::SetIOResponse& resp) {
00397                 resp.success = true;
00398                 //if (req.fun == ur_msgs::SetIO::Request::FUN_SET_DIGITAL_OUT) {
00399                 if (req.fun == 1) {
00400                         robot_.setDigitalOut(req.pin, req.state > 0.0 ? true : false);
00401                 } else if (req.fun == 2) {
00402                         //} else if (req.fun == ur_msgs::SetIO::Request::FUN_SET_FLAG) {
00403                         robot_.setFlag(req.pin, req.state > 0.0 ? true : false);
00404                         //According to urdriver.py, set_flag will fail if called to rapidly in succession
00405                         ros::Duration(io_flag_delay_).sleep();
00406                 } else if (req.fun == 3) {
00407                         //} else if (req.fun == ur_msgs::SetIO::Request::FUN_SET_ANALOG_OUT) {
00408                         robot_.setAnalogOut(req.pin, req.state);
00409                 } else if (req.fun == 4) {
00410                         //} else if (req.fun == ur_msgs::SetIO::Request::FUN_SET_TOOL_VOLTAGE) {
00411                         robot_.setToolVoltage((int) req.state);
00412                 } else {
00413                         resp.success = false;
00414                 }
00415                 return resp.success;
00416         }
00417 
00418         bool setPayload(ur_msgs::SetPayloadRequest& req,
00419                         ur_msgs::SetPayloadResponse& resp) {
00420                 if (robot_.setPayload(req.payload))
00421                         resp.success = true;
00422                 else
00423                         resp.success = true;
00424                 return resp.success;
00425         }
00426 
00427         bool validateJointNames() {
00428                 std::vector<std::string> actual_joint_names = robot_.getJointNames();
00429                 actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction>::Goal goal =
00430                                 *goal_handle_.getGoal();
00431                 if (goal.trajectory.joint_names.size() != actual_joint_names.size())
00432                         return false;
00433 
00434                 for (unsigned int i = 0; i < goal.trajectory.joint_names.size(); i++) {
00435                         unsigned int j;
00436                         for (j = 0; j < actual_joint_names.size(); j++) {
00437                                 if (goal.trajectory.joint_names[i] == actual_joint_names[j])
00438                                         break;
00439                         }
00440                         if (goal.trajectory.joint_names[i] == actual_joint_names[j]) {
00441                                 actual_joint_names.erase(actual_joint_names.begin() + j);
00442                         } else {
00443                                 return false;
00444                         }
00445                 }
00446 
00447                 return true;
00448         }
00449 
00450         void reorder_traj_joints(trajectory_msgs::JointTrajectory& traj) {
00451                 /* Reorders trajectory - destructive */
00452                 std::vector<std::string> actual_joint_names = robot_.getJointNames();
00453                 std::vector<unsigned int> mapping;
00454                 mapping.resize(actual_joint_names.size(), actual_joint_names.size());
00455                 for (unsigned int i = 0; i < traj.joint_names.size(); i++) {
00456                         for (unsigned int j = 0; j < actual_joint_names.size(); j++) {
00457                                 if (traj.joint_names[i] == actual_joint_names[j])
00458                                         mapping[j] = i;
00459                         }
00460                 }
00461                 traj.joint_names = actual_joint_names;
00462                 std::vector<trajectory_msgs::JointTrajectoryPoint> new_traj;
00463                 for (unsigned int i = 0; i < traj.points.size(); i++) {
00464                         trajectory_msgs::JointTrajectoryPoint new_point;
00465                         for (unsigned int j = 0; j < traj.points[i].positions.size(); j++) {
00466                                 new_point.positions.push_back(
00467                                                 traj.points[i].positions[mapping[j]]);
00468                                 new_point.velocities.push_back(
00469                                                 traj.points[i].velocities[mapping[j]]);
00470                                 if (traj.points[i].accelerations.size() != 0)
00471                                         new_point.accelerations.push_back(
00472                                                         traj.points[i].accelerations[mapping[j]]);
00473                         }
00474                         new_point.time_from_start = traj.points[i].time_from_start;
00475                         new_traj.push_back(new_point);
00476                 }
00477                 traj.points = new_traj;
00478         }
00479 
00480         bool has_velocities() {
00481                 actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction>::Goal goal =
00482                                 *goal_handle_.getGoal();
00483                 for (unsigned int i = 0; i < goal.trajectory.points.size(); i++) {
00484                         if (goal.trajectory.points[i].positions.size()
00485                                         != goal.trajectory.points[i].velocities.size())
00486                                 return false;
00487                 }
00488                 return true;
00489         }
00490 
00491         bool has_positions() {
00492                 actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction>::Goal goal =
00493                                 *goal_handle_.getGoal();
00494                 if (goal.trajectory.points.size() == 0)
00495                         return false;
00496                 for (unsigned int i = 0; i < goal.trajectory.points.size(); i++) {
00497                         if (goal.trajectory.points[i].positions.size()
00498                                         != goal.trajectory.joint_names.size())
00499                                 return false;
00500                 }
00501                 return true;
00502         }
00503 
00504         bool start_positions_match(const trajectory_msgs::JointTrajectory &traj, double eps)
00505         {
00506                 for (unsigned int i = 0; i < traj.points[0].positions.size(); i++)
00507                 {
00508                         std::vector<double> qActual = robot_.rt_interface_->robot_state_->getQActual();
00509                         if( fabs(traj.points[0].positions[i] - qActual[i]) > eps )
00510                         {
00511                                 return false;
00512                         }
00513                 }
00514                 return true;
00515         }
00516 
00517         bool has_limited_velocities() {
00518                 actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction>::Goal goal =
00519                                 *goal_handle_.getGoal();
00520                 for (unsigned int i = 0; i < goal.trajectory.points.size(); i++) {
00521                         for (unsigned int j = 0;
00522                                         j < goal.trajectory.points[i].velocities.size(); j++) {
00523                                 if (fabs(goal.trajectory.points[i].velocities[j])
00524                                                 > max_velocity_)
00525                                         return false;
00526                         }
00527                 }
00528                 return true;
00529         }
00530 
00531         bool traj_is_finite() {
00532                 actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction>::Goal goal =
00533                                 *goal_handle_.getGoal();
00534                 for (unsigned int i = 0; i < goal.trajectory.points.size(); i++) {
00535                         for (unsigned int j = 0;
00536                                         j < goal.trajectory.points[i].velocities.size(); j++) {
00537                                 if (!std::isfinite(goal.trajectory.points[i].positions[j]))
00538                                         return false;
00539                                 if (!std::isfinite(goal.trajectory.points[i].velocities[j]))
00540                                         return false;
00541                         }
00542                 }
00543                 return true;
00544         }
00545 
00546         void speedInterface(const trajectory_msgs::JointTrajectory::Ptr& msg) {
00547                 if (msg->points[0].velocities.size() == 6) {
00548                         double acc = 100;
00549                         if (msg->points[0].accelerations.size() > 0)
00550                                 acc = *std::max_element(msg->points[0].accelerations.begin(),
00551                                                 msg->points[0].accelerations.end());
00552                         robot_.setSpeed(msg->points[0].velocities[0],
00553                                         msg->points[0].velocities[1], msg->points[0].velocities[2],
00554                                         msg->points[0].velocities[3], msg->points[0].velocities[4],
00555                                         msg->points[0].velocities[5], acc);
00556                 }
00557 
00558         }
00559         void urscriptInterface(const std_msgs::String::ConstPtr& msg) {
00560 
00561                 robot_.rt_interface_->addCommandToQueue(msg->data);
00562 
00563         }
00564 
00565         void rosControlLoop() {
00566                 ros::Duration elapsed_time;
00567                 struct timespec last_time, current_time;
00568                 static const double BILLION = 1000000000.0;
00569 
00570                 realtime_tools::RealtimePublisher<tf::tfMessage> tf_pub( nh_, "/tf", 1 );
00571                 geometry_msgs::TransformStamped tool_transform;
00572                 tool_transform.header.frame_id = base_frame_;
00573                 tool_transform.child_frame_id = tool_frame_;
00574                 tf_pub.msg_.transforms.push_back( tool_transform );
00575 
00576                 realtime_tools::RealtimePublisher<geometry_msgs::TwistStamped> tool_vel_pub( nh_, "tool_velocity", 1 );
00577                 tool_vel_pub.msg_.header.frame_id = base_frame_;
00578 
00579 
00580                 clock_gettime(CLOCK_MONOTONIC, &last_time);
00581                 while (ros::ok()) {
00582                         std::mutex msg_lock; // The values are locked for reading in the class, so just use a dummy mutex
00583                         std::unique_lock<std::mutex> locker(msg_lock);
00584                         while (!robot_.rt_interface_->robot_state_->getControllerUpdated()) {
00585                                 rt_msg_cond_.wait(locker);
00586                         }
00587                         // Input
00588                         hardware_interface_->read();
00589                         robot_.rt_interface_->robot_state_->setControllerUpdated();
00590 
00591                         // Control
00592                         clock_gettime(CLOCK_MONOTONIC, &current_time);
00593                         elapsed_time = ros::Duration(current_time.tv_sec - last_time.tv_sec + (current_time.tv_nsec - last_time.tv_nsec)/ BILLION);
00594                         ros::Time ros_time = ros::Time::now();
00595                         controller_manager_->update(ros_time, elapsed_time);
00596                         last_time = current_time;
00597 
00598                         // Output
00599                         hardware_interface_->write();
00600 
00601                         // Tool vector: Actual Cartesian coordinates of the tool: (x,y,z,rx,ry,rz), where rx, ry and rz is a rotation vector representation of the tool orientation
00602                         std::vector<double> tool_vector_actual = robot_.rt_interface_->robot_state_->getToolVectorActual();
00603 
00604                         // Compute rotation angle
00605                         double rx = tool_vector_actual[3];
00606                         double ry = tool_vector_actual[4];
00607                         double rz = tool_vector_actual[5];
00608                         double angle = std::sqrt(std::pow(rx,2) + std::pow(ry,2) + std::pow(rz,2));
00609 
00610                         // Broadcast transform
00611                         if( tf_pub.trylock() )
00612                         {                       
00613                                 tf_pub.msg_.transforms[0].header.stamp = ros_time;
00614                                 if (angle < 1e-16) {
00615                                         tf_pub.msg_.transforms[0].transform.rotation.x = 0;
00616                                         tf_pub.msg_.transforms[0].transform.rotation.y = 0;
00617                                         tf_pub.msg_.transforms[0].transform.rotation.z = 0;
00618                                         tf_pub.msg_.transforms[0].transform.rotation.w = 1;
00619                                 } else {
00620                                         tf_pub.msg_.transforms[0].transform.rotation.x = (rx/angle) * std::sin(angle*0.5);
00621                                         tf_pub.msg_.transforms[0].transform.rotation.y = (ry/angle) * std::sin(angle*0.5);
00622                                         tf_pub.msg_.transforms[0].transform.rotation.z = (rz/angle) * std::sin(angle*0.5);
00623                                         tf_pub.msg_.transforms[0].transform.rotation.w = std::cos(angle*0.5);
00624                                 }
00625                                 tf_pub.msg_.transforms[0].transform.translation.x = tool_vector_actual[0];
00626                                 tf_pub.msg_.transforms[0].transform.translation.y = tool_vector_actual[1];
00627                                 tf_pub.msg_.transforms[0].transform.translation.z = tool_vector_actual[2];
00628 
00629                                 tf_pub.unlockAndPublish();
00630                         }
00631 
00632                         //Publish tool velocity
00633                         std::vector<double> tcp_speed = robot_.rt_interface_->robot_state_->getTcpSpeedActual();
00634 
00635                         if( tool_vel_pub.trylock() )
00636                         {                       
00637                                 tool_vel_pub.msg_.header.stamp = ros_time;
00638                                 tool_vel_pub.msg_.twist.linear.x = tcp_speed[0];
00639                                 tool_vel_pub.msg_.twist.linear.y = tcp_speed[1];
00640                                 tool_vel_pub.msg_.twist.linear.z = tcp_speed[2];
00641                                 tool_vel_pub.msg_.twist.angular.x = tcp_speed[3];
00642                                 tool_vel_pub.msg_.twist.angular.y = tcp_speed[4];
00643                                 tool_vel_pub.msg_.twist.angular.z = tcp_speed[5];
00644 
00645                                 tool_vel_pub.unlockAndPublish();
00646                         }
00647 
00648                 }
00649         }
00650 
00651         void publishRTMsg() {
00652                 ros::Publisher joint_pub = nh_.advertise<sensor_msgs::JointState>(
00653                                 "joint_states", 1);
00654                 ros::Publisher wrench_pub = nh_.advertise<geometry_msgs::WrenchStamped>(
00655                                 "wrench", 1);
00656         ros::Publisher tool_vel_pub = nh_.advertise<geometry_msgs::TwistStamped>("tool_velocity", 1);
00657         static tf::TransformBroadcaster br;
00658                 while (ros::ok()) {
00659                         sensor_msgs::JointState joint_msg;
00660                         joint_msg.name = robot_.getJointNames();
00661                         geometry_msgs::WrenchStamped wrench_msg;
00662             geometry_msgs::PoseStamped tool_pose_msg;
00663                         std::mutex msg_lock; // The values are locked for reading in the class, so just use a dummy mutex
00664                         std::unique_lock<std::mutex> locker(msg_lock);
00665                         while (!robot_.rt_interface_->robot_state_->getDataPublished()) {
00666                                 rt_msg_cond_.wait(locker);
00667                         }
00668                         joint_msg.header.stamp = ros::Time::now();
00669                         joint_msg.position =
00670                                         robot_.rt_interface_->robot_state_->getQActual();
00671                         for (unsigned int i = 0; i < joint_msg.position.size(); i++) {
00672                                 joint_msg.position[i] += joint_offsets_[i];
00673                         }
00674                         joint_msg.velocity =
00675                                         robot_.rt_interface_->robot_state_->getQdActual();
00676                         joint_msg.effort = robot_.rt_interface_->robot_state_->getIActual();
00677                         joint_pub.publish(joint_msg);
00678                         std::vector<double> tcp_force =
00679                                         robot_.rt_interface_->robot_state_->getTcpForce();
00680                         wrench_msg.header.stamp = joint_msg.header.stamp;
00681                         wrench_msg.wrench.force.x = tcp_force[0];
00682                         wrench_msg.wrench.force.y = tcp_force[1];
00683                         wrench_msg.wrench.force.z = tcp_force[2];
00684                         wrench_msg.wrench.torque.x = tcp_force[3];
00685                         wrench_msg.wrench.torque.y = tcp_force[4];
00686                         wrench_msg.wrench.torque.z = tcp_force[5];
00687                         wrench_pub.publish(wrench_msg);
00688 
00689             // Tool vector: Actual Cartesian coordinates of the tool: (x,y,z,rx,ry,rz), where rx, ry and rz is a rotation vector representation of the tool orientation
00690             std::vector<double> tool_vector_actual = robot_.rt_interface_->robot_state_->getToolVectorActual();
00691 
00692             //Create quaternion
00693             tf::Quaternion quat;
00694             double rx = tool_vector_actual[3];
00695             double ry = tool_vector_actual[4];
00696             double rz = tool_vector_actual[5];
00697             double angle = std::sqrt(std::pow(rx,2) + std::pow(ry,2) + std::pow(rz,2));
00698             if (angle < 1e-16) {
00699                 quat.setValue(0, 0, 0, 1);
00700             } else {
00701                 quat.setRotation(tf::Vector3(rx/angle, ry/angle, rz/angle), angle);
00702             }
00703 
00704             //Create and broadcast transform
00705             tf::Transform transform;
00706             transform.setOrigin(tf::Vector3(tool_vector_actual[0], tool_vector_actual[1], tool_vector_actual[2]));
00707             transform.setRotation(quat);
00708             br.sendTransform(tf::StampedTransform(transform, joint_msg.header.stamp, base_frame_, tool_frame_));
00709 
00710             //Publish tool velocity
00711             std::vector<double> tcp_speed =
00712                     robot_.rt_interface_->robot_state_->getTcpSpeedActual();
00713             geometry_msgs::TwistStamped tool_twist;
00714             tool_twist.header.frame_id = base_frame_;
00715             tool_twist.header.stamp = joint_msg.header.stamp;
00716             tool_twist.twist.linear.x = tcp_speed[0];
00717             tool_twist.twist.linear.y = tcp_speed[1];
00718             tool_twist.twist.linear.z = tcp_speed[2];
00719             tool_twist.twist.angular.x = tcp_speed[3];
00720             tool_twist.twist.angular.y = tcp_speed[4];
00721             tool_twist.twist.angular.z = tcp_speed[5];
00722             tool_vel_pub.publish(tool_twist);
00723 
00724                         robot_.rt_interface_->robot_state_->setDataPublished();
00725                 }
00726         }
00727 
00728         void publishMbMsg() {
00729                 bool warned = false;
00730                 ros::Publisher io_pub = nh_.advertise<ur_msgs::IOStates>(
00731                                 "ur_driver/io_states", 1);
00732 
00733                 while (ros::ok()) {
00734                         ur_msgs::IOStates io_msg;
00735                         std::mutex msg_lock; // The values are locked for reading in the class, so just use a dummy mutex
00736                         std::unique_lock<std::mutex> locker(msg_lock);
00737                         while (!robot_.sec_interface_->robot_state_->getNewDataAvailable()) {
00738                                 msg_cond_.wait(locker);
00739                         }
00740                         int i_max = 10;
00741                         if (robot_.sec_interface_->robot_state_->getVersion() > 3.0)
00742                                 i_max = 18; // From version 3.0, there are up to 18 inputs and outputs
00743                         for (unsigned int i = 0; i < i_max; i++) {
00744                                 ur_msgs::Digital digi;
00745                                 digi.pin = i;
00746                                 digi.state =
00747                                                 ((robot_.sec_interface_->robot_state_->getDigitalInputBits()
00748                                                                 & (1 << i)) >> i);
00749                                 io_msg.digital_in_states.push_back(digi);
00750                                 digi.state =
00751                                                 ((robot_.sec_interface_->robot_state_->getDigitalOutputBits()
00752                                                                 & (1 << i)) >> i);
00753                                 io_msg.digital_out_states.push_back(digi);
00754                         }
00755                         ur_msgs::Analog ana;
00756                         ana.pin = 0;
00757                         ana.state = robot_.sec_interface_->robot_state_->getAnalogInput0();
00758                         io_msg.analog_in_states.push_back(ana);
00759                         ana.pin = 1;
00760                         ana.state = robot_.sec_interface_->robot_state_->getAnalogInput1();
00761                         io_msg.analog_in_states.push_back(ana);
00762 
00763                         ana.pin = 0;
00764                         ana.state = robot_.sec_interface_->robot_state_->getAnalogOutput0();
00765                         io_msg.analog_out_states.push_back(ana);
00766                         ana.pin = 1;
00767                         ana.state = robot_.sec_interface_->robot_state_->getAnalogOutput1();
00768                         io_msg.analog_out_states.push_back(ana);
00769                         io_pub.publish(io_msg);
00770 
00771                         if (robot_.sec_interface_->robot_state_->isEmergencyStopped()
00772                                         or robot_.sec_interface_->robot_state_->isProtectiveStopped()) {
00773                                 if (robot_.sec_interface_->robot_state_->isEmergencyStopped()
00774                                                 and !warned) {
00775                                         print_error("Emergency stop pressed!");
00776                                 } else if (robot_.sec_interface_->robot_state_->isProtectiveStopped()
00777                                                 and !warned) {
00778                                         print_error("Robot is protective stopped!");
00779                                 }
00780                                 if (has_goal_) {
00781                                         print_error("Aborting trajectory");
00782                                         robot_.stopTraj();
00783                                         result_.error_code = result_.SUCCESSFUL;
00784                                         result_.error_string = "Robot was halted";
00785                                         goal_handle_.setAborted(result_, result_.error_string);
00786                                         has_goal_ = false;
00787                                 }
00788                                 warned = true;
00789                         } else
00790                                 warned = false;
00791 
00792                         robot_.sec_interface_->robot_state_->finishedReading();
00793 
00794                 }
00795         }
00796 
00797 };
00798 
00799 int main(int argc, char **argv) {
00800         bool use_sim_time = false;
00801         std::string host;
00802         int reverse_port = 50001;
00803 
00804         ros::init(argc, argv, "ur_driver");
00805         ros::NodeHandle nh;
00806         if (ros::param::get("use_sim_time", use_sim_time)) {
00807                 print_warning("use_sim_time is set!!");
00808         }
00809         if (!(ros::param::get("~robot_ip_address", host))) {
00810                 if (argc > 1) {
00811                         print_warning(
00812                                         "Please set the parameter robot_ip_address instead of giving it as a command line argument. This method is DEPRECATED");
00813                         host = argv[1];
00814                 } else {
00815                         print_fatal(
00816                                         "Could not get robot ip. Please supply it as command line parameter or on the parameter server as robot_ip");
00817                         exit(1);
00818                 }
00819 
00820         }
00821         if ((ros::param::get("~reverse_port", reverse_port))) {
00822                 if((reverse_port <= 0) or (reverse_port >= 65535)) {
00823                         print_warning("Reverse port value is not valid (Use number between 1 and 65534. Using default value of 50001");
00824                         reverse_port = 50001;
00825                 }
00826         } else
00827                 reverse_port = 50001;
00828 
00829         RosWrapper interface(host, reverse_port);
00830 
00831         ros::AsyncSpinner spinner(3);
00832         spinner.start();
00833 
00834         ros::waitForShutdown();
00835 
00836         interface.halt();
00837 
00838         exit(0);
00839 }


ur_modern_driver
Author(s): Thomas Timm Andersen
autogenerated on Wed Apr 3 2019 02:55:31