SVHNode.cpp
Go to the documentation of this file.
00001 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
00002 
00003 // -- BEGIN LICENSE BLOCK ----------------------------------------------
00004 // This file is part of the SCHUNK SVH Driver suite.
00005 //
00006 // This program is free software licensed under the LGPL
00007 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
00008 // You can find a copy of this license in LICENSE folder in the top
00009 // directory of the source code.
00010 //
00011 // © Copyright 2014 SCHUNK Mobile Greifsysteme GmbH, Lauffen/Neckar Germany
00012 // © Copyright 2014 FZI Forschungszentrum Informatik, Karlsruhe, Germany
00013 //
00014 // -- END LICENSE BLOCK ------------------------------------------------
00015 
00016 //----------------------------------------------------------------------
00024 //----------------------------------------------------------------------
00025 // ROS includes.
00026 #include <ros/ros.h>
00027 #include <string>
00028 
00029 // Custom includes
00030 #include "SVHNode.h"
00031 #include <icl_core/EnumHelper.h>
00032 
00033 
00034 
00035 /*--------------------------------------------------------------------
00036  * Callback functions
00037  *------------------------------------------------------------------*/
00038 
00039 SVHNode::SVHNode(const ros::NodeHandle & nh)
00040 {
00041 
00042   //==========
00043   // Params
00044   //==========
00045 
00046   bool autostart,use_internal_logging;
00047   int reset_timeout;
00048   std::vector<bool> disable_flags(driver_svh::eSVH_DIMENSION, false);
00049   // Config that contains the log stream configuration without the file names
00050   std::string logging_config_file;
00051 
00052 
00053   try
00054   {
00055     nh.param<bool>("autostart",autostart,false);
00056     nh.param<bool>("use_internal_logging",use_internal_logging,false);
00057     nh.param<std::string>("serial_device",serial_device_name_,"/dev/ttyUSB0");
00058     // Note : Wrong values (like numerics) in the launch file will lead to a "true" value here
00059     nh.getParam("disable_flags",disable_flags);
00060     nh.param<int>("reset_timeout",reset_timeout,5);
00061     nh.getParam("logging_config",logging_config_file);
00062     nh.param<std::string>("name_prefix",name_prefix,"left_hand");
00063     nh.param<int>("connect_retry_count",connect_retry_count,3);
00064   }
00065   catch (ros::InvalidNameException e)
00066   {
00067     ROS_ERROR("Parameter Error!");
00068   }
00069 
00070   // Tell the user what we are using
00071   ROS_INFO("Name prefix for this Hand was set to :%s",name_prefix.c_str());
00072 
00073   // Initialize the icl_library logging framework ( THIS NEEDS TO BE DONE BEFORE ANY LIB OBJECT IS CREATED)
00074   if (use_internal_logging)
00075   {
00076     // Fake an input to the logging call to tell it where to look for the logging config
00077 
00078     // Strdup to create non const chars as it is required by the initialize function.
00079     // not really beatiful but it works.
00080     char * argv[]= {
00081       strdup("Logging"),
00082       strdup("-c"),
00083       strdup(logging_config_file.c_str())
00084     };
00085     int argc = 3; // number of elements above
00086 
00087     // In case the file is not present (event though the parameter is) the logging will just put out a
00088     // warning so we dont need to check it further. However the log level will only be Info (out of the available Error, Warning, Info, Debug, Trace)
00089     // in that case also the log files will be disregarded
00090     if (icl_core::logging::initialize(argc,argv))
00091       ROS_INFO("Internal logging was activated, output will be written as configured in logging.xml (default to ~/.ros/log)");
00092     else
00093       ROS_WARN("Internal logging was enabled but config file could not be read. Please make sure the provided path to the config file is correct.");
00094   }
00095   else
00096   {
00097     icl_core::logging::initialize();
00098   }
00099 
00100 
00101 
00102 
00103   for (size_t i = 0; i < 9; ++i)
00104   {
00105     if(disable_flags[i])
00106     {
00107       ROS_WARN("svh_controller disabling channel nr %i", i);
00108     }
00109   }
00110 
00111   // Init the actual driver hook (after logging initialize)
00112   fm_.reset(new driver_svh::SVHFingerManager(disable_flags,reset_timeout));
00113 
00114   // Rosparam can only fill plain vectors so we will have to go through them
00115   std::vector< std::vector<float> > position_settings(driver_svh::eSVH_DIMENSION);
00116   std::vector<bool> postion_settings_given(driver_svh::eSVH_DIMENSION,false);
00117 
00118   std::vector< std::vector<float> > current_settings(driver_svh::eSVH_DIMENSION);
00119   std::vector<bool> current_settings_given(driver_svh::eSVH_DIMENSION,false);
00120 
00121   std::vector< std::vector<float> > home_settings(driver_svh::eSVH_DIMENSION);
00122   std::vector<bool> home_settings_given(driver_svh::eSVH_DIMENSION,false);
00123 
00124 
00125   // get the the indidividual finger params
00126   // We will read out all of them, so that in case we fail half way we do not set anything
00127   try
00128   {
00129     postion_settings_given[driver_svh::eSVH_THUMB_FLEXION] = nh.getParam("THUMB_FLEXION/position_controller",position_settings[driver_svh::eSVH_THUMB_FLEXION]);
00130     current_settings_given[driver_svh::eSVH_THUMB_FLEXION] = nh.getParam("THUMB_FLEXION/current_controller",current_settings[driver_svh::eSVH_THUMB_FLEXION]);
00131     home_settings_given[driver_svh::eSVH_THUMB_FLEXION]    = nh.getParam("THUMB_FLEXION/home_settings",home_settings[driver_svh::eSVH_THUMB_FLEXION]);
00132 
00133     postion_settings_given[driver_svh::eSVH_THUMB_OPPOSITION] = nh.getParam("THUMB_OPPOSITION/position_controller",position_settings[driver_svh::eSVH_THUMB_OPPOSITION]);
00134     current_settings_given[driver_svh::eSVH_THUMB_OPPOSITION] = nh.getParam("THUMB_OPPOSITION/current_controller",current_settings[driver_svh::eSVH_THUMB_OPPOSITION]);
00135     home_settings_given[driver_svh::eSVH_THUMB_OPPOSITION]    = nh.getParam("THUMB_OPPOSITION/home_settings",home_settings[driver_svh::eSVH_THUMB_OPPOSITION]);
00136 
00137     postion_settings_given[driver_svh::eSVH_INDEX_FINGER_DISTAL] = nh.getParam("INDEX_FINGER_DISTAL/position_controller",position_settings[driver_svh::eSVH_INDEX_FINGER_DISTAL]);
00138     current_settings_given[driver_svh::eSVH_INDEX_FINGER_DISTAL] = nh.getParam("INDEX_FINGER_DISTAL/current_controller",current_settings[driver_svh::eSVH_INDEX_FINGER_DISTAL]);
00139     home_settings_given[driver_svh::eSVH_INDEX_FINGER_DISTAL]    = nh.getParam("INDEX_FINGER_DISTAL/home_settings",home_settings[driver_svh::eSVH_INDEX_FINGER_DISTAL]);
00140 
00141     postion_settings_given[driver_svh::eSVH_INDEX_FINGER_PROXIMAL] = nh.getParam("INDEX_FINGER_PROXIMAL/position_controller",position_settings[driver_svh::eSVH_INDEX_FINGER_PROXIMAL]);
00142     current_settings_given[driver_svh::eSVH_INDEX_FINGER_PROXIMAL] = nh.getParam("INDEX_FINGER_PROXIMAL/current_controller",current_settings[driver_svh::eSVH_INDEX_FINGER_PROXIMAL]);
00143     home_settings_given[driver_svh::eSVH_INDEX_FINGER_PROXIMAL]    = nh.getParam("INDEX_FINGER_PROXIMAL/home_settings",home_settings[driver_svh::eSVH_INDEX_FINGER_PROXIMAL]);
00144 
00145     postion_settings_given[driver_svh::eSVH_MIDDLE_FINGER_DISTAL] = nh.getParam("MIDDLE_FINGER_DISTAL/position_controller",position_settings[driver_svh::eSVH_MIDDLE_FINGER_DISTAL]);
00146     current_settings_given[driver_svh::eSVH_MIDDLE_FINGER_DISTAL] = nh.getParam("MIDDLE_FINGER_DISTAL/current_controller",current_settings[driver_svh::eSVH_MIDDLE_FINGER_DISTAL]);
00147     home_settings_given[driver_svh::eSVH_MIDDLE_FINGER_DISTAL]    = nh.getParam("MIDDLE_FINGER_DISTAL/home_settings",home_settings[driver_svh::eSVH_MIDDLE_FINGER_DISTAL]);
00148 
00149     postion_settings_given[driver_svh::eSVH_MIDDLE_FINGER_PROXIMAL] = nh.getParam("MIDDLE_FINGER_PROXIMAL/position_controller",position_settings[driver_svh::eSVH_MIDDLE_FINGER_PROXIMAL]);
00150     current_settings_given[driver_svh::eSVH_MIDDLE_FINGER_PROXIMAL] = nh.getParam("MIDDLE_FINGER_PROXIMAL/current_controller",current_settings[driver_svh::eSVH_MIDDLE_FINGER_PROXIMAL]);
00151     home_settings_given[driver_svh::eSVH_MIDDLE_FINGER_PROXIMAL]    = nh.getParam("MIDDLE_FINGER_PROXIMAL/home_settings",home_settings[driver_svh::eSVH_MIDDLE_FINGER_PROXIMAL]);
00152 
00153     postion_settings_given[driver_svh::eSVH_RING_FINGER] = nh.getParam("RING_FINGER/position_controller",position_settings[driver_svh::eSVH_RING_FINGER]);
00154     current_settings_given[driver_svh::eSVH_RING_FINGER] = nh.getParam("RING_FINGER/current_controller",current_settings[driver_svh::eSVH_RING_FINGER]);
00155     home_settings_given[driver_svh::eSVH_RING_FINGER]    = nh.getParam("RING_FINGER/home_settings",home_settings[driver_svh::eSVH_RING_FINGER]);
00156 
00157     postion_settings_given[driver_svh::eSVH_PINKY] = nh.getParam("PINKY/position_controller",position_settings[driver_svh::eSVH_PINKY]);
00158     current_settings_given[driver_svh::eSVH_PINKY] = nh.getParam("PINKY/current_controller",current_settings[driver_svh::eSVH_PINKY]);
00159     home_settings_given[driver_svh::eSVH_PINKY]    = nh.getParam("PINKY/home_settings",home_settings[driver_svh::eSVH_PINKY]);
00160 
00161     postion_settings_given[driver_svh::eSVH_FINGER_SPREAD] = nh.getParam("FINGER_SPREAD/position_controller",position_settings[driver_svh::eSVH_FINGER_SPREAD]);
00162     current_settings_given[driver_svh::eSVH_FINGER_SPREAD] = nh.getParam("FINGER_SPREAD/current_controller",current_settings[driver_svh::eSVH_FINGER_SPREAD]);
00163     home_settings_given[driver_svh::eSVH_FINGER_SPREAD]    = nh.getParam("FINGER_SPREAD/home_settings",home_settings[driver_svh::eSVH_FINGER_SPREAD]);
00164 
00165     for (size_t channel = 0; channel < driver_svh::eSVH_DIMENSION; ++channel)
00166     {
00167       // Only update the values in case actually have some. Otherwise the driver will use internal defaults. Overwriting them with zeros would be counter productive
00168       if (current_settings_given[channel])
00169       {
00170         fm_->setCurrentSettings(static_cast<driver_svh::SVHChannel>(channel),driver_svh::SVHCurrentSettings(current_settings[channel]));
00171       }
00172       if (postion_settings_given[channel])
00173       {
00174         fm_->setPositionSettings(static_cast<driver_svh::SVHChannel>(channel),driver_svh::SVHPositionSettings(position_settings[channel]));
00175       }
00176       if (home_settings_given[channel])
00177       {
00178         fm_->setHomeSettings(static_cast<driver_svh::SVHChannel>(channel),driver_svh::SVHHomeSettings(home_settings[channel]));
00179       }
00180     }
00181   }
00182   catch (ros::InvalidNameException e)
00183   {
00184     ROS_ERROR("Parameter Error! While reading the controller settings. Will use default settings");
00185   }
00186 
00187   // prepare the channel position message for later sending
00188   channel_pos_.name.resize(driver_svh::eSVH_DIMENSION);
00189   channel_pos_.position.resize(driver_svh::eSVH_DIMENSION, 0.0);
00190   channel_pos_.effort.resize(driver_svh::eSVH_DIMENSION, 0.0);
00191   for (size_t channel = 0; channel < driver_svh::eSVH_DIMENSION; ++channel)
00192   {
00193     channel_pos_.name[channel] = name_prefix + "_" + driver_svh::SVHController::m_channel_description[channel];
00194   }
00195 
00196   // Prepare the channel current message for later sending
00197   channel_currents.data.clear();
00198   channel_currents.data.resize(driver_svh::eSVH_DIMENSION, 0.0);
00199   channel_currents.layout.data_offset = 0;
00200   std_msgs::MultiArrayDimension dim ;
00201   dim.label ="channel currents";
00202   dim.size = 9;
00203   dim.stride = 0;
00204   channel_currents.layout.dim.push_back(dim);
00205 
00206   // Connect and start the reset so that the hand is ready for use
00207   if (autostart && fm_->connect(serial_device_name_,connect_retry_count))
00208   {
00209     fm_->resetChannel(driver_svh::eSVH_ALL);
00210     ROS_INFO("Driver was autostarted! Input can now be sent. Have a safe and productive day!");
00211   }
00212   else
00213   {
00214     ROS_INFO("SVH Driver Ready, you will need to connect and reset the fingers before you can use the hand.");
00215   }
00216 
00217 }
00218 
00219 SVHNode::~SVHNode()
00220 {
00221   // Tell the driver to close connections
00222   fm_->disconnect();
00223 }
00224 
00225 // Callback function for changing parameters dynamically
00226 void SVHNode::dynamic_reconfigure_callback(svh_controller::svhConfig &config, uint32_t level)
00227 {
00228   serial_device_name_ = config.serial_device;
00229 
00230   fm_->setResetSpeed(config.finger_reset_speed);
00231   fm_->setResetTimeout(config.reset_timeout);
00232 }
00233 
00234 // Callback function for connecting to SCHUNK five finger hand
00235 void SVHNode::connectCallback(const std_msgs::Empty&)
00236 {
00237   if (fm_->isConnected())
00238   {
00239     fm_->disconnect();
00240   }
00241 
00242   if (!fm_->connect(serial_device_name_,connect_retry_count))
00243   {
00244     ROS_ERROR("Could not connect to SCHUNK five finger hand with serial device %s, and retry count %i", serial_device_name_.c_str(),connect_retry_count);
00245   }
00246 }
00247 
00248 // Callback function to reset/home channels of SCHUNK five finger hand
00249 void SVHNode::resetChannelCallback(const std_msgs::Int8ConstPtr& channel)
00250 {
00251   // convert int8 channel into SVHChannel enum
00252   driver_svh::SVHChannel svh_channel = static_cast<driver_svh::SVHChannel>(channel->data);
00253 
00254   if (fm_->resetChannel(svh_channel))
00255   {
00256     ROS_INFO("Channel %i successfully homed!", svh_channel);
00257   }
00258   else
00259   {
00260     ROS_ERROR("Could not reset channel %i !", svh_channel);
00261   }
00262 }
00263 
00264 // Callback function to enable channels of SCHUNK five finger hand
00265 void SVHNode::enableChannelCallback(const std_msgs::Int8ConstPtr& channel)
00266 {
00267   fm_->enableChannel(static_cast<driver_svh::SVHChannel>(channel->data));
00268 }
00269 
00270 // Callback function for setting channel target positions to SCHUNK five finger hand
00271 void SVHNode::jointStateCallback(const sensor_msgs::JointStateConstPtr& input )
00272 {
00273   // vector to read target positions from joint states
00274   std::vector<double> target_positions(driver_svh::eSVH_DIMENSION, 0.0);
00275   // bool vector storing true, if new target position read
00276   std::vector<bool> pos_read(driver_svh::eSVH_DIMENSION, false);
00277   // target positions read counter
00278   uint8_t pos_read_counter = 0;
00279 
00280   size_t index = 0;
00281   std::vector<std::string>::const_iterator joint_name;
00282   for (joint_name = input->name.begin(); joint_name != input->name.end(); ++joint_name,++index)
00283   {
00284     int32_t channel = 0;
00285 
00286     // Find the corresponding channels to the input joint names
00287     bool valid_input = false;
00288     for (channel=0;!valid_input && (channel < driver_svh::eSVH_DIMENSION) && (driver_svh::SVHController::m_channel_description[channel] != NULL);++channel)
00289     {
00290         valid_input = (joint_name->compare(name_prefix + "_" + driver_svh::SVHController::m_channel_description[channel]) == 0);
00291     }
00292 
00293     // We count one to high with the for loop so we have to correct that
00294     --channel;
00295 
00296 
00297     if (valid_input)//(icl_core::string2Enum((*joint_name), channel, driver_svh::SVHController::m_channel_description))
00298     {
00299       if (input->position.size() > index)
00300       {
00301         target_positions[channel] = input->position[index];
00302         pos_read[channel] = true;
00303         pos_read_counter++;
00304       }
00305       else
00306       {
00307         ROS_WARN("Vector of input joint state is too small! Cannot acces elemnt nr %i", index);
00308       }
00309     }
00310     else
00311     {
00312       //ROS_WARN("Could not map joint name %s to channel!", (*joint_name).c_str());
00313     }
00314   }
00315 
00316   // send target values at once
00317   if (pos_read_counter == driver_svh::eSVH_DIMENSION)
00318   {
00319     if (!fm_->setAllTargetPositions(target_positions))
00320     {
00321       ROS_WARN_ONCE("Set target position command rejected!");
00322     }
00323   }
00324   // not all positions has been set: send only the available positions
00325   else
00326   {
00327     for (size_t i = 0; i < driver_svh::eSVH_DIMENSION; ++i)
00328     {
00329       if (pos_read[i])
00330       {
00331         fm_->setTargetPosition(static_cast<driver_svh::SVHChannel>(i), target_positions[i], 0.0);
00332       }
00333     }
00334   }
00335 }
00336 
00337 
00338 sensor_msgs::JointState SVHNode::getChannelFeedback()
00339 {
00340   if (fm_->isConnected())
00341   {
00342     // Get positions in rad
00343     for (size_t channel = 0; channel < driver_svh::eSVH_DIMENSION; ++channel)
00344     {
00345       double cur_pos = 0.0;
00346       double cur_cur = 0.0;
00347       if (fm_->isHomed(static_cast<driver_svh::SVHChannel>(channel)))
00348       {
00349         fm_->getPosition(static_cast<driver_svh::SVHChannel>(channel), cur_pos);
00350         // Read out currents if you want to
00351         fm_->getCurrent(static_cast<driver_svh::SVHChannel>(channel),cur_cur);
00352       }
00353       channel_pos_.position[channel] = cur_pos;
00354       channel_pos_.effort[channel] = cur_cur * driver_svh::SVHController::channel_effort_constants[channel];
00355     }
00356   }
00357 
00358   channel_pos_.header.stamp = ros::Time::now();
00359   return  channel_pos_;
00360 }
00361 
00362 std_msgs::Float64MultiArray SVHNode::getChannelCurrents()
00363 {
00364   if (fm_->isConnected())
00365   {
00366     // Get currents
00367     for (size_t channel = 0; channel < driver_svh::eSVH_DIMENSION; ++channel)
00368     {
00369       double cur_cur = 0.0;
00370       if (fm_->isHomed(static_cast<driver_svh::SVHChannel>(channel)))
00371       {
00372         fm_->getCurrent(static_cast<driver_svh::SVHChannel>(channel),cur_cur);
00373       }
00374       channel_currents.data[channel] = cur_cur;
00375     }
00376   }
00377 
00378   return  channel_currents;
00379 
00380 }
00381 
00382 
00383 /*--------------------------------------------------------------------
00384  * main()
00385  * Main function to set up ROS node.
00386  *------------------------------------------------------------------*/
00387 
00388 int main(int argc, char **argv)
00389 {
00390   //==========
00391   // ROS
00392   //==========
00393 
00394   // Set up ROS.
00395   ros::init(argc, argv, "svh_controller");
00396   // Private NH for general params
00397   ros::NodeHandle nh("~");
00398 
00399 
00400   // Tell ROS how fast to run this node. (100 = 100 Hz = 10 ms)
00401   ros::Rate rate(50);
00402 
00403   //==========
00404   // Logic
00405   //==========
00406   // Node object holding all the relevant functions
00407   SVHNode svh_node(nh);
00408 
00409   //==========
00410   // Dynamic Reconfigure
00411   //==========
00412 
00413   dynamic_reconfigure::Server<svh_controller::svhConfig> server;
00414   dynamic_reconfigure::Server<svh_controller::svhConfig>::CallbackType f;
00415 
00416   f = boost::bind(&SVHNode::dynamic_reconfigure_callback,&svh_node, _1, _2);
00417   server.setCallback(f);
00418 
00419   //==========
00420   // Callbacks
00421   //==========
00422 
00423   // Subscribe connect topic (Empty)
00424   ros::Subscriber connect_sub = nh.subscribe("connect", 1, &SVHNode::connectCallback,&svh_node);
00425   // Subscribe reset channel topic (Int8)
00426   ros::Subscriber reset_sub = nh.subscribe("reset_channel", 1, &SVHNode::resetChannelCallback,&svh_node);
00427   // Subscribe enable channel topic (Int8)
00428   ros::Subscriber enable_sub = nh.subscribe("enable_channel", 1, &SVHNode::enableChannelCallback, &svh_node);
00429   // Subscribe joint state topic
00430   ros::Subscriber channel_target_sub = nh.subscribe<sensor_msgs::JointState>("channel_targets", 1, &SVHNode::jointStateCallback,&svh_node,ros::TransportHints().tcpNoDelay() );
00431   // Publish current channel positions
00432   ros::Publisher channel_pos_pub = nh.advertise<sensor_msgs::JointState>("channel_feedback", 1);
00433   // Additionally publish just the current values of the motors
00434   ros::Publisher channel_current_pub = nh.advertise<std_msgs::Float64MultiArray>("channel_currents", 1);
00435 
00436   //==========
00437   // Messaging
00438   //==========
00439 
00440   // Main loop.
00441   while (nh.ok())
00442   {
00443     // get the current positions of all joints and publish them
00444     channel_pos_pub.publish(svh_node.getChannelFeedback());
00445     channel_current_pub.publish(svh_node.getChannelCurrents());
00446 
00447     ros::spinOnce();
00448     rate.sleep();
00449   }
00450 
00451 
00452   return 0;
00453 }


schunk_svh_driver
Author(s): Georg Heppner
autogenerated on Fri Aug 28 2015 12:59:19