real_shadowhand.cpp
Go to the documentation of this file.
1 
27 #include <ros/ros.h>
28 #include <utility>
29 #include <string>
30 #include <vector>
31 #include <map>
32 
34 // our robot code
35 #include <robot/config.h>
36 #include <robot/robot.h>
37 #include <robot/hand_protocol.h>
38 #include <robot/hand.h>
39 
40 #ifdef FINGER
41 #define LAST_HAND_JOINT NUM_FINGER_JOINTS
42 #else
43 #define LAST_HAND_JOINT START_OF_ARM
44 #endif
45 
46 namespace shadowrobot
47 {
50  {
51  /* We need to attach the program to the robot, or fail if we cannot. */
52  if (robot_init() < 0)
53  {
54  ROS_FATAL("Robot interface broken\n");
55  ROS_BREAK();
56  }
57 
58  /* We need to attach the program to the hand as well, or fail if we cannot. */
59  if (hand_init() < 0)
60  {
61  ROS_FATAL("Hand interface broken\n");
62  ROS_BREAK();
63  }
64 
65  initializeMap();
66 
68 
69  self_test->add("Pretest", this, &RealShadowhand::pretest);
70  self_test->add("Number of messages Received", this, &RealShadowhand::test_messages);
71  self_test->add("Posttest", this, &RealShadowhand::posttest);
72  }
73 
75  {
76  }
77 
79  {
80  joints_map_mutex.lock();
81  parameters_map_mutex.lock();
82 
83  JointData tmpData;
84 
85  tmpData.position = 0.0;
86  tmpData.target = 0.0;
87  tmpData.temperature = 0.0;
88  tmpData.current = 0.0;
89  tmpData.force = 0.0;
90  tmpData.flags = "";
91 
92  for (unsigned int i = 0; i < LAST_HAND_JOINT; i++)
93  {
94  std::string name = hand_joints[i].joint_name;
95  tmpData.jointIndex = i;
96 
97  joints_map[name] = tmpData;
98 
99  ROS_DEBUG("NAME[%d]: %s ", i, name.c_str());
100  }
101 
102  parameters_map["d"] = PARAM_d;
103  parameters_map["i"] = PARAM_i;
104  parameters_map["p"] = PARAM_p;
105  parameters_map["target"] = PARAM_target;
106  parameters_map["sensor"] = PARAM_sensor;
107 
108  parameters_map["valve"] = PARAM_valve;
109  parameters_map["dead"] = PARAM_deadband;
110  parameters_map["deadband"] = PARAM_deadband;
111  parameters_map["imax"] = PARAM_imax;
112  parameters_map["offset"] = PARAM_output_offset;
113  parameters_map["shift"] = PARAM_shift;
114  parameters_map["max"] = PARAM_output_max;
115 
116  // ! the parameters for the motors
117  parameters_map["motor_maxforce"] = PARAM_motor_maxforce;
118  parameters_map["motor_safeforce"] = PARAM_motor_safeforce;
119 
120  parameters_map["force_p"] = PARAM_force_p;
121  parameters_map["force_i"] = PARAM_force_i;
122  parameters_map["force_d"] = PARAM_force_d;
123 
124  parameters_map["force_imax"] = PARAM_force_imax;
125  parameters_map["force_out_shift"] = PARAM_force_out_shift;
126  parameters_map["force_deadband"] = PARAM_force_deadband;
127  parameters_map["force_offset"] = PARAM_force_offset;
128 
129  parameters_map["sensor_imax"] = PARAM_sensor_imax;
130  parameters_map["sensor_out_shift"] = PARAM_sensor_out_shift;
131  parameters_map["sensor_deadband"] = PARAM_sensor_deadband;
132  parameters_map["sensor_offset"] = PARAM_sensor_offset;
133  parameters_map["max_temp"] = PARAM_max_temperature;
134  parameters_map["max_temperature"] = PARAM_max_temperature;
135  parameters_map["max_current"] = PARAM_max_current;
136 
137  parameters_map_mutex.unlock();
138  joints_map_mutex.unlock();
139  }
140 
141  int16_t RealShadowhand::sendupdate(std::string joint_name, double target)
142  {
143  joints_map_mutex.lock();
144 
145  // search the sensor in the hash_map
146  JointsMap::iterator iter = joints_map.find(joint_name);
147 
148  if (iter != joints_map.end())
149  {
150  JointData tmpData = joints_map.find(joint_name)->second;
151  int index_hand_joints = tmpData.jointIndex;
152 
153  // trim to the correct range
154  if (target < hand_joints[index_hand_joints].min_angle)
155  {
156  target = hand_joints[index_hand_joints].min_angle;
157  }
158  if (target > hand_joints[index_hand_joints].max_angle)
159  {
160  target = hand_joints[index_hand_joints].max_angle;
161  }
162 
163  // here we update the actual hand angles
164  robot_update_sensor(&hand_joints[index_hand_joints].joint_target, target);
165  joints_map_mutex.unlock();
166  return 0;
167  }
168 
169  ROS_DEBUG("Joint %s not found", joint_name.c_str());
170 
171  joints_map_mutex.unlock();
172  return -1;
173  }
174 
175  JointData RealShadowhand::getJointData(std::string joint_name)
176  {
177  joints_map_mutex.lock();
178 
179  JointsMap::iterator iter = joints_map.find(joint_name);
180 
181  // joint not found
182  if (iter == joints_map.end())
183  {
184  ROS_ERROR("Joint %s not found.", joint_name.c_str());
185  JointData noData;
186  noData.position = 0.0;
187  noData.target = 0.0;
188  noData.temperature = 0.0;
189  noData.current = 0.0;
190  noData.force = 0.0;
191  noData.flags = "";
192  noData.jointIndex = 0;
193 
194  joints_map_mutex.unlock();
195  return noData;
196  }
197 
198  // joint found
199  JointData tmpData = iter->second;
200  int index = tmpData.jointIndex;
201 
202  tmpData.position = robot_read_sensor(&hand_joints[index].position);
203  tmpData.target = robot_read_sensor(&hand_joints[index].joint_target);
204 
205  // more information
206  if (hand_joints[index].a.smartmotor.has_sensors)
207  {
208  tmpData.temperature = robot_read_sensor(&hand_joints[index].a.smartmotor.temperature);
209  tmpData.current = robot_read_sensor(&hand_joints[index].a.smartmotor.current);
210  tmpData.force = robot_read_sensor(&hand_joints[index].a.smartmotor.torque);
211  tmpData.flags = "";
212  }
213 
214  joints_map[joint_name] = tmpData;
215 
216  joints_map_mutex.unlock();
217  return tmpData;
218  }
219 
221  {
222  // update the map for each joints
223  for (JointsMap::const_iterator it = joints_map.begin(); it != joints_map.end(); ++it)
224  {
225  getJointData(it->first);
226  }
227 
228  // hack for C6M2 with 4 fingers with coupling J1+J2=J0
229  // copy J0/2 to J1 and J2 for FF MF RF LF
230  joints_map_mutex.lock();
231 
232  std::string fingername("FF");
233 
234  JointsMap::iterator it_j0 = joints_map.find(fingername + "J0");
235  JointsMap::iterator it_j1 = joints_map.find(fingername + "J1");
236  JointsMap::iterator it_j2 = joints_map.find(fingername + "J2");
237  it_j1->second.target = it_j0->second.target / 2.0;
238  it_j2->second.target = it_j0->second.target / 2.0;
239 
240  fingername.assign("MF");
241  it_j0 = joints_map.find(fingername + "J0");
242  it_j1 = joints_map.find(fingername + "J1");
243  it_j2 = joints_map.find(fingername + "J2");
244  it_j1->second.target = it_j0->second.target / 2.0;
245  it_j2->second.target = it_j0->second.target / 2.0;
246 
247  fingername.assign("RF");
248  it_j0 = joints_map.find(fingername + "J0");
249  it_j1 = joints_map.find(fingername + "J1");
250  it_j2 = joints_map.find(fingername + "J2");
251  it_j1->second.target = it_j0->second.target / 2.0;
252  it_j2->second.target = it_j0->second.target / 2.0;
253 
254  fingername.assign("LF");
255  it_j0 = joints_map.find(fingername + "J0");
256  it_j1 = joints_map.find(fingername + "J1");
257  it_j2 = joints_map.find(fingername + "J2");
258  it_j1->second.target = it_j0->second.target / 2.0;
259  it_j2->second.target = it_j0->second.target / 2.0;
260 
261  joints_map_mutex.unlock();
262 
264 
265  // return the map
266  return tmp;
267  }
268 
269  int16_t RealShadowhand::setContrl(std::string contrlr_name, JointControllerData ctrlr_data)
270  {
271  parameters_map_mutex.lock();
272 
273  struct controller_config myConfig;
274  memset(&myConfig, 0, sizeof(myConfig));
275 
276  // set the nodename from contrlr_name
277  myConfig.nodename = contrlr_name.c_str();
278 
279  controller_read_from_hardware(&myConfig);
280  ROS_DEBUG("%s", controller_to_string(&myConfig));
281 
282  for (unsigned int i = 0; i < ctrlr_data.data.size(); ++i)
283  {
284  std::string name = ctrlr_data.data[i].name;
285  ParametersMap::iterator iter = parameters_map.find(name);
286 
287  // parameter not found
288  if (iter == parameters_map.end())
289  {
290  ROS_ERROR("Parameter %s not found.", name.c_str());
291  continue;
292  }
293 
294  // parameter found
295  controller_update_param(&myConfig, (controller_param) iter->second, ctrlr_data.data[i].value.c_str());
296  }
297 
298  parameters_map_mutex.unlock();
299 
300  int result_ctrlr = controller_write_to_hardware(&myConfig);
301  if (result_ctrlr)
302  {
303  ROS_ERROR("Failed to update contrlr (%s)", myConfig.nodename);
304  return -1;
305  }
306 
307  return 0;
308  }
309 
311  {
312  struct controller_config myConfig;
313  memset(&myConfig, 0, sizeof(myConfig));
314 
315  // set the nodename from contrlr_name
316  myConfig.nodename = contrlr_name.c_str();
317 
318  controller_read_from_hardware(&myConfig);
319 
320  JointControllerData tmp_data;
321 
322  ROS_WARN("The get contrlr function is not implemented in the real shadowhand.");
323 
324  return tmp_data;
325  }
326 
327  int16_t RealShadowhand::setConfig(std::vector <std::string> myConfig)
328  {
329  ROS_WARN("The set config function is not implemented in the real shadowhand.");
330 
331  /*
332  hand_protocol_config_t cfg;
333  hand_protocol_get_config(cfg);
334 
335  // set the transmit rate value
336  int value = msg->rate_value;
337  cfg->u.palm.tx_freq[num]=value;
338 
339  // send the config to the palm.
340  hand_protocol_set_config(cfg);
341  */
342 
343  return 0;
344  }
345 
346  void RealShadowhand::getConfig(std::string joint_name)
347  {
348  ROS_WARN("The get config function is not yet implement in the real shadow hand.");
349  }
350 
351  std::vector <DiagnosticData> RealShadowhand::getDiagnostics()
352  {
353  // it's alright to do the tests when we're publishing the diagnostics
354  self_test->checkTest();
355 
356  std::vector <DiagnosticData> returnVector;
357 
358  DiagnosticData tmpData;
359  std::stringstream ss;
360 
361  // get the data from the hand
362  for (unsigned int index = 0; index < START_OF_ARM; ++index)
363  {
364  tmpData.joint_name = std::string(hand_joints[index].joint_name);
365  tmpData.level = 0;
366 
367  tmpData.position = robot_read_sensor(&hand_joints[index].position);
368  tmpData.target = robot_read_sensor(&hand_joints[index].joint_target);
369 
370  // more information
371  if (hand_joints[index].a.smartmotor.has_sensors)
372  {
373  // reads the number of received sensor msgs from the debug node.
374  int res;
375  if (*(&hand_joints[index].a.smartmotor.debug_nodename) != NULL)
376  {
377  std::string debug_node_name = *(&hand_joints[index].a.smartmotor.debug_nodename);
378 
379  // get all the debug values
380  std::map<const std::string, const unsigned int>::const_iterator iter;
381  for (iter = debug_values::names_and_offsets.begin();
382  iter != debug_values::names_and_offsets.end(); ++iter)
383  {
384  struct sensor sensor_tmp;
385 
386  res = robot_channel_to_sensor(debug_node_name.c_str(), iter->second, &sensor_tmp);
387  tmpData.debug_values[iter->first] = robot_read_incoming(&sensor_tmp);
388  }
389  }
390  // else
391  // ROS_ERROR_STREAM(tmpData.joint_name << ": no debug sensor" );
392  // reads temperature current and force.
393  tmpData.temperature = robot_read_sensor(&hand_joints[index].a.smartmotor.temperature);
394  tmpData.current = robot_read_sensor(&hand_joints[index].a.smartmotor.current);
395  tmpData.force = robot_read_sensor(&hand_joints[index].a.smartmotor.torque);
396 
397  // check for error_flags
398 
399  struct hand_protocol_flags fl;
400  uint64_t uuid = robot_node_id(hand_joints[index].a.smartmotor.nodename);
401  fl = hand_protocol_get_status_flags(uuid);
402  if (fl.valid)
403  {
404  ss.clear();
405  struct hand_protocol_flags_smart_motor f;
406  f = fl.u.smart_motor;
407 
408  bool at_least_one_error_flag = false;
409  if (f.nfault_pin)
410  {
411  at_least_one_error_flag = true;
412  ss << "NFAULT ";
413  ROS_WARN("[%s]: NFAULT", hand_joints[index].joint_name);
414  }
415  if (f.temperature_cutout)
416  {
417  at_least_one_error_flag = true;
418  ss << "TEMP ";
419  }
420  if (f.current_throttle)
421  {
422  at_least_one_error_flag = true;
423  ss << "CURRENT ";
424  }
425  if (f.force_hard_limit)
426  {
427  at_least_one_error_flag = true;
428  ss << "FORCE ";
429  }
430  if (hand_protocol_dead(uuid))
431  {
432  at_least_one_error_flag = true;
433  ss << "DEAD ";
434  }
435 
436  // if a flag is up, then print a warning as well
437  if (at_least_one_error_flag)
438  {
439  ROS_WARN("[%s]: %s", hand_joints[index].joint_name, (ss.str()).c_str());
440  tmpData.level = 1;
441  }
442 
443  tmpData.flags = ss.str();
444  }
445  }
446 
447  returnVector.push_back(tmpData);
448  }
449  return returnVector;
450  }
451 
453  // TESTS //
456  {
457  ROS_INFO("Preparing the environment to run self tests.");
458 
459  // lock all the mutexes to make sure we're not publishing other messages
460  joints_map_mutex.lock();
461  parameters_map_mutex.lock();
462  controllers_map_mutex.lock();
463 
464  // @todo set the palm transmit rate to max?
465 
466  sleep(1);
467 
468  status.summary(diagnostic_msgs::DiagnosticStatus::OK, "Pretest completed successfully.");
469  }
470 
472  {
473  ROS_INFO("Restoring the environment after the self tests.");
474 
475  // test finished, unlocking all the mutexes
476  joints_map_mutex.unlock();
477  parameters_map_mutex.unlock();
478  controllers_map_mutex.unlock();
479 
480  // @todo reset the palm transmit rate to previous state?
481 
482  status.summary(diagnostic_msgs::DiagnosticStatus::OK, "Postest completed successfully.");
483  }
484 
486  {
487  ROS_WARN("Starting the test: Number of messages Received");
488 
489  std::pair<unsigned char, std::string> test_result;
490  test_result.first = diagnostic_msgs::DiagnosticStatus::OK;
491 
492  for (unsigned int index_freq = 0; index_freq < sr_self_tests::msgs_frequency_size; ++index_freq)
493  {
494  ros::Rate test_rate(sr_self_tests::msgs_frequency[index_freq]);
495  for (unsigned int index_joint = 0; index_joint < sr_self_tests::joints_to_test_size; ++index_joint)
496  {
497  std::pair<unsigned char, std::string> tmp_test_result;
498  tmp_test_result = test_messages_routine(sr_self_tests::joints_to_test[index_joint],
500 
501  if (tmp_test_result.first == diagnostic_msgs::DiagnosticStatus::ERROR)
502  {
503  test_result.first = diagnostic_msgs::DiagnosticStatus::ERROR;
504  }
505 
506  std::stringstream ss;
507  ss << "\n[" << sr_self_tests::msgs_frequency[index_freq] << "Hz]: ";
508  ss << tmp_test_result.second;
509 
510  test_result.second += ss.str();
511  }
512  }
513  status.summary(test_result.first, test_result.second);
514  }
515 
516  std::pair<unsigned char, std::string> RealShadowhand::test_messages_routine(std::string joint_name,
517  unsigned int repeat, ros::Rate rate)
518  {
519  std::pair<unsigned char, std::string> test_result;
520 
521  // id should be motor board number
522  std::string ID = "1";
523  self_test->setID(ID.c_str());
524 
525  unsigned int nb_msgs_sent = 0;
526  unsigned int nb_msgs_received = 0;
527 
528  // sending lots of data to one joint
529  JointsMap::iterator iter_joints_map = joints_map.find(joint_name);
530 
531  struct sensor sensor_msgs_received;
532 
533  if (iter_joints_map == joints_map.end())
534  {
535  std::stringstream ss;
536  ss << "No messages sent: couldn't find joint " << joint_name;
537 
538  test_result.first = diagnostic_msgs::DiagnosticStatus::ERROR;
539  test_result.second = ss.str();
540  return test_result;
541  }
542 
543  // OK joint found
544  JointData tmpData = joints_map.find(joint_name)->second;
545  int index_hand_joints = tmpData.jointIndex;
546  float target = hand_joints[index_hand_joints].min_angle;
547 
548  // testing a joint which doesn't have a smartmotor
549  if (!hand_joints[index_hand_joints].a.smartmotor.has_sensors)
550  {
551  std::stringstream ss;
552  ss << "No messages sent: joint[" << joint_name << "] doesn't have any motor attached";
553 
554  test_result.first = diagnostic_msgs::DiagnosticStatus::ERROR;
555  test_result.second = ss.str();
556  return test_result;
557  }
558 
559  ROS_DEBUG("Checking the current number of received messages");
560 
561  int res;
562  std::string debug_node_name = *(&hand_joints[index_hand_joints].a.smartmotor.debug_nodename);
563  std::map<const std::string, const unsigned int>::const_iterator
564  iter_debug_values = debug_values::names_and_offsets.find("Num sensor Msgs received");
565 
566  res = robot_channel_to_sensor(debug_node_name.c_str(), iter_debug_values->second, &sensor_msgs_received);
567 
568  // check the number of messages already received when starting the test
569  nb_msgs_received = robot_read_incoming(&sensor_msgs_received) - nb_msgs_received;
570 
571  sleep(1);
572 
573  // check if no other messages have been received
574  if (nb_msgs_received != robot_read_incoming(&sensor_msgs_received))
575  {
576  std::stringstream ss;
577  ss << "New messages were received on the joint[" << joint_name.c_str() << "].";
578  test_result.first = diagnostic_msgs::DiagnosticStatus::ERROR;
579  test_result.second = ss.str();
580 
581  return test_result;
582  }
583  // ok still the same number of messages
584 
585  ROS_DEBUG("Sending lots of messages.");
586 
587  for (; nb_msgs_sent < repeat; ++nb_msgs_sent)
588  {
589  // send values to the sensor
590  robot_update_sensor(&hand_joints[index_hand_joints].joint_target, target);
591  rate.sleep();
592  ROS_DEBUG_STREAM("msg " << nb_msgs_sent << "/" << sr_self_tests::nb_targets_to_send);
593  }
594 
595  ROS_DEBUG("Done sending the messages.");
596  // wait for all the messages to be received?
597  sleep(0.5);
598 
599  ROS_DEBUG("Reading the number of received messages.");
600  // compute the number of messages received during the test
601  nb_msgs_received = robot_read_incoming(&sensor_msgs_received) - nb_msgs_received;
602 
603  if (nb_msgs_sent == nb_msgs_received)
604  {
605  std::stringstream ss;
606  ss << nb_msgs_sent << " messages sent, all received";
607  test_result.first = diagnostic_msgs::DiagnosticStatus::OK;
608  test_result.second = ss.str();
609  return test_result;
610  }
611  else
612  {
613  std::stringstream ss;
614  ss << nb_msgs_sent << " messages sent, " << nb_msgs_received << " messages received";
615  test_result.first = diagnostic_msgs::DiagnosticStatus::ERROR;
616  test_result.second = ss.str();
617  return test_result;
618  }
619  }
620 } // namespace shadowrobot
621 
622 /* For the emacs weenies in the crowd.
623  Local Variables:
624  c-basic-offset: 2
625  End:
626 */
virtual int16_t setContrl(std::string contrlr_name, JointControllerData ctrlr_data)
#define ROS_FATAL(...)
void pretest(diagnostic_updater::DiagnosticStatusWrapper &status)
#define LAST_HAND_JOINT
void summary(unsigned char lvl, const std::string s)
static const std::string joints_to_test[joints_to_test_size]
virtual void getConfig(std::string joint_name)
virtual JointsMap getAllJointsData()
virtual int16_t sendupdate(std::string joint_name, double target)
std::string flags
a string containing flags: FORCE, TEMPERATURE, ... indicating the different cutouts / warning sent by...
std::string joint_name
the name of the joint
static const unsigned int nb_targets_to_send
The number of targets to send during the test.
std::map< std::string, JointData > JointsMap
static const std::map< const std::string, const unsigned int > names_and_offsets
a map containing the names and offsets of the smart motor node
#define ROS_WARN(...)
static const unsigned int msgs_frequency_size
the size of the msgs_frequency array
static const int msgs_frequency[msgs_frequency_size]
the rate at which we&#39;ll publish the data
virtual JointControllerData getContrl(std::string contrlr_name)
virtual std::vector< DiagnosticData > getDiagnostics()
std::map< std::string, int > debug_values
the debug values
#define ROS_INFO(...)
JointsMap joints_map
A mapping between the joint names and the information regarding those joints.
virtual int16_t setConfig(std::vector< std::string > myConfig)
void posttest(diagnostic_updater::DiagnosticStatusWrapper &status)
#define ROS_DEBUG_STREAM(args)
void test_messages(diagnostic_updater::DiagnosticStatusWrapper &status)
bool sleep()
ParametersMap parameters_map
A mapping between the parameter names and their values.
This is a parent class for the different types of Shadowhand we can have. It makes it possible to swa...
The real shadowhand is the ROS interface to Shadow Robot robotic hand.
double temperature
temperature value
std::pair< unsigned char, std::string > test_messages_routine(std::string joint_name, unsigned int repeat, ros::Rate rate)
virtual JointData getJointData(std::string joint_name)
int16_t level
the level of alert: 0 = OK, 1 = WARNING, 2 = ERROR
double target
the actual value of the target
#define ROS_BREAK()
#define ROS_ERROR(...)
static const unsigned int joints_to_test_size
the size of the joints_to_test array
double position
the actual value of the position
#define ROS_DEBUG(...)


sr_hand
Author(s): Ugo Cupcic
autogenerated on Tue Oct 13 2020 03:55:53