SVHNode.cpp
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // This file is part of the SCHUNK SVH Driver suite.
5 //
6 // This program is free software licensed under the LGPL
7 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
8 // You can find a copy of this license in LICENSE folder in the top
9 // directory of the source code.
10 //
11 // © Copyright 2014 SCHUNK Mobile Greifsysteme GmbH, Lauffen/Neckar Germany
12 // © Copyright 2014 FZI Forschungszentrum Informatik, Karlsruhe, Germany
13 //
14 // -- END LICENSE BLOCK ------------------------------------------------
15 
16 //----------------------------------------------------------------------
24 //----------------------------------------------------------------------
25 // ROS includes.
26 #include <ros/ros.h>
27 #include <string>
28 
29 // Custom includes
30 #include "DynamicParameterClass.h"
31 #include "SVHNode.h"
32 #include <icl_core/EnumHelper.h>
33 
34 
35 /*--------------------------------------------------------------------
36  * Callback functions
37  *------------------------------------------------------------------*/
38 
40 {
41  //==========
42  // Params
43  //==========
44 
45  bool autostart, use_internal_logging;
46  int reset_timeout;
47  std::vector<bool> disable_flags(driver_svh::eSVH_DIMENSION, false);
48  // Config that contains the log stream configuration without the file names
49  std::string logging_config_file;
50 
51  // Parameters that depend on the hardware version of the hand.
52  XmlRpc::XmlRpcValue dynamic_parameters;
53 
54  uint16_t manual_major_version = 0;
55  int manual_major_version_int = 0;
56  uint16_t manual_minor_version = 0;
57  int manual_minor_version_int = 0;
58 
59  try
60  {
61  nh.param<bool>("autostart", autostart, false);
62  nh.param<bool>("use_internal_logging", use_internal_logging, false);
63  nh.param<std::string>("serial_device", serial_device_name_, "/dev/ttyUSB0");
64  // Note : Wrong values (like numerics) in the launch file will lead to a "true" value here
65  nh.getParam("disable_flags", disable_flags);
66  nh.param<int>("reset_timeout", reset_timeout, 5);
67  nh.getParam("logging_config", logging_config_file);
68  nh.param<std::string>("name_prefix", name_prefix, "left_hand");
69  nh.param<int>("connect_retry_count", connect_retry_count, 3);
70  nh.getParam("VERSIONS_PARAMETERS", dynamic_parameters);
71  nh.param<int>("use_major_version", manual_major_version_int, 0);
72  manual_major_version = static_cast<uint16_t>(manual_major_version_int);
73  nh.param<int>("use_minor_version", manual_minor_version_int, 0);
74  manual_minor_version = static_cast<uint16_t>(manual_minor_version_int);
75  }
77  {
78  ROS_ERROR("Parameter Error!");
79  }
80 
81  // Tell the user what we are using
82  ROS_INFO("Name prefix for this Hand was set to :%s", name_prefix.c_str());
83 
84  // Initialize the icl_library logging framework ( THIS NEEDS TO BE DONE BEFORE ANY LIB OBJECT IS
85  // CREATED)
86  if (use_internal_logging)
87  {
88  // Fake an input to the logging call to tell it where to look for the logging config
89 
90  // Strdup to create non const chars as it is required by the initialize function.
91  // not really beatiful but it works.
92  char* argv[] = {strdup("Logging"), strdup("-c"), strdup(logging_config_file.c_str())};
93  int argc = 3; // number of elements above
94 
95  // In case the file is not present (event though the parameter is) the logging will just put out
96  // a
97  // warning so we dont need to check it further. However the log level will only be Info (out of
98  // the available Error, Warning, Info, Debug, Trace)
99  // in that case also the log files will be disregarded
100  if (icl_core::logging::initialize(argc, argv))
101  {
102  ROS_INFO("Internal logging was activated, output will be written as configured in "
103  "logging.xml (default to ~/.ros/log)");
104  }
105  else
106  {
107  ROS_WARN("Internal logging was enabled but config file could not be read. Please make sure "
108  "the provided path to the config file is correct.");
109  }
110  }
111  else
112  {
114  }
115 
116  for (size_t i = 0; i < 9; ++i)
117  {
118  if (disable_flags[i])
119  {
120  ROS_WARN_STREAM("svh_controller disabling channel nr " << i);
121  }
122  }
123 
124  // Init the actual driver hook (after logging initialize)
125  fm_.reset(new driver_svh::SVHFingerManager(disable_flags, reset_timeout));
126 
127  // Receives current Firmware Version
128  // because some parameters depend on the version
129  if (manual_major_version == 0 && manual_minor_version == 0)
130  {
132  driver_svh::SVHFirmwareInfo version_info = fm_->getFirmwareInfo();
133  ROS_INFO("Hand hardware controller version: %d.%d",
134  version_info.version_major,
135  version_info.version_minor);
136 
137  manual_major_version = version_info.version_major;
138  manual_minor_version = version_info.version_minor;
139 
140  fm_->disconnect();
141  }
142  // get the the individual finger parameters
143  // We will read out all of them, so that in case we fail half way we do not set anything
144  try
145  {
146  // Loading hand parameters
147  DynamicParameter dyn_parameters(manual_major_version, manual_minor_version, dynamic_parameters);
148 
149 
150  for (size_t channel = 0; channel < driver_svh::eSVH_DIMENSION; ++channel)
151  {
152  // Only update the values in case actually have some. Otherwise the driver will use internal
153  // defaults. Overwriting them with zeros would be counter productive
154  if (dyn_parameters.getSettings().current_settings_given[channel])
155  {
156  fm_->setCurrentSettings(
157  static_cast<driver_svh::SVHChannel>(channel),
158  driver_svh::SVHCurrentSettings(dyn_parameters.getSettings().current_settings[channel]));
159  }
160  if (dyn_parameters.getSettings().position_settings_given[channel])
161  {
162  fm_->setPositionSettings(
163  static_cast<driver_svh::SVHChannel>(channel),
165  }
166  if (dyn_parameters.getSettings().home_settings_given[channel])
167  {
168  fm_->setHomeSettings(static_cast<driver_svh::SVHChannel>(channel),
170  dyn_parameters.getSettings().home_settings[channel]
171  ));
172  }
173  }
174  }
175  catch (ros::InvalidNameException e)
176  {
177  ROS_ERROR("Parameter Error! While reading the controller settings. Will use default settings");
178  }
179 
180  // prepare the channel position message for later sending
182  channel_pos_.position.resize(driver_svh::eSVH_DIMENSION, 0.0);
183  channel_pos_.effort.resize(driver_svh::eSVH_DIMENSION, 0.0);
184  for (size_t channel = 0; channel < driver_svh::eSVH_DIMENSION; ++channel)
185  {
186  channel_pos_.name[channel] =
188  }
189 
190  // Prepare the channel current message for later sending
191  channel_currents.data.clear();
192  channel_currents.data.resize(driver_svh::eSVH_DIMENSION, 0.0);
193  channel_currents.layout.data_offset = 0;
194  std_msgs::MultiArrayDimension dim;
195  dim.label = "channel currents";
196  dim.size = 9;
197  dim.stride = 0;
198  channel_currents.layout.dim.push_back(dim);
199 
200  // Connect and start the reset so that the hand is ready for use
201  if (autostart && fm_->connect(serial_device_name_, connect_retry_count))
202  {
203  fm_->resetChannel(driver_svh::eSVH_ALL);
204  ROS_INFO("Driver was autostarted! Input can now be sent. Have a safe and productive day!");
205  }
206  else
207  {
208  ROS_INFO("SVH Driver Ready, you will need to connect and reset the fingers before you can use "
209  "the hand.");
210  }
211 }
212 
214 {
215  // Tell the driver to close connections
216  fm_->disconnect();
217 }
218 
219 // Callback function for changing parameters dynamically
220 void SVHNode::dynamic_reconfigure_callback(svh_controller::svhConfig& config, uint32_t level)
221 {
222  serial_device_name_ = config.serial_device;
223 
224  fm_->setResetSpeed(config.finger_reset_speed);
225  fm_->setResetTimeout(config.reset_timeout);
226 }
227 
228 // Callback function for connecting to SCHUNK five finger hand
229 void SVHNode::connectCallback(const std_msgs::Empty&)
230 {
231  if (fm_->isConnected())
232  {
233  fm_->disconnect();
234  }
235 
237  {
238  ROS_ERROR(
239  "Could not connect to SCHUNK five finger hand with serial device %s, and retry count %i",
240  serial_device_name_.c_str(),
242  }
243 }
244 
245 // Callback function to reset/home channels of SCHUNK five finger hand
246 void SVHNode::resetChannelCallback(const std_msgs::Int8ConstPtr& channel)
247 {
248  // convert int8 channel into SVHChannel enum
249  driver_svh::SVHChannel svh_channel = static_cast<driver_svh::SVHChannel>(channel->data);
250 
251  if (fm_->resetChannel(svh_channel))
252  {
253  ROS_INFO("Channel %i successfully homed!", svh_channel);
254  }
255  else
256  {
257  ROS_ERROR("Could not reset channel %i !", svh_channel);
258  }
259 }
260 
261 // Callback function to enable channels of SCHUNK five finger hand
262 void SVHNode::enableChannelCallback(const std_msgs::Int8ConstPtr& channel)
263 {
264  fm_->enableChannel(static_cast<driver_svh::SVHChannel>(channel->data));
265 }
266 
267 // Callback function for setting channel target positions to SCHUNK five finger hand
268 void SVHNode::jointStateCallback(const sensor_msgs::JointStateConstPtr& input)
269 {
270  // vector to read target positions from joint states
271  std::vector<double> target_positions(driver_svh::eSVH_DIMENSION, 0.0);
272  // bool vector storing true, if new target position read
273  std::vector<bool> pos_read(driver_svh::eSVH_DIMENSION, false);
274  // target positions read counter
275  uint8_t pos_read_counter = 0;
276 
277  size_t index = 0;
278  std::vector<std::string>::const_iterator joint_name;
279  for (joint_name = input->name.begin(); joint_name != input->name.end(); ++joint_name, ++index)
280  {
281  int32_t channel = 0;
282 
283  // Find the corresponding channels to the input joint names
284  bool valid_input = false;
285  for (channel = 0; !valid_input && (channel < driver_svh::eSVH_DIMENSION) &&
287  ++channel)
288  {
289  valid_input =
290  (joint_name->compare(name_prefix + "_" +
292  }
293 
294  // We count one to high with the for loop so we have to correct that
295  --channel;
296 
297 
298  if (valid_input) //(icl_core::string2Enum((*joint_name), channel,
299  //driver_svh::SVHController::m_channel_description))
300  {
301  if (input->position.size() > index)
302  {
303  target_positions[channel] = input->position[index];
304  pos_read[channel] = true;
305  pos_read_counter++;
306  }
307  else
308  {
309  ROS_WARN_STREAM("Vector of input joint state is too small! Cannot access element nr "
310  << index);
311  }
312  }
313  else
314  {
315  // ROS_WARN("Could not map joint name %s to channel!", (*joint_name).c_str());
316  }
317  }
318 
319  // send target values at once
320  if (pos_read_counter == driver_svh::eSVH_DIMENSION)
321  {
322  if (!fm_->setAllTargetPositions(target_positions))
323  {
324  ROS_WARN_ONCE("Set target position command rejected!");
325  }
326  }
327  // not all positions has been set: send only the available positions
328  else
329  {
330  for (size_t i = 0; i < driver_svh::eSVH_DIMENSION; ++i)
331  {
332  if (pos_read[i])
333  {
334  fm_->setTargetPosition(static_cast<driver_svh::SVHChannel>(i), target_positions[i], 0.0);
335  }
336  }
337  }
338 }
339 
340 
341 sensor_msgs::JointState SVHNode::getChannelFeedback()
342 {
343  if (fm_->isConnected())
344  {
345  // Get positions in rad
346  for (size_t channel = 0; channel < driver_svh::eSVH_DIMENSION; ++channel)
347  {
348  double cur_pos = 0.0;
349  double cur_cur = 0.0;
350  if (fm_->isHomed(static_cast<driver_svh::SVHChannel>(channel)))
351  {
352  fm_->getPosition(static_cast<driver_svh::SVHChannel>(channel), cur_pos);
353  // Read out currents if you want to
354  fm_->getCurrent(static_cast<driver_svh::SVHChannel>(channel), cur_cur);
355  }
356  channel_pos_.position[channel] = cur_pos;
357  channel_pos_.effort[channel] =
359  }
360  }
361 
362  channel_pos_.header.stamp = ros::Time::now();
363  return channel_pos_;
364 }
365 
366 std_msgs::Float64MultiArray SVHNode::getChannelCurrents()
367 {
368  if (fm_->isConnected())
369  {
370  // Get currents
371  for (size_t channel = 0; channel < driver_svh::eSVH_DIMENSION; ++channel)
372  {
373  double cur_cur = 0.0;
374  if (fm_->isHomed(static_cast<driver_svh::SVHChannel>(channel)))
375  {
376  fm_->getCurrent(static_cast<driver_svh::SVHChannel>(channel), cur_cur);
377  }
378  channel_currents.data[channel] = cur_cur;
379  }
380  }
381 
382  return channel_currents;
383 }
384 
385 
386 /*--------------------------------------------------------------------
387  * main()
388  * Main function to set up ROS node.
389  *------------------------------------------------------------------*/
390 
391 int main(int argc, char** argv)
392 {
393  //==========
394  // ROS
395  //==========
396 
397  // Set up ROS.
398  ros::init(argc, argv, "svh_controller");
399  // Private NH for general params
400  ros::NodeHandle nh("~");
401 
402 
403  // Tell ROS how fast to run this node. (100 = 100 Hz = 10 ms)
404  ros::Rate rate(50);
405 
406  //==========
407  // Logic
408  //==========
409  // Node object holding all the relevant functions
410  SVHNode svh_node(nh);
411 
412  //==========
413  // Dynamic Reconfigure
414  //==========
415 
416  dynamic_reconfigure::Server<svh_controller::svhConfig> server;
417  dynamic_reconfigure::Server<svh_controller::svhConfig>::CallbackType f;
418 
419  f = boost::bind(&SVHNode::dynamic_reconfigure_callback, &svh_node, _1, _2);
420  server.setCallback(f);
421 
422  //==========
423  // Callbacks
424  //==========
425 
426  // Subscribe connect topic (Empty)
427  ros::Subscriber connect_sub = nh.subscribe("connect", 1, &SVHNode::connectCallback, &svh_node);
428  // Subscribe reset channel topic (Int8)
429  ros::Subscriber reset_sub =
430  nh.subscribe("reset_channel", 1, &SVHNode::resetChannelCallback, &svh_node);
431  // Subscribe enable channel topic (Int8)
432  ros::Subscriber enable_sub =
433  nh.subscribe("enable_channel", 1, &SVHNode::enableChannelCallback, &svh_node);
434  // Subscribe joint state topic
435  ros::Subscriber channel_target_sub =
436  nh.subscribe<sensor_msgs::JointState>("channel_targets",
437  1,
439  &svh_node,
441  // Publish current channel positions
442  ros::Publisher channel_pos_pub = nh.advertise<sensor_msgs::JointState>("channel_feedback", 1);
443  // Additionally publish just the current values of the motors
444  ros::Publisher channel_current_pub =
445  nh.advertise<std_msgs::Float64MultiArray>("channel_currents", 1);
446 
447  //==========
448  // Messaging
449  //==========
450 
451  // Main loop.
452  while (nh.ok())
453  {
454  // get the current positions of all joints and publish them
455  channel_pos_pub.publish(svh_node.getChannelFeedback());
456  channel_current_pub.publish(svh_node.getChannelCurrents());
457 
458  ros::spinOnce();
459  rate.sleep();
460  }
461 
462 
463  return 0;
464 }
std_msgs::Float64MultiArray getChannelCurrents()
getChannelCurrents Returns the current values of the channels as raw output
Definition: SVHNode.cpp:366
SVHNode(const ros::NodeHandle &nh)
SVHNode constructs a new node object that handles most of the functionality.
Definition: SVHNode.cpp:39
signed int int32_t
unsigned int uint32_t
std::string serial_device_name_
Serial device to use for communication with hardware.
Definition: SVHNode.h:92
bool initialize(int &argc, char *argv[], bool remove_read_arguments)
void publish(const boost::shared_ptr< M > &message) const
f
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
char * strdup(const char *s)
void enableChannelCallback(const std_msgs::Int8ConstPtr &channel)
Callback function to enable channels of SCHUNK five finger hand.
Definition: SVHNode.cpp:262
The SVHCurrentSettings save the current controller paramters for a single motor.
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::vector< bool > home_settings_given
void jointStateCallback(const sensor_msgs::JointStateConstPtr &input)
Callback function for setting channel target positions to SCHUNK five finger hand.
Definition: SVHNode.cpp:268
uint16_t version_minor
Minor version number.
void dynamic_reconfigure_callback(svh_controller::svhConfig &config, uint32_t level)
Dynamic reconfigure callback to update changing parameters.
Definition: SVHNode.cpp:220
#define ROS_WARN(...)
std::vector< bool > position_settings_given
std::vector< std::vector< float > > position_settings
std::vector< std::vector< float > > home_settings
TransportHints & tcpNoDelay(bool nodelay=true)
std::vector< bool > current_settings_given
void resetChannelCallback(const std_msgs::Int8ConstPtr &channel)
Callback function to reset/home channels of SCHUNK five finger hand.
Definition: SVHNode.cpp:246
Class to read parameter file and set the correct hardware parameters.
unsigned char uint8_t
#define ROS_WARN_ONCE(...)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
The SVHFirmwareInfo holds the data of a firmware response from the hardware.
uint16_t version_major
Major version number.
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
std_msgs::Float64MultiArray channel_currents
Current Value message template.
Definition: SVHNode.h:104
std::string name_prefix
Prefix for the driver to identify joint names if the Driver should expext "left_hand_Pinky" than the ...
Definition: SVHNode.h:98
static const char * m_channel_description[]
Description values to get the corresponding string value to a channel enum.
#define ROS_WARN_STREAM(args)
bool sleep()
int connect_retry_count
Number of times the connect routine tries to connect in case that we receive at least one package...
Definition: SVHNode.h:95
sensor_msgs::JointState getChannelFeedback()
SVHNode::getChannelFeedback Gets the latest received positions and efforts from the driver...
Definition: SVHNode.cpp:341
sensor_msgs::JointState channel_pos_
joint state message template
Definition: SVHNode.h:101
void connectCallback(const std_msgs::Empty &)
Callback function for connecting to SCHUNK five finger hand.
Definition: SVHNode.cpp:229
const Settings & getSettings() const
The SVHPositionSettings save the position controller paramters for a single motor.
bool getParam(const std::string &key, std::string &s) const
static const float channel_effort_constants[9]
Effort multipliers to calculate the torque of the motors for the individual channels.
int main(int argc, char **argv)
Definition: SVHNode.cpp:391
static Time now()
boost::shared_ptr< driver_svh::SVHFingerManager > fm_
Handle to the SVH finger manager for library access.
Definition: SVHNode.h:89
bool ok() const
data sctructure for home positions
ROSCPP_DECL void spinOnce()
unsigned short uint16_t
#define ROS_ERROR(...)
SVHChannel
Channel indicates which motor to use in command calls. WARNING: DO NOT CHANGE THE ORDER OF THESE as i...
Definition: SVHController.h:56
std::vector< std::vector< float > > current_settings
~SVHNode()
Default DTOR.
Definition: SVHNode.cpp:213


schunk_svh_driver
Author(s): Georg Heppner
autogenerated on Mon Jun 10 2019 15:04:59