SchunkServer.h
Go to the documentation of this file.
00001 #ifndef SCHUNKSERVER_H_
00002 #define SCHUNKSERVER_H_
00003 
00004 #include <boost/thread.hpp>
00005 #include <boost/noncopyable.hpp>
00006 
00007 #include <ros/ros.h>
00008 #include <actionlib/server/simple_action_server.h>
00009 
00010 #include <urdf/model.h>
00011 #include <tf/transform_broadcaster.h>
00012 
00013 #include <std_msgs/Int8.h>
00014 
00015 #include <metralabs_msgs/IDAndFloat.h>
00016 #include <metralabs_msgs/SchunkStatus.h>
00017 
00018 #include <sensor_msgs/JointState.h>
00019 
00020 #include <trajectory_msgs/JointTrajectory.h>
00021 #include <control_msgs/JointTrajectoryControllerState.h>
00022 #include <control_msgs/FollowJointTrajectoryAction.h>
00023 
00024 #include "RobotArm.h"
00025 #include "AmtecProtocolArm.h"
00026 #include "SchunkProtocolArm.h"
00027 #include "LWA3ArmUASHH.h"
00028 #include "PowerCubeArmUUISRC.h"
00029 
00030 using namespace std;
00031 
00032 
00033 #define DEG_TO_RAD(d)   ((d)*M_PI/180.0)
00034 #define RAD_TO_DEG(r)   ((r)*180.0/M_PI)
00035 
00036 #define SLOWEST_REASONABLE_JOINT_SPEED  0.015f // the slowest reasonable speed for our joints (IMHO)
00037 #define TOO_SLOW        0.002f //
00038 
00039 
00040 
00041 class TrajectoryExecuter : private boost::noncopyable {
00042 public:
00043         TrajectoryExecuter(ros::NodeHandle& nh) :
00044                 nh_(nh),
00045                 as_(NULL),
00046                 arm_(NULL)
00047         {
00048                 run_ = false;
00049                 waiting_ = false;
00050 
00051                 // make sure isnanf is working here and now
00052                 ROS_ASSERT(isnanf(0 / (float)0));
00053                 ROS_ASSERT(isnanf(-0 / (float)0));
00054         }
00055 
00056         void init(RobotArm* arm, std::map<std::string, RobotArm::IDType>& joints_name_to_number_map) {
00057 
00058                 arm_ = arm;
00059                 joints_name_to_number_map_ = joints_name_to_number_map;
00060 
00061                 state_publisher_ = nh_.advertise<control_msgs::JointTrajectoryControllerState>("trajectory_state", 5);
00062 
00063                 std::map<std::string, RobotArm::IDType>::iterator it;
00064                 for (it = joints_name_to_number_map_.begin(); it != joints_name_to_number_map_.end(); ++it) {
00065                         state_msg_.joint_names.push_back(it->first);
00066                 }
00067                 int num_of_joints = joints_name_to_number_map_.size();
00068                 state_msg_.desired.positions.resize(num_of_joints);
00069                 state_msg_.desired.velocities.resize(num_of_joints);
00070                 state_msg_.desired.accelerations.resize(num_of_joints);
00071                 state_msg_.actual.positions.resize(num_of_joints);
00072                 state_msg_.actual.velocities.resize(num_of_joints);
00073                 state_msg_.error.positions.resize(num_of_joints);
00074                 state_msg_.error.velocities.resize(num_of_joints);
00075 
00076 
00077                 nh_.param<std::string>("follow_joint_trajectory_action_name", action_name_, "follow_joint_trajectory");
00078                 as_ = new ActionServerType(nh_, action_name_,
00079                                 boost::bind(&TrajectoryExecuter::trajectoryActionCallback, this, _1), false);
00080                 as_->start();
00081         }
00082 
00083         ~TrajectoryExecuter() {
00084                 delete as_;
00085         }
00086 
00087         void main() {
00088                 while (true) {
00089                         {
00090                                 boost::unique_lock<boost::mutex> lock(mut_);
00091                                 waiting_ = true;
00092                                 bool gotit = false;
00093                                 while (!run_){
00094                                         if(!nh_.ok()) {
00095                                                 return;
00096                                         }
00097                                         try {
00098                                                 boost::this_thread::interruption_point();
00099                                                 gotit = cond_.timed_wait(lock, boost::posix_time::milliseconds(100));
00100                                         }
00101                                         catch(const boost::thread_interrupted&) {
00102                                                 ROS_INFO("Trajectory thread was interrupted and returns, stopping the arm.");
00103                                                 arm_->normalStopAll();
00104                                                 return;
00105                                         }
00106                                         if (! gotit) {
00107                                                 //Let's make people happy by publishing a state message
00108                                                 for (unsigned int joint_i = 0; joint_i<joints_name_to_number_map_.size(); ++joint_i) {
00109                                                         //fill in the message
00110                                                         state_msg_.desired = state_msg_.actual;
00111                                                         state_msg_.actual.positions[joint_i] = arm_->getPosition(joint_i);
00112                                                         state_msg_.actual.velocities[joint_i] = 0;
00113                                                         state_msg_.actual.time_from_start = ros::Duration(0);
00114                                                 }
00115 
00116                                                 //finally publish the state message
00117                                                 state_msg_.header.stamp = ros::Time::now();
00118                                                 state_publisher_.publish(state_msg_);
00119                                         }
00120 
00121                                 }
00122                         }
00123                         //I hope the mutex is unlocked now
00124                         {
00125                                 boost::unique_lock<boost::mutex> lock(mut_);
00126                                 waiting_ = false;
00127                         }
00128 
00129                         ROS_INFO("Trajectory thread is starting its job");
00130                         followTrajectory();
00131                         arm_->normalStopAll();
00132 
00133                         {
00134                                 //Self deactivate
00135                                 boost::unique_lock<boost::mutex> lock(mut_);
00136                                 run_ = false;
00137                         }
00138                         ROS_INFO("Trajectory thread has finished its job");
00139                 }
00140         }
00141 
00142         void start(const trajectory_msgs::JointTrajectory& newtraj) {
00143                 {
00144                         boost::unique_lock<boost::mutex> lock(mut_);
00145                         if (run_) {
00146                                 ROS_WARN("You need to stop a trajectory before issuing a new command. Ignoring the new command");
00147                                 return;
00148                         }
00149 
00150                         traj_ = newtraj;
00151                         run_ = true;
00152                 }
00153                 ROS_INFO("Waking up the thread");
00154                 cond_.notify_one();
00155         }
00156 
00157         void stop() {
00158                 boost::unique_lock<boost::mutex> lock(mut_);
00159                 run_ = false;
00160         }
00161 
00162         bool isRunning() {
00163                 boost::unique_lock<boost::mutex> lock(mut_);
00164                 return run_;
00165         }
00166 
00167         bool isWaiting() {
00168                 boost::unique_lock<boost::mutex> lock(mut_);
00169                 return waiting_;
00170         }
00171 
00172 
00173         // TODO: DOC choose this only if the velocity and time are calculated precisely
00174         void trajectoryActionCallback(const control_msgs::FollowJointTrajectoryGoalConstPtr& goal)
00175         {
00176                 const trajectory_msgs::JointTrajectory& traj = goal->trajectory;
00177                 const unsigned int num_of_joints = traj.joint_names.size();
00178 
00179                 // joint order does not change within trajectory, therefore
00180                 //  to prevent superfluous joint name comparisons this array maps the
00181                 //  index in the message  (usually joint_i) to the id in the model
00182                 RobotArm::IDType msg_index_to_model_index[num_of_joints];
00183                 // for each joint in step... map id
00184                 for (unsigned int joint_i = 0; joint_i < num_of_joints; ++joint_i) {
00185                         RobotArm::IDType id = joints_name_to_number_map_[traj.joint_names[joint_i]];
00186                         msg_index_to_model_index[joint_i] = id;
00187                         ROS_INFO_STREAM("TrajectoryAction callback: mapping joint: msg id "<<joint_i<<" to model id "<<id);
00188                 }
00189 
00190 
00191                 // check arm conditions before starting trajectory execution
00192                 for (unsigned int joint_i = 0; joint_i < num_of_joints; ++joint_i) {
00193                         RobotArm::IDType id = msg_index_to_model_index[joint_i];
00194 
00195                         // check joint status
00196                         uint8_t moving, error, brake, foo;
00197                         float foofl;
00198                         arm_->getModuleStatus(id, foo, moving, foo, foo, error, brake, foo, foo, foo, foofl);
00199                         if(moving || error) {
00200                                 arm_->normalStopAll();
00201                                 ROS_ERROR("Arm in error state or moving, rejecting trajectory action.");
00202                                 as_->setAborted();
00203                                 return;
00204                         }
00205 
00206                         // check joint position
00207                         float MAX_ALLOWED_DEVIANCE = 0.05; // rad
00208                         float first_step_position = traj.points[0].positions[joint_i];
00209                         float current_position = arm_->getPosition(id);
00210                         float actual_difference = first_step_position-current_position;
00211                         if (abs(actual_difference) > MAX_ALLOWED_DEVIANCE) {
00212                                 arm_->normalStopAll();
00213                                 ROS_ERROR_STREAM("Arm pose and first trajectory step differ to much, "
00214                                                 << "rejecting trajectory action. Joint ID: " << id <<
00215                                                 " difference: " << actual_difference << " allowed: " << MAX_ALLOWED_DEVIANCE);
00216                                 as_->setAborted();
00217                                 return;
00218                         }
00219 
00220                 }
00221                 ROS_INFO("Arm in valid state, starting trajectory..");
00222 
00223 
00224                 // init feedback message
00225                 feedback_.joint_names = traj.joint_names;
00226                 feedback_.desired.positions.resize(num_of_joints);
00227                 feedback_.desired.velocities.resize(num_of_joints);
00228                 feedback_.desired.accelerations.resize(num_of_joints);
00229                 feedback_.actual.positions.resize(num_of_joints);
00230                 feedback_.actual.velocities.resize(num_of_joints);
00231                 feedback_.actual.accelerations.resize(num_of_joints);
00232                 feedback_.error.positions.resize(num_of_joints);
00233                 feedback_.error.velocities.resize(num_of_joints);
00234                 feedback_.error.accelerations.resize(num_of_joints);
00235 
00236                 const ros::Time traj_start_time = ros::Time::now();
00237 
00239                 // for each trajectory step...
00240                 unsigned int steps = traj.points.size();
00241                 for (unsigned int step_i = 0; step_i < steps; ++step_i) {
00242 
00243                         // check that preempt has not been requested by the client
00244                         if (as_->isPreemptRequested() || !ros::ok()) {
00245                                 arm_->normalStopAll();
00246                                 ROS_INFO("%s: Preempted", action_name_.c_str());
00247                                 as_->setPreempted();
00248                                 return;
00249                         }
00250 
00251                         // check no module is in error state
00252                         for (unsigned int joint_i = 0; joint_i < num_of_joints; ++joint_i) {
00253                                 RobotArm::IDType id = msg_index_to_model_index[joint_i];
00254                                 uint8_t error, foo;
00255                                 float foofl;
00256                                 arm_->getModuleStatus(id, foo, foo, foo, foo, error, foo, foo, foo, foo, foofl);
00257                                 if(error) {
00258                                         arm_->normalStopAll();
00259                                         ROS_ERROR("Arm in error state, aborting trajectory action.");
00260                                         as_->setAborted();
00261                                         return;
00262                                 }
00263                         }
00264 
00265                         // get the step target
00266                         const trajectory_msgs::JointTrajectoryPoint& traj_step = traj.points[step_i];
00267                         feedback_.desired = traj_step;
00268 
00269                         ROS_INFO_STREAM("Trajectory thread executing step "<<step_i<<"+1/"<<steps<<" until "<<traj_step.time_from_start<<" s");
00270 
00272                         // for each joint in step... move
00273                         for (unsigned int joint_i = 0; joint_i < num_of_joints; ++joint_i) {
00274 
00275                                 RobotArm::IDType id = msg_index_to_model_index[joint_i];
00276                                 float acceleration = traj_step.accelerations[joint_i];
00277                                 float velocity = traj_step.velocities[joint_i];
00278                                 float position = traj_step.positions[joint_i];
00279 
00280 //                              ROS_DEBUG_STREAM("Step for module "<<id<<": "<<setiosflags(ios::fixed)<<velocity<<" rad/s, "<<acceleration<<" rad/s*s, "<<position<<" rad");
00281 
00282                                 if (isnanf(acceleration) || isnanf(velocity) || isnanf(position)) {
00283                                         arm_->normalStopAll();
00284                                         ROS_ERROR("Received NAN in trajectory step! Aborting trajectory action.");
00285                                         ROS_ERROR_STREAM(traj);
00286                                         as_->setAborted();
00287                                         return;
00288                                 }
00289 
00290                                 if(step_i == steps-1) {
00291 //                                      ROS_INFO("Last step, moving to position instead of with velocity.");
00292                                         velocity = 0.05;
00293                                         arm_->setVelocity(id, velocity);
00294                                         arm_->movePosition(id, position);
00295                                 }
00296                                 else if(abs(velocity) < TOO_SLOW) {
00297                                         // make joints near step goal reach that goal via position
00298                                         // as the velocity might be too slow already
00299                                         ROS_INFO_STREAM("Velocity for module "<<id<<" to close to zero to move with velocity, therefore moving to position with fix velocity.");
00300                                         velocity = 0.05;
00301                                         arm_->setVelocity(id, velocity);
00302                                         arm_->movePosition(id, position);
00303                                 }
00304                                 else {
00305                                         arm_->moveVelocity(id, velocity);
00306                                 }
00307                         }
00308 
00309                         // for each joint in step... feedback
00310                         for (unsigned int joint_i = 0; joint_i < num_of_joints; ++joint_i) {
00311                                 // fill the joint individual feedback part
00312                                 RobotArm::IDType id = msg_index_to_model_index[joint_i];
00313                                 feedback_.actual.positions[joint_i] = arm_->getPosition(id);
00314                                 feedback_.actual.velocities[joint_i] = arm_->getVelocity(id);   // Note: not supported in SchunkProtocol
00315                         }
00316 
00317                         // publish the feedback
00318                         feedback_.header.stamp = ros::Time::now();
00319                         feedback_.actual.time_from_start = feedback_.header.stamp - traj_start_time;
00320                         as_->publishFeedback(feedback_);
00321 
00322                         // sleep until step time has passed
00323                         ros::Time step_end_time = traj_start_time + traj_step.time_from_start;
00324                         if(step_end_time <= ros::Time::now())
00325                                 ROS_WARN("Trajectory follower to slow, has to sleep a negative duration!");
00326                         else
00327                                 ros::Time::sleepUntil(step_end_time);
00328 
00329                         // TODO: what about a check if joints have moved beyond the goal and stop them?
00330 
00331 //                      // the arm is too slow, wait until each joint is near its goal
00332 //      note: this does not work (unless fixed) when using moveVelocity, as the joint
00333 //      could have passed the step goal, in which case waiting would be disastrous
00334 //                      ROS_INFO("Waiting for arm to reach trajectory step..");
00335 //                      bool all_joints_near_goal;
00336 //                      do {
00337 //                              ros::WallDuration(0.06).sleep();
00338 //                              all_joints_near_goal = true;
00339 //                              for (unsigned int joint_i = 0; joint_i < num_of_joints; ++joint_i) {
00340 //                                      RobotArm::IDType id = msg_index_to_model_index[joint_i];
00341 //
00342 //                                      float position_goal = traj_step.positions[joint_i];
00343 //                                      float position_current = arm_->getPosition(id);
00344 //                                      float position_deviation = std::abs(position_goal - position_current);
00345 //
00346 //                                      if(position_deviation > 0.1) {
00347 //                                              ROS_INFO_STREAM("Module "<<id<<" not yet near goal: deviation="<<position_deviation<<
00348 //                                                              " goal="<<position_goal<<" current="<<position_current<<" rad");
00349 //                                              all_joints_near_goal = false;
00350 //                                              break;
00351 //                                      }
00352 //                              }
00353 //
00354 //                              // check that preempt has not been requested by the client
00355 //                              if (as_->isPreemptRequested() || !ros::ok()) {
00356 //                                      ROS_INFO("%s: Preempted", action_name_.c_str());
00357 //                                      // set the action state to preempted
00358 //                                      as_->setPreempted();
00359 //                                      arm_->normalStopAll();
00360 //                                      return;
00361 //                              }
00362 //                      } while(!all_joints_near_goal);
00363 
00364                 }//for each trajectory step...
00365 
00366 
00367                 ROS_INFO("Trajectory done, waiting for joints to stop...");
00368                 bool all_joints_stopped;
00369                 do {
00370                         ros::WallDuration(0.06).sleep();
00371                         all_joints_stopped = true;
00372                         for (unsigned int joint_i = 0; joint_i < num_of_joints; ++joint_i) {
00373                                 RobotArm::IDType id = msg_index_to_model_index[joint_i];
00374                                 uint8_t moving, brake, foo;
00375                                 float foofl;
00376                                 arm_->getModuleStatus(id, foo, moving, foo, foo, foo, brake, foo, foo, foo, foofl);
00377                                 if(moving) {
00378                                         all_joints_stopped = false;
00379                                         break;
00380                                 }
00381                         }
00382                 } while (!all_joints_stopped);
00383 
00384                 result_.error_code = control_msgs::FollowJointTrajectoryResult::SUCCESSFUL;
00385                 ROS_INFO("%s: Succeeded", action_name_.c_str());
00386                 // set the action state to succeeded
00387                 as_->setSucceeded(result_);
00388         }
00389 
00390 
00391         // from action tutorial
00392 protected:
00393         ros::NodeHandle nh_;
00394         typedef actionlib::SimpleActionServer<control_msgs::FollowJointTrajectoryAction> ActionServerType;
00395         ActionServerType* as_;
00396         std::string action_name_;
00397         // create messages that are used to published feedback/result
00398         control_msgs::FollowJointTrajectoryFeedback feedback_;
00399         control_msgs::FollowJointTrajectoryResult result_;
00400 
00401 
00402 private:
00403         /* At this time only velocity values are followed. */
00404         void followTrajectory() {
00405                 //I am not entirely sure that this code actually looks like real-time
00406                 ros::Time trajStartTime = ros::Time::now();
00407                 for (unsigned int step = 0; step < traj_.points.size(); ++step) {
00408                         trajectory_msgs::JointTrajectoryPoint& point = traj_.points[step];
00409 
00410                         ROS_INFO_STREAM("Trajectory thread executing step "<<step);
00411                         //now apply speed to each joint
00412                         for (unsigned int joint_i = 0; joint_i < traj_.joint_names.size(); ++joint_i) {
00413 
00414                                 RobotArm::IDType id = joints_name_to_number_map_[traj_.joint_names[joint_i]];
00415                                 float velocity = point.velocities[joint_i];
00416 
00417                                 ROS_INFO_STREAM("Moving module "<<id<<" with "<<velocity<<" rad/s = "<<RAD_TO_DEG(velocity)<<" deg/s");
00418                                 arm_->moveVelocity(id, velocity);
00419 
00420                                 //fill in the message
00421                                 state_msg_.desired = state_msg_.actual;
00422                                 state_msg_.actual.positions[joint_i] = arm_->getPosition(joint_i);
00423                                 state_msg_.actual.velocities[joint_i] = arm_->getVelocity(joint_i);     // Note: not supported on SchunkProtocol
00424                                 state_msg_.actual.time_from_start = point.time_from_start;
00425                         }
00426 
00427                         //finally publish the state message
00428                         state_msg_.header.stamp = ros::Time::now();
00429                         state_publisher_.publish(state_msg_);
00430 
00431 
00432                         //wait for the right time and check if it has to die
00433                         while (ros::Time::now() < trajStartTime + point.time_from_start) {
00434                                 ; // <- Now things are really dirty
00435                                 { //This is tricky... a block as the only body of a loop!
00436                                         boost::unique_lock<boost::mutex> lock(mut_);
00437                                         if (!run_) {
00438                                                 ROS_INFO("Trajectory thread has been commanded to stop");
00439                                                 return;
00440                                         }
00441                                 }
00442                         }
00443                 }
00444         }
00445 
00446         RobotArm* arm_;
00447         std::map<std::string, RobotArm::IDType> joints_name_to_number_map_;
00448         trajectory_msgs::JointTrajectory traj_;
00449         bool run_;
00450         bool waiting_;
00451         boost::condition_variable cond_;
00452         boost::mutex mut_;
00453         control_msgs::JointTrajectoryControllerState state_msg_;
00454         ros::Publisher state_publisher_;
00455 };
00456 
00457 
00458 
00459 class SchunkServer : private boost::noncopyable {
00460 public:
00461         SchunkServer(ros::NodeHandle &nh) :
00462                 node_handle_(nh),
00463                 arm_(NULL),
00464                 trajectory_executer_(nh)
00465         {
00466                 init();
00467         }
00468 
00469         ~SchunkServer() {
00470                 trajectory_executer_.stop();
00471                 trajectory_executer_thread_.interrupt();
00472                 trajectory_executer_thread_.join();
00473                 if(arm_ != NULL)
00474                         delete arm_;
00475         }
00476 
00477 private:
00478         void renewRobotArm() {
00479                 // delete old instance if existent
00480                 if(arm_ != NULL)
00481                         delete arm_;
00482 
00483                 std::string robot_arm_class;
00484                 ros::NodeHandle nh_private("~");
00485                 if(!nh_private.getParam("robot_arm_class", robot_arm_class)) {
00486                         ROS_WARN_STREAM("Parameter robot arm class not set, defaulting to AmtecProtocolArm.");
00487                         robot_arm_class = "AmtecProtocolArm";
00488                 }
00489 
00490                 // TODO implement real class loader
00491                 if(robot_arm_class == "AmtecProtocolArm")
00492                         arm_ = new AmtecProtocolArm();
00493                 else if(robot_arm_class == "SchunkProtocolArm")
00494                         arm_ = new SchunkProtocolArm();
00495                 else if(robot_arm_class == "LWA3ArmUASHH")
00496                         arm_ = new LWA3ArmUASHH();
00497                 else if(robot_arm_class == "PowerCubeArmUUISRC")
00498                         arm_ = new PowerCubeArmUUISRC();
00499                 else {
00500                         ROS_FATAL_STREAM("Cannot load unknown robot arm class: "<<robot_arm_class);
00501                         exit(1);
00502                 }
00503         }
00504 
00505         void init() {
00506                 // Initialise the arm model parser and find out what non-fixed joints are present
00507                 arm_model_.initParam("robot_description");
00508                 std::map<std::string, boost::shared_ptr<urdf::Joint> >::const_iterator mapElement;
00509                 for (mapElement = arm_model_.joints_.begin(); mapElement != arm_model_.joints_.end(); ++mapElement) {
00510                         boost::shared_ptr<urdf::Joint> joint = mapElement->second;
00511                         ROS_DEBUG_STREAM("Joint: Name="<<joint->name<<" MimicPtr="<<joint->mimic);
00512                         if (joint->type != urdf::Joint::FIXED &&
00513                                         joint->mimic == 0)      // ignore virtual joints mimicking a physical one
00514                                 joints_list_.push_back(joint);
00515                 }
00516                 ROS_INFO("URDF specifies %d non-fixed non-mimicking joints.", joints_list_.size());
00517 
00518                 // Initialise the arm
00519                 renewRobotArm();
00520                 arm_->init();
00521 
00522                 // Check if reinitialisation is needed
00523                 while(arm_->getModulesCount() != joints_list_.size()) {
00524                         ROS_WARN("Reinitialising robot arm... found %d joints but need %d", arm_->getModulesCount(), joints_list_.size());
00525                         renewRobotArm();
00526                         ros::WallDuration(1).sleep(); // let arm start up
00527                         arm_->init();
00528                 }
00529 
00530                 // Check that the required modules are present.
00531                 ROS_WARN("Didn't check that the modules in the description match modules in reality.");
00532 
00533                 // Set up the joint state publisher with the joint names
00534                 // This assumes that the joints are ordered on the robot in the same order as the URDF!!!
00535                 current_JointState_.name.resize(joints_list_.size());
00536                 current_JointState_.position.resize(joints_list_.size());
00537                 current_JointState_.velocity.resize(joints_list_.size());
00538                 for (unsigned int i = 0; i < joints_list_.size(); ++i) {
00539                         current_JointState_.name[i] = joints_list_[i]->name;
00540                         joints_name_to_number_map_[joints_list_[i]->name] = i;
00541                         ROS_INFO("%d is mapping to %s", i, joints_list_[i]->name.c_str());
00542                 }
00543                 current_JointState_publisher_ = node_handle_.advertise<sensor_msgs::JointState>("/joint_states", 1);
00544 
00545                 // Set up the schunk status publisher
00546                 current_SchunkStatus_publisher_ = node_handle_.advertise<metralabs_msgs::SchunkStatus>("status", 1);
00547                 for (uint i = 0; i < joints_list_.size(); ++i) {
00548                         metralabs_msgs::SchunkJointStatus status;
00549                         status.jointName = joints_list_[i]->name;
00550                         current_SchunkStatus_.joints.push_back(status);
00551                 }
00552 
00553                 trajectory_executer_.init(arm_, joints_name_to_number_map_);
00554 
00555                 ROS_INFO("Starting the trajectory executer thread");
00556                 trajectory_executer_thread_ = boost::thread(boost::bind(&TrajectoryExecuter::main, &trajectory_executer_));
00557 
00558 
00559                 /*
00560                  * /schunk/position/joint_state -> publishes joint state for kinematics modules
00561                  * /schunk/target_pc/joint_state <- for received position control commands
00562                  * /schunk/target_vc/joint_state  <- for receiving velocity control commands
00563                  * /schunk/status -> to publish all the statuses
00564                  */
00565 
00566                 ROS_INFO("Subscribing schunk topics...");
00567 
00568                 // those topics which must be received multiple times (for each joint) got a 10 for their message buffer
00569                 emergency_subscriber_ = node_handle_.subscribe("emergency", 1, &SchunkServer::cb_emergency, this);
00570                 stop_subscriber_ = node_handle_.subscribe("stop", 1, &SchunkServer::cb_stop, this);
00571                 ack_subscriber_ = node_handle_.subscribe("ack", 10, &SchunkServer::cb_ack, this);
00572                 ack_all_subscriber_ = node_handle_.subscribe("ack_all", 1, &SchunkServer::cb_ackAll, this);
00573                 ref_subscriber_ = node_handle_.subscribe("ref", 10, &SchunkServer::cb_ref, this);
00574                 ref_all_subscriber_ = node_handle_.subscribe("ref_all", 1, &SchunkServer::cb_refAll, this);
00575 
00576                 set_velocity_subscriber_ = node_handle_.subscribe("set_velocity", 10, &SchunkServer::cb_setVelocity, this);
00577                 set_acceleration_subscriber_ = node_handle_.subscribe("set_acceleration", 10, &SchunkServer::cb_setAcceleration, this);
00578                 set_current_subscriber_ = node_handle_.subscribe("set_current", 10, &SchunkServer::cb_setCurrent, this);
00579                 set_currents_max_all_subscriber_ = node_handle_.subscribe("set_current_max_all", 1, &SchunkServer::cb_setCurrentsMaxAll, this);
00580 
00581                 move_position_subscriber_ = node_handle_.subscribe("move_position", 10, &SchunkServer::cb_movePosition, this);
00582                 move_velocity_subscriber_ = node_handle_.subscribe("move_velocity", 10, &SchunkServer::cb_moveVelocity, this);
00583                 move_all_position_subscriber_ = node_handle_.subscribe("move_all_position", 1, &SchunkServer::cb_moveAllPosition, this);
00584                 move_all_velocity_subscriber_ = node_handle_.subscribe("move_all_velocity", 1, &SchunkServer::cb_moveAllVelocity, this);
00585                 trajectory_command_subscriber_ = node_handle_.subscribe("trajectory_command", 1, &SchunkServer::cb_commandTrajectory, this);
00586 
00587                 boost::thread(&SchunkServer::publishingLoop, this, ros::Rate(30));
00588 
00589                 ROS_INFO("SchunkServer Ready");
00590 
00591         }
00592 
00593         void cb_emergency(const std_msgs::Empty::ConstPtr& dummy)       {
00594                 ROS_INFO("emergency");
00595                 arm_->emergencyStopAll();
00596         }
00597 
00598         void cb_stop(const std_msgs::Empty::ConstPtr& dummy)    {
00599                 ROS_INFO("stop");
00600                 arm_->normalStopAll();
00601         }
00602 
00603         void cb_ack(const std_msgs::Int8::ConstPtr& id)         {
00604                 ROS_INFO("cb_ack: [%d]", id->data);
00605                 arm_->ackJoint(id->data);
00606         }
00607 
00608         void cb_ackAll(const std_msgs::Empty::ConstPtr& dummy)  {
00609                 ROS_INFO("cb_ackAll");
00610                 arm_->ackAll();
00611         }
00612 
00613         void cb_ref(const std_msgs::Int8::ConstPtr& id) {
00614                 ROS_INFO("cb_ref: [%d]", id->data);
00615                 arm_->refJoint(id->data);
00616         }
00617 
00618         void cb_refAll(const std_msgs::Empty::ConstPtr& dummy)  {
00619                 ROS_INFO("cb_refAll");
00620                 arm_->refAll();
00621         }
00622 
00623 
00624         void cb_setVelocity(const metralabs_msgs::IDAndFloat::ConstPtr& data)   {
00625                 ROS_INFO("cb_setVelocity: [%d, %f]", data->id, data->value);
00626                 arm_->setVelocity(data->id, data->value);
00627         }
00628 
00629         void cb_setAcceleration(const metralabs_msgs::IDAndFloat::ConstPtr& data)       {
00630                 ROS_INFO("cb_setAcceleration: [%d, %f]", data->id, data->value);
00631                 arm_->setAcceleration(data->id, data->value);
00632         }
00633 
00634         void cb_setCurrent(const metralabs_msgs::IDAndFloat::ConstPtr& data)    {
00635                 ROS_INFO("cb_setCurrent: [%d, %f]", data->id, data->value);
00636                 arm_->setCurrent(data->id, data->value);
00637         }
00638 
00639         void cb_setCurrentsMaxAll(const std_msgs::Empty::ConstPtr& dummy)       {
00640                 ROS_INFO("cb_setCurrentsMaxAll");
00641                 arm_->setCurrentsToMax();
00642         }
00643 
00644 
00645         void cb_movePosition(const metralabs_msgs::IDAndFloat::ConstPtr& data)  {
00646                 ROS_INFO("cb_movePosition: [%d, %f]", data->id, data->value);
00647                 arm_->movePosition(data->id, data->value);
00648         }
00649 
00650         void cb_moveVelocity(const metralabs_msgs::IDAndFloat::ConstPtr& data)  {
00651                 ROS_INFO("cb_moveVelocity: [%d, %f]", data->id, data->value);
00652                 if (data->value == 0.0)
00653                         arm_->normalStopJoint(data->id);
00654                 else
00655                         arm_->moveVelocity(data->id, data->value);
00656         }
00657 
00658         void cb_moveAllPosition(const sensor_msgs::JointState::ConstPtr& data) {
00659                 // The "names" member says how many joints, the other members may be empty.
00660                 // Not all the joints have to be specified in the message
00661                 // and not all types must be filled
00662                 for (uint i = 0; i < data.get()->name.size(); ++i) {
00663                         string joint_name = data.get()->name[i];
00664                         RobotArm::IDType joint_number = joints_name_to_number_map_[joint_name];
00665                         ROS_INFO_STREAM("cb_PositionControl: joint "<<joint_name<<" (#"<<joint_number<<")");
00666 
00667                         arm_->setCurrentsToMax();
00668                         if (data.get()->position.size()!=0) {
00669                                 double pos = data.get()->position[i];
00670                                 ROS_INFO_STREAM(" to position "<<pos);
00671                                 arm_->movePosition(joint_number, pos);
00672                         }
00673                         if (data.get()->velocity.size()!=0) {
00674                                 double vel = data.get()->velocity[i];
00675                                 ROS_INFO_STREAM(" with velocity "<<vel);
00676                                 arm_->setVelocity(joint_number, vel);
00677                         }
00678                         if (data.get()->effort.size()!=0) {
00679                                 double eff = data.get()->effort[i];
00680                                 ROS_INFO_STREAM(" with effort "<<eff);
00681                                 arm_->setCurrent(joint_number, eff);
00682                         }
00683                 }
00684         }
00685 
00686         void cb_moveAllVelocity(const sensor_msgs::JointState::ConstPtr& data) {
00687                 // The "names" member says how many joints, the other members may be empty.
00688                 // Not all the joints have to be specified in the message
00689                 // and not all types must be filled
00690                 for (uint i = 0; i < data.get()->name.size(); ++i) {
00691                         string joint_name = data.get()->name[i];
00692                         RobotArm::IDType joint_number = joints_name_to_number_map_[joint_name];
00693                         ROS_INFO_STREAM("cb_VelocityControl: joint "<<joint_name<<" (#"<<joint_number<<")");
00694 
00695 //                      m_powerCube.setCurrentsToMax();
00696 
00697                         if (data.get()->velocity.size() != 0) {
00698                                 double vel = data.get()->velocity[i];
00699                                 ROS_INFO_STREAM(" with velocity "<<vel);
00700                                 if (vel == 0.0)
00701                                         arm_->normalStopJoint(joint_number);
00702                                 else
00703                                         arm_->moveVelocity(joint_number, vel);
00704                         }
00705                         if (data.get()->effort.size()!=0) {
00706                                 double eff = data.get()->effort[i];
00707                                 ROS_INFO_STREAM(" with effort "<<eff);
00708                                 arm_->setCurrent(joint_number, eff);
00709                         }
00710                 }
00711         }
00712 
00713         void cb_commandTrajectory(const trajectory_msgs::JointTrajectory traj) {
00714                 ROS_INFO("Schunk Server: received a new trajectory");
00715                 trajectory_executer_.stop();
00716                 while (! trajectory_executer_.isWaiting() ) {
00717                         ROS_INFO("Waiting for the controller to be ready..");
00718                 }
00719                 trajectory_executer_.start(traj);
00720         }
00721 
00722 private:
00723         void publishingLoop(ros::Rate loop_rate) {
00724                 // TODO: convert to publisher
00725                 while (node_handle_.ok()) {
00726                         publishCurrentJointState();
00727                         publishCurrentSchunkStatus();
00728                         // This will adjust as needed per iteration
00729                         loop_rate.sleep();
00730                 }
00731         }
00732 
00733         void publishCurrentJointState() {
00734                 current_JointState_.header.stamp = ros::Time::now();
00735                 for (unsigned int i = 0; i < current_JointState_.name.size(); ++i) {
00736                         current_JointState_.position[i] = arm_->getPosition(i);
00737                         current_JointState_.velocity[i] = arm_->getVelocity(i);
00738                 }
00739                 current_JointState_publisher_.publish(current_JointState_);
00740         }
00741 
00742         void publishCurrentSchunkStatus() {
00743                 std::vector<metralabs_msgs::SchunkJointStatus>::iterator it;
00744                 for (it = current_SchunkStatus_.joints.begin(); it != current_SchunkStatus_.joints.end(); ++it) {
00745                         RobotArm::IDType module_number = joints_name_to_number_map_[it->jointName];
00746                         arm_->getModuleStatus(module_number, it->referenced, it->moving, it->progMode, it->warning,
00747                                         it->error, it->brake, it->moveEnd, it->posReached, it->errorCode, it->current);
00748                 }
00749                 current_SchunkStatus_publisher_.publish(current_SchunkStatus_);
00750         }
00751 
00752 
00753 private:
00754         ros::NodeHandle node_handle_;
00755         RobotArm* arm_;
00756         urdf::Model arm_model_; // A parsing of the model description
00757         std::vector<boost::shared_ptr<urdf::Joint> > joints_list_;
00758         std::map<std::string, RobotArm::IDType> joints_name_to_number_map_;
00759 
00760         sensor_msgs::JointState current_JointState_;
00761         metralabs_msgs::SchunkStatus current_SchunkStatus_;
00762         ros::Publisher current_JointState_publisher_;
00763         ros::Publisher current_SchunkStatus_publisher_;
00764 
00765         TrajectoryExecuter trajectory_executer_;
00766         boost::thread trajectory_executer_thread_;
00767 
00768         ros::Subscriber emergency_subscriber_;
00769         ros::Subscriber stop_subscriber_;
00770         ros::Subscriber first_ref_subscriber_;
00771         ros::Subscriber ack_subscriber_;
00772         ros::Subscriber ack_all_subscriber_;
00773         ros::Subscriber ref_subscriber_;
00774         ros::Subscriber ref_all_subscriber_;
00775 
00776         ros::Subscriber set_velocity_subscriber_;
00777         ros::Subscriber set_acceleration_subscriber_;
00778         ros::Subscriber set_current_subscriber_;
00779         ros::Subscriber set_currents_max_all_subscriber_;
00780 
00781         ros::Subscriber move_position_subscriber_;
00782         ros::Subscriber move_velocity_subscriber_;
00783         ros::Subscriber move_all_position_subscriber_;
00784         ros::Subscriber move_all_velocity_subscriber_;
00785         ros::Subscriber trajectory_command_subscriber_;
00786 };
00787 
00788 
00789 #endif /* SCHUNKSERVER_H_ */


metralabs_ros
Author(s): Yianni Gatsoulis and Chris Burbridge and Lorenzo Riano and Felix Kolbe
autogenerated on Mon Oct 6 2014 07:27:58