openrover_driver.cpp
Go to the documentation of this file.
1 #include "ros/ros.h"
2 
3 #include <fcntl.h>
4 #include <termios.h>
5 #include <ctime>
6 #include <vector>
7 #include <string>
8 #include <cmath>
9 #include <fstream>
10 #include <iostream>
11 #include <sys/ioctl.h>
12 
13 #include <sensor_msgs/Joy.h>
16 #include "std_msgs/Int32.h"
17 #include "std_msgs/Int32MultiArray.h"
18 #include "std_msgs/Float32MultiArray.h"
19 #include "std_msgs/Float32.h"
20 #include "geometry_msgs/Twist.h"
21 #include <std_msgs/Bool.h>
22 #include "nav_msgs/Odometry.h"
23 #include "rr_openrover_driver_msgs/RawRrOpenroverDriverFastRateData.h"
24 #include "rr_openrover_driver_msgs/RawRrOpenroverDriverMedRateData.h"
25 #include "rr_openrover_driver_msgs/RawRrOpenroverDriverSlowRateData.h"
26 #include "rr_openrover_driver_msgs/SmartBatteryStatus.h"
27 
29 
30 namespace openrover
31 {
33  : nh_(nh)
34  , nh_priv_(nh_priv)
35  , port_("/dev/ttyUSB0")
36  , serial_baud_rate_(57600)
37  , use_legacy_(false)
38  , fast_rate_hz_(10.0) // can increase to 60Hz for TX2
39  , medium_rate_hz_(2.0)
40  , slow_rate_hz_(1.0)
41  , motor_speeds_commanded_{ MOTOR_NEUTRAL, MOTOR_NEUTRAL, MOTOR_NEUTRAL } // default motor commands to neutral
42  , timeout_(0.2) // in seconds
46  , is_serial_coms_open_(false)
48  , pidGains_(40, 100, 0)
55  , e_stop_on_(false)
59  , l_pid_csv_file_("")
60  , r_pid_csv_file_("")
61 {
62  ROS_INFO("Initializing rover driver.");
63 }
64 
66 {
67  if (!setupRobotParams())
68  {
69  ROS_WARN("Failed to setup Robot parameters.");
70  return false;
71  }
72 
73  if (l_fs_.is_open()) {
75  }
76 
77  if (r_fs_.is_open()) {
79  }
80 
83 
84  serial_fast_buffer_.reserve(5 * FAST_SIZE); // reserve space for 5 sets of FAST rate data
85  serial_medium_buffer_.reserve(5 * MEDIUM_SIZE); // reserve space for 5 sets of Medium rate data
86  serial_slow_buffer_.reserve(5 * SLOW_SIZE); // reserve space for 5 sets of Slow rate data
87  serial_fan_buffer_.reserve(5); // reserve space for 5 sets of Fan commands
88 
89  ROS_INFO("Creating Publishers and Subscribers");
90  // WallTimers simplify the timing of updating parameters by reloading serial buffers at specified rates.
91  // without them the serial buffers will never be loaded with new commands
96 
97  if (!(nh_priv_.getParam("use_legacy", use_legacy_)))
98  {
99  ROS_WARN("Failed to retrieve use_legacy from parameter.Defaulting to %s", use_legacy_ ? "true" : "false");
100  }
101 
102  if(use_legacy_) {
103  fast_rate_pub = nh_priv_.advertise<rr_openrover_driver_msgs::RawRrOpenroverDriverFastRateData>("raw_fast_rate_data",
104  1);
105  medium_rate_pub = nh_priv_.advertise<rr_openrover_driver_msgs::RawRrOpenroverDriverMedRateData>("raw_med_rate_data",
106  1);
107  slow_rate_pub = nh_priv_.advertise<rr_openrover_driver_msgs::RawRrOpenroverDriverSlowRateData>("raw_slow_rate_data",
108  1);
109  }
110  battery_status_a_pub = nh_priv_.advertise<rr_openrover_driver_msgs::SmartBatteryStatus>("battery_status_a", 1);
111  battery_status_b_pub = nh_priv_.advertise<rr_openrover_driver_msgs::SmartBatteryStatus>("battery_status_b", 1);
112  battery_state_of_charge_pub = nh_priv_.advertise<std_msgs::Int32>("battery_state_of_charge", 1);
113  odom_enc_pub = nh_priv_.advertise<nav_msgs::Odometry>("odom_encoder", 1);
114  is_charging_pub = nh_priv_.advertise<std_msgs::Bool>("charging", 1);
115 
116  motor_speeds_pub = nh_priv_.advertise<std_msgs::Int32MultiArray>("motor_speeds_commanded", 1);
117  vel_calc_pub = nh_priv_.advertise<std_msgs::Float32MultiArray>("wheel_velocities", 1);
118 
119  trim_sub = nh_priv_.subscribe("/trim_increment", 1, &OpenRover::trimCB, this);
120  cmd_vel_sub = nh_priv_.subscribe("/cmd_vel/managed", 1, &OpenRover::cmdVelCB, this);
121  fan_speed_sub = nh_priv_.subscribe("/rr_openrover_driver/fan_speed", 1, &OpenRover::fanSpeedCB, this);
122  e_stop_sub = nh_priv_.subscribe("/soft_estop/enable", 1, &OpenRover::eStopCB, this);
123  e_stop_reset_sub = nh_priv_.subscribe("/soft_estop/reset", 1, &OpenRover::eStopResetCB, this);
124  trim = 0;
125  return true;
126 }
127 
129 { // Get ROS params and save them to class variables
130 
131  if (!(nh_priv_.getParam("port", port_)))
132  {
133  ROS_WARN("Failed to retrieve port from parameter server.Defaulting to %s", port_.c_str());
134  }
135 
136  if (!(openComs()))
137  {
138  is_serial_coms_open_ = false;
139  ROS_ERROR("Failed to start serial communication.");
140  return false;
141  }
142 
143  if (!(nh_priv_.getParam("fast_data_rate", fast_rate_hz_)))
144  {
145  ROS_WARN("Failed to retrieve fast_data_rate from parameter. Defaulting to 10");
146  }
147 
148  if (!(nh_priv_.getParam("medium_data_rate", medium_rate_hz_)))
149  {
150  ROS_WARN("Failed to retrieve medium_data_rate from parameter. Defaulting to 2");
151  }
152 
153  if (!(nh_priv_.getParam("slow_data_rate", slow_rate_hz_)))
154  {
155  ROS_WARN("Failed to retrieve slow_data_rate from parameter. Defaulting to 1");
156  }
157 
158 
159  if (!(nh_priv_.getParam("closed_loop_control_on", closed_loop_control_on_)))
160  {
161  ROS_WARN("Failed to retrieve closed_loop_control_on from parameter server. Defaulting to off.");
162  }
163 
164  if (!(nh_priv_.getParam("timeout", timeout_)))
165  {
166  ROS_WARN("Failed to retrieve timeout from parameter server. Defaulting to %f s", timeout_);
167  }
168 
169  if (!(nh_priv_.getParam("total_weight", total_weight_)))
170  {
171  ROS_WARN("Failed to retrieve total_weight from parameter server. Defaulting to %f lbs", total_weight_);
172  }
173 
174  if (!(nh_priv_.getParam("drive_type", drive_type_)))
175  {
176  ROS_WARN("Failed to retrieve drive_type from parameter.Defaulting to %s", drive_type_.c_str());
177  }
178 
179  if (!(nh_priv_.getParam("Kp", pidGains_.Kp)))
180  {
181  ROS_WARN("Failed to retrieve Kp from parameter.Defaulting to %f", pidGains_.Kp);
182  }
183  else{
184  ROS_INFO("Kp: %f", pidGains_.Kp);
185  }
186 
187  if (!(nh_priv_.getParam("Ki", pidGains_.Ki)))
188  {
189  ROS_WARN("Failed to retrieve Ki from parameter.Defaulting to %f", pidGains_.Ki);
190  }
191  else{
192  ROS_INFO("Ki: %f", pidGains_.Ki);
193  }
194 
195  if (!(nh_priv_.getParam("Kd", pidGains_.Kd)))
196  {
197  ROS_WARN("Failed to retrieve Kd from parameter.Defaulting to %f", pidGains_.Kd);
198  }
199  else{
200  ROS_INFO("Kd: %f", pidGains_.Kd);
201  }
202 
203  if (!(nh_priv_.getParam("left_motor_pid_csv", l_pid_csv_file_)))
204  {
205  ROS_INFO("Not logging left motor PID");
206  }
207  else{
208  ROS_INFO("Recording left motor PID data to %s", l_pid_csv_file_.c_str());
209  }
210 
211  if (!(nh_priv_.getParam("right_motor_pid_csv", r_pid_csv_file_)))
212  {
213  ROS_INFO("Not logging right motor PID");
214  }
215  else{
216  ROS_INFO("Recording right motor PID data to %s", r_pid_csv_file_.c_str());
217  }
218 
219  if (!l_pid_csv_file_.empty()){
220  l_fs_.open(l_pid_csv_file_, std::ofstream::out);
221  if(!l_fs_.is_open()){
222  ROS_WARN("Could not open file: %s", l_pid_csv_file_.c_str());
223  }
224  }
225 
226  if (!r_pid_csv_file_.empty()){
227  r_fs_.open(r_pid_csv_file_, std::ofstream::out);
228  if(!r_fs_.is_open()){
229  ROS_WARN("Could not open file: %s", r_pid_csv_file_.c_str());
230  }
231  }
232 
233  if (drive_type_ == (std::string) "2wd")
234  {
235  ROS_INFO("2wd parameters loaded.");
240 
243 
246  }
247  else if (drive_type_ == (std::string) "4wd")
248  {
249  ROS_INFO("4wd parameters loaded.");
254 
257 
260  }
261  else if (drive_type_ == (std::string) "flippers")
262  {
263  ROS_INFO("flipper parameters loaded.");
268 
271 
274  }
275  else
276  {
277  ROS_WARN("Unclear ROS param drive_type. Defaulting to flippers params.");
282 
285 
288  }
289 
290  if (!(nh_priv_.getParam("traction_factor", odom_traction_factor_)))
291  {
292  ROS_WARN("Failed to retrieve traction_factor from parameter. Defaulting to %f", odom_traction_factor_);
293  odom_traction_factor_ = 0.61;
294  }
295 
296  if (!(nh_priv_.getParam("odom_covariance_0", odom_covariance_0_)))
297  {
298  ROS_WARN("Failed to retrieve odom_covariance_0 from parameter. Defaulting to 0.01");
299  odom_covariance_0_ = 0.01;
300  }
301 
302  if (!(nh_priv_.getParam("odom_covariance_35", odom_covariance_35_)))
303  {
304  ROS_WARN("Failed to retrieve odom_covariance_35 from parameter. Defaulting to 0.03");
305  odom_covariance_35_ = 0.03;
306  }
307 
308  ROS_INFO("Openrover parameters loaded:");
309  ROS_INFO("port: %s", port_.c_str());
310  ROS_INFO("drive_type: %s", drive_type_.c_str());
311  ROS_INFO("timeout: %f s", timeout_);
312  ROS_INFO("closed_loop_control_on: %i", closed_loop_control_on_);
313  ROS_INFO("total_weight: %f kg", total_weight_);
314  ROS_INFO("traction_factor: %f", odom_traction_factor_);
315  ROS_INFO("odom_covariance_0: %f", odom_covariance_0_);
316  ROS_INFO("odom_covariance_35: %f", odom_covariance_35_);
317  ROS_INFO("fast_data_rate: %f hz", fast_rate_hz_);
318  ROS_INFO("medium_data_rate: %f hz", medium_rate_hz_);
319  ROS_INFO("slow_data_rate: %f hz", slow_rate_hz_);
320 
321  return true;
322 }
323 
325 {
327  {
328  for (int i = 0; i < SLOW_SIZE; i++)
329  {
331  }
333  }
334  return;
335 }
336 
338 {
340  {
341  for (int i = 0; i < MEDIUM_SIZE; i++)
342  {
344  }
346  }
347  return;
348 }
349 
351 {
353  {
354  for (int i = 0; i < FAST_SIZE; i++)
355  {
356  // Fill buffer with all the param2's defined as fast data
357  // by the ROBOT_DATA_INDEX_FAST array
359  }
361  }
362  else
363  {
364  ROS_WARN_DELAYED_THROTTLE(5, "Fast data rate too high. Consider reducing fast_data_rate param");
365  }
366  return;
367 }
368 
370 { // Timer goes off when a command isn't received soon enough. Sets motors to neutral values
374  left_vel_commanded_ = 0.0;
375  right_vel_commanded_ = 0.0;
376 
377  return;
378 }
379 
380 void OpenRover::fanSpeedCB(const std_msgs::Int32::ConstPtr& msg)
381 {
382  if (is_serial_coms_open_ && (serial_fan_buffer_.size() == 0))
383  {
384  serial_fan_buffer_.push_back(msg->data);
385  }
386  // ROS_DEBUG("Fan Buffer size is %i, new data is %i", serial_fan_buffer_.size(), msg->data);
387  return;
388 }
389 
390 void OpenRover::trimCB(const std_msgs::Float32::ConstPtr& msg){
391 //Get trim_increment value
392  trim+= msg->data;
393  ROS_INFO("Trim value is at %f", trim);
394 }
395 
396 void OpenRover::cmdVelCB(const geometry_msgs::Twist::ConstPtr& msg){ // converts from cmd_vel (m/s and radians/s) into motor speed commands
397  cmd_vel_commanded_ = *msg;
398  float left_motor_speed, right_motor_speed;
399  int flipper_motor_speed;
400  int motor_speed_deadband_scaled;
401  double turn_rate = msg->angular.z;
402  double linear_rate = msg->linear.x;
403  double flipper_rate = msg->angular.y;
404  if (turn_rate == 0){
405  if(linear_rate > 0){
406  turn_rate = trim;
407  }
408  else if(linear_rate <0){
409  turn_rate = -trim;
410  }
411  }
412  static bool prev_e_stop_state_ = false;
413 
414  double diff_vel_commanded = turn_rate / odom_angular_coef_ / odom_traction_factor_;
415 
416  right_vel_commanded_ = linear_rate + 0.5 * diff_vel_commanded;
417  left_vel_commanded_ = linear_rate - 0.5 * diff_vel_commanded;
418 
420 
421  if (e_stop_on_)
422  {
423  if (!prev_e_stop_state_)
424  {
425  prev_e_stop_state_ = true;
426  ROS_WARN("Openrover driver - Soft e-stop on.");
427  }
431  return;
432  }
433  else
434  {
435  if (prev_e_stop_state_)
436  {
437  prev_e_stop_state_ = false;
438  ROS_INFO("Openrover driver - Soft e-stop off.");
439  }
440  }
441 
442  flipper_motor_speed = ((int)round(flipper_rate * motor_speed_flipper_coef_) + 125) % 250;
443 
444  motor_speeds_commanded_[FLIPPER_MOTOR_INDEX_] = (unsigned char)flipper_motor_speed;
445 
447  return;
448 }
449 
450 void OpenRover::eStopCB(const std_msgs::Bool::ConstPtr& msg)
451 {
452  static bool prev_e_stop_state_ = false;
453 
454  // e-stop only trigger on the rising edge of the signal and only deactivates when reset
455  if(msg->data && !prev_e_stop_state_)
456  {
457  e_stop_on_ = true;
458  }
459 
460  prev_e_stop_state_ = msg->data;
461  return;
462 }
463 
464 void OpenRover::eStopResetCB(const std_msgs::Bool::ConstPtr& msg)
465 {
466  if(msg->data)
467  {
468  e_stop_on_ = false;
469  }
470  return;
471 }
472 
473 void OpenRover::publishOdometry(float left_vel, float right_vel)
474 { // convert encoder readings to real world values and publish as Odometry
475  static double left_dist = 0;
476  static double right_dist = 0;
477  static double pos_x = 0;
478  static double pos_y = 0;
479  static double theta = 0;
480  static double past_time = 0;
481  double net_vel = 0;
482  double diff_vel = 0;
483  double alpha = 0;
484  double dt = 0;
485  tf2::Quaternion q_new;
486 
487  ros::Time ros_now_time = ros::Time::now();
488  double now_time = ros_now_time.toSec();
489 
490  nav_msgs::Odometry odom_msg;
491 
492  dt = now_time - past_time;
493  past_time = now_time;
494 
495  if (past_time != 0)
496  {
497  left_dist += left_vel * dt;
498  right_dist += right_vel * dt;
499 
500  net_vel = 0.5 * (left_vel + right_vel);
501  diff_vel = right_vel - left_vel;
502 
503  alpha = odom_angular_coef_ * diff_vel * odom_traction_factor_;
504 
505  pos_x = pos_x + net_vel * cos(theta) * dt;
506  pos_y = pos_y + net_vel * sin(theta) * dt;
507  theta = (theta + alpha * dt);
508 
509  q_new.setRPY(0, 0, theta);
510  tf2::convert(q_new, odom_msg.pose.pose.orientation);
511  }
512 
513  odom_msg.header.stamp = ros_now_time;
514  odom_msg.header.frame_id = "odom";
515  odom_msg.child_frame_id = "base_link";
516 
517  odom_msg.twist.twist.linear.x = net_vel;
518  odom_msg.twist.twist.angular.z = alpha;
519 
520  // If not moving, trust the encoders completely
521  // otherwise set them to the ROS param
522  if (net_vel == 0 && alpha == 0)
523  {
524  odom_msg.twist.covariance[0] = odom_covariance_0_ / 1e3;
525  odom_msg.twist.covariance[7] = odom_covariance_0_ / 1e3;
526  odom_msg.twist.covariance[35] = odom_covariance_35_ / 1e6;
527  }
528  else
529  {
530  odom_msg.twist.covariance[0] = odom_covariance_0_;
531  odom_msg.twist.covariance[7] = odom_covariance_0_;
532  odom_msg.twist.covariance[35] = odom_covariance_35_;
533  }
534 
535  odom_msg.pose.pose.position.x = pos_x;
536  odom_msg.pose.pose.position.y = pos_y;
537 
538  odom_enc_pub.publish(odom_msg);
539  return;
540 }
541 
543 { // Update to publish from OdomControl
544  static ros::Time ros_start_time = ros::Time::now();
545  ros::Time ros_now_time = ros::Time::now();
546  double run_time = (ros_now_time - ros_start_time).toSec();
547  std_msgs::Float32MultiArray vel_vec;
548 
549  vel_vec.data.push_back(left_vel_filtered_);
550  vel_vec.data.push_back(left_vel_measured_);
551  vel_vec.data.push_back(left_vel_commanded_);
552  vel_vec.data.push_back(right_vel_filtered_);
553  vel_vec.data.push_back(right_vel_measured_);
554  vel_vec.data.push_back(right_vel_commanded_);
555 
556  vel_vec.data.push_back(motor_speeds_commanded_[LEFT_MOTOR_INDEX_]);
557  vel_vec.data.push_back(motor_speeds_commanded_[RIGHT_MOTOR_INDEX_]);
558 
559  vel_calc_pub.publish(vel_vec);
560 
561  return;
562 }
563 
565 {
566  rr_openrover_driver_msgs::RawRrOpenroverDriverFastRateData msg;
567 
568  msg.header.stamp = ros::Time::now();
569  msg.header.frame_id = "";
570 
571  msg.left_motor = robot_data_[i_ENCODER_INTERVAL_MOTOR_LEFT];
572  msg.right_motor = robot_data_[i_ENCODER_INTERVAL_MOTOR_RIGHT];
573  msg.flipper_motor = robot_data_[i_ENCODER_INTERVAL_MOTOR_FLIPPER];
574  if(use_legacy_) {
575  fast_rate_pub.publish(msg);
576  }
578  return;
579 }
580 
582 {
583  rr_openrover_driver_msgs::RawRrOpenroverDriverMedRateData med_msg;
584  std_msgs::Bool is_charging_msg;
585 
586  med_msg.header.stamp = ros::Time::now();
587  med_msg.header.frame_id = "";
588 
589  med_msg.reg_pwr_total_current = robot_data_[i_REG_PWR_TOTAL_CURRENT];
590  med_msg.reg_motor_fb_rpm_left = robot_data_[i_REG_MOTOR_FB_RPM_LEFT];
591  med_msg.reg_motor_fb_rpm_right = robot_data_[i_REG_MOTOR_FB_RPM_RIGHT];
592  med_msg.reg_flipper_fb_position_pot1 = robot_data_[i_REG_FLIPPER_FB_POSITION_POT1];
593  med_msg.reg_flipper_fb_position_pot2 = robot_data_[i_REG_FLIPPER_FB_POSITION_POT2];
594  med_msg.reg_motor_fb_current_left = robot_data_[i_REG_MOTOR_FB_CURRENT_LEFT];
595  med_msg.reg_motor_fb_current_right = robot_data_[i_REG_MOTOR_FB_CURRENT_RIGHT];
596  med_msg.reg_motor_charger_state = robot_data_[i_REG_MOTOR_CHARGER_STATE];
597  med_msg.reg_power_a_current = robot_data_[i_REG_POWER_A_CURRENT];
598  med_msg.reg_power_b_current = robot_data_[i_REG_POWER_B_CURRENT];
599  med_msg.reg_motor_flipper_angle = robot_data_[i_REG_MOTOR_FLIPPER_ANGLE];
600  med_msg.battery_current_a = robot_data_[i_BATTERY_CURRENT_A];
601  med_msg.battery_current_b = robot_data_[i_BATTERY_CURRENT_B];
602 
603  if (robot_data_[i_REG_MOTOR_CHARGER_STATE] == 0xDADA)
604  {
605  is_charging_ = true;
606  is_charging_msg.data = true;
607  is_charging_pub.publish(is_charging_msg);
608  }
609  else
610  {
611  is_charging_ = false;
612  is_charging_msg.data = false;
613  is_charging_pub.publish(is_charging_msg);
614  }
615 
616  if(use_legacy_) {
617  medium_rate_pub.publish(med_msg);
618  }
619  publish_med_rate_values_ = false;
620  return;
621 }
622 
623 rr_openrover_driver_msgs::SmartBatteryStatus interpret_battery_status(uint16_t bits)
624 {
625  rr_openrover_driver_msgs::SmartBatteryStatus status_msg;
626  status_msg.over_charged_alarm = bool(bits & 0x8000);
627  status_msg.terminate_charge_alarm = bool(bits & 0x4000);
628  status_msg.over_temp_alarm = bool(bits & 0x1000);
629  status_msg.terminate_discharge_alarm = bool(bits & 0x0800);
630  status_msg.remaining_capacity_alarm = bool(bits & 0x0200);
631  status_msg.remaining_time_alarm = bool(bits & 0x0100);
632  status_msg.initialized = bool(bits & 0x0080);
633  status_msg.discharging = bool(bits & 0x0040);
634  status_msg.fully_charged = bool(bits & 0x0020);
635  status_msg.fully_discharged = bool(bits & 0x0010);
636  return status_msg;
637 }
638 
640 {
641  rr_openrover_driver_msgs::RawRrOpenroverDriverSlowRateData slow_msg;
642  rr_openrover_driver_msgs::SmartBatteryStatus batteryStatusA;
643 
644  slow_msg.header.stamp = ros::Time::now();
645  slow_msg.header.frame_id = "";
646 
647  slow_msg.reg_motor_fault_flag_left = robot_data_[i_REG_MOTOR_FAULT_FLAG_LEFT];
648  slow_msg.reg_motor_temp_left = robot_data_[i_REG_MOTOR_TEMP_LEFT];
649  slow_msg.reg_motor_temp_right = robot_data_[i_REG_MOTOR_TEMP_RIGHT];
650  slow_msg.reg_power_bat_voltage_a = robot_data_[i_REG_POWER_BAT_VOLTAGE_A];
651  slow_msg.reg_power_bat_voltage_b = robot_data_[i_REG_POWER_BAT_VOLTAGE_B];
652  slow_msg.reg_robot_rel_soc_a = robot_data_[i_REG_ROBOT_REL_SOC_A];
653  slow_msg.reg_robot_rel_soc_b = robot_data_[i_REG_ROBOT_REL_SOC_B];
654  slow_msg.battery_mode_a = robot_data_[i_BATTERY_MODE_A];
655  slow_msg.battery_mode_b = robot_data_[i_BATTERY_MODE_B];
656  slow_msg.battery_temp_a = robot_data_[i_BATTERY_TEMP_A];
657  slow_msg.battery_temp_b = robot_data_[i_BATTERY_TEMP_B];
658  slow_msg.battery_voltage_a = robot_data_[i_BATTERY_VOLTAGE_A];
659  slow_msg.battery_voltage_b = robot_data_[i_BATTERY_VOLTAGE_B];
660  slow_msg.buildno = robot_data_[i_BUILDNO];
661 
664 
665  std_msgs::Int32 soc;
668 
669  if(use_legacy_) {
670  slow_rate_pub.publish(slow_msg);
671  }
673  return;
674 }
675 
677 {
678  std_msgs::Int32MultiArray motor_speeds_msg;
679  motor_speeds_msg.data.clear();
680  motor_speeds_msg.data.push_back(motor_speeds_commanded_[LEFT_MOTOR_INDEX_]);
681  motor_speeds_msg.data.push_back(motor_speeds_commanded_[RIGHT_MOTOR_INDEX_]);
682  motor_speeds_msg.data.push_back(motor_speeds_commanded_[FLIPPER_MOTOR_INDEX_]);
683 
684  motor_speeds_pub.publish(motor_speeds_msg);
685  return;
686 }
687 
689 { // sends serial commands stored in the 3 buffers in order of speed with fast getting highest priority
690  unsigned char param1;
691  unsigned char param2;
692  static double past_time = 0;
693 
694  while ((serial_fast_buffer_.size() > 0) || (serial_medium_buffer_.size() > 0) || (serial_slow_buffer_.size() > 0) ||
695  (serial_fan_buffer_.size() > 0))
696  {
697  // Fast data gets highest priority from being first in this if statement
698  // If the CPU running the driver can only process 60 commands / second and the fast
699  // data rate is set to 60hz, no other data will be gathered and the medium and slow Buffers
700  // will fill up and issue a warning.
701  if (serial_fast_buffer_.size() > 0)
702  {
703  param1 = 10;
704  param2 = serial_fast_buffer_.back();
705  serial_fast_buffer_.pop_back();
706  ROS_DEBUG("Its fast data's turn to be sent: %i", param2);
707  }
708  else if (serial_fan_buffer_.size() > 0)
709  {
710  param1 = 20;
711  param2 = serial_fan_buffer_.back();
712  serial_fan_buffer_.pop_back();
713  ROS_DEBUG("Its fan speed's turn to be sent: %i", param2);
714  }
715  else if (serial_medium_buffer_.size() > 0)
716  {
717  param1 = 10;
718  param2 = serial_medium_buffer_.back();
719  serial_medium_buffer_.pop_back();
720  ROS_DEBUG("Its medium data's turn to be sent: %i", param2);
721  }
722  else if (serial_slow_buffer_.size() > 0)
723  {
724  param1 = 10;
725  param2 = serial_slow_buffer_.back();
726  serial_slow_buffer_.pop_back();
727  ROS_DEBUG("Its slow data's turn to be sent: %i", param2);
728  }
729  else
730  {
731  param2 = 0;
732  param1 = 0;
733  }
734 
735  // Check param1 to determine what communication to the robot is required
736  try
737  {
738  if (param1 == 10) // Param1==10 requests data with index of param2
739  {
740  updateRobotData(param2);
741  }
742  else if (param1 == 20)
743  { // param1==20 means sending fan speed of param2
744  setParameterData(param1, param2);
745  }
746  else if (param1 == 250)
747  { // param1==250 means calibrating flipper DO NOT USE OFTEN
748  setParameterData(param1, param2);
749  }
750  else if (param1 == 0)
751  { // param1==0 means buffers are empty and doesn't need to do anything
752  }
753  else
754  {
755  throw std::string("Unknown param1. Removing parameter from buffer");
756  }
757  }
758  catch (std::string s)
759  {
760  throw;
761  }
762  catch (...)
763  {
764  throw;
765  }
766 
767  // If one of the buffers are empty, publish the values
768  if ((serial_fast_buffer_.size() == 0) && publish_fast_rate_values_)
769  {
770  ros::Time ros_now_time = ros::Time::now();
771  double now_time = ros_now_time.toSec();
772 
773  double dt = now_time - past_time;
774  past_time = now_time;
776  updateMeasuredVelocities(); // Update openrover measured velocities based on latest encoder readings
777 
782 
785 
786  publishOdometry(left_vel_measured_, right_vel_measured_); // Publish new calculated odometry
787  publishWheelVels(); // call after publishOdometry()
789  }
790  else if ((serial_medium_buffer_.size() == 0) && publish_med_rate_values_)
791  {
793  }
794  else if ((serial_slow_buffer_.size() == 0) && publish_slow_rate_values_)
795  {
797  }
798 
799  // Checks timers and subscribers
800  ros::spinOnce();
801  }
802 
803  if ((serial_fast_buffer_.size() == 0) && publish_fast_rate_values_)
804  {
806  }
807 
808  if ((serial_medium_buffer_.size() == 0) && publish_med_rate_values_)
809  {
810  publish_med_rate_values_ = false;
811  }
812 
813  if ((serial_slow_buffer_.size() == 0) && publish_slow_rate_values_)
814  {
816  }
817 
818  return;
819 }
820 
822 {
823  /*
824  Truncate the last two digits of the firmware version number,
825  which returns in the format aabbcc. We divide by 100 to truncate
826  cc since we don't care about the PATCH field of semantic versioning
827  */
828  int robotFirmwareBuild = robot_data_[i_BUILDNO] / 100;
829 
830  if(robotFirmwareBuild == BUILD_NUMBER_WITH_GOOD_RPM_DATA){
831  signed short int left_rpm = robot_data_[i_REG_MOTOR_FB_RPM_LEFT];
832  signed short int right_rpm = robot_data_[i_REG_MOTOR_FB_RPM_RIGHT];
833 
836 
837  if(left_rpm > 0){
839  }
840  else if(left_rpm < 0){
842  }
843  else{
844  left_vel_measured_ = 0;
845  }
846 
847  if(right_rpm > 0){
849  }
850  else if(right_rpm < 0){
852  }
853  else{
855  }
856 
860  }
861 
862  }
863  else{
864  //do it the old way
867 
868  // Bound left_encoder readings to range of normal operation.
869  if (left_enc < ENCODER_MIN)
870  {
871  left_vel_measured_ = 0;
872  }
873  else if (left_enc > ENCODER_MAX)
874  {
875  left_vel_measured_ = 0;
876  }
877  else if (motor_speeds_commanded_[LEFT_MOTOR_INDEX_] > MOTOR_NEUTRAL) // this sets direction of measured
878  {
880  }
881  else
882  {
884  }
885 
886  // Bound right_encoder readings to range of normal operation.
887  if (right_enc < ENCODER_MIN)
888  {
890  }
891  else if (right_enc > ENCODER_MAX)
892  {
894  }
895  else if (motor_speeds_commanded_[RIGHT_MOTOR_INDEX_] > MOTOR_NEUTRAL) // this sets direction of measured
896  {
898  }
899  else
900  {
902  }
903 
904  }
905  return;
906 }
907 
909 {
910  try
911  {
912  int data = getParameterData(param);
913  if (data < 0) // check if val is good (not negative) and if not, push param back to buffer
914  {
915  throw;
916  }
917 
918  robot_data_[param] = data;
919  }
920  catch (std::string s)
921  {
922  char str_ex[70];
923  sprintf(str_ex, "Failed to update param %i. Will try to re-open port", param);
924  //try to re-open the serial port
925  if (!(openComs()))
926  {
927  ROS_WARN("Failed to restart serial communication.");
928  }
929  }
930  return;
931 }
932 
933 bool OpenRover::sendCommand(int param1, int param2)
934 {
935  unsigned char write_buffer[SERIAL_OUT_PACKAGE_LENGTH];
936 
937  write_buffer[0] = SERIAL_START_BYTE;
938  write_buffer[1] = (unsigned char)motor_speeds_commanded_[LEFT_MOTOR_INDEX_]; // left motor
939  write_buffer[2] = (unsigned char)motor_speeds_commanded_[RIGHT_MOTOR_INDEX_]; // right motor
940  write_buffer[3] = (unsigned char)motor_speeds_commanded_[FLIPPER_MOTOR_INDEX_]; // flipper
941  write_buffer[4] = (unsigned char)param1; // Param 1: 10 to get data, 240 for low speed mode
942  write_buffer[5] = (unsigned char)param2; // Param 2:
943  // Calculate Checksum
944  write_buffer[6] =
945  (char)255 - (write_buffer[1] + write_buffer[2] + write_buffer[3] + write_buffer[4] + write_buffer[5]) % 255;
946 
948  {
949  char str_ex[50];
950  sprintf(str_ex, "Failed to send command: %02x,%02x,%02x,%02x,%02x,%02x,%02x", write_buffer[0], write_buffer[1],
951  write_buffer[2], write_buffer[3], write_buffer[4], write_buffer[5], write_buffer[6]);
952  throw std::string(str_ex);
953  }
954 
955  return true;
956 }
957 
959 { // only used after a send command with param1==10
960  unsigned char read_buffer[1];
961  unsigned char start_byte_read, checksum, read_checksum, data1, data2, dataNO;
962  int data;
963 
964  int bits_read = read(serial_port_fd_, read_buffer, 1);
965  start_byte_read = read_buffer[0];
966 
967  read(serial_port_fd_, read_buffer, 1); // get param
968  dataNO = read_buffer[0];
969 
970  read(serial_port_fd_, read_buffer, 1); // get data1
971  data1 = read_buffer[0];
972 
973  read(serial_port_fd_, read_buffer, 1); // get data2
974  data2 = read_buffer[0];
975 
976  read(serial_port_fd_, read_buffer, 1); // get checksum
977  read_checksum = read_buffer[0];
978 
979  checksum = 255 - (dataNO + data1 + data2) % 255;
980 
981  if (!(SERIAL_START_BYTE == start_byte_read))
982  {
983  char str_ex[50];
984  sprintf(str_ex, "Received bad start byte. Received: %02x", start_byte_read);
985  tcflush(serial_port_fd_, TCIOFLUSH); // flush received buffer
986  throw std::string(str_ex);
987  }
988  else if (checksum != read_checksum)
989  {
990  char str_ex[50];
991  sprintf(str_ex, "Received bad CRC. Received: %02x,%02x,%02x,%02x,%02x", start_byte_read, dataNO, data1, data2,
992  read_checksum);
993  tcflush(serial_port_fd_, TCIOFLUSH); // flush received buffer
994  throw std::string(str_ex);
995  }
996  data = (data1 << 8) + data2;
997  return data;
998 }
999 
1000 bool OpenRover::setParameterData(int param1, int param2)
1001 {
1002  try
1003  {
1004  if (!sendCommand(param1, param2))
1005  {
1006  throw;
1007  }
1008 
1009  return true;
1010  }
1011  catch (std::string s)
1012  {
1013  std::string s2("setParameterData() failed. ");
1014  throw(s2 + s);
1015  }
1016 }
1017 
1019 {
1020  int data;
1021 
1022  try
1023  {
1024  if (!sendCommand(10, param))
1025  {
1026  throw;
1027  }
1028 
1029  data = readCommand();
1030 
1031  if (0 > data)
1032  {
1033  throw;
1034  }
1035  return data;
1036  }
1037  catch (std::string s)
1038  {
1039  std::string s2("getParameterData() failed. "); // %i. ", param);
1040  throw(s2 + s);
1041  }
1042 }
1043 
1045 {
1046  ROS_INFO("Opening serial port");
1047  struct termios serial_port_fd__options;
1048 
1049  serial_port_fd_ = ::open(port_.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
1050  if (serial_port_fd_ < 0)
1051  {
1052  ROS_ERROR("Failed to open port: %s", strerror(errno));
1053  return false;
1054  }
1055  if (0 > fcntl(serial_port_fd_, F_SETFL, 0))
1056  {
1057  ROS_ERROR("Failed to set port descriptor: %s", strerror(errno));
1058  return false;
1059  }
1060  if (0 > tcgetattr(serial_port_fd_, &serial_port_fd__options))
1061  {
1062  ROS_ERROR("Failed to fetch port attributes: %s", strerror(errno));
1063  return false;
1064  }
1065  if (0 > cfsetispeed(&serial_port_fd__options, B57600))
1066  {
1067  ROS_ERROR("Failed to set input baud: %s", strerror(errno));
1068  return false;
1069  }
1070  if (0 > cfsetospeed(&serial_port_fd__options, B57600))
1071  {
1072  ROS_ERROR("Failed to set output baud: %s", strerror(errno));
1073  return false;
1074  }
1075 
1076  serial_port_fd__options.c_cflag |= (CREAD | CLOCAL | CS8);
1077  serial_port_fd__options.c_cflag &= ~(PARODD | CRTSCTS | CSTOPB | PARENB);
1078  serial_port_fd__options.c_iflag &= ~(IUCLC | IXANY | IMAXBEL | IXON | IXOFF | IUTF8 | ICRNL | INPCK); // input modes
1079  serial_port_fd__options.c_oflag |= (NL0 | CR0 | TAB0 | BS0 | VT0 | FF0);
1080  serial_port_fd__options.c_oflag &=
1081  ~(OPOST | ONLCR | OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL | NL1 | CR1 | CR2 | TAB3 | BS1 | VT1 | FF1);
1082  serial_port_fd__options.c_lflag |= (NOFLSH);
1083  serial_port_fd__options.c_lflag &= ~(ICANON | IEXTEN | TOSTOP | ISIG | ECHOPRT | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE);
1084  serial_port_fd__options.c_cc[VINTR] = 0x03; // INTR Character
1085  serial_port_fd__options.c_cc[VQUIT] = 0x1C; // QUIT Character
1086  serial_port_fd__options.c_cc[VERASE] = 0x7F; // ERASE Character
1087  serial_port_fd__options.c_cc[VKILL] = 0x15; // KILL Character
1088  serial_port_fd__options.c_cc[VEOF] = 0x04; // EOF Character
1089  serial_port_fd__options.c_cc[VTIME] = 0x01; // Timeout in 0.1s of serial read
1090  serial_port_fd__options.c_cc[VMIN] = 0; // SERIAL_IN_PACKAGE_LENGTH; //Min Number of bytes to read
1091  serial_port_fd__options.c_cc[VSWTC] = 0x00;
1092  serial_port_fd__options.c_cc[VSTART] = SERIAL_START_BYTE; // START Character
1093  serial_port_fd__options.c_cc[VSTOP] = 0x13; // STOP character
1094  serial_port_fd__options.c_cc[VSUSP] = 0x1A; // SUSP character
1095  serial_port_fd__options.c_cc[VEOL] = 0x00; // EOL Character
1096  serial_port_fd__options.c_cc[VREPRINT] = 0x12;
1097  serial_port_fd__options.c_cc[VDISCARD] = 0x0F;
1098  serial_port_fd__options.c_cc[VWERASE] = 0x17;
1099  serial_port_fd__options.c_cc[VLNEXT] = 0x16;
1100  serial_port_fd__options.c_cc[VEOL2] = 0x00;
1101 
1102  if (0 > tcsetattr(serial_port_fd_, TCSANOW, &serial_port_fd__options))
1103  {
1104  ROS_ERROR("Failed to set port attributes: %s", strerror(errno));
1105  return false;
1106  }
1107  ::ioctl(serial_port_fd_, TIOCEXCL); // turn on exclusive mode
1108 
1109  ROS_INFO("Serial port opened");
1110  is_serial_coms_open_ = true;
1111  tcflush(serial_port_fd_, TCIOFLUSH); // flush received buffer
1112 
1113  return true;
1114 }
1115 
1116 } // namespace openrover
1117 
1118 int main(int argc, char* argv[])
1119 {
1120  // Create ROS node
1121  ros::init(argc, argv, "rr_openrover_driver_node");
1122 
1123  ros::NodeHandle nh("");
1124  ros::NodeHandle nh_priv("~");
1125  openrover::OpenRover openrover(nh, nh_priv);
1126  /* if( !nh )
1127  {
1128  ROS_FATAL( "Failed to initialize NodeHandle" );
1129  ros::shutdown( );
1130  return -1;
1131  }
1132  if( !nh_priv )
1133  {
1134  ROS_FATAL( "Failed to initialize private NodeHandle" );
1135  delete nh;
1136  ros::shutdown( );
1137  return -2;
1138  }
1139  if( !openrover )
1140  {
1141  ROS_FATAL( "Failed to initialize driver" );
1142  delete nh_priv;
1143  delete nh;
1144  ros::shutdown( );
1145  return -3;
1146  }
1147  */
1148  if (!openrover.start())
1149  {
1150  ROS_FATAL("Failed to start the rover driver");
1152  }
1153 
1154  ros::Rate loop_rate(openrover::LOOP_RATE);
1155 
1156  while (ros::ok())
1157  {
1158  try
1159  {
1160  ros::spinOnce();
1161  // Process Serial Buffers
1162  openrover.serialManager();
1163  loop_rate.sleep(); // sleeping greatly reduces CPU
1164  }
1165  catch (std::string s)
1166  {
1167  ROS_ERROR("%s", s.c_str());
1168  }
1169  catch (...)
1170  {
1171  ROS_ERROR("Unknown Exception occurred");
1172  }
1173  }
1174  /*
1175  delete openrover;
1176  delete nh_priv;
1177  delete nh;
1178  */
1179 
1180  return 0;
1181 }
void robotDataMediumCB(const ros::WallTimerEvent &e)
void robotDataSlowCB(const ros::WallTimerEvent &e)
msg
#define ROS_WARN_DELAYED_THROTTLE(period,...)
const int i_REG_MOTOR_FB_CURRENT_LEFT
Definition: constants.hpp:78
const int i_BATTERY_VOLTAGE_B
Definition: constants.hpp:110
int main(int argc, char *argv[])
const int i_REG_MOTOR_FLIPPER_ANGLE
Definition: constants.hpp:97
void setRPY(const tf2Scalar &roll, const tf2Scalar &pitch, const tf2Scalar &yaw)
std::vector< unsigned char > serial_fast_buffer_
Definition: openrover.hpp:134
void robotDataFastCB(const ros::WallTimerEvent &e)
const int MOTOR_SPEED_ANGULAR_COEF_4WD_HS
Definition: constants.hpp:37
#define ROS_FATAL(...)
const int MOTOR_SPEED_LINEAR_COEF_F_HS
Definition: constants.hpp:26
std::vector< unsigned char > serial_slow_buffer_
Definition: openrover.hpp:136
const int LOOP_RATE
Definition: constants.hpp:17
const float ODOM_AXLE_TRACK_F
Definition: constants.hpp:22
void eStopCB(const std_msgs::Bool::ConstPtr &msg)
const int i_REG_MOTOR_TEMP_RIGHT
Definition: constants.hpp:82
const int i_REG_POWER_BAT_VOLTAGE_A
Definition: constants.hpp:84
ros::NodeHandle & nh_priv_
Definition: openrover.hpp:68
const int i_ENCODER_INTERVAL_MOTOR_RIGHT
Definition: constants.hpp:87
OdomControl left_controller_
Definition: openrover.hpp:30
const int MEDIUM_SIZE
Definition: constants.hpp:139
const int i_REG_ROBOT_REL_SOC_A
Definition: constants.hpp:90
const float ODOM_AXLE_TRACK_2WD
Definition: constants.hpp:43
const int LEFT_MOTOR_INDEX_
Definition: openrover.hpp:101
std::string r_pid_csv_file_
Definition: openrover.hpp:56
ros::Publisher is_charging_pub
Definition: openrover.hpp:79
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
const int i_REG_MOTOR_CHARGER_STATE
Definition: constants.hpp:92
const int i_BATTERY_VOLTAGE_A
Definition: constants.hpp:109
void eStopResetCB(const std_msgs::Bool::ConstPtr &msg)
const float ODOM_ENCODER_COEF_2WD
Definition: constants.hpp:42
ros::Publisher battery_status_a_pub
Definition: openrover.hpp:86
const int i_BATTERY_MODE_A
Definition: constants.hpp:104
XmlRpcServer s
int motor_speeds_commanded_[3]
Definition: openrover.hpp:100
const float ODOM_ENCODER_COEF_F
Definition: constants.hpp:21
std::string drive_type_
Definition: openrover.hpp:62
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
const int ENCODER_MIN
Definition: constants.hpp:59
ros::WallTimer medium_timer
Definition: openrover.hpp:72
const int i_ENCODER_INTERVAL_MOTOR_FLIPPER
Definition: constants.hpp:88
data
ros::Publisher slow_rate_pub
Definition: openrover.hpp:85
const float MOTOR_RPM_TO_MPS_RATIO
Definition: constants.hpp:10
void updateRobotData(int parameter)
bool publish_fast_rate_values_
Definition: openrover.hpp:47
const int MOTOR_SPEED_ANGULAR_COEF_F_HS
Definition: constants.hpp:27
const float ODOM_TRACTION_FACTOR_2WD
Definition: constants.hpp:45
const int i_REG_FLIPPER_FB_POSITION_POT2
Definition: constants.hpp:76
const int ROBOT_DATA_INDEX_FAST[]
Definition: constants.hpp:114
#define ROS_WARN(...)
bool publish_slow_rate_values_
Definition: openrover.hpp:49
const float ODOM_ANGULAR_COEF_4WD
Definition: constants.hpp:33
const int i_REG_MOTOR_FAULT_FLAG_LEFT
Definition: constants.hpp:80
const int RIGHT_MOTOR_INDEX_
Definition: openrover.hpp:102
const int ENCODER_MAX
Definition: constants.hpp:58
OdomControl right_controller_
Definition: openrover.hpp:31
ros::Publisher battery_status_b_pub
Definition: openrover.hpp:86
void timeoutCB(const ros::WallTimerEvent &e)
WallTimer createWallTimer(WallDuration period, void(T::*callback)(const WallTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
const int i_BATTERY_CURRENT_B
Definition: constants.hpp:112
void publish(const boost::shared_ptr< M > &message) const
const int i_REG_FLIPPER_FB_POSITION_POT1
Definition: constants.hpp:75
std::string l_pid_csv_file_
Definition: openrover.hpp:55
const int MOTOR_SPEED_MAX
Definition: constants.hpp:64
const int SERIAL_OUT_PACKAGE_LENGTH
Definition: constants.hpp:15
const float ODOM_AXLE_TRACK_4WD
Definition: constants.hpp:32
const int MOTOR_FLIPPER_COEF
Definition: constants.hpp:60
ros::Subscriber fan_speed_sub
Definition: openrover.hpp:91
std::ofstream l_fs_
Definition: openrover.hpp:57
ros::Publisher battery_state_of_charge_pub
Definition: openrover.hpp:87
const int FAST_SIZE
Definition: constants.hpp:138
ros::Publisher fast_rate_pub
Definition: openrover.hpp:83
ros::Subscriber trim_sub
Definition: openrover.hpp:89
const int i_BATTERY_MODE_B
Definition: constants.hpp:105
void fanSpeedCB(const std_msgs::Int32::ConstPtr &msg)
std::vector< unsigned char > serial_fan_buffer_
Definition: openrover.hpp:137
const int i_REG_POWER_B_CURRENT
Definition: constants.hpp:96
#define ROS_INFO(...)
bool getParam(const std::string &key, std::string &s) const
const int i_BATTERY_TEMP_A
Definition: constants.hpp:106
const int i_REG_ROBOT_REL_SOC_B
Definition: constants.hpp:91
void start(bool use_control, PidGains pid_gains, int max, int min)
const int MOTOR_NEUTRAL
Definition: constants.hpp:63
const int i_BATTERY_TEMP_B
Definition: constants.hpp:107
ROSCPP_DECL bool ok()
const int i_ENCODER_INTERVAL_MOTOR_LEFT
Definition: constants.hpp:86
const int MOTOR_SPEED_ANGULAR_COEF_2WD_HS
Definition: constants.hpp:48
ros::Subscriber e_stop_reset_sub
Definition: openrover.hpp:93
ros::Publisher vel_calc_pub
Definition: openrover.hpp:81
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
const int i_REG_POWER_BAT_VOLTAGE_B
Definition: constants.hpp:85
rr_openrover_driver_msgs::SmartBatteryStatus interpret_battery_status(uint16_t bits)
const int i_REG_MOTOR_FB_RPM_RIGHT
Definition: constants.hpp:74
const float ODOM_TRACTION_FACTOR_F
Definition: constants.hpp:24
const float MOTOR_RPM_TO_MPS_CFB
Definition: constants.hpp:11
void trimCB(const std_msgs::Float32::ConstPtr &msg)
bool sleep()
ros::Subscriber e_stop_sub
Definition: openrover.hpp:92
const int i_BATTERY_STATUS_A
Definition: constants.hpp:102
const int i_REG_MOTOR_TEMP_LEFT
Definition: constants.hpp:81
ros::WallTimer slow_timer
Definition: openrover.hpp:73
const float ODOM_ENCODER_COEF_4WD
Definition: constants.hpp:31
ros::Subscriber cmd_vel_sub
Definition: openrover.hpp:90
const float WHEEL_TO_TRACK_RATIO
Definition: constants.hpp:12
const int MOTOR_SPEED_LINEAR_COEF_4WD_HS
Definition: constants.hpp:36
ros::Publisher medium_rate_pub
Definition: openrover.hpp:84
ROSCPP_DECL void requestShutdown()
std::vector< unsigned char > serial_medium_buffer_
Definition: openrover.hpp:135
const int ROBOT_DATA_INDEX_SLOW[]
Definition: constants.hpp:129
const int ROBOT_DATA_INDEX_MEDIUM[]
Definition: constants.hpp:120
const int i_REG_PWR_TOTAL_CURRENT
Definition: constants.hpp:72
const float ODOM_ANGULAR_COEF_2WD
Definition: constants.hpp:44
ros::WallTimer timeout_timer
Definition: openrover.hpp:74
const int SLOW_SIZE
Definition: constants.hpp:140
const int i_REG_POWER_A_CURRENT
Definition: constants.hpp:94
static Time now()
void convert(const A &a, B &b)
ros::WallTimer fast_timer
Definition: openrover.hpp:71
bool sendCommand(int param1, int param2)
const int MOTOR_DEADBAND
Definition: constants.hpp:62
ros::Publisher odom_enc_pub
Definition: openrover.hpp:77
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
const float ODOM_TRACTION_FACTOR_4WD
Definition: constants.hpp:34
OpenRover(ros::NodeHandle &nh, ros::NodeHandle &nh_priv)
int getParameterData(int parameter)
const int BUILD_NUMBER_WITH_GOOD_RPM_DATA
Definition: constants.hpp:7
const int i_REG_MOTOR_FB_CURRENT_RIGHT
Definition: constants.hpp:79
bool setParameterData(int param1, int param2)
const int MOTOR_SPEED_MIN
Definition: constants.hpp:65
ros::Publisher motor_speeds_pub
Definition: openrover.hpp:80
const float ODOM_ANGULAR_COEF_F
Definition: constants.hpp:23
const int i_REG_MOTOR_FB_RPM_LEFT
Definition: constants.hpp:73
ROSCPP_DECL void spinOnce()
const int MOTOR_SPEED_LINEAR_COEF_2WD_HS
Definition: constants.hpp:47
const int i_BATTERY_STATUS_B
Definition: constants.hpp:103
void publishOdometry(float left_vel, float right_vel)
const int FLIPPER_MOTOR_INDEX_
Definition: openrover.hpp:103
geometry_msgs::Twist cmd_vel_commanded_
Definition: openrover.hpp:133
std::string port_
Definition: openrover.hpp:61
#define ROS_ERROR(...)
void cmdVelCB(const geometry_msgs::Twist::ConstPtr &msg)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
const unsigned char SERIAL_START_BYTE
Definition: constants.hpp:14
const int i_BATTERY_CURRENT_A
Definition: constants.hpp:111
std::ofstream r_fs_
Definition: openrover.hpp:58
unsigned char run(bool e_stop_on, bool control_on, double commanded_vel, double measured_vel, double dt, int firmwareBuildNumber)
const int i_BUILDNO
Definition: constants.hpp:93
#define ROS_DEBUG(...)


rr_openrover_driver
Author(s): Jack Kilian
autogenerated on Mon Feb 28 2022 23:43:54