motor_hardware.cc
Go to the documentation of this file.
1 
32 #include <boost/assign.hpp>
33 #include <boost/math/special_functions/round.hpp>
34 
35 // To access I2C we need some system includes
36 #include <linux/i2c-dev.h>
37 #include <linux/i2c.h>
38 #include <fcntl.h>
39 #include <sys/ioctl.h>
40 #define I2C_DEVICE "/dev/i2c-1" // This is specific to default Magni I2C port on host
41 const static uint8_t I2C_PCF8574_8BIT_ADDR = 0x40; // I2C addresses are 7 bits but often shown as 8-bit
42 
43 //#define SENSOR_DISTANCE 0.002478
44 
45 
46 // For experimental purposes users will see that the wheel encoders are three phases
47 // of very neaar 43 pulses per revolution or about 43*3 edges so we see very about 129 ticks per rev
48 // This leads to 129/(2*Pi) or about 20.53 ticks per radian experimentally.
49 // 60 ticks per revolution of the motor (pre gearbox) and a gear ratio of 4.2941176:1 for 1st rev Magni wheels
50 // An unexplained constant from the past I leave here till explained is: 17.2328767
51 
52 #define TICKS_PER_RAD_FROM_GEAR_RATIO ((double)(4.774556)*(double)(2.0)) // Used to generate ticks per radian
53 #define TICKS_PER_RADIAN_DEFAULT 41.004 // For runtime use getWheelGearRatio() * TICKS_PER_RAD_FROM_GEAR_RATIO
54 #define WHEEL_GEAR_RATIO_DEFAULT WHEEL_GEAR_RATIO_1
55 
56 // TODO: Make HIGH_SPEED_RADIANS, WHEEL_VELOCITY_NEAR_ZERO and ODOM_4WD_ROTATION_SCALE all ROS params
57 #define HIGH_SPEED_RADIANS (1.8) // threshold to consider wheel turning 'very fast'
58 #define WHEEL_VELOCITY_NEAR_ZERO ((double)(0.08))
59 #define ODOM_4WD_ROTATION_SCALE ((double)(1.65)) // Used to correct for 4WD skid rotation error
60 
61 #define MOTOR_AMPS_PER_ADC_COUNT ((double)(0.0238)) // 0.1V/Amp 2.44V=1024 count so 41.97 cnt/amp
62 
63 #define VELOCITY_READ_PER_SECOND ((double)(10.0)) // read = ticks / (100 ms), so we scale of 10 for ticks/second
64 #define LOWEST_FIRMWARE_VERSION 28
65 
66 // Debug verification use only
67 int32_t g_odomLeft = 0;
68 int32_t g_odomRight = 0;
69 int32_t g_odomEvent = 0;
70 
71 //lead acid battery percentage levels for a single cell
72 const static float SLA_AGM[11] = {
73  1.800, // 0
74  1.837, // 10
75  1.875, // 20
76  1.912, // 30
77  1.950, // 40
78  2.010, // 50
79  2.025, // 60
80  2.062, // 70
81  2.100, // 80
82  2.137, // 90
83  2.175, // 100
84 };
85 
86 
87 //li-ion battery percentage levels for a single cell
88 const static float LI_ION[11] = {
89  3.3, // 0
90  3.49, // 10
91  3.53, // 20
92  3.55, // 30
93  3.60, // 40
94  3.64, // 50
95  3.70, // 60
96  3.80, // 70
97  3.85, // 80
98  4.05, // 90
99  4.20, // 100
100 };
101 
102 // We sometimes need to know if we are rotating in place due to special ways of dealing with
103 // A 4wd robot must skid to turn. This factor approximates the actual rotation done vs what
104 // the wheel encoders have indicated. This only applies if in 4WD mode
106 
107 // 4WD robot chassis that has to use extensive torque to rotate in place and due to wheel slip has odom scale factor
108 double g_radiansLeft = 0.0;
109 double g_radiansRight = 0.0;
110 
111 // This utility opens and reads 1 or more bytes from a device on an I2C bus
112 // This method was taken on it's own from a big I2C class we may choose to use later
113 static int i2c_BufferRead(const char *i2cDevFile, uint8_t i2c8bitAddr,
114  uint8_t *pBuffer, int16_t chipRegAddr, uint16_t NumBytesToRead);
115 
117  FirmwareParams firmware_params) {
118  ros::V_string joint_names =
119  boost::assign::list_of("left_wheel_joint")("right_wheel_joint");
120 
121  for (size_t i = 0; i < joint_names.size(); i++) {
122  hardware_interface::JointStateHandle joint_state_handle(
123  joint_names[i], &joints_[i].position, &joints_[i].velocity,
124  &joints_[i].effort);
125  joint_state_interface_.registerHandle(joint_state_handle);
126 
127  hardware_interface::JointHandle joint_handle(
128  joint_state_handle, &joints_[i].velocity_command);
130  }
133 
134  // Insert a delay prior to serial port setup to avoid a race defect.
135  // We see soemtimes the OS sets the port to 115200 baud just after we set it
136  ROS_INFO("Delay before MCB serial port initialization");
137  ros::Duration(5.0).sleep();
138  ROS_INFO("Initialize MCB serial port '%s' for %d baud",
139  serial_params.serial_port.c_str(), serial_params.baud_rate);
140 
141  motor_serial_ =
142  new MotorSerial(serial_params.serial_port, serial_params.baud_rate);
143 
144  ROS_INFO("MCB serial port initialized");
145 
146  // For motor tunning and other uses we publish details for each wheel
147  leftError = nh.advertise<std_msgs::Int32>("left_error", 1);
148  rightError = nh.advertise<std_msgs::Int32>("right_error", 1);
149  leftTickInterval = nh.advertise<std_msgs::Int32>("left_tick_interval", 1);
150  rightTickInterval = nh.advertise<std_msgs::Int32>("right_tick_interval", 1);
151 
152  firmware_state = nh.advertise<std_msgs::String>("firmware_version", 1, true);
153  battery_state = nh.advertise<sensor_msgs::BatteryState>("battery_state", 1);
154  motor_power_active = nh.advertise<std_msgs::Bool>("motor_power_active", 1);
155 
156  motor_state = nh.advertise<ubiquity_motor::MotorState>("motor_state", 1);
157  leftCurrent = nh.advertise<std_msgs::Float32>("left_current", 1);
158  rightCurrent = nh.advertise<std_msgs::Float32>("right_current", 1);
159 
160  sendPid_count = 0;
161  num_fw_params = 8; // number of params sent if any change
162 
163  estop_motor_power_off = false; // Keeps state of ESTOP switch where true is in ESTOP state
164 
165  // Save default hardware encoder specifics for ticks in one radian of rotation of main wheel
168 
169  fw_params = firmware_params;
170 
190  prev_fw_params.max_pwm = -1;
191 
192  hardware_version = 0;
193  firmware_version = 0;
194  firmware_date = 0;
195 
196  diag_updater.setHardwareID("Motor Controller");
208 }
209 
211 
212 // Close of the serial port is used in a special case of suspending the motor controller
213 // so that another service can load firmware or do direct MCB diagnostics
216 }
217 
218 // After we have given up the MCB we open serial port again using current instance of Serial
220  return motor_serial_->openPort();
221 }
222 
224  for (size_t i = 0; i < sizeof(joints_) / sizeof(joints_[0]); i++) {
225  joints_[i].velocity_command = 0;
226  }
227 }
228 
229 // Read the current wheel positions in radians both at once for a snapshot of position
230 void MotorHardware::getWheelJointPositions(double &leftWheelPosition, double &rightWheelPosition) {
231  leftWheelPosition = joints_[WheelJointLocation::Left].position;
232  rightWheelPosition = joints_[WheelJointLocation::Right].position;
233  return;
234 }
235 
236 // Set the current wheel joing velocities in radians/sec both at once for a snapshot of velocity
237 // This interface is supplied because MotorHardware does not do a loop on it's own
238 void MotorHardware::setWheelJointVelocities(double leftWheelVelocity, double rightWheelVelocity) {
239  joints_[WheelJointLocation::Left].velocity = leftWheelVelocity;
240  joints_[WheelJointLocation::Right].velocity = rightWheelVelocity;
241  return;
242 }
243 
244 // Publish motor state conditions
246  ubiquity_motor::MotorState mstateMsg;
247 
248  mstateMsg.header.frame_id = ""; // Could be base_link. We will use empty till required
249  mstateMsg.header.stamp = ros::Time::now();
250 
251  mstateMsg.leftPosition = joints_[WheelJointLocation::Left].position;
252  mstateMsg.rightPosition = joints_[WheelJointLocation::Right].position;
253  mstateMsg.leftRotateRate = joints_[WheelJointLocation::Left].velocity;
254  mstateMsg.rightRotateRate = joints_[WheelJointLocation::Right].velocity;
255  mstateMsg.leftCurrent = motor_diag_.motorCurrentLeft;
256  mstateMsg.rightCurrent = motor_diag_.motorCurrentRight;
257  mstateMsg.leftPwmDrive = motor_diag_.motorPwmDriveLeft;
258  mstateMsg.rightPwmDrive = motor_diag_.motorPwmDriveRight;
259  motor_state.publish(mstateMsg);
260  return;
261 }
262 
263 // readInputs() will receive serial and act on the response from motor controller
264 //
265 // The motor controller sends unsolicited messages periodically so we must read the
266 // messages to update status in near realtime
267 //
268 void MotorHardware::readInputs(uint32_t index) {
269  while (motor_serial_->commandAvailable()) {
270  MotorMessage mm;
272  if (mm.getType() == MotorMessage::TYPE_RESPONSE) {
273  switch (mm.getRegister()) {
274 
276  if ((mm.getData() & MotorMessage::SYS_EVENT_POWERON) != 0) {
277  ROS_WARN("Firmware System Event for PowerOn transition");
278  system_events = mm.getData();
279  }
280  break;
282  if (mm.getData() < LOWEST_FIRMWARE_VERSION) {
283  ROS_FATAL("Firmware version %d, expect %d or above",
285  throw std::runtime_error("Firmware version too low");
286  } else {
287  ROS_INFO_ONCE("Firmware version %d", mm.getData());
288  firmware_version = mm.getData();
290  }
292  break;
293 
295  // Firmware date is only supported as of fw version MIN_FW_FIRMWARE_DATE
296  ROS_INFO_ONCE("Firmware date 0x%x (format 0xYYYYMMDD)", mm.getData());
297  firmware_date = mm.getData();
299 
301  break;
302 
304  /*
305  * ODOM messages from the MCB tell us how far wheels have rotated
306  *
307  * It is here we keep track of wheel joint position
308  * The odom counts from the MCB are the incremental number of ticks since last report
309  * WARNING: IF WE LOOSE A MESSAGE WE DRIFT FROM REAL POSITION
310  */
311  int32_t odom = mm.getData();
312  // ROS_ERROR("odom signed %d", odom);
313  int16_t odomLeft = (odom >> 16) & 0xffff;
314  int16_t odomRight = odom & 0xffff;
315 
316  // Debug code to be used for verification
317  g_odomLeft += odomLeft;
318  g_odomRight += odomRight;
319  g_odomEvent += 1;
320  //if ((g_odomEvent % 50) == 1) { ROS_ERROR("leftOdom %d rightOdom %d", g_odomLeft, g_odomRight); }
321 
322  // Due to extreme wheel slip that is required to turn a 4WD robot we are doing a scale factor.
323  // When doing a rotation on the 4WD robot that is in place where linear velocity is zero
324  // we will adjust the odom values for wheel joint rotation using the scale factor.
325  double odom4wdRotationScale = 1.0;
326 
327  // Determine if we are rotating then set a scale to account for rotational wheel slip
328  double near0WheelVel = (double)(WHEEL_VELOCITY_NEAR_ZERO);
329  double leftWheelVel = g_radiansLeft; // rotational speed of motor
330  double rightWheelVel = g_radiansRight; // rotational speed of motor
331 
332  int leftDir = (leftWheelVel >= (double)(0.0)) ? 1 : -1;
333  int rightDir = (rightWheelVel >= (double)(0.0)) ? 1 : -1;
335  if (
336  // Is this in 4wd robot mode
337  (is4wdMode != 0)
338 
339  // Do the joints have Different rotational directions
340  && ((leftDir + rightDir) == 0)
341 
342  // Are Both joints not near joint velocity of 0
343  && ((fabs(leftWheelVel) > near0WheelVel) && (fabs(rightWheelVel) > near0WheelVel))
344 
345  // Is the difference of the two absolute values of the joint velocities near zero
346  && ((fabs(leftWheelVel) - fabs(rightWheelVel)) < near0WheelVel) ) {
347 
348  odom4wdRotationScale = g_odom4wdRotationScale;
349  if ((index % 16) == 1) { // This throttles the messages for rotational torque enhancement
350  ROS_INFO("ROTATIONAL_SCALING_ACTIVE: odom4wdRotationScale = %4.2f [%4.2f, %4.2f] [%d,%d] opt 0x%x 4wd=%d",
351  odom4wdRotationScale, leftWheelVel, rightWheelVel, leftDir, rightDir, fw_params.hw_options, is4wdMode);
352  }
353  } else {
354  if (fabs(leftWheelVel) > near0WheelVel) {
355  ROS_DEBUG("odom4wdRotationScale = %4.2f [%4.2f, %4.2f] [%d,%d] opt 0x%x 4wd=%d",
356  odom4wdRotationScale, leftWheelVel, rightWheelVel, leftDir, rightDir, fw_params.hw_options, is4wdMode);
357  }
358  }
359 
360  // Add or subtract from position in radians using the incremental odom value
361  joints_[WheelJointLocation::Left].position +=
362  ((double)odomLeft / (this->ticks_per_radian * odom4wdRotationScale));
363  joints_[WheelJointLocation::Right].position +=
364  ((double)odomRight / (this->ticks_per_radian * odom4wdRotationScale));
365 
366  motor_diag_.odom_update_status.tick(); // Let diag know we got odom
367 
368  break;
369  }
371  std_msgs::Int32 left;
372  std_msgs::Int32 right;
373  int32_t speed = mm.getData();
374  int16_t leftSpeed = (speed >> 16) & 0xffff;
375  int16_t rightSpeed = speed & 0xffff;
376 
377  left.data = leftSpeed;
378  right.data = rightSpeed;
379  leftError.publish(left);
380  rightError.publish(right);
381  break;
382  }
383 
385  int32_t bothPwm = mm.getData();
386  motor_diag_.motorPwmDriveLeft = (bothPwm >> 16) & 0xffff;
387  motor_diag_.motorPwmDriveRight = bothPwm & 0xffff;
388  break;
389  }
390 
392  // Motor current is an absolute value and goes up from a nominal count of near 1024
393  // So we subtract a nominal offset then multiply count * scale factor to get amps
394  int32_t data = mm.getData() & 0xffff;
397  break;
398  }
400  // Motor current is an absolute value and goes up from a nominal count of near 1024
401  // So we subtract a nominal offset then multiply count * scale factor to get amps
402  int32_t data = mm.getData() & 0xffff;
405  break;
406  }
407 
409  int32_t data = mm.getData();
410 
411  // Enable or disable hardware options reported from firmware
413 
414  // Set radians per encoder tic based on encoder specifics
416  ROS_WARN_ONCE("Encoder Resolution: 'Enhanced'");
419  } else {
420  ROS_WARN_ONCE("Encoder Resolution: 'Standard'");
421  fw_params.hw_options &= ~MotorMessage::OPT_ENC_6_STATE;
422  this->ticks_per_radian = this->getWheelTicksPerRadian() / (double)(2.0);
423  }
424 
426  ROS_WARN_ONCE("Wheel type is: 'thin'");
428  } else {
429  ROS_WARN_ONCE("Wheel type is: 'standard'");
430  fw_params.hw_options &= ~MotorMessage::OPT_WHEEL_TYPE_THIN;
431  }
432 
434  ROS_WARN_ONCE("Drive type is: '4wd'");
436  } else {
437  ROS_WARN_ONCE("Drive type is: '2wd'");
438  fw_params.hw_options &= ~MotorMessage::OPT_DRIVE_TYPE_4WD;
439  }
440 
442  ROS_WARN_ONCE("Wheel direction is: 'reverse'");
444  } else {
445  ROS_WARN_ONCE("Wheel direction is: 'standard'");
446  fw_params.hw_options &= ~MotorMessage::OPT_WHEEL_DIR_REVERSE;
447  }
448  break;
449  }
450 
452  int32_t data = mm.getData();
453 
455  ROS_WARN("left PWM limit reached");
457  }
459  ROS_WARN("right PWM limit reached");
461  }
463  ROS_DEBUG("left Integral limit reached");
465  }
467  ROS_DEBUG("right Integral limit reached");
469  }
471  ROS_WARN("left Maximum speed reached");
473  }
475  ROS_WARN("right Maximum speed reached");
477  }
479  ROS_WARN_ONCE("parameter limit in firmware");
481  }
482  break;
483  }
485  int32_t data = mm.getData();
486  sensor_msgs::BatteryState bstate;
487  bstate.voltage = (float)data * fw_params.battery_voltage_multiplier +
489  bstate.current = std::numeric_limits<float>::quiet_NaN();
490  bstate.charge = std::numeric_limits<float>::quiet_NaN();
491  bstate.capacity = std::numeric_limits<float>::quiet_NaN();
492  bstate.design_capacity = std::numeric_limits<float>::quiet_NaN();
493 
494  // Hardcoded to a sealed lead acid 12S battery, but adjustable for future use
495  bstate.percentage = calculateBatteryPercentage(bstate.voltage, 12, SLA_AGM);
496  bstate.power_supply_status = sensor_msgs::BatteryState::POWER_SUPPLY_STATUS_UNKNOWN;
497  bstate.power_supply_health = sensor_msgs::BatteryState::POWER_SUPPLY_HEALTH_UNKNOWN;
498  bstate.power_supply_technology = sensor_msgs::BatteryState::POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
499  battery_state.publish(bstate);
500 
501  motor_diag_.battery_voltage = bstate.voltage;
504  break;
505  }
506  case MotorMessage::REG_MOT_PWR_ACTIVE: { // Starting with rev 5.0 board we can see power state
507  int32_t data = mm.getData();
508 
510  if (estop_motor_power_off == true) {
511  ROS_WARN("Motor power has gone from inactive to active. Most likely from ESTOP switch");
512  }
513  estop_motor_power_off = false;
514  } else {
515  if (estop_motor_power_off == false) {
516  ROS_WARN("Motor power has gone inactive. Most likely from ESTOP switch active");
517  }
518  estop_motor_power_off = true;
519  }
520  motor_diag_.estop_motor_power_off = estop_motor_power_off; // A copy for diagnostics topic
521 
522  std_msgs::Bool estop_message;
523  estop_message.data = !estop_motor_power_off;
524  motor_power_active.publish(estop_message);
525  }
526 
527  case MotorMessage::REG_TINT_BOTH_WHLS: { // As of v41 show time between wheel enc edges
528  int32_t data = mm.getData();
529  uint16_t leftTickSpacing = (data >> 16) & 0xffff;
530  uint16_t rightTickSpacing = data & 0xffff;
531  uint16_t tickCap = 0; // We can cap the max value if desired
532 
533  if ((tickCap > 0) && (leftTickSpacing > tickCap)) { leftTickSpacing = tickCap; }
534  if ((tickCap > 0) && (rightTickSpacing > tickCap)) { rightTickSpacing = tickCap; }
535 
536  // Publish the two wheel tic intervals
537  std_msgs::Int32 leftInterval;
538  std_msgs::Int32 rightInterval;
539 
540  leftInterval.data = leftTickSpacing;
541  rightInterval.data = rightTickSpacing;
542 
543  // Only publish the tic intervals when wheels are moving
544  if (data > 1) { // Optionally show the intervals for debug
545  leftTickInterval.publish(leftInterval);
546  rightTickInterval.publish(rightInterval);
547 
548  ROS_DEBUG("Tic Ints M1 %d [0x%x] M2 %d [0x%x]",
549  leftTickSpacing, leftTickSpacing, rightTickSpacing, rightTickSpacing);
550  }
551  }
552  default:
553  break;
554  }
555  }
556  }
557 }
558 
559 
561  //publish the firmware version and optional date to ROS
562  if(firmware_version > 0){
563 
564  std_msgs::String fstate;
565  fstate.data = "v"+std::to_string(firmware_version);
566 
567  if(firmware_date > 0){
568  std::stringstream stream;
569  stream << std::hex << firmware_date;
570  std::string daycode(stream.str());
571 
572  fstate.data +=" "+daycode;
573  }
574 
575  firmware_state.publish(fstate);
576  }
577 }
578 
579 // calculateBatteryPercentage() takes in battery voltage, number of cells, and type; returns approximate percentage
580 //
581 // A battery type is defined by an array of 11 values, each corresponding to one 10% sized step from 0% to 100%.
582 // If the values fall between the steps, they are linearly interpolated to give a more accurate reading.
583 //
584 float MotorHardware::calculateBatteryPercentage(float voltage, int cells, const float* type) {
585  float onecell = voltage / (float)cells;
586 
587  if(onecell >= type[10])
588  return 1.0;
589  else if(onecell <= type[0])
590  return 0.0;
591 
592  int upper = 0;
593  int lower = 0;
594 
595  for(int i = 0; i < 11; i++){
596  if(onecell > type[i]){
597  lower = i;
598  }else{
599  upper = i;
600  break;
601  }
602  }
603 
604  float deltavoltage = type[upper] - type[lower];
605  float between_percent = (onecell - type[lower]) / deltavoltage;
606 
607  return (float)lower * 0.1 + between_percent * 0.1;
608 }
609 
610 // writeSpeedsInRadians() Take in radians per sec for wheels and send in message to controller
611 //
612 // A direct write speeds that allows caller setting speeds in radians
613 // This interface allows maintaining of system speed in state but override to zero
614 // which is of value for such a case as ESTOP implementation
615 //
616 void MotorHardware::writeSpeedsInRadians(double left_radians, double right_radians) {
617  MotorMessage both;
620 
621  g_radiansLeft = left_radians;
622  g_radiansRight = right_radians;
623 
624  // We are going to implement a message when robot is moving very fast or rotating very fast
625  if (((left_radians / VELOCITY_READ_PER_SECOND) > HIGH_SPEED_RADIANS) ||
626  ((right_radians / VELOCITY_READ_PER_SECOND) > HIGH_SPEED_RADIANS)) {
627  ROS_WARN("Wheel rotation at high radians per sec. Left %f rad/s Right %f rad/s",
628  left_radians, right_radians);
629  }
630 
631  int16_t left_speed = calculateSpeedFromRadians(left_radians);
632  int16_t right_speed = calculateSpeedFromRadians(right_radians);
633 
634  // The masking with 0x0000ffff is necessary for handling -ve numbers
635  int32_t data = (left_speed << 16) | (right_speed & 0x0000ffff);
636  both.setData(data);
637 
638  std_msgs::Int32 smsg;
639  smsg.data = left_speed;
640 
642 
643  // ROS_ERROR("velocity_command %f rad/s %f rad/s",
644  // joints_[WheelJointLocation::Left].velocity_command, joints_[WheelJointLocation::Right].velocity_command);
645  // joints_[LEFT_WHEEL_JOINT].velocity_command, joints_[RIGHT_WHEEL_JOINT].velocity_command);
646  // ROS_ERROR("SPEEDS %d %d", left.getData(), right.getData());
647 }
648 
649 // writeSpeeds() Take in radians per sec for wheels and send in message to controller
650 //
651 // Legacy interface where no speed overrides are supported
652 //
654  // This call pulls in speeds from the joints array maintained by other layers
655 
656  double left_radians = joints_[WheelJointLocation::Left].velocity_command;
657  double right_radians = joints_[WheelJointLocation::Right].velocity_command;
658 
659  writeSpeedsInRadians(left_radians, right_radians);
660 }
661 
662 // areWheelSpeedsLower() Determine if all wheel joint speeds are below given threshold
663 //
664 int MotorHardware::areWheelSpeedsLower(double wheelSpeedRadPerSec) {
665  int retCode = 0;
666 
667  // This call pulls in speeds from the joints array maintained by other layers
668 
669  double left_radians = joints_[WheelJointLocation::Left].velocity_command;
670  double right_radians = joints_[WheelJointLocation::Right].velocity_command;
671 
672  if ((std::abs(left_radians) < wheelSpeedRadPerSec) &&
673  (std::abs(right_radians) < wheelSpeedRadPerSec)) {
674  retCode = 1;
675  }
676 
677  return retCode;
678 }
679 
681  MotorMessage fw_version_msg;
683  fw_version_msg.setType(MotorMessage::TYPE_READ);
684  fw_version_msg.setData(0);
685  motor_serial_->transmitCommand(fw_version_msg);
686 }
687 
688 // Firmware date register implemented as of MIN_FW_FIRMWARE_DATE
690  MotorMessage fw_date_msg;
692  fw_date_msg.setType(MotorMessage::TYPE_READ);
693  fw_date_msg.setData(0);
694  motor_serial_->transmitCommand(fw_date_msg);
695 }
696 
697 // Request the MCB system event register
699  MotorMessage sys_event_msg;
701  sys_event_msg.setType(MotorMessage::TYPE_READ);
702  sys_event_msg.setData(0);
703  motor_serial_->transmitCommand(sys_event_msg);
704 }
705 
706 // Read the wheel currents in amps
707 void MotorHardware::getMotorCurrents(double &currentLeft, double &currentRight) {
708  currentLeft = motor_diag_.motorCurrentLeft;
709  currentRight = motor_diag_.motorCurrentRight;
710  return;
711 }
712 
713 
714 // Due to greatly limited pins on the firmware processor the host figures out the hardware rev and sends it to fw
715 // The hardware version is 0x0000MMmm where MM is major rev like 4 and mm is minor rev like 9 for first units.
716 // The 1st firmware version this is set for is 32, before it was always 1
717 void MotorHardware::setHardwareVersion(int32_t hardware_version) {
718  ROS_INFO("setting hardware_version to %x", (int)hardware_version);
719  this->hardware_version = hardware_version;
720  MotorMessage mm;
725 }
726 
727 // Setup the controller board threshold to put into force estop protection on boards prior to rev 5.0 with hardware support
728 void MotorHardware::setEstopPidThreshold(int32_t estop_pid_threshold) {
729  ROS_INFO("setting Estop PID threshold to %d", (int)estop_pid_threshold);
730  MotorMessage mm;
735 }
736 
737 // Setup the controller board to have estop button state detection feature enabled or not
738 void MotorHardware::setEstopDetection(int32_t estop_detection) {
739  ROS_INFO("setting estop button detection to %x", (int)estop_detection);
740  MotorMessage mm;
743  mm.setData(estop_detection);
745 }
746 
747 // Returns true if estop switch is active OR if motor power is off somehow off
749  return estop_motor_power_off;
750 }
751 
752 // Setup the controller board maximum settable motor forward speed
753 void MotorHardware::setMaxFwdSpeed(int32_t max_speed_fwd) {
754  ROS_INFO("setting max motor forward speed to %d", (int)max_speed_fwd);
755  MotorMessage mm;
760 }
761 
762 // Setup the Wheel Type. Overrides mode in use on hardware
763 // This used to only be standard but THIN_WHEELS were added in Jun 2020
764 void MotorHardware::setWheelType(int32_t new_wheel_type) {
765 
766  MotorMessage ho;
767  switch(new_wheel_type) {
770  ROS_INFO_ONCE("setting MCB wheel type %d", (int)new_wheel_type);
771  wheel_type = new_wheel_type;
774  ho.setData(wheel_type);
776  break;
777  default:
778  ROS_ERROR("Illegal MCB wheel type 0x%x will not be set!", (int)new_wheel_type);
779  }
780 }
781 
782 // A simple fetch of the wheel_gear_ratio
784  return this->wheel_gear_ratio;
785 }
786 
787 // A simple fetch of the encoder ticks per radian of wheel rotation
789  double result = this->getWheelGearRatio() * TICKS_PER_RAD_FROM_GEAR_RATIO;
790  return result;
791 }
792 
793 // Setup the local Wheel gear ratio so the motor hardware layer can adjust wheel odom reporting
794 // This gear ratio was introduced for a new version of the standard wheels in late 2021 production
795 // This is slightly more complex in that it is compounded with the now default 6 state encoder hw option
796 void MotorHardware::setWheelGearRatio(double new_wheel_gear_ratio) {
797  // This gear ratio is not used by the firmware so it is a simple state element in this module
798  this->wheel_gear_ratio = new_wheel_gear_ratio;
799  this->ticks_per_radian = this->getWheelTicksPerRadian(); // Need to also reset ticks_per_radian
801  this->ticks_per_radian = this->ticks_per_radian / (double)(2.0); // 3 state was half
802  }
803  ROS_INFO("Setting Wheel gear ratio to %6.4f and tics_per_radian to %6.4f",
804  this->wheel_gear_ratio, this->ticks_per_radian);
805 }
806 
807 // Setup the Drive Type. Overrides mode in use on hardware
808 // This used to only be 2WD and use of THIN_WHEELS set 4WD
809 // We are not trying to decouple wheel type from drive type
810 // This register always existed but was a do nothing till firmware v42
811 void MotorHardware::setDriveType(int32_t drive_type) {
812  ROS_INFO_ONCE("setting MCB drive type %d", (int)drive_type);
813  MotorMessage mm;
816  mm.setData(drive_type);
818 }
819 
820 // Setup the PID control options. Overrides modes in use on hardware
821 void MotorHardware::setPidControl(int32_t pid_control_word) {
822  ROS_INFO_ONCE("setting MCB pid control word to 0x%x", (int)pid_control_word);
823  MotorMessage mm;
826  mm.setData(pid_control_word);
828 }
829 
830 // Do a one time NULL of the wheel setpoint based on current position error
831 // This allows to relieve stress in static situation where wheels cannot slip to match setpoint
833  ROS_DEBUG("Nulling MCB wheel errors using current wheel positions");
834  MotorMessage mm;
837  mm.setData(MotorOrWheelNumber::Motor_M1|MotorOrWheelNumber::Motor_M2);
839 }
840 
841 // Setup the Wheel direction. Overrides mode in use on hardware
842 // This allows for customer to install wheels on cutom robots as they like
843 void MotorHardware::setWheelDirection(int32_t wheel_direction) {
844  ROS_INFO("setting MCB wheel direction to %d", (int)wheel_direction);
845  MotorMessage ho;
848  ho.setData(wheel_direction);
850 }
851 
852 // A simple fetch of the pid_control word from firmware params
854  int pidControlWord;
855  pidControlWord = motor_diag_.fw_pid_control;
856  return pidControlWord;
857 }
858 
859 // Read the controller board option switch itself that resides on the I2C bus but is on the MCB
860 // This call inverts the bits because a shorted option switch is a 0 where we want it as 1
861 // If return is negative something went wrong
863  uint8_t buf[16];
864  int retBits = 0;
865  ROS_INFO("reading MCB option switch on the I2C bus");
866  int retCount = i2c_BufferRead(I2C_DEVICE, I2C_PCF8574_8BIT_ADDR, &buf[0], -1, 1);
867  if (retCount < 0) {
868  ROS_ERROR("Error %d in reading MCB option switch at 8bit Addr 0x%x",
869  retCount, I2C_PCF8574_8BIT_ADDR);
870  retBits = retCount;
871  } else if (retCount != 1) {
872  ROS_ERROR("Cannot read byte from MCB option switch at 8bit Addr 0x%x", I2C_PCF8574_8BIT_ADDR);
873  retBits = -1;
874  } else {
875  retBits = (0xff) & ~buf[0];
876  }
877 
878  return retBits;
879 }
880 
881 // Setup the controller board option switch register which comes from the I2C 8-bit IO chip on MCB
882 void MotorHardware::setOptionSwitchReg(int32_t option_switch_bits) {
883  ROS_INFO("setting MCB option switch register to 0x%x", (int)option_switch_bits);
884  MotorMessage os;
887  os.setData(option_switch_bits);
889 }
890 
891 // Setup the controller board system event register or clear bits in the register
892 void MotorHardware::setSystemEvents(int32_t system_events) {
893  ROS_INFO("setting MCB system event register to %d", (int)system_events);
894  MotorMessage se;
899 }
900 
901 // Setup the controller board maximum settable motor reverse speed
902 void MotorHardware::setMaxRevSpeed(int32_t max_speed_rev) {
903  ROS_INFO("setting max motor reverse speed to %d", (int)max_speed_rev);
904  MotorMessage mm;
909 }
910 
911 // Setup the controller board maximum PWM level allowed for a motor
912 void MotorHardware::setMaxPwm(int32_t max_pwm) {
913  ROS_INFO("setting max motor PWM to %x", (int)max_pwm);
914  MotorMessage mm;
917  mm.setData(max_pwm);
919 }
920 
921 void MotorHardware::setDeadmanTimer(int32_t deadman_timer) {
922  ROS_ERROR("setting deadman to %d", (int)deadman_timer);
923  MotorMessage mm;
928 }
929 
930 void MotorHardware::setDeadzoneEnable(int32_t deadzone_enable) {
931  ROS_ERROR("setting deadzone enable to %d", (int)deadzone_enable);
932  MotorMessage mm;
937 }
938 
950 }
951 
952 // Forces next calls to sendParams() to always update each parameter.
953 // KEEP THIS IN SYNC WITH CHANGES TO sendParams()
955 
956  // Reset each of the flags that causes parameters to be sent to MCB by sendParams()
963  prev_fw_params.max_pwm = -1;
965 }
966 
968  std::vector<MotorMessage> commands;
969 
970  // ROS_ERROR("sending PID %d %d %d %d",
971  //(int)p_value, (int)i_value, (int)d_value, (int)denominator_value);
972 
973  // Only send one register at a time to avoid overwhelming serial comms
974  // SUPPORT NOTE! Adjust modulo for total parameters in the cycle
975  // and be sure no duplicate modulos are used!
976  int cycle = (sendPid_count++) % num_fw_params; // MUST BE THE TOTAL NUMBER IN THIS HANDLING
977 
978  if (cycle == 0 &&
980  ROS_WARN("Setting PidParam P to %d", fw_params.pid_proportional);
983  MotorMessage p;
987  commands.push_back(p);
988  }
989 
990  if (cycle == 1 && fw_params.pid_integral != prev_fw_params.pid_integral) {
991  ROS_WARN("Setting PidParam I to %d", fw_params.pid_integral);
994  MotorMessage i;
998  commands.push_back(i);
999  }
1000 
1001  if (cycle == 2 &&
1003  ROS_WARN("Setting PidParam D to %d", fw_params.pid_derivative);
1006  MotorMessage d;
1007  d.setRegister(MotorMessage::REG_PARAM_D);
1008  d.setType(MotorMessage::TYPE_WRITE);
1009  d.setData(fw_params.pid_derivative);
1010  commands.push_back(d);
1011  }
1012 
1013  if (cycle == 3 && (motor_diag_.firmware_version >= MIN_FW_PID_V_TERM) &&
1015  ROS_WARN("Setting PidParam V to %d", fw_params.pid_velocity);
1018  MotorMessage v;
1022  commands.push_back(v);
1023  }
1024 
1025  if (cycle == 4 &&
1027  ROS_WARN("Setting PidParam Denominator to %d", fw_params.pid_denominator);
1030  MotorMessage denominator;
1032  denominator.setType(MotorMessage::TYPE_WRITE);
1033  denominator.setData(fw_params.pid_denominator);
1034  commands.push_back(denominator);
1035  }
1036 
1037  if (cycle == 5 &&
1040  ROS_WARN("Setting PidParam D window to %d", fw_params.pid_moving_buffer_size);
1044  MotorMessage winsize;
1048  commands.push_back(winsize);
1049  }
1050 
1051  if (cycle == 6 &&
1053  ROS_WARN("Setting PidParam max_pwm to %d", fw_params.max_pwm);
1056  MotorMessage maxpwm;
1059  maxpwm.setData(fw_params.max_pwm);
1060  commands.push_back(maxpwm);
1061  }
1062 
1063  if (cycle == 7 &&
1065  ROS_WARN("Setting PidParam pid_control to %d", fw_params.pid_control);
1068  MotorMessage mmsg;
1072  commands.push_back(mmsg);
1073  }
1074 
1075  // SUPPORT NOTE! Adjust max modulo for total parameters in the cycle, be sure no duplicates used!
1076 
1077  if (commands.size() != 0) {
1078  motor_serial_->transmitCommands(commands);
1079  }
1080 }
1081 
1082 // Get current battery voltage
1084  return motor_diag_.battery_voltage; // We keep battery_voltage in diagnostic context
1085 }
1086 
1087 void MotorHardware::setDebugLeds(bool led_1, bool led_2) {
1088  std::vector<MotorMessage> commands;
1089 
1090  MotorMessage led1;
1093  if (led_1) {
1094  led1.setData(0x00000001);
1095  } else {
1096  led1.setData(0x00000000);
1097  }
1098  commands.push_back(led1);
1099 
1100  MotorMessage led2;
1103  if (led_2) {
1104  led2.setData(0x00000001);
1105  } else {
1106  led2.setData(0x00000000);
1107  }
1108  commands.push_back(led2);
1109 
1110  motor_serial_->transmitCommands(commands);
1111 }
1112 
1113 // calculate the binary speed value sent to motor controller board
1114 // using an input expressed in radians.
1115 // The firmware uses the same speed value no matter what type of encoder is used
1117  int16_t speed;
1118  double encoderFactor = 1.0;
1119  double speedFloat;
1120 
1121  // The firmware accepts same units for speed value
1122  // and will deal with it properly depending on encoder handling in use
1124  encoderFactor = (double)(0.5);
1125  }
1126 
1127  speedFloat = encoderFactor * radians * ((getWheelTicksPerRadian() * (double)(4.0)) / VELOCITY_READ_PER_SECOND);
1128  speed = boost::math::iround(speedFloat);
1129 
1130  return speed;
1131 }
1132 
1134  double result;
1135 
1136  result = ((double)ticks * VELOCITY_READ_PER_SECOND) / (getWheelTicksPerRadian() * (double)(4.0));
1137  return result;
1138 }
1139 
1140 // Diagnostics Status Updater Functions
1142 using diagnostic_msgs::DiagnosticStatus;
1143 
1145  stat.add("Firmware Version", firmware_version);
1146  if (firmware_version == 0) {
1147  stat.summary(DiagnosticStatus::ERROR, "No firmware version reported. Power may be off.");
1148  }
1149  else if (firmware_version < MIN_FW_RECOMMENDED) {
1150  stat.summary(DiagnosticStatus::WARN, "Firmware is older than recommended! You must update firmware!");
1151  }
1152  else {
1153  stat.summary(DiagnosticStatus::OK, "Firmware version is OK");
1154  }
1155 }
1156 
1158 
1159  // Only output status if the firmware daycode is supported
1161  std::stringstream stream;
1162  stream << std::hex << firmware_date;
1163  std::string daycode(stream.str());
1164 
1165  stat.add("Firmware Date", daycode);
1166  stat.summary(DiagnosticStatus::OK, "Firmware daycode format is YYYYMMDD");
1167  }
1168 }
1169 
1170 // When a firmware limit condition is reported the diagnostic topic reports it.
1171 // Once the report is made the condition is cleared till next time firmware reports that limit
1173  stat.summary(DiagnosticStatus::OK, "Limits reached:");
1174  if (left_pwm_limit) {
1175  stat.mergeSummary(DiagnosticStatusWrapper::ERROR, " left pwm,");
1176  left_pwm_limit = false;
1177  }
1178  if (right_pwm_limit) {
1179  stat.mergeSummary(DiagnosticStatusWrapper::ERROR, " right pwm,");
1180  right_pwm_limit = false;
1181  }
1182  if (left_integral_limit) {
1183  stat.mergeSummary(DiagnosticStatusWrapper::WARN, " left integral,");
1184  left_integral_limit = false;
1185  }
1186  if (right_integral_limit) {
1187  stat.mergeSummary(DiagnosticStatusWrapper::WARN, " right integral,");
1188  right_integral_limit = false;
1189  }
1190  if (left_max_speed_limit) {
1191  stat.mergeSummary(DiagnosticStatusWrapper::WARN, " left speed,");
1192  left_max_speed_limit = false;
1193  }
1194  if (right_max_speed_limit) {
1195  stat.mergeSummary(DiagnosticStatusWrapper::WARN, " right speed,");
1196  right_max_speed_limit = false;
1197  }
1199  // A parameter was sent to firmware that was out of limits for the firmware register
1200  stat.mergeSummary(DiagnosticStatusWrapper::WARN, " firmware limit,");
1201  param_limit_in_firmware = false;
1202  }
1203 }
1204 
1206  stat.add("Battery Voltage", battery_voltage);
1208  stat.summary(DiagnosticStatusWrapper::WARN, "Battery low");
1209  }
1211  stat.summary(DiagnosticStatusWrapper::ERROR, "Battery critical");
1212  }
1213  else {
1214  stat.summary(DiagnosticStatusWrapper::OK, "Battery OK");
1215  }
1216 }
1217 
1218 // PID parameters for motor control
1220  stat.add("PidParam P", fw_pid_proportional);
1221  stat.summary(DiagnosticStatus::OK, "PID Parameter P");
1222 }
1224  stat.add("PidParam I", fw_pid_integral);
1225  stat.summary(DiagnosticStatus::OK, "PID Parameter I");
1226 }
1228  stat.add("PidParam D", fw_pid_derivative);
1229  stat.summary(DiagnosticStatus::OK, "PID Parameter D");
1230 }
1232  stat.add("PidParam V", fw_pid_velocity);
1233  stat.summary(DiagnosticStatus::OK, "PID Parameter V");
1234 }
1236  stat.add("PidParam MaxPWM", fw_max_pwm);
1237  stat.summary(DiagnosticStatus::OK, "PID Max PWM");
1238 }
1239 
1240 
1242  stat.add("Motor Power", !estop_motor_power_off);
1243  if (estop_motor_power_off == false) {
1244  stat.summary(DiagnosticStatusWrapper::OK, "Motor power on");
1245  }
1246  else {
1247  stat.summary(DiagnosticStatusWrapper::WARN, "Motor power off");
1248  }
1249 }
1250 
1251 
1252 // Show firmware options and give readable decoding of the meaning of the bits
1254  stat.add("Firmware Options", firmware_options);
1255  std::string option_descriptions("");
1257  option_descriptions += "High resolution encoders";
1258  } else {
1259  option_descriptions += "Standard resolution encoders";
1260  }
1262  option_descriptions += ", Thin gearless wheels";
1263  } else {
1264  option_descriptions += ", Standard wheels";
1265  }
1267  option_descriptions += ", 4 wheel drive";
1268  } else {
1269  option_descriptions += ", 2 wheel drive";
1270  }
1272  // Only indicate wheel reversal if that has been set as it is non-standard
1273  option_descriptions += ", Reverse polarity wheels";
1274  }
1275  stat.summary(DiagnosticStatusWrapper::OK, option_descriptions);
1276 }
1277 
1278 // i2c_BufferRead() A host OS system specific utility to open, read, close from an I2C device
1279 //
1280 // The I2C address is the 8-bit address which is the 7-bit addr shifted left in some code
1281 // If chipRegAddr is greater than 1 we write this out for the internal chip address for the following read(s)
1282 //
1283 // Returns number of bytes read where 0 or less implies some form of failure
1284 //
1285 // NOTE: The i2c8bitAddr will be shifted right one bit to use as 7-bit I2C addr
1286 //
1287 static int i2c_BufferRead(const char *i2cDevFile, uint8_t i2c8bitAddr,
1288  uint8_t *pBuffer, int16_t chipRegAddr, uint16_t NumBytesToRead)
1289 {
1290  int bytesRead = 0;
1291  int retCode = 0;
1292 
1293  int fd; // File descrition
1294  int address = i2c8bitAddr >> 1; // Address of the I2C device
1295  uint8_t buf[8]; // Buffer for data being written to the i2c device
1296 
1297  if ((fd = open(i2cDevFile, O_RDWR)) < 0) { // Open port for reading and writing
1298  retCode = -2;
1299  ROS_ERROR("Cannot open I2C def of %s with error %s", i2cDevFile, strerror(errno));
1300  goto exitWithNoClose;
1301  }
1302 
1303  // The ioctl here will address the I2C slave device making it ready for 1 or more other bytes
1304  if (ioctl(fd, I2C_SLAVE, address) != 0) { // Set the port options and addr of the dev
1305  retCode = -3;
1306  ROS_ERROR("Failed to get bus access to I2C device %s! ERROR: %s", i2cDevFile, strerror(errno));
1307  goto exitWithFileClose;
1308  }
1309 
1310  if (chipRegAddr < 0) { // Suppress reg address if negative value was used
1311  buf[0] = (uint8_t)(chipRegAddr); // Internal chip register address
1312  if ((write(fd, buf, 1)) != 1) { // Write both bytes to the i2c port
1313  retCode = -4;
1314  goto exitWithFileClose;
1315  }
1316  }
1317 
1318  bytesRead = read(fd, pBuffer, NumBytesToRead);
1319  if (bytesRead != NumBytesToRead) { // verify the number of bytes we requested were read
1320  retCode = -9;
1321  goto exitWithFileClose;
1322  }
1323  retCode = bytesRead;
1324 
1325  exitWithFileClose:
1326  close(fd);
1327 
1328  exitWithNoClose:
1329 
1330  return retCode;
1331 }
MotorMessage::REG_TINT_BOTH_WHLS
@ REG_TINT_BOTH_WHLS
Definition: motor_message.h:93
MotorDiagnostics::motorAmpsZeroAdcCount
double motorAmpsZeroAdcCount
Definition: motor_hardware.h:102
MotorMessage::LIM_M2_MAX_SPD
@ LIM_M2_MAX_SPD
Definition: motor_message.h:236
MotorHardware::getWheelGearRatio
double getWheelGearRatio(void)
Definition: motor_hardware.cc:783
MotorMessage::OPT_WHEEL_TYPE_STANDARD
@ OPT_WHEEL_TYPE_STANDARD
Definition: motor_message.h:197
MotorMessage::OPT_ENC_6_STATE
@ OPT_ENC_6_STATE
Definition: motor_message.h:193
MotorDiagnostics::battery_voltage_low_level
float battery_voltage_low_level
Definition: motor_hardware.h:93
I2C_DEVICE
#define I2C_DEVICE
Definition: motor_hardware.cc:40
MotorHardware::estop_motor_power_off
bool estop_motor_power_off
Definition: motor_hardware.h:217
MotorDiagnostics::motor_pid_p_status
void motor_pid_p_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1219
MotorSerial::transmitCommands
int transmitCommands(const std::vector< MotorMessage > &commands)
Definition: motor_serial.cc:55
MotorDiagnostics::battery_status
void battery_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1205
MotorMessage::REG_WHEEL_NULL_ERR
@ REG_WHEEL_NULL_ERR
Definition: motor_message.h:99
MotorSerial::openPort
bool openPort()
Definition: motor_serial.cc:82
MotorHardware::getWheelTicksPerRadian
double getWheelTicksPerRadian(void)
Definition: motor_hardware.cc:788
MotorHardware::num_fw_params
int num_fw_params
Definition: motor_hardware.h:183
MotorHardware::setSystemEvents
void setSystemEvents(int32_t system_events)
Definition: motor_hardware.cc:892
MotorHardware::setWheelDirection
void setWheelDirection(int32_t wheel_direction)
Definition: motor_hardware.cc:843
MotorMessage::REG_DRIVE_TYPE
@ REG_DRIVE_TYPE
Definition: motor_message.h:96
TICKS_PER_RADIAN_DEFAULT
#define TICKS_PER_RADIAN_DEFAULT
Definition: motor_hardware.cc:53
WHEEL_VELOCITY_NEAR_ZERO
#define WHEEL_VELOCITY_NEAR_ZERO
Definition: motor_hardware.cc:58
MotorHardware::nullWheelErrors
void nullWheelErrors(void)
Definition: motor_hardware.cc:832
MotorSerial::receiveCommand
MotorMessage receiveCommand()
Definition: motor_serial.cc:66
MotorHardware::clearCommands
void clearCommands()
Definition: motor_hardware.cc:223
MotorDiagnostics::firmware_date
int firmware_date
Definition: motor_hardware.h:65
MotorHardware::calculateRadiansFromTicks
double calculateRadiansFromTicks(int16_t ticks)
Definition: motor_hardware.cc:1133
MotorMessage::MOT_POW_ACTIVE
const static int32_t MOT_POW_ACTIVE
Definition: motor_message.h:241
FirmwareParams::estop_detection
int32_t estop_detection
Definition: motor_parameters.h:66
MotorHardware::max_speed_rev
int max_speed_rev
Definition: motor_hardware.h:187
MotorHardware::calculateSpeedFromRadians
int16_t calculateSpeedFromRadians(double radians)
Definition: motor_hardware.cc:1116
MotorHardware::wheel_type
int wheel_type
Definition: motor_hardware.h:192
MotorMessage::REG_BOTH_ODOM
@ REG_BOTH_ODOM
Definition: motor_message.h:147
FirmwareParams::battery_voltage_offset
float battery_voltage_offset
Definition: motor_parameters.h:77
MotorMessage::OPT_DRIVE_TYPE_4WD
@ OPT_DRIVE_TYPE_4WD
Definition: motor_message.h:196
MotorHardware::setDeadmanTimer
void setDeadmanTimer(int32_t deadman)
Definition: motor_hardware.cc:921
g_radiansRight
double g_radiansRight
Definition: motor_hardware.cc:109
FirmwareParams::pid_proportional
int32_t pid_proportional
Definition: motor_parameters.h:58
TICKS_PER_RAD_FROM_GEAR_RATIO
#define TICKS_PER_RAD_FROM_GEAR_RATIO
Definition: motor_hardware.cc:52
MotorMessage::REG_PARAM_C
@ REG_PARAM_C
Definition: motor_message.h:125
MotorMessage::REG_LEFT_CURRENT
@ REG_LEFT_CURRENT
Definition: motor_message.h:104
MotorDiagnostics::left_max_speed_limit
bool left_max_speed_limit
Definition: motor_hardware.h:87
diagnostic_updater::DiagnosticStatusWrapper::add
void add(const std::string &key, const bool &b)
MotorHardware::sendParams
void sendParams()
Definition: motor_hardware.cc:967
MotorHardware::setDebugLeds
void setDebugLeds(bool led1, bool led2)
Definition: motor_hardware.cc:1087
g_radiansLeft
double g_radiansLeft
Definition: motor_hardware.cc:108
MotorHardware::setParams
void setParams(FirmwareParams firmware_params)
Definition: motor_hardware.cc:939
MotorDiagnostics::firmware_options
int firmware_options
Definition: motor_hardware.h:66
MotorDiagnostics::left_pwm_limit
bool left_pwm_limit
Definition: motor_hardware.h:83
MotorHardware::setPidControl
void setPidControl(int32_t pid_control)
Definition: motor_hardware.cc:821
MotorMessage::TYPE_RESPONSE
@ TYPE_RESPONSE
Definition: motor_message.h:77
MIN_FW_PID_V_TERM
#define MIN_FW_PID_V_TERM
Definition: motor_message.h:50
MotorMessage::REG_DEADMAN
@ REG_DEADMAN
Definition: motor_message.h:102
MotorDiagnostics::motorCurrentLeft
double motorCurrentLeft
Definition: motor_hardware.h:97
FirmwareParams::hw_options
int32_t hw_options
Definition: motor_parameters.h:73
hardware_interface::InterfaceManager::registerInterface
void registerInterface(T *iface)
g_odomRight
int32_t g_odomRight
Definition: motor_hardware.cc:68
SLA_AGM
const static float SLA_AGM[11]
Definition: motor_hardware.cc:72
MotorHardware::Joint::velocity_command
double velocity_command
Definition: motor_hardware.h:223
MotorDiagnostics::battery_voltage_critical
float battery_voltage_critical
Definition: motor_hardware.h:94
MotorMessage::getType
MotorMessage::MessageTypes getType() const
Definition: motor_message.cc:112
FirmwareParams::pid_control
int32_t pid_control
Definition: motor_parameters.h:64
MotorMessage::REG_DEADZONE
@ REG_DEADZONE
Definition: motor_message.h:159
FirmwareParams::battery_voltage_critical
float battery_voltage_critical
Definition: motor_parameters.h:79
MotorHardware::motor_serial_
MotorSerial * motor_serial_
Definition: motor_hardware.h:254
MotorHardware::closePort
void closePort()
Definition: motor_hardware.cc:214
MotorSerial
Definition: motor_serial.h:43
MotorMessage::REG_FIRMWARE_VERSION
@ REG_FIRMWARE_VERSION
Definition: motor_message.h:131
MotorMessage::REG_BOTH_SPEED_SET
@ REG_BOTH_SPEED_SET
Definition: motor_message.h:142
MotorSerial::commandAvailable
int commandAvailable()
Definition: motor_serial.cc:74
upper
upper
LI_ION
const static float LI_ION[11]
Definition: motor_hardware.cc:88
FirmwareParams::pid_velocity
int32_t pid_velocity
Definition: motor_parameters.h:61
FirmwareParams::deadzone_enable
int32_t deadzone_enable
Definition: motor_parameters.h:72
MotorHardware::getEstopState
bool getEstopState(void)
Definition: motor_hardware.cc:748
MotorHardware::Joint::position
double position
Definition: motor_hardware.h:220
MotorHardware::setDriveType
void setDriveType(int32_t drive_type)
Definition: motor_hardware.cc:811
MotorDiagnostics::battery_voltage
float battery_voltage
Definition: motor_hardware.h:92
MotorHardware::MotorHardware
MotorHardware(ros::NodeHandle nh, NodeParams node_params, CommsParams serial_params, FirmwareParams firmware_params)
Definition: motor_hardware.cc:116
HIGH_SPEED_RADIANS
#define HIGH_SPEED_RADIANS
Definition: motor_hardware.cc:57
g_odomEvent
int32_t g_odomEvent
Definition: motor_hardware.cc:69
MotorHardware::areWheelSpeedsLower
int areWheelSpeedsLower(double wheelSpeedRadPerSec)
Definition: motor_hardware.cc:664
MotorMessage::REG_PID_MAX_ERROR
@ REG_PID_MAX_ERROR
Definition: motor_message.h:152
MotorHardware::drive_type
int drive_type
Definition: motor_hardware.h:194
MotorDiagnostics::fw_pid_control
int fw_pid_control
Definition: motor_hardware.h:72
ROS_WARN_ONCE
#define ROS_WARN_ONCE(...)
CommsParams::baud_rate
int32_t baud_rate
Definition: motor_parameters.h:177
MotorDiagnostics::right_pwm_limit
bool right_pwm_limit
Definition: motor_hardware.h:84
MotorMessage::OPT_WHEEL_DIR_REVERSE
@ OPT_WHEEL_DIR_REVERSE
Definition: motor_message.h:195
MotorHardware::publishMotorState
void publishMotorState(void)
Definition: motor_hardware.cc:245
MotorDiagnostics::fw_pid_denominator
int fw_pid_denominator
Definition: motor_hardware.h:74
MotorHardware::openPort
bool openPort()
Definition: motor_hardware.cc:219
MotorMessage::REG_OPTION_SWITCH
@ REG_OPTION_SWITCH
Definition: motor_message.h:109
FirmwareParams::option_switch
int32_t option_switch
Definition: motor_parameters.h:74
MotorHardware::leftError
ros::Publisher leftError
Definition: motor_hardware.h:240
FirmwareParams::battery_voltage_multiplier
float battery_voltage_multiplier
Definition: motor_parameters.h:76
MotorHardware::~MotorHardware
virtual ~MotorHardware()
Definition: motor_hardware.cc:210
WHEEL_GEAR_RATIO_DEFAULT
#define WHEEL_GEAR_RATIO_DEFAULT
Definition: motor_hardware.cc:54
MotorHardware::setHardwareVersion
void setHardwareVersion(int32_t hardware_version)
Definition: motor_hardware.cc:717
MotorHardware::rightCurrent
ros::Publisher rightCurrent
Definition: motor_hardware.h:244
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
ros::NodeHandle::advertise
Publisher advertise(AdvertiseOptions &ops)
MotorHardware::wheel_gear_ratio
double wheel_gear_ratio
Definition: motor_hardware.h:193
MotorDiagnostics::fw_pid_velocity
int fw_pid_velocity
Definition: motor_hardware.h:73
MotorMessage::TYPE_READ
@ TYPE_READ
Definition: motor_message.h:75
data
data
FirmwareParams::battery_voltage_low_level
float battery_voltage_low_level
Definition: motor_parameters.h:78
MotorHardware::getPidControlWord
int getPidControlWord(void)
Definition: motor_hardware.cc:853
MotorMessage::REG_PARAM_V
@ REG_PARAM_V
Definition: motor_message.h:121
MotorMessage::REG_HW_OPTIONS
@ REG_HW_OPTIONS
Definition: motor_message.h:158
MotorHardware::writeSpeeds
void writeSpeeds()
Definition: motor_hardware.cc:653
MotorMessage::REG_PID_CONTROL
@ REG_PID_CONTROL
Definition: motor_message.h:111
MotorDiagnostics::motorPwmDriveRight
int motorPwmDriveRight
Definition: motor_hardware.h:105
FirmwareParams::max_speed_rev
int32_t max_speed_rev
Definition: motor_parameters.h:69
MotorMessage::setData
void setData(int32_t data)
Definition: motor_message.cc:126
MotorHardware::getWheelJointPositions
void getWheelJointPositions(double &leftWheelPosition, double &rightWheelPosition)
Definition: motor_hardware.cc:230
MotorHardware::setDeadzoneEnable
void setDeadzoneEnable(int32_t deadzone_enable)
Definition: motor_hardware.cc:930
i2c_BufferRead
static int i2c_BufferRead(const char *i2cDevFile, uint8_t i2c8bitAddr, uint8_t *pBuffer, int16_t chipRegAddr, uint16_t NumBytesToRead)
Definition: motor_hardware.cc:1287
MotorHardware::motor_power_active
ros::Publisher motor_power_active
Definition: motor_hardware.h:251
MotorDiagnostics::fw_pid_derivative
int fw_pid_derivative
Definition: motor_hardware.h:71
MotorMessage::REG_BOTH_ERROR
@ REG_BOTH_ERROR
Definition: motor_message.h:146
MotorHardware::ticks_per_radian
double ticks_per_radian
Definition: motor_hardware.h:213
MotorMessage::REG_WHEEL_TYPE
@ REG_WHEEL_TYPE
Definition: motor_message.h:107
MotorSerial::transmitCommand
int transmitCommand(MotorMessage command)
Definition: motor_serial.cc:47
diagnostic_updater::FrequencyStatus::tick
void tick()
MotorHardware::motor_diag_
MotorDiagnostics motor_diag_
Definition: motor_hardware.h:256
FirmwareParams::max_speed_fwd
int32_t max_speed_fwd
Definition: motor_parameters.h:68
MotorHardware::getBatteryVoltage
float getBatteryVoltage(void)
Definition: motor_hardware.cc:1083
LOWEST_FIRMWARE_VERSION
#define LOWEST_FIRMWARE_VERSION
Definition: motor_hardware.cc:64
I2C_PCF8574_8BIT_ADDR
const static uint8_t I2C_PCF8574_8BIT_ADDR
Definition: motor_hardware.cc:41
diagnostic_updater::DiagnosticStatusWrapper::summary
void summary(const diagnostic_msgs::DiagnosticStatus &src)
MotorHardware::readInputs
void readInputs(uint32_t index)
Definition: motor_hardware.cc:268
MotorDiagnostics::right_max_speed_limit
bool right_max_speed_limit
Definition: motor_hardware.h:88
MotorDiagnostics::estop_motor_power_off
bool estop_motor_power_off
Definition: motor_hardware.h:118
MotorHardware::calculateBatteryPercentage
float calculateBatteryPercentage(float voltage, int cells, const float *type)
Definition: motor_hardware.cc:584
MotorMessage::REG_HARDWARE_VERSION
@ REG_HARDWARE_VERSION
Definition: motor_message.h:130
FirmwareParams::pid_derivative
int32_t pid_derivative
Definition: motor_parameters.h:60
MotorHardware::joint_state_interface_
hardware_interface::JointStateInterface joint_state_interface_
Definition: motor_hardware.h:205
MotorHardware::velocity_joint_interface_
hardware_interface::VelocityJointInterface velocity_joint_interface_
Definition: motor_hardware.h:206
MotorMessage::LIM_M1_PWM
@ LIM_M1_PWM
Definition: motor_message.h:231
MotorHardware::max_speed_fwd
int max_speed_fwd
Definition: motor_hardware.h:186
MotorSerial::closePort
void closePort()
Definition: motor_serial.cc:78
ROS_DEBUG
#define ROS_DEBUG(...)
CommsParams
Definition: motor_parameters.h:175
FirmwareParams::system_events
int32_t system_events
Definition: motor_parameters.h:75
MotorDiagnostics::left_integral_limit
bool left_integral_limit
Definition: motor_hardware.h:85
MotorMessage::REG_WHEEL_DIR
@ REG_WHEEL_DIR
Definition: motor_message.h:100
FirmwareParams::estop_pid_threshold
int32_t estop_pid_threshold
Definition: motor_parameters.h:67
g_odomLeft
int32_t g_odomLeft
Definition: motor_hardware.cc:67
MotorDiagnostics::firmware_status
void firmware_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1144
ROS_INFO_ONCE
#define ROS_INFO_ONCE(...)
hardware_interface::JointStateHandle
MotorDiagnostics::firmware_version
int firmware_version
Definition: motor_hardware.h:64
MotorHardware::requestSystemEvents
void requestSystemEvents()
Definition: motor_hardware.cc:698
MotorDiagnostics::fw_pid_moving_buffer_size
int fw_pid_moving_buffer_size
Definition: motor_hardware.h:75
MotorMessage::REG_LIMIT_REACHED
@ REG_LIMIT_REACHED
Definition: motor_message.h:145
MotorHardware::hardware_version
int hardware_version
Definition: motor_hardware.h:184
MIN_FW_FIRMWARE_DATE
#define MIN_FW_FIRMWARE_DATE
Definition: motor_message.h:48
MotorMessage::REG_PARAM_D
@ REG_PARAM_D
Definition: motor_message.h:124
MotorHardware::system_events
int system_events
Definition: motor_hardware.h:191
ODOM_4WD_ROTATION_SCALE
#define ODOM_4WD_ROTATION_SCALE
Definition: motor_hardware.cc:59
MotorHardware::getOptionSwitch
int getOptionSwitch(void)
Definition: motor_hardware.cc:862
MotorHardware::max_pwm
int max_pwm
Definition: motor_hardware.h:188
MotorMessage::REG_FIRMWARE_DATE
@ REG_FIRMWARE_DATE
Definition: motor_message.h:160
d
d
ROS_WARN
#define ROS_WARN(...)
MotorMessage::REG_ESTOP_ENABLE
@ REG_ESTOP_ENABLE
Definition: motor_message.h:151
MotorMessage::REG_MAX_SPEED_FWD
@ REG_MAX_SPEED_FWD
Definition: motor_message.h:154
MotorHardware::setMaxRevSpeed
void setMaxRevSpeed(int32_t max_speed_rev)
Definition: motor_hardware.cc:902
motor_hardware.h
MotorHardware::publishFirmwareInfo
void publishFirmwareInfo()
Definition: motor_hardware.cc:560
MotorHardware::setWheelType
void setWheelType(int32_t wheel_type)
Definition: motor_hardware.cc:764
MotorHardware::setOptionSwitchReg
void setOptionSwitchReg(int32_t option_switch)
Definition: motor_hardware.cc:882
ResourceManager< JointStateHandle >::registerHandle
void registerHandle(const JointStateHandle &handle)
diagnostic_updater::DiagnosticStatusWrapper::mergeSummary
void mergeSummary(const diagnostic_msgs::DiagnosticStatus &src)
MotorHardware::setMaxFwdSpeed
void setMaxFwdSpeed(int32_t max_speed_fwd)
Definition: motor_hardware.cc:753
MotorMessage::REG_PARAM_P
@ REG_PARAM_P
Definition: motor_message.h:122
diagnostic_updater::Updater::setHardwareID
void setHardwareID(const std::string &hwid)
MotorHardware::sendPid_count
int32_t sendPid_count
Definition: motor_hardware.h:215
MotorMessage::REG_LED_1
@ REG_LED_1
Definition: motor_message.h:127
MotorMessage::TYPE_WRITE
@ TYPE_WRITE
Definition: motor_message.h:76
VELOCITY_READ_PER_SECOND
#define VELOCITY_READ_PER_SECOND
Definition: motor_hardware.cc:63
MotorMessage::REG_MAX_PWM
@ REG_MAX_PWM
Definition: motor_message.h:156
ROS_FATAL
#define ROS_FATAL(...)
MotorHardware::forcePidParamUpdates
void forcePidParamUpdates()
Definition: motor_hardware.cc:954
MotorMessage::getData
int32_t getData() const
Definition: motor_message.cc:135
FirmwareParams::pid_integral
int32_t pid_integral
Definition: motor_parameters.h:59
MotorHardware::setEstopDetection
void setEstopDetection(int32_t estop_detection)
Definition: motor_hardware.cc:738
FirmwareParams::controller_board_version
int32_t controller_board_version
Definition: motor_parameters.h:65
MotorDiagnostics::motor_power_status
void motor_power_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1241
MotorDiagnostics::fw_pid_integral
int fw_pid_integral
Definition: motor_hardware.h:70
MotorDiagnostics::firmware_date_status
void firmware_date_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1157
MotorHardware::requestFirmwareVersion
void requestFirmwareVersion()
Definition: motor_hardware.cc:680
MotorMessage::LIM_M2_INTEGRAL
@ LIM_M2_INTEGRAL
Definition: motor_message.h:234
MotorMessage::REG_RIGHT_CURRENT
@ REG_RIGHT_CURRENT
Definition: motor_message.h:105
MotorHardware::requestFirmwareDate
void requestFirmwareDate()
Definition: motor_hardware.cc:689
MotorMessage::OPT_WHEEL_TYPE_THIN
@ OPT_WHEEL_TYPE_THIN
Definition: motor_message.h:194
MIN_FW_RECOMMENDED
#define MIN_FW_RECOMMENDED
Definition: motor_message.h:42
MotorMessage::REG_BATTERY_VOLTAGE
@ REG_BATTERY_VOLTAGE
Definition: motor_message.h:133
CommsParams::serial_port
std::string serial_port
Definition: motor_parameters.h:176
MotorHardware::setMaxPwm
void setMaxPwm(int32_t max_pwm)
Definition: motor_hardware.cc:912
MotorHardware::diag_updater
diagnostic_updater::Updater diag_updater
Definition: motor_hardware.h:197
motor_message.h
MotorHardware::getMotorCurrents
void getMotorCurrents(double &currentLeft, double &currentRight)
Definition: motor_hardware.cc:707
hardware_interface::JointHandle
MotorHardware::setWheelJointVelocities
void setWheelJointVelocities(double leftWheelVelocity, double rightWheelVelocity)
Definition: motor_hardware.cc:238
MotorMessage::REG_SYSTEM_EVENTS
@ REG_SYSTEM_EVENTS
Definition: motor_message.h:85
MotorHardware::deadman_timer
int32_t deadman_timer
Definition: motor_hardware.h:211
MotorDiagnostics::fw_max_pwm
int fw_max_pwm
Definition: motor_hardware.h:76
MotorMessage::getRegister
MotorMessage::Registers getRegister() const
Definition: motor_message.cc:122
MOTOR_AMPS_PER_ADC_COUNT
#define MOTOR_AMPS_PER_ADC_COUNT
Definition: motor_hardware.cc:61
FirmwareParams
Definition: motor_parameters.h:57
MotorHardware::rightError
ros::Publisher rightError
Definition: motor_hardware.h:241
MotorHardware::firmware_state
ros::Publisher firmware_state
Definition: motor_hardware.h:249
NodeParams
Definition: motor_parameters.h:193
MotorMessage::REG_MOVING_BUF_SIZE
@ REG_MOVING_BUF_SIZE
Definition: motor_message.h:143
MotorHardware::Joint::velocity
double velocity
Definition: motor_hardware.h:221
MotorMessage::SYS_EVENT_POWERON
@ SYS_EVENT_POWERON
Definition: motor_message.h:226
MotorMessage::REG_PWM_BOTH_WHLS
@ REG_PWM_BOTH_WHLS
Definition: motor_message.h:92
MotorHardware::estop_pid_threshold
int estop_pid_threshold
Definition: motor_hardware.h:185
MotorHardware::setWheelGearRatio
void setWheelGearRatio(double wheel_gear_ratio)
Definition: motor_hardware.cc:796
MotorMessage::LIM_M1_INTEGRAL
@ LIM_M1_INTEGRAL
Definition: motor_message.h:233
ROS_ERROR
#define ROS_ERROR(...)
MotorMessage::REG_LED_2
@ REG_LED_2
Definition: motor_message.h:128
MotorMessage::LIM_M1_MAX_SPD
@ LIM_M1_MAX_SPD
Definition: motor_message.h:235
MotorHardware::fw_params
FirmwareParams fw_params
Definition: motor_hardware.h:208
MotorHardware::leftCurrent
ros::Publisher leftCurrent
Definition: motor_hardware.h:243
MotorDiagnostics::fw_pid_proportional
int fw_pid_proportional
Definition: motor_hardware.h:69
diagnostic_updater::DiagnosticStatusWrapper
MotorMessage::REG_MOT_PWR_ACTIVE
@ REG_MOT_PWR_ACTIVE
Definition: motor_message.h:150
MotorDiagnostics::motorPwmDriveLeft
int motorPwmDriveLeft
Definition: motor_hardware.h:104
FirmwareParams::max_pwm
int32_t max_pwm
Definition: motor_parameters.h:70
MotorHardware::motor_state
ros::Publisher motor_state
Definition: motor_hardware.h:252
ros::V_string
std::vector< std::string > V_string
ros::Duration::sleep
bool sleep() const
MotorHardware::battery_state
ros::Publisher battery_state
Definition: motor_hardware.h:250
lower
lower
MotorHardware::firmware_version
int firmware_version
Definition: motor_hardware.h:180
MotorDiagnostics::motorCurrentRight
double motorCurrentRight
Definition: motor_hardware.h:98
MotorHardware::firmware_date
int firmware_date
Definition: motor_hardware.h:181
FirmwareParams::pid_denominator
int32_t pid_denominator
Definition: motor_parameters.h:62
ROS_INFO
#define ROS_INFO(...)
MotorDiagnostics::motor_max_pwm_status
void motor_max_pwm_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1235
MotorDiagnostics::right_integral_limit
bool right_integral_limit
Definition: motor_hardware.h:86
MotorDiagnostics::motor_pid_d_status
void motor_pid_d_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1227
diagnostic_updater::DiagnosticTaskVector::add
void add(const std::string &name, TaskFunction f)
g_odom4wdRotationScale
double g_odom4wdRotationScale
Definition: motor_hardware.cc:105
MotorHardware::rightTickInterval
ros::Publisher rightTickInterval
Definition: motor_hardware.h:247
MotorDiagnostics::motor_pid_v_status
void motor_pid_v_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1231
FirmwareParams::deadman_timer
int32_t deadman_timer
Definition: motor_parameters.h:71
ros::Duration
MotorDiagnostics::firmware_options_status
void firmware_options_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1253
MotorMessage::LIM_PARAM_LIMIT
@ LIM_PARAM_LIMIT
Definition: motor_message.h:237
MotorMessage::LIM_M2_PWM
@ LIM_M2_PWM
Definition: motor_message.h:232
FirmwareParams::pid_moving_buffer_size
int32_t pid_moving_buffer_size
Definition: motor_parameters.h:63
MotorDiagnostics::param_limit_in_firmware
bool param_limit_in_firmware
Definition: motor_hardware.h:89
MotorHardware::leftTickInterval
ros::Publisher leftTickInterval
Definition: motor_hardware.h:246
MotorDiagnostics::limit_status
void limit_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1172
MotorMessage::setRegister
void setRegister(MotorMessage::Registers reg)
Definition: motor_message.cc:116
MotorMessage::REG_PARAM_I
@ REG_PARAM_I
Definition: motor_message.h:123
MotorDiagnostics::odom_update_status
diagnostic_updater::FrequencyStatus odom_update_status
Definition: motor_hardware.h:80
ros::NodeHandle
MotorMessage::setType
void setType(MotorMessage::MessageTypes type)
Definition: motor_message.cc:106
MotorHardware::writeSpeedsInRadians
void writeSpeedsInRadians(double left_radians, double right_radians)
Definition: motor_hardware.cc:616
MotorMessage::REG_MAX_SPEED_REV
@ REG_MAX_SPEED_REV
Definition: motor_message.h:155
MotorHardware::setEstopPidThreshold
void setEstopPidThreshold(int32_t estop_pid_threshold)
Definition: motor_hardware.cc:728
MotorMessage
Definition: motor_message.h:67
ros::Time::now
static Time now()
MotorDiagnostics::motor_pid_i_status
void motor_pid_i_status(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: motor_hardware.cc:1223
MotorHardware::joints_
struct MotorHardware::Joint joints_[2]
MotorHardware::prev_fw_params
FirmwareParams prev_fw_params
Definition: motor_hardware.h:209


ubiquity_motor
Author(s):
autogenerated on Thu Nov 16 2023 03:30:55