sr_muscle_robot_lib.cpp
Go to the documentation of this file.
1 
28 #include <string>
29 #include <utility>
30 #include <map>
31 #include <vector>
32 #include <boost/foreach.hpp>
33 
34 #include <sys/time.h>
35 
36 #include <ros/ros.h>
37 
38 #include <controller_manager_msgs/ListControllers.h>
39 
40 #define SERIOUS_ERROR_FLAGS PALM_0300_EDC_SERIOUS_ERROR_FLAGS
41 #define error_flag_names palm_0300_edc_error_flag_names
42 
43 
44 using std::vector;
45 using std::string;
46 using std::pair;
47 using std::map;
48 using std::ostringstream;
49 using sr_actuator::SrMuscleActuator;
58 using boost::shared_ptr;
59 using boost::static_pointer_cast;
60 using boost::shared_ptr;
61 
62 namespace shadow_robot
63 {
64  template<class StatusType, class CommandType>
66 
67  template<class StatusType, class CommandType>
68  SrMuscleRobotLib<StatusType, CommandType>::SrMuscleRobotLib(hardware_interface::HardwareInterface *hw,
69  ros::NodeHandle nh, ros::NodeHandle nhtilde,
70  string device_id, string joint_prefix)
71  : SrRobotLib<StatusType, CommandType>(hw, nh, nhtilde, device_id, joint_prefix),
72  muscle_current_state(operation_mode::device_update_state::INITIALIZATION), init_max_duration(timeout),
73  lock_init_timeout_(shared_ptr<boost::mutex>(new boost::mutex())),
74 
75  // Create a one-shot timer
76  check_init_timeout_timer(this->nh_tilde.createTimer(init_max_duration,
77  boost::bind(
78  &SrMuscleRobotLib<StatusType,
79  CommandType>::init_timer_callback,
80  this, _1), true)),
81  pressure_calibration_map_(read_pressure_calibration())
82  {
83 #ifdef DEBUG_PUBLISHER
84  this->debug_muscle_indexes_and_data.resize(this->nb_debug_publishers_const);
85  for (int i = 0; i < this->nb_debug_publishers_const; ++i)
86  {
87  ostringstream ss;
88  ss << "srh/debug_" << i;
89  this->debug_publishers.push_back(this->node_handle.template advertise<std_msgs::Int16>(ss.str().c_str(), 100));
90  }
91 #endif
92  }
93 
94  template<class StatusType, class CommandType>
96  {
97  ROS_INFO("Reading pressure calibration");
98  CalibrationMap pressure_calibration;
99  string param_name = "sr_pressure_calibrations";
100 
101  XmlRpc::XmlRpcValue calib;
102  this->nodehandle_.getParam(param_name, calib);
104  // iterate on all the joints
105  for (int32_t index_cal = 0; index_cal < calib.size(); ++index_cal)
106  {
107  // check the calibration is well formatted:
108  // first joint name, then calibration table
109  ROS_ASSERT(calib[index_cal][0].getType() == XmlRpc::XmlRpcValue::TypeString);
110  ROS_ASSERT(calib[index_cal][1].getType() == XmlRpc::XmlRpcValue::TypeArray);
111 
112  string joint_name = static_cast<string> (calib[index_cal][0]);
113  vector<joint_calibration::Point> calib_table_tmp;
114 
115  // now iterates on the calibration table for the current joint
116  for (int32_t index_table = 0; index_table < calib[index_cal][1].size(); ++index_table)
117  {
118  ROS_ASSERT(calib[index_cal][1][index_table].getType() == XmlRpc::XmlRpcValue::TypeArray);
119  // only 2 values per calibration point: raw and calibrated (doubles)
120  ROS_ASSERT(calib[index_cal][1][index_table].size() == 2);
121  ROS_ASSERT(calib[index_cal][1][index_table][0].getType() == XmlRpc::XmlRpcValue::TypeDouble);
122  ROS_ASSERT(calib[index_cal][1][index_table][1].getType() == XmlRpc::XmlRpcValue::TypeDouble);
123 
124 
125  joint_calibration::Point point_tmp;
126  point_tmp.raw_value = static_cast<double> (calib[index_cal][1][index_table][0]);
127  point_tmp.calibrated_value = static_cast<double> (calib[index_cal][1][index_table][1]);
128  calib_table_tmp.push_back(point_tmp);
129  }
130 
131  pressure_calibration.insert(joint_name, shared_ptr<shadow_robot::JointCalibration>(
132  new shadow_robot::JointCalibration(calib_table_tmp)));
133  }
134 
135  return pressure_calibration;
136  }
137 
138  template<class StatusType, class CommandType>
140  {
141  // read the PIC idle time
142  this->main_pic_idle_time = status_data->idle_time_us;
143  if (status_data->idle_time_us < this->main_pic_idle_time_min)
144  {
145  this->main_pic_idle_time_min = status_data->idle_time_us;
146  }
147 
148  // get the current timestamp
149  struct timeval tv;
150  double timestamp = 0.0;
151  if (gettimeofday(&tv, NULL))
152  {
153  ROS_WARN("SrMuscleRobotLib: Failed to get system time, timestamp in state will be zero");
154  }
155  else
156  {
157  timestamp = static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1.0e+6;
158  }
159 
160  // First we read the tactile sensors information
161  this->update_tactile_info(status_data);
162 
163  // then we read the muscle drivers information
164  for (vector<MuscleDriver>::iterator muscle_driver_tmp = this->muscle_drivers_vector_.begin();
165  muscle_driver_tmp != this->muscle_drivers_vector_.end();
166  ++muscle_driver_tmp)
167  {
168  read_muscle_driver_data(muscle_driver_tmp, status_data);
169  }
170 
171  // then we read the joints informations
172  for (vector<Joint>::iterator joint_tmp = this->joints_vector.begin();
173  joint_tmp != this->joints_vector.end();
174  ++joint_tmp)
175  {
176  if (!joint_tmp->has_actuator)
177  {
178  continue;
179  }
180 
181  SrMuscleActuator *actuator = this->get_joint_actuator(joint_tmp);
182  shared_ptr<MuscleWrapper> muscle_wrapper = static_pointer_cast<MuscleWrapper>(joint_tmp->actuator_wrapper);
183 
184  // Fill in the tactiles.
185  if (this->tactiles != NULL)
186  {
187  actuator->muscle_state_.tactiles_ = this->tactiles->get_tactile_data();
188  }
189 
190  this->process_position_sensor_data(joint_tmp, status_data, timestamp);
191 
192  // if no muscle is associated to this joint, then continue
193  if ((muscle_wrapper->muscle_driver_id[0] == -1))
194  {
195  continue;
196  }
197 
198  read_additional_muscle_data(joint_tmp, status_data);
199  } // end for joint
200  } // end update()
201 
202  template<class StatusType, class CommandType>
204  {
206  {
207  muscle_current_state = muscle_updater_->build_init_command(command);
208  }
209  else
210  {
211  // build the muscle command
212  muscle_current_state = muscle_updater_->build_command(command);
213  }
214 
215  // Build the tactile sensors command
216  this->build_tactile_command(command);
217 
219  // Now we chose the command to send to the muscle
220  // by default we send a valve demand, but if we have a reset command,
221  // then we send the reset.
222  if (reset_muscle_driver_queue.empty())
223  {
224  command->to_muscle_data_type = MUSCLE_DEMAND_VALVES;
225 
226  // loop on all the joints and update their muscle: we're sending commands to all the muscles.
227  for (vector<Joint>::iterator joint_tmp = this->joints_vector.begin();
228  joint_tmp != this->joints_vector.end();
229  ++joint_tmp)
230  {
231  if (joint_tmp->has_actuator)
232  {
233  shared_ptr<MuscleWrapper> muscle_wrapper = static_pointer_cast<MuscleWrapper>(joint_tmp->actuator_wrapper);
234  SrMuscleActuator *muscle_actuator = static_cast<SrMuscleActuator *> (muscle_wrapper->actuator);
235 
236  unsigned int muscle_driver_id_0 = muscle_wrapper->muscle_driver_id[0];
237  unsigned int muscle_driver_id_1 = muscle_wrapper->muscle_driver_id[1];
238  unsigned int muscle_id_0 = muscle_wrapper->muscle_id[0];
239  unsigned int muscle_id_1 = muscle_wrapper->muscle_id[1];
240 
241  if (!this->nullify_demand_)
242  {
243  set_valve_demand(&(command->muscle_data[(muscle_driver_id_0 * 10 + muscle_id_0) / 2]),
244  muscle_actuator->muscle_command_.valve_[0], ((uint8_t) muscle_id_0) & 0x01);
245  set_valve_demand(&(command->muscle_data[(muscle_driver_id_1 * 10 + muscle_id_1) / 2]),
246  muscle_actuator->muscle_command_.valve_[1], ((uint8_t) muscle_id_1) & 0x01);
247 
248  muscle_actuator->muscle_state_.last_commanded_valve_[0] = muscle_actuator->muscle_command_.valve_[0];
249  muscle_actuator->muscle_state_.last_commanded_valve_[1] = muscle_actuator->muscle_command_.valve_[1];
250  }
251  else
252  {
253  // We want to send a demand of 0
254  set_valve_demand(&(command->muscle_data[(muscle_driver_id_0 * 10 + muscle_id_0) / 2]), 0,
255  ((uint8_t) muscle_id_0) & 0x01);
256  set_valve_demand(&(command->muscle_data[(muscle_driver_id_1 * 10 + muscle_id_1) / 2]), 0,
257  ((uint8_t) muscle_id_1) & 0x01);
258 
259  muscle_actuator->muscle_state_.last_commanded_valve_[0] = 0;
260  muscle_actuator->muscle_state_.last_commanded_valve_[1] = 0;
261  }
262 
263 #ifdef DEBUG_PUBLISHER
264  // publish the debug values for the given muscles.
265  // NB: debug_muscle_indexes_and_data is smaller
266  // than debug_publishers.
267  int publisher_index = 0;
268  shared_ptr<pair<int, int> > debug_pair;
269  if (this->debug_mutex.try_lock())
270  {
271  BOOST_FOREACH(debug_pair, this->debug_muscle_indexes_and_data)
272  {
273  if (debug_pair != NULL)
274  {
275  MuscleWrapper* actuator_wrapper = static_cast<MuscleWrapper*> (joint_tmp->actuator_wrapper.get());
276  // check if we want to publish some data for the current muscle
277  if (debug_pair->first == actuator_wrapper->muscle_id[0])
278  {
279  // check if it's the correct data
280  if (debug_pair->second == -1)
281  {
282  this->msg_debug.data = joint_tmp->actuator_wrapper->actuator->command_.effort_;
283  this->debug_publishers[publisher_index].publish(this->msg_debug);
284  }
285  }
286  }
287  publisher_index++;
288  }
289 
290  this->debug_mutex.unlock();
291  } // end try_lock
292 #endif
293  } // end if has_actuator
294  } // end for each joint
295  } // endif
296  else
297  {
298  // we have some reset command waiting.
299  // We'll send all of them
300  command->to_muscle_data_type = MUSCLE_SYSTEM_RESET;
301 
302  while (!reset_muscle_driver_queue.empty())
303  {
304  int16_t muscle_driver_id = reset_muscle_driver_queue.front();
306 
307  // reset the CAN messages counters for the muscle driver we're going to reset.
308  for (vector<MuscleDriver>::iterator driver = this->muscle_drivers_vector_.begin();
309  driver != this->muscle_drivers_vector_.end();
310  ++driver)
311  {
312  if (driver->muscle_driver_id == muscle_driver_id)
313  {
314  driver->can_msgs_transmitted_ = 0;
315  driver->can_msgs_received_ = 0;
316  }
317  }
318 
319  // we send the MUSCLE_SYSTEM_RESET_KEY
320  // and the muscle_driver_id (on the bus)
321  crc_unions::union16 to_send;
322  to_send.byte[1] = MUSCLE_SYSTEM_RESET_KEY >> 8;
323  if (muscle_driver_id > 1)
324  {
325  to_send.byte[0] = muscle_driver_id - 2;
326  }
327  else
328  {
329  to_send.byte[0] = muscle_driver_id;
330  }
331 
332  command->muscle_data[muscle_driver_id * 5] = to_send.byte[0];
333  command->muscle_data[muscle_driver_id * 5 + 1] = to_send.byte[1];
334  }
335  } // end if reset queue not empty
336  }
337 
338  template<class StatusType, class CommandType>
339  inline void SrMuscleRobotLib<StatusType, CommandType>::set_valve_demand(uint8_t *muscle_data_byte_to_set,
340  int8_t valve_value, uint8_t shift)
341  {
342  uint8_t tmp_valve = 0;
343 
344  // The encoding we want for the negative integers is represented in two's complement,
345  // but based on a 4 bit data size instead of 8 bit, so
346  // we'll have to do it manually
347  if (valve_value < 0)
348  {
349  // Take the value as positive
350  tmp_valve = -valve_value;
351  // Do a bitwise inversion on the 4 lowest bytes only
352  tmp_valve = (~tmp_valve) & 0x0F;
353  // Add one
354  tmp_valve = tmp_valve + 1;
355  }
356  else // Positive representation is straightforward
357  {
358  tmp_valve = valve_value & 0x0F;
359  }
360 
361  // A shift of 0 means that we want to write the value on the 4 least significant bits
362  // shift of 1 means that we want to write the value on the 4 most significant bits
363 
364  // We zero the 4 bits that we want to write our valve value on
365  *muscle_data_byte_to_set &= (0xF0 >> (shift * 4));
366  // We write our valve value on those 4 bits
367  *muscle_data_byte_to_set |= (tmp_valve << (shift * 4));
368  }
369 
370  template<class StatusType, class CommandType>
371  void SrMuscleRobotLib<StatusType, CommandType>::add_diagnostics(vector<diagnostic_msgs::DiagnosticStatus> &vec,
373  {
374  for (vector<Joint>::iterator joint = this->joints_vector.begin();
375  joint != this->joints_vector.end();
376  ++joint)
377  {
378  ostringstream name("");
379  string prefix = this->device_id_.empty() ? this->device_id_ : (this->device_id_ + " ");
380  name << prefix << "SRDMuscle " << joint->joint_name;
381  d.name = name.str();
382 
383  if (joint->has_actuator)
384  {
385  shared_ptr<MuscleWrapper> actuator_wrapper = static_pointer_cast<MuscleWrapper>(joint->actuator_wrapper);
386  SrMuscleActuator *actuator = get_joint_actuator(joint);
387 
388  if (actuator_wrapper->actuator_ok)
389  {
390  if (actuator_wrapper->bad_data)
391  {
392  d.summary(d.WARN, "WARNING, bad CAN data received");
393 
394  d.clear();
395  d.addf("Muscle ID 0", "%d", actuator_wrapper->muscle_id[0]);
396  d.addf("Muscle driver ID 0", "%d", actuator_wrapper->muscle_driver_id[0]);
397  d.addf("Muscle ID 1", "%d", actuator_wrapper->muscle_id[1]);
398  d.addf("Muscle driver ID 1", "%d", actuator_wrapper->muscle_driver_id[1]);
399  }
400  else // the data is good
401  {
402  d.summary(d.OK, "OK");
403 
404  d.clear();
405  d.addf("Muscle ID 0", "%d", actuator_wrapper->muscle_id[0]);
406  d.addf("Muscle driver ID 0", "%d", actuator_wrapper->muscle_driver_id[0]);
407  d.addf("Muscle ID 1", "%d", actuator_wrapper->muscle_id[1]);
408  d.addf("Muscle driver ID 1", "%d", actuator_wrapper->muscle_driver_id[1]);
409 
410  d.addf("Unfiltered position", "%f", actuator->muscle_state_.position_unfiltered_);
411 
412  d.addf("Last Commanded Valve 0", "%d", actuator->muscle_state_.last_commanded_valve_[0]);
413  d.addf("Last Commanded Valve 1", "%d", actuator->muscle_state_.last_commanded_valve_[1]);
414 
415  d.addf("Unfiltered Pressure 0", "%u", actuator->muscle_state_.pressure_[0]);
416  d.addf("Unfiltered Pressure 1", "%u", actuator->muscle_state_.pressure_[1]);
417 
418  d.addf("Position", "%f", actuator->state_.position_);
419  }
420  }
421  else
422  {
423  d.summary(d.ERROR, "Muscle error");
424  d.clear();
425  d.addf("Muscle ID 0", "%d", actuator_wrapper->muscle_id[0]);
426  d.addf("Muscle driver ID 0", "%d", actuator_wrapper->muscle_driver_id[0]);
427  d.addf("Muscle ID 1", "%d", actuator_wrapper->muscle_id[1]);
428  d.addf("Muscle driver ID 1", "%d", actuator_wrapper->muscle_driver_id[1]);
429  }
430  }
431  else
432  {
433  d.summary(d.OK, "No muscle associated to this joint");
434  d.clear();
435  }
436  vec.push_back(d);
437  } // end for each joints
438 
439  for (vector<MuscleDriver>::iterator muscle_driver = this->muscle_drivers_vector_.begin();
440  muscle_driver != this->muscle_drivers_vector_.end();
441  ++muscle_driver)
442  {
443  ostringstream name("");
444  name << "Muscle driver " << muscle_driver->muscle_driver_id;
445  d.name = name.str();
446 
447  if (muscle_driver->driver_ok)
448  {
449  if (muscle_driver->bad_data)
450  {
451  d.summary(d.WARN, "WARNING, bad CAN data received");
452 
453  d.clear();
454  d.addf("Muscle Driver ID", "%d", muscle_driver->muscle_driver_id);
455  }
456  else // the data is good
457  {
458  d.summary(d.OK, "OK");
459 
460  d.clear();
461  d.addf("Muscle Driver ID", "%d", muscle_driver->muscle_driver_id);
462  d.addf("Serial Number", "%d", muscle_driver->serial_number);
463  d.addf("Assembly date", "%d / %d / %d", muscle_driver->assembly_date_day, muscle_driver->assembly_date_month,
464  muscle_driver->assembly_date_year);
465 
466  d.addf("Number of CAN messages received", "%lld", muscle_driver->can_msgs_received_);
467  d.addf("Number of CAN messages transmitted", "%lld", muscle_driver->can_msgs_transmitted_);
468 
469  if (muscle_driver->firmware_modified_)
470  {
471  d.addf("Firmware git revision (server / pic / modified)", "%d / %d / True",
472  muscle_driver->server_firmware_git_revision_, muscle_driver->pic_firmware_git_revision_);
473  }
474  else
475  {
476  d.addf("Firmware git revision (server / pic / modified)", "%d / %d / False",
477  muscle_driver->server_firmware_git_revision_, muscle_driver->pic_firmware_git_revision_);
478  }
479  }
480  }
481  else
482  {
483  d.summary(d.ERROR, "Muscle Driver error");
484  d.clear();
485  d.addf("Muscle Driver ID", "%d", muscle_driver->muscle_driver_id);
486  }
487 
488  vec.push_back(d);
489  } // end for each muscle driver
490  }
491 
492  template<class StatusType, class CommandType>
494  StatusType *status_data)
495  {
496  if (!joint_tmp->has_actuator)
497  {
498  return;
499  }
500 
501  int packet_offset_muscle_0 = 0;
502  int packet_offset_muscle_1 = 0;
503 
504  shared_ptr<MuscleWrapper> muscle_wrapper = static_pointer_cast<MuscleWrapper>(joint_tmp->actuator_wrapper);
505 
506  // Every muscle driver sends two muscle_data_packet containing pressures from 5 muscles each
507  if (muscle_wrapper->muscle_id[0] >= NUM_PRESSURE_SENSORS_PER_MESSAGE)
508  {
509  packet_offset_muscle_0 = 1;
510  }
511 
512  if (muscle_wrapper->muscle_id[1] >= NUM_PRESSURE_SENSORS_PER_MESSAGE)
513  {
514  packet_offset_muscle_1 = 1;
515  }
516 
517  // check the masks to see if the CAN messages arrived from the muscle driver
518  // the flag should be set to 1 for each muscle driver CAN message
519  // (a muscle driver sends 2 separate CAN messages with 5 muscle pressures each.
520  // Every actuator (every joint) has two muscles, so we check both flags to decide that the actuator is OK
521  muscle_wrapper->actuator_ok = sr_math_utils::is_bit_mask_index_true(status_data->which_muscle_data_arrived,
522  muscle_wrapper->muscle_driver_id[0] * 2 +
523  packet_offset_muscle_0)
524  && sr_math_utils::is_bit_mask_index_true(status_data->which_muscle_data_arrived,
525  muscle_wrapper->muscle_driver_id[1] * 2 +
526  packet_offset_muscle_1);
527 
528  /*
529  // check the masks to see if a bad CAN message arrived
530  // the flag should be 0
531  muscle_wrapper->bad_data =
532  sr_math_utils::is_bit_mask_index_true(status_data->which_pressure_data_had_errors,
533  muscle_wrapper->muscle_driver_id[0] * 10 +
534  muscle_wrapper->muscle_id[0]) &&
535  sr_math_utils::is_bit_mask_index_true(status_data->which_pressure_data_had_errors,
536  muscle_wrapper->muscle_driver_id[1] * 10 +
537  muscle_wrapper->muscle_id[1]);
538  */
539 
540  if (muscle_wrapper->actuator_ok)
541  {
542  SrMuscleActuator *actuator = static_cast<SrMuscleActuator *> (joint_tmp->actuator_wrapper->actuator);
543  MuscleWrapper *actuator_wrapper = static_cast<MuscleWrapper *> (joint_tmp->actuator_wrapper.get());
544 
545 #ifdef DEBUG_PUBLISHER
546  int publisher_index = 0;
547  // publish the debug values for the given muscles.
548  // NB: debug_muscle_indexes_and_data is smaller
549  // than debug_publishers.
550  shared_ptr<pair<int, int> > debug_pair;
551 
552  if (this->debug_mutex.try_lock())
553  {
554  BOOST_FOREACH(debug_pair, this->debug_muscle_indexes_and_data)
555  {
556  if (debug_pair != NULL)
557  {
558  // check if we want to publish some data for the current muscle
559  if (debug_pair->first == actuator_wrapper->muscle_id[0])
560  {
561  // if < 0, then we're not asking for a FROM_MOTOR_DATA_TYPE
562  if (debug_pair->second > 0)
563  {
564  // check if it's the correct data
565  if (debug_pair->second == status_data->muscle_data_type)
566  {
567  // @todo do something meaningful here
568  // this->msg_debug.data = status_data->muscle_data_packet[0].misc;
569  this->msg_debug.data = 0;
570  this->debug_publishers[publisher_index].publish(this->msg_debug);
571  }
572  }
573  }
574  }
575  publisher_index++;
576  }
577 
578  this->debug_mutex.unlock();
579  } // end try_lock
580 #endif
581 
582  // we received the data and it was correct
583  unsigned int p1 = 0;
584  switch (status_data->muscle_data_type)
585  {
587  // Calibrate the raw values to bar pressure values.
588  for (int i = 0; i < 2; ++i)
589  {
590  p1 = get_muscle_pressure(muscle_wrapper->muscle_driver_id[i], muscle_wrapper->muscle_id[i], status_data);
591  string name = joint_tmp->joint_name + "_" + boost::lexical_cast<string>(i);
592  // XXX: If the joint isn't found we crash
593  // ROS_INFO_STREAM("Calib: "<<name);
595  double bar = pressure_calibration_tmp_->compute(static_cast<double> (p1));
596  if (bar < 0.0)
597  {
598  bar = 0.0;
599  }
600  actuator->muscle_state_.pressure_[i] = static_cast<int16u> (bar);
601  }
602  // Raw values
603  // actuator->state_.pressure_[0] = static_cast<int16u>(
604  // get_muscle_pressure(muscle_wrapper->muscle_driver_id[0],
605  // muscle_wrapper->muscle_id[0],
606  // status_data));
607  // actuator->state_.pressure_[1] = static_cast<int16u>(
608  // get_muscle_pressure(muscle_wrapper->muscle_driver_id[1],
609  // muscle_wrapper->muscle_id[1],
610  // status_data));
611  // ROS_WARN("DriverID: %u MuscleID: %u Pressure 0: %u", muscle_wrapper->muscle_driver_id[0],
612  // muscle_wrapper->muscle_id[0], actuator->state_.pressure_[0]);
613  // ROS_WARN("DriverID: %u MuscleID: %u Pressure 1: %u", muscle_wrapper->muscle_driver_id[1],
614  // muscle_wrapper->muscle_id[1], actuator->state_.pressure_[1]);
615 
616 #ifdef DEBUG_PUBLISHER
617  if (actuator_wrapper->muscle_id[0] == 8)
618  {
619  // ROS_ERROR_STREAM("SGL " <<actuator->state_.strain_gauge_left_);
620  // this->msg_debug.data = actuator->state_.strain_gauge_left_;
621  // this->debug_publishers[0].publish(this->msg_debug);
622  }
623 #endif
624  break;
625 
626 
627  default:
628  break;
629  }
630  }
631  }
632 
633  template<class StatusType, class CommandType>
634  unsigned int SrMuscleRobotLib<StatusType, CommandType>::get_muscle_pressure(int muscle_driver_id, int muscle_id,
635  StatusType *status_data)
636  {
637  unsigned int muscle_pressure = 0;
638  int packet_offset = 0;
639  int muscle_index = muscle_id;
640 
641  // Every muscle driver sends two muscle_data_packet containing pressures from 5 muscles each
642  if (muscle_id >= NUM_PRESSURE_SENSORS_PER_MESSAGE)
643  {
644  packet_offset = 1;
645  muscle_index = muscle_id - NUM_PRESSURE_SENSORS_PER_MESSAGE;
646  }
647 
648  switch (muscle_index)
649  {
650  case 0:
651  muscle_pressure =
652  (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure0_H << 8)
653  + (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure0_M << 4)
654  + status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure0_L;
655  break;
656 
657  case 1:
658  muscle_pressure =
659  (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure1_H << 8)
660  + (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure1_M << 4)
661  + status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure1_L;
662  break;
663 
664  case 2:
665  muscle_pressure =
666  (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure2_H << 8)
667  + (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure2_M << 4)
668  + status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure2_L;
669  break;
670 
671  case 3:
672  muscle_pressure =
673  (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure3_H << 8)
674  + (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure3_M << 4)
675  + status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure3_L;
676  break;
677 
678  case 4:
679  muscle_pressure =
680  (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure4_H << 8)
681  + (status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure4_M << 4)
682  + status_data->muscle_data_packet[muscle_driver_id * 2 + packet_offset].packed.pressure4_L;
683  break;
684 
685  default:
686  ROS_ERROR("Incorrect muscle index: %d", muscle_index);
687  break;
688  }
689 
690  return muscle_pressure;
691  }
692 
693  template<class StatusType, class CommandType>
695  vector<MuscleDriver>::iterator muscle_driver_tmp, StatusType *status_data)
696  {
697  // check one the masks (e.g. the first) for this muscle driver to see if
698  // the CAN messages arrived correctly from the muscle driver
699  // the flag should be set to 1 for each message in this driver.
700  muscle_driver_tmp->driver_ok = sr_math_utils::is_bit_mask_index_true(status_data->which_muscle_data_arrived,
701  muscle_driver_tmp->muscle_driver_id * 2);
702  /*
703  // check the masks to see if a bad CAN message arrived
704  // the flag should be 0
705  muscle_driver_tmp->bad_data = sr_math_utils::is_bit_mask_index_true(status_data->which_pressure_data_had_errors,
706  muscle_driver_tmp->muscle_driver_id * 2 );
707  */
708 
709  if (muscle_driver_tmp->driver_ok)
710  {
711  // we received the data and it was correct
712  set_muscle_driver_data_received_flags(status_data->muscle_data_type, muscle_driver_tmp->muscle_driver_id);
713 
714  switch (status_data->muscle_data_type)
715  {
717  // We don't do anything here. This will be treated in a per-joint loop in read_additional_muscle_data
718  break;
719 
721  // For the moment all the CAN data statistics for a muscle driver are contained
722  // in the first packet coming from that driver
723  // these are 16 bits values and will overflow -> we compute the real value.
724  // This needs to be updated faster than the overflowing period (which should be roughly every 30s)
725  muscle_driver_tmp->can_msgs_received_ = sr_math_utils::counter_with_overflow(
726  muscle_driver_tmp->can_msgs_received_,
727  static_cast<int16u> (status_data->muscle_data_packet[muscle_driver_tmp->muscle_driver_id *
728  2].misc.can_msgs_rx));
729  muscle_driver_tmp->can_msgs_transmitted_ = sr_math_utils::counter_with_overflow(
730  muscle_driver_tmp->can_msgs_transmitted_,
731  static_cast<int16u> (status_data->muscle_data_packet[muscle_driver_tmp->muscle_driver_id *
732  2].misc.can_msgs_tx));
733 
734  // CAN bus errors
735  muscle_driver_tmp->can_err_rx = static_cast<unsigned int> (status_data->muscle_data_packet[
736  muscle_driver_tmp->muscle_driver_id * 2].misc.can_err_rx);
737  muscle_driver_tmp->can_err_tx = static_cast<unsigned int> (status_data->muscle_data_packet[
738  muscle_driver_tmp->muscle_driver_id * 2].misc.can_err_tx);
739  break;
740 
742  // We received a slow data:
743  // the slow data type is not transmitted anymore (as it was in the muscle hand protocol)
744  // Instead, all the information (of every data type) is contained in the 2 packets
745  // that come from every muscle driver
746  // So in fact this message is not "slow" anymore.
747  muscle_driver_tmp->pic_firmware_git_revision_ = static_cast<unsigned int> (status_data->muscle_data_packet[
748  muscle_driver_tmp->muscle_driver_id * 2].slow_0.SVN_revision);
749  muscle_driver_tmp->server_firmware_git_revision_ = static_cast<unsigned int> (status_data->muscle_data_packet[
750  muscle_driver_tmp->muscle_driver_id * 2].slow_0.SVN_server);
751  muscle_driver_tmp->firmware_modified_ =
752  static_cast<bool> (static_cast<unsigned int> (status_data->muscle_data_packet[
753  muscle_driver_tmp->muscle_driver_id * 2].slow_0.SVN_modified));
754 
755  muscle_driver_tmp->serial_number = static_cast<unsigned int> (status_data->muscle_data_packet[
756  muscle_driver_tmp->muscle_driver_id * 2 + 1].slow_1.serial_number);
757  muscle_driver_tmp->assembly_date_year = static_cast<unsigned int> (status_data->muscle_data_packet[
758  muscle_driver_tmp->muscle_driver_id * 2 + 1].slow_1.assembly_date_YYYY);
759  muscle_driver_tmp->assembly_date_month = static_cast<unsigned int> (status_data->muscle_data_packet[
760  muscle_driver_tmp->muscle_driver_id * 2 + 1].slow_1.assembly_date_MM);
761  muscle_driver_tmp->assembly_date_day = static_cast<unsigned int> (status_data->muscle_data_packet[
762  muscle_driver_tmp->muscle_driver_id * 2 + 1].slow_1.assembly_date_DD);
763  break;
764 
765  default:
766  break;
767  }
768 
769  // Mutual exclusion with the the initialization timeout
770  boost::mutex::scoped_lock l(*lock_init_timeout_);
771 
772  // Check the message to see if everything has already been received
774  {
777  {
780  // stop the timer
782 
783  ROS_INFO("All muscle data initialized.");
784  }
785  }
786  }
787  }
788 
789  template<class StatusType, class CommandType>
791  int muscle_driver_id)
792  {
794  {
795  map<unsigned int, unsigned int>::iterator it = from_muscle_driver_data_received_flags_.find(msg_type);
797  {
798  it->second = it->second | (1 << muscle_driver_id);
799  }
800  }
801  }
802 
803  template<class StatusType, class CommandType>
805  {
806  map<unsigned int, unsigned int>::iterator it = from_muscle_driver_data_received_flags_.begin();
807  for (; it != from_muscle_driver_data_received_flags_.end(); ++it)
808  {
809  // We want to detect when the flag for every driver is checked,
810  // so, for NUM_MUSCLE_DRIVERS = 4 we want to have 00001111
811  if (it->second != (1 << NUM_MUSCLE_DRIVERS) - 1)
812  {
813  return false;
814  }
815  }
816  return true;
817  }
818 
819  template<class StatusType, class CommandType>
820  void SrMuscleRobotLib<StatusType, CommandType>::calibrate_joint(vector<Joint>::iterator joint_tmp,
821  StatusType *status_data)
822  {
823  SrMuscleActuator *actuator = get_joint_actuator(joint_tmp);
824 
825  actuator->muscle_state_.raw_sensor_values_.clear();
826  actuator->muscle_state_.calibrated_sensor_values_.clear();
827 
828  if (joint_tmp->joint_to_sensor.calibrate_after_combining_sensors)
829  {
830  // first we combine the different sensors and then we
831  // calibrate the value we obtained. This is used for
832  // some compound sensors ( THJ5 = cal(THJ5A + THJ5B))
833  double raw_position = 0.0;
834  // when combining the values, we use the coefficient imported
835  // from the sensor_to_joint.yaml file (in sr_edc_launch/config)
836 
837  BOOST_FOREACH(PartialJointToSensor joint_to_sensor, joint_tmp->joint_to_sensor.joint_to_sensor_vector)
838  {
839  int tmp_raw = status_data->sensors[joint_to_sensor.sensor_id];
840  actuator->muscle_state_.raw_sensor_values_.push_back(tmp_raw);
841  raw_position += static_cast<double> (tmp_raw) * joint_to_sensor.coeff;
842  }
843 
844  // and now we calibrate
845  this->calibration_tmp = this->calibration_map.find(joint_tmp->joint_name);
846  actuator->muscle_state_.position_unfiltered_ = this->calibration_tmp->compute(static_cast<double> (raw_position));
847  }
848  else
849  {
850  // we calibrate the different sensors first and we combine the calibrated
851  // values. This is used in the joint 0s for example ( J0 = cal(J1)+cal(J2) )
852  double calibrated_position = 0.0;
853  PartialJointToSensor joint_to_sensor;
854  string sensor_name;
855 
856  ROS_DEBUG_STREAM("Combining actuator " << joint_tmp->joint_name);
857 
858  for (unsigned int index_joint_to_sensor = 0;
859  index_joint_to_sensor < joint_tmp->joint_to_sensor.joint_to_sensor_vector.size();
860  ++index_joint_to_sensor)
861  {
862  joint_to_sensor = joint_tmp->joint_to_sensor.joint_to_sensor_vector[index_joint_to_sensor];
863  sensor_name = joint_tmp->joint_to_sensor.sensor_names[index_joint_to_sensor];
864 
865  // get the raw position
866  int raw_pos = status_data->sensors[joint_to_sensor.sensor_id];
867  // push the new raw values
868  actuator->muscle_state_.raw_sensor_values_.push_back(raw_pos);
869 
870  // calibrate and then combine
871  this->calibration_tmp = this->calibration_map.find(sensor_name);
872  double tmp_cal_value = this->calibration_tmp->compute(static_cast<double> (raw_pos));
873 
874  // push the new calibrated values.
875  actuator->muscle_state_.calibrated_sensor_values_.push_back(tmp_cal_value);
876 
877  calibrated_position += tmp_cal_value * joint_to_sensor.coeff;
878 
879  ROS_DEBUG_STREAM(" -> " << sensor_name << " raw = " << raw_pos << " calibrated = " << calibrated_position);
880  }
881  actuator->muscle_state_.position_unfiltered_ = calibrated_position;
882  ROS_DEBUG_STREAM(" => " << actuator->muscle_state_.position_unfiltered_);
883  }
884  } // end calibrate_joint()
885 
886  template<class StatusType, class CommandType>
888  StatusType *status_data,
889  double timestamp)
890  {
891  SrMuscleActuator *actuator = get_joint_actuator(joint_tmp);
892 
893  // calibrate the joint and update the position.
894  calibrate_joint(joint_tmp, status_data);
895 
896  // filter the position and velocity
897  pair<double, double> pos_and_velocity = joint_tmp->pos_filter.compute(actuator->muscle_state_.position_unfiltered_,
898  timestamp);
899  // reset the position to the filtered value
900  actuator->state_.position_ = pos_and_velocity.first;
901  // set the velocity to the filtered velocity
902  actuator->state_.velocity_ = pos_and_velocity.second;
903  }
904 
905  template<class StatusType, class CommandType>
906  vector<pair<string, bool> > SrMuscleRobotLib<StatusType, CommandType>::humanize_flags(int flag)
907  {
908  vector<pair<string, bool> > flags;
909 
910  // 16 is the number of flags
911  for (unsigned int i = 0; i < 16; ++i)
912  {
913  pair<string, bool> new_flag;
914  // if the flag is set add the name
915  if (sr_math_utils::is_bit_mask_index_true(flag, i))
916  {
917  if (sr_math_utils::is_bit_mask_index_true(SERIOUS_ERROR_FLAGS, i))
918  {
919  new_flag.second = true;
920  }
921  else
922  {
923  new_flag.second = false;
924  }
925 
926  new_flag.first = error_flag_names[i];
927  flags.push_back(new_flag);
928  }
929  }
930  return flags;
931  }
932 
933  template<class StatusType, class CommandType>
935  {
936  // Mutual exclusion with the the initialization timeout
937  boost::mutex::scoped_lock l(*lock_init_timeout_);
938 
939  // stop the timer just in case it was still running
941  // Create a new MuscleUpdater object
946  // To reschedule the one-shot timer
949  }
950 
951  template<class StatusType, class CommandType>
953  {
954  // Mutual exclusion with the the initialization timeout
955  boost::mutex::scoped_lock l(*lock_init_timeout_);
956 
958  {
962  "Muscle Initialization Timeout: the static information in the diagnostics may not be up to date.");
963  }
964  }
965 
966  // Only to ensure that the template class is compiled for the types we are interested in
967  template
969 } // namespace shadow_robot
970 
971 /* For the emacs weenies in the crowd.
972  Local Variables:
973  c-basic-offset: 2
974  End:
975 */
unsigned short int16u
void set_muscle_driver_data_received_flags(unsigned int msg_type, int muscle_driver_id)
std::queue< int16_t, std::list< int16_t > > reset_muscle_driver_queue
MUSCLE_DEMAND_VALVES
void init_timer_callback(const ros::TimerEvent &event)
std::vector< shadow_joints::MuscleDriver > muscle_drivers_vector_
#define MUSCLE_SYSTEM_RESET_KEY
std::vector< shadow_joints::Joint > joints_vector
The vector containing all the robot joints.
MUSCLE_DATA_SLOW_MISC
void summary(unsigned char lvl, const std::string s)
boost::shared_ptr< shadow_robot::JointCalibration > pressure_calibration_tmp_
A temporary calibration for a given joint.
MUSCLE_SYSTEM_RESET
#define SERIOUS_ERROR_FLAGS
int size() const
void stop()
void read_additional_muscle_data(std::vector< shadow_joints::Joint >::iterator joint_tmp, StatusType *status_data)
void setPeriod(const Duration &period, bool reset=true)
void build_command(CommandType *command)
ros::NodeHandle nodehandle_
a ros nodehandle to be able to access resources out of the node namespace
void start()
virtual shadow_joints::CalibrationMap read_pressure_calibration()
void build_tactile_command(CommandType *command)
shadow_joints::CalibrationMap calibration_map
The map used to calibrate each joint.
void set_valve_demand(uint8_t *muscle_data_byte_to_set, int8_t valve_value, uint8_t shifting_index)
Type const & getType() const
SrMuscleRobotLib(hardware_interface::HardwareInterface *hw, ros::NodeHandle nh, ros::NodeHandle nhtilde, std::string device_id, std::string joint_prefix)
#define ROS_WARN(...)
void addf(const std::string &key, const char *format,...)
ros_ethercat_model::Actuator * actuator
#define error_flag_names
std::map< unsigned int, unsigned int > from_muscle_driver_data_received_flags_
#define NUM_PRESSURE_SENSORS_PER_MESSAGE
boost::shared_ptr< shadow_robot::JointCalibration > calibration_tmp
A temporary calibration for a given joint.
operation_mode::device_update_state::DeviceUpdateState muscle_current_state
#define ROS_INFO(...)
void process_position_sensor_data(std::vector< shadow_joints::Joint >::iterator joint_tmp, StatusType *status_data, double timestamp)
MUSCLE_DATA_PRESSURE
void read_muscle_driver_data(std::vector< shadow_joints::MuscleDriver >::iterator muscle_driver_tmp, StatusType *status_data)
#define ROS_DEBUG_STREAM(args)
boost::shared_ptr< generic_updater::MuscleUpdater< CommandType > > muscle_updater_
std::vector< std::pair< std::string, bool > > humanize_flags(int flag)
unsigned int get_muscle_pressure(int muscle_driver_id, int muscle_id, StatusType *status_data)
bool getParam(const std::string &key, std::string &s) const
std::string device_id_
Id of the ethercat device (alias)
MUSCLE_DATA_CAN_STATS
void update_tactile_info(StatusType *status)
shadow_joints::CalibrationMap pressure_calibration_map_
The map used to calibrate each pressure sensor.
void calibrate_joint(std::vector< shadow_joints::Joint >::iterator joint_tmp, StatusType *status_data)
threadsafe::Map< boost::shared_ptr< shadow_robot::JointCalibration > > CalibrationMap
sr_actuator::SrMuscleActuator * get_joint_actuator(std::vector< shadow_joints::Joint >::iterator joint_tmp)
#define ROS_ERROR_STREAM(args)
#define ROS_ASSERT(cond)
void update(StatusType *status_data)
std::vector< generic_updater::UpdateConfig > muscle_update_rate_configs_vector
#define NUM_MUSCLE_DRIVERS
#define ROS_ERROR(...)
boost::shared_ptr< boost::mutex > lock_init_timeout_
int muscle_id[2]
id of the muscles for this joint (the id indicates the order from 0 to 9 of the muscle in its muscle ...
void add_diagnostics(std::vector< diagnostic_msgs::DiagnosticStatus > &vec, diagnostic_updater::DiagnosticStatusWrapper &d)


sr_robot_lib
Author(s): Ugo Cupcic, Toni Oliver
autogenerated on Tue Oct 13 2020 04:01:58