openrover_basic.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 "tf/tf.h"
14 #include "std_msgs/Int32.h"
15 #include "std_msgs/Int32MultiArray.h"
16 #include "std_msgs/Float32MultiArray.h"
17 #include "geometry_msgs/TwistStamped.h"
18 #include <std_msgs/Bool.h>
19 #include "nav_msgs/Odometry.h"
20 #include "rr_openrover_basic/RawRrOpenroverBasicFastRateData.h"
21 #include "rr_openrover_basic/RawRrOpenroverBasicMedRateData.h"
22 #include "rr_openrover_basic/RawRrOpenroverBasicSlowRateData.h"
23 #include "rr_openrover_basic/SmartBatteryStatus.h"
24 
27 
28 namespace openrover
29 {
31  : nh_(nh)
32  , nh_priv_(nh_priv)
33  , port_("/dev/ttyUSB0")
34  , serial_baud_rate_(57600)
35  , fast_rate_hz_(10.0) // can increase to 60Hz for TX2
36  , medium_rate_hz_(2.0)
37  , slow_rate_hz_(1.0)
38  , motor_speeds_commanded_{ MOTOR_NEUTRAL, MOTOR_NEUTRAL, MOTOR_NEUTRAL } // default motor commands to neutral
39  , timeout_(0.2) // in seconds
43  , is_serial_coms_open_(false)
45  , pidGains_(40, 100, 0)
52  , e_stop_on_(false)
56 {
57  ROS_INFO("Initializing openrover driver.");
58  ROS_INFO("Kp %f", pidGains_.Kp);
59  ROS_INFO("Ki %f", pidGains_.Ki);
60  ROS_INFO("Kd %f", pidGains_.Kd);
61 
62 }
63 
65 {
66  if (!setupRobotParams())
67  {
68  ROS_WARN("Failed to setup Robot parameters.");
69  return false;
70  }
71 
74 
75  serial_fast_buffer_.reserve(5 * FAST_SIZE); // reserve space for 5 sets of FAST rate data
76  serial_medium_buffer_.reserve(5 * MEDIUM_SIZE); // reserve space for 5 sets of Medium rate data
77  serial_slow_buffer_.reserve(5 * SLOW_SIZE); // reserve space for 5 sets of Slow rate data
78  serial_fan_buffer_.reserve(5); // reserve space for 5 sets of Fan commands
79 
80  ROS_INFO("Creating Publishers and Subscribers");
81  // WallTimers simplify the timing of updating parameters by reloading serial buffers at specified rates.
82  // without them the serial buffers will never be loaded with new commands
87 
88  fast_rate_pub = nh_priv_.advertise<rr_openrover_basic::RawRrOpenroverBasicFastRateData>("raw_fast_rate_data", 1);
89  medium_rate_pub = nh_priv_.advertise<rr_openrover_basic::RawRrOpenroverBasicMedRateData>("raw_med_rate_data", 1);
90  slow_rate_pub = nh_priv_.advertise<rr_openrover_basic::RawRrOpenroverBasicSlowRateData>("raw_slow_rate_data", 1);
91  battery_status_a_pub = nh_priv_.advertise<rr_openrover_basic::SmartBatteryStatus>("battery_status_a", 1);
92  battery_status_b_pub = nh_priv_.advertise<rr_openrover_basic::SmartBatteryStatus>("battery_status_b", 1);
93  odom_enc_pub = nh_priv_.advertise<nav_msgs::Odometry>("odom_encoder", 1);
94  is_charging_pub = nh_priv_.advertise<std_msgs::Bool>("charging", 1);
95 
96  motor_speeds_pub = nh_priv_.advertise<std_msgs::Int32MultiArray>("motor_speeds_commanded", 1);
97  vel_calc_pub = nh_priv_.advertise<std_msgs::Float32MultiArray>("vel_calc_pub", 1);
98 
99  cmd_vel_sub = nh_priv_.subscribe("/cmd_vel/managed", 1, &OpenRover::cmdVelCB, this);
100  fan_speed_sub = nh_priv_.subscribe("/rr_openrover_basic/fan_speed", 1, &OpenRover::fanSpeedCB, this);
101 
102  return true;
103 }
104 
106 { // Get ROS params and save them to class variables
107 
108  if (!(nh_priv_.getParam("port", port_)))
109  {
110  ROS_WARN("Failed to retrieve port from parameter server.Defaulting to %s", port_.c_str());
111  }
112 
113  if (!(openComs()))
114  {
115  is_serial_coms_open_ = false;
116  ROS_ERROR("Failed to start serial communication.");
117  return false;
118  }
119 
120  if (!(nh_priv_.getParam("fast_data_rate", fast_rate_hz_)))
121  {
122  ROS_WARN("Failed to retrieve fast_data_rate from parameter. Defaulting to 10");
123  }
124 
125  if (!(nh_priv_.getParam("medium_data_rate", medium_rate_hz_)))
126  {
127  ROS_WARN("Failed to retrieve medium_data_rate from parameter. Defaulting to 2");
128  }
129 
130  if (!(nh_priv_.getParam("slow_data_rate", slow_rate_hz_)))
131  {
132  ROS_WARN("Failed to retrieve slow_data_rate from parameter. Defaulting to 1");
133  }
134 
135 
136  if (!(nh_priv_.getParam("closed_loop_control_on", closed_loop_control_on_)))
137  {
138  ROS_WARN("Failed to retrieve closed_loop_control_on from parameter server. Defaulting to off.");
139  }
140 
141  if (!(nh_priv_.getParam("timeout", timeout_)))
142  {
143  ROS_WARN("Failed to retrieve timeout from parameter server. Defaulting to %f s", timeout_);
144  }
145 
146  if (!(nh_priv_.getParam("total_weight", total_weight_)))
147  {
148  ROS_WARN("Failed to retrieve total_weight from parameter server. Defaulting to %f lbs", total_weight_);
149  }
150 
151  if (!(nh_priv_.getParam("drive_type", drive_type_)))
152  {
153  ROS_WARN("Failed to retrieve drive_type from parameter.Defaulting to %s", drive_type_.c_str());
154  }
155 
156  if (drive_type_ == (std::string) "2wd")
157  {
158  ROS_INFO("2wd parameters loaded.");
163 
167  }
168  else if (drive_type_ == (std::string) "4wd")
169  {
170  ROS_INFO("4wd parameters loaded.");
175 
179  }
180  else if (drive_type_ == (std::string) "flippers")
181  {
182  ROS_INFO("flipper parameters loaded.");
187 
191  }
192  else
193  {
194  ROS_WARN("Unclear ROS param drive_type. Defaulting to flippers params.");
199 
203  }
204 
205  if (!(nh_priv_.getParam("traction_factor", odom_traction_factor_)))
206  {
207  ROS_WARN("Failed to retrieve traction_factor from parameter. Defaulting to %f", odom_traction_factor_);
208  odom_traction_factor_ = 0.61;
209  }
210 
211  if (!(nh_priv_.getParam("odom_covariance_0", odom_covariance_0_)))
212  {
213  ROS_WARN("Failed to retrieve odom_covariance_0 from parameter. Defaulting to 0.01");
214  odom_covariance_0_ = 0.01;
215  }
216 
217  if (!(nh_priv_.getParam("odom_covariance_35", odom_covariance_35_)))
218  {
219  ROS_WARN("Failed to retrieve odom_covariance_35 from parameter. Defaulting to 0.03");
220  odom_covariance_35_ = 0.03;
221  }
222 
223  ROS_INFO("Openrover parameters loaded:");
224  ROS_INFO("port: %s", port_.c_str());
225  ROS_INFO("drive_type: %s", drive_type_.c_str());
226  ROS_INFO("timeout: %f s", timeout_);
227  ROS_INFO("closed_loop_control_on: %i", closed_loop_control_on_);
228  ROS_INFO("total_weight: %f kg", total_weight_);
229  ROS_INFO("traction_factor: %f", odom_traction_factor_);
230  ROS_INFO("odom_covariance_0: %f", odom_covariance_0_);
231  ROS_INFO("odom_covariance_35: %f", odom_covariance_35_);
232  ROS_INFO("fast_data_rate: %f hz", fast_rate_hz_);
233  ROS_INFO("medium_data_rate: %f hz", medium_rate_hz_);
234  ROS_INFO("slow_data_rate: %f hz", slow_rate_hz_);
235 
236  return true;
237 }
238 
240 {
242  {
243  for (int i = 0; i < SLOW_SIZE; i++)
244  {
246  }
248  }
249  return;
250 }
251 
253 {
255  {
256  for (int i = 0; i < MEDIUM_SIZE; i++)
257  {
259  }
261  }
262  return;
263 }
264 
266 {
268  {
269  for (int i = 0; i < FAST_SIZE; i++)
270  {
271  // Fill buffer with all the param2's defined as fast data
272  // by the ROBOT_DATA_INDEX_FAST array
274  }
276  }
277  else
278  {
279  ROS_WARN_DELAYED_THROTTLE(5, "Fast data rate too high. Consider reducing fast_data_rate param");
280  }
281  return;
282 }
283 
285 { // Timer goes off when a command isn't received soon enough. Sets motors to neutral values
289  return;
290 }
291 
292 void OpenRover::fanSpeedCB(const std_msgs::Int32::ConstPtr& msg)
293 {
294  if (is_serial_coms_open_ && (serial_fan_buffer_.size() == 0))
295  {
296  serial_fan_buffer_.push_back(msg->data);
297  }
298  // ROS_DEBUG("Fan Buffer size is %i, new data is %i", serial_fan_buffer_.size(), msg->data);
299  return;
300 }
301 
302 void OpenRover::cmdVelCB(const geometry_msgs::TwistStamped::ConstPtr& msg)
303 { // converts from cmd_vel (m/s and radians/s) into motor speed commands
304  cmd_vel_commanded_ = msg->twist;
305  float left_motor_speed, right_motor_speed;
306  int flipper_motor_speed;
307  int motor_speed_deadband_scaled;
308  double turn_rate = msg->twist.angular.z;
309  double linear_rate = msg->twist.linear.x;
310  double flipper_rate = msg->twist.angular.y;
311  std::string frame_id = msg->header.frame_id;
312 
313  double diff_vel_commanded = turn_rate / odom_angular_coef_ / odom_traction_factor_;
314 
315  right_vel_commanded_ = linear_rate + 0.5 * diff_vel_commanded;
316  left_vel_commanded_ = linear_rate - 0.5 * diff_vel_commanded;
317 
319 
320  if (frame_id == (std::string) "soft e-stopped")
321  {
322  if (!e_stop_on_)
323  {
324  e_stop_on_ = true;
325  ROS_WARN("Openrover driver - Soft e-stop on.");
326  }
327  return;
328  }
329  else
330  {
331  if (e_stop_on_)
332  {
333  e_stop_on_ = false;
334  ROS_INFO("Openrover driver - Soft e-stop off.");
335  }
336  }
337 
338  flipper_motor_speed = ((int)round(flipper_rate * motor_speed_flipper_coef_) + 125) % 250;
339 
340  motor_speeds_commanded_[FLIPPER_MOTOR_INDEX_] = (unsigned char)flipper_motor_speed;
341 
343  return;
344 }
345 
346 void OpenRover::publishOdometry(float left_vel, float right_vel)
347 { // convert encoder readings to real world values and publish as Odometry
348  static double left_dist = 0;
349  static double right_dist = 0;
350  static double pos_x = 0;
351  static double pos_y = 0;
352  static double theta = 0;
353  static double past_time = 0;
354  double net_vel = 0;
355  double diff_vel = 0;
356  double alpha = 0;
357  double dt = 0;
358  tf::Quaternion q_new;
359 
360  ros::Time ros_now_time = ros::Time::now();
361  double now_time = ros_now_time.toSec();
362 
363  nav_msgs::Odometry odom_msg;
364 
365  dt = now_time - past_time;
366  past_time = now_time;
367 
368  if (past_time != 0)
369  {
370  left_dist += left_vel * dt;
371  right_dist += right_vel * dt;
372 
373  net_vel = 0.5 * (left_vel + right_vel);
374  diff_vel = right_vel - left_vel;
375 
376  alpha = odom_angular_coef_ * diff_vel * odom_traction_factor_;
377 
378  pos_x = pos_x + net_vel * cos(theta) * dt;
379  pos_y = pos_y + net_vel * sin(theta) * dt;
380  theta = (theta + alpha * dt);
381 
382  q_new = tf::createQuaternionFromRPY(0, 0, theta);
383  quaternionTFToMsg(q_new, odom_msg.pose.pose.orientation);
384  }
385 
386  odom_msg.header.stamp = ros_now_time;
387  odom_msg.header.frame_id = "odom";
388  odom_msg.child_frame_id = "base_link";
389 
390  odom_msg.twist.twist.linear.x = net_vel;
391  odom_msg.twist.twist.angular.z = alpha;
392 
393  // If not moving, trust the encoders completely
394  // otherwise set them to the ROS param
395  if (net_vel == 0 && alpha == 0)
396  {
397  odom_msg.twist.covariance[0] = odom_covariance_0_ / 1e3;
398  odom_msg.twist.covariance[7] = odom_covariance_0_ / 1e3;
399  odom_msg.twist.covariance[35] = odom_covariance_35_ / 1e6;
400  }
401  else
402  {
403  odom_msg.twist.covariance[0] = odom_covariance_0_;
404  odom_msg.twist.covariance[7] = odom_covariance_0_;
405  odom_msg.twist.covariance[35] = odom_covariance_35_;
406  }
407 
408  odom_msg.pose.pose.position.x = pos_x;
409  odom_msg.pose.pose.position.y = pos_y;
410 
411  odom_enc_pub.publish(odom_msg);
412  return;
413 }
414 
416 { // Update to publish from OdomControl
417  static ros::Time ros_start_time = ros::Time::now();
418  ros::Time ros_now_time = ros::Time::now();
419  double run_time = (ros_now_time - ros_start_time).toSec();
420  std_msgs::Float32MultiArray vel_vec;
421 
422  vel_vec.data.push_back(left_vel_filtered_);
423  vel_vec.data.push_back(left_vel_measured_);
424  vel_vec.data.push_back(left_vel_commanded_);
425  vel_vec.data.push_back(right_vel_filtered_);
426  vel_vec.data.push_back(right_vel_measured_);
427  vel_vec.data.push_back(right_vel_commanded_);
428 
429  vel_vec.data.push_back(motor_speeds_commanded_[LEFT_MOTOR_INDEX_]);
430  vel_vec.data.push_back(motor_speeds_commanded_[RIGHT_MOTOR_INDEX_]);
431 
432  vel_calc_pub.publish(vel_vec);
433 
434  return;
435 }
436 
438 {
439  rr_openrover_basic::RawRrOpenroverBasicFastRateData msg;
440 
441  msg.header.stamp = ros::Time::now();
442  msg.header.frame_id = "";
443 
444  msg.left_motor = robot_data_[i_ENCODER_INTERVAL_MOTOR_LEFT];
445  msg.right_motor = robot_data_[i_ENCODER_INTERVAL_MOTOR_RIGHT];
446  msg.flipper_motor = robot_data_[i_ENCODER_INTERVAL_MOTOR_FLIPPER];
447  fast_rate_pub.publish(msg);
449  return;
450 }
451 
453 {
454  rr_openrover_basic::RawRrOpenroverBasicMedRateData med_msg;
455  std_msgs::Bool is_charging_msg;
456 
457  med_msg.header.stamp = ros::Time::now();
458  med_msg.header.frame_id = "";
459 
460  med_msg.reg_pwr_total_current = robot_data_[i_REG_PWR_TOTAL_CURRENT];
461  med_msg.reg_motor_fb_rpm_left = robot_data_[i_REG_MOTOR_FB_RPM_LEFT];
462  med_msg.reg_motor_fb_rpm_right = robot_data_[i_REG_MOTOR_FB_RPM_RIGHT];
463  med_msg.reg_flipper_fb_position_pot1 = robot_data_[i_REG_FLIPPER_FB_POSITION_POT1];
464  med_msg.reg_flipper_fb_position_pot2 = robot_data_[i_REG_FLIPPER_FB_POSITION_POT2];
465  med_msg.reg_motor_fb_current_left = robot_data_[i_REG_MOTOR_FB_CURRENT_LEFT];
466  med_msg.reg_motor_fb_current_right = robot_data_[i_REG_MOTOR_FB_CURRENT_RIGHT];
467  med_msg.reg_motor_charger_state = robot_data_[i_REG_MOTOR_CHARGER_STATE];
468  med_msg.reg_power_a_current = robot_data_[i_REG_POWER_A_CURRENT];
469  med_msg.reg_power_b_current = robot_data_[i_REG_POWER_B_CURRENT];
470  med_msg.reg_motor_flipper_angle = robot_data_[i_REG_MOTOR_FLIPPER_ANGLE];
471  med_msg.battery_current_a = robot_data_[i_BATTERY_CURRENT_A];
472  med_msg.battery_current_b = robot_data_[i_BATTERY_CURRENT_B];
473 
474  if (robot_data_[i_REG_MOTOR_CHARGER_STATE] == 0xDADA)
475  {
476  is_charging_ = true;
477  is_charging_msg.data = true;
478  is_charging_pub.publish(is_charging_msg);
479  }
480  else
481  {
482  is_charging_ = false;
483  is_charging_msg.data = false;
484  is_charging_pub.publish(is_charging_msg);
485  }
486 
487  medium_rate_pub.publish(med_msg);
488  publish_med_rate_values_ = false;
489  return;
490 }
491 
492 rr_openrover_basic::SmartBatteryStatus interpret_battery_status(uint16_t bits)
493 {
494  rr_openrover_basic::SmartBatteryStatus status_msg;
495  status_msg.over_charged_alarm = bool(bits & 0x8000);
496  status_msg.terminate_charge_alarm = bool(bits & 0x4000);
497  status_msg.over_temp_alarm = bool(bits & 0x1000);
498  status_msg.terminate_discharge_alarm = bool(bits & 0x0800);
499  status_msg.remaining_capacity_alarm = bool(bits & 0x0200);
500  status_msg.remaining_time_alarm = bool(bits & 0x0100);
501  status_msg.initialized = bool(bits & 0x0080);
502  status_msg.discharging = bool(bits & 0x0040);
503  status_msg.fully_charged = bool(bits & 0x0020);
504  status_msg.fully_discharged = bool(bits & 0x0010);
505  return status_msg;
506 }
507 
509 {
510  rr_openrover_basic::RawRrOpenroverBasicSlowRateData slow_msg;
511  rr_openrover_basic::SmartBatteryStatus batteryStatusA;
512 
513  slow_msg.header.stamp = ros::Time::now();
514  slow_msg.header.frame_id = "";
515 
516  slow_msg.reg_motor_fault_flag_left = robot_data_[i_REG_MOTOR_FAULT_FLAG_LEFT];
517  slow_msg.reg_motor_temp_left = robot_data_[i_REG_MOTOR_TEMP_LEFT];
518  slow_msg.reg_motor_temp_right = robot_data_[i_REG_MOTOR_TEMP_RIGHT];
519  slow_msg.reg_power_bat_voltage_a = robot_data_[i_REG_POWER_BAT_VOLTAGE_A];
520  slow_msg.reg_power_bat_voltage_b = robot_data_[i_REG_POWER_BAT_VOLTAGE_B];
521  slow_msg.reg_robot_rel_soc_a = robot_data_[i_REG_ROBOT_REL_SOC_A];
522  slow_msg.reg_robot_rel_soc_b = robot_data_[i_REG_ROBOT_REL_SOC_B];
523  slow_msg.battery_mode_a = robot_data_[i_BATTERY_MODE_A];
524  slow_msg.battery_mode_b = robot_data_[i_BATTERY_MODE_B];
525  slow_msg.battery_temp_a = robot_data_[i_BATTERY_TEMP_A];
526  slow_msg.battery_temp_b = robot_data_[i_BATTERY_TEMP_B];
527  slow_msg.battery_voltage_a = robot_data_[i_BATTERY_VOLTAGE_A];
528  slow_msg.battery_voltage_b = robot_data_[i_BATTERY_VOLTAGE_B];
529  slow_msg.buildno = robot_data_[i_BUILDNO];
530 
533 
534  slow_rate_pub.publish(slow_msg);
536  return;
537 }
538 
540 {
541  std_msgs::Int32MultiArray motor_speeds_msg;
542  motor_speeds_msg.data.clear();
543  motor_speeds_msg.data.push_back(motor_speeds_commanded_[LEFT_MOTOR_INDEX_]);
544  motor_speeds_msg.data.push_back(motor_speeds_commanded_[RIGHT_MOTOR_INDEX_]);
545  motor_speeds_msg.data.push_back(motor_speeds_commanded_[FLIPPER_MOTOR_INDEX_]);
546 
547  motor_speeds_pub.publish(motor_speeds_msg);
548  return;
549 }
550 
552 { // sends serial commands stored in the 3 buffers in order of speed with fast getting highest priority
553  unsigned char param1;
554  unsigned char param2;
555  static double past_time = 0;
556 
557  while ((serial_fast_buffer_.size() > 0) || (serial_medium_buffer_.size() > 0) || (serial_slow_buffer_.size() > 0) ||
558  (serial_fan_buffer_.size() > 0))
559  {
560  // Fast data gets highest priority from being first in this if statement
561  // If the CPU running the driver can only process 60 commands / second and the fast
562  // data rate is set to 60hz, no other data will be gathered and the medium and slow Buffers
563  // will fill up and issue a warning.
564  if (serial_fast_buffer_.size() > 0)
565  {
566  param1 = 10;
567  param2 = serial_fast_buffer_.back();
568  serial_fast_buffer_.pop_back();
569  ROS_DEBUG("Its fast data's turn to be sent: %i", param2);
570  }
571  else if (serial_fan_buffer_.size() > 0)
572  {
573  param1 = 20;
574  param2 = serial_fan_buffer_.back();
575  serial_fan_buffer_.pop_back();
576  ROS_DEBUG("Its fan speed's turn to be sent: %i", param2);
577  }
578  else if (serial_medium_buffer_.size() > 0)
579  {
580  param1 = 10;
581  param2 = serial_medium_buffer_.back();
582  serial_medium_buffer_.pop_back();
583  ROS_DEBUG("Its medium data's turn to be sent: %i", param2);
584  }
585  else if (serial_slow_buffer_.size() > 0)
586  {
587  param1 = 10;
588  param2 = serial_slow_buffer_.back();
589  serial_slow_buffer_.pop_back();
590  ROS_DEBUG("Its slow data's turn to be sent: %i", param2);
591  }
592  else
593  {
594  param2 = 0;
595  param1 = 0;
596  }
597 
598  // Check param1 to determine what communication to the robot is required
599  try
600  {
601  if (param1 == 10) // Param1==10 requests data with index of param2
602  {
603  updateRobotData(param2);
604  }
605  else if (param1 == 20)
606  { // param1==20 means sending fan speed of param2
607  setParameterData(param1, param2);
608  }
609  else if (param1 == 250)
610  { // param1==250 means calibrating flipper DO NOT USE OFTEN
611  setParameterData(param1, param2);
612  }
613  else if (param1 == 0)
614  { // param1==0 means buffers are empty and doesn't need to do anything
615  }
616  else
617  {
618  throw std::string("Unknown param1. Removing parameter from buffer");
619  }
620  }
621  catch (std::string s)
622  {
623  throw;
624  }
625  catch (...)
626  {
627  throw;
628  }
629 
630  // If one of the buffers are empty, publish the values
631  if ((serial_fast_buffer_.size() == 0) && publish_fast_rate_values_)
632  {
633  ros::Time ros_now_time = ros::Time::now();
634  double now_time = ros_now_time.toSec();
635 
636  double dt = now_time - past_time;
637  past_time = now_time;
639  updateMeasuredVelocities(); // Update openrover measured velocities based on latest encoder readings
640 
645 
648 
649  publishOdometry(left_vel_measured_, right_vel_measured_); // Publish new calculated odometry
650  publishWheelVels(); // call after publishOdometry()
652  }
653  else if ((serial_medium_buffer_.size() == 0) && publish_med_rate_values_)
654  {
656  }
657  else if ((serial_slow_buffer_.size() == 0) && publish_slow_rate_values_)
658  {
660  }
661 
662  // Checks timers and subscribers
663  ros::spinOnce();
664  }
665  return;
666 }
667 
669 {
672 
673  // Bound left_encoder readings to range of normal operation.
674  if (left_enc < ENCODER_MIN)
675  {
676  left_vel_measured_ = 0;
677  }
678  else if (left_enc > ENCODER_MAX)
679  {
680  left_vel_measured_ = 0;
681  }
682  else if (motor_speeds_commanded_[LEFT_MOTOR_INDEX_] > MOTOR_NEUTRAL) // this sets direction of measured
683  {
685  }
686  else
687  {
689  }
690 
691  // Bound left_encoder readings to range of normal operation.
692  if (right_enc < ENCODER_MIN)
693  {
695  }
696  else if (right_enc > ENCODER_MAX)
697  {
699  }
700  else if (motor_speeds_commanded_[RIGHT_MOTOR_INDEX_] > MOTOR_NEUTRAL) // this sets direction of measured
701  {
703  }
704  else
705  {
707  }
708 
709  return;
710 }
711 
713 {
714  try
715  {
716  int data = getParameterData(param);
717  if (data < 0) // check if val is good (not negative) and if not, push param back to buffer
718  {
719  throw;
720  }
721 
722  robot_data_[param] = data;
723  }
724  catch (std::string s)
725  {
726  char str_ex[50];
727  sprintf(str_ex, "Failed to update param %i. ", param);
728  throw std::string(str_ex) + s;
729  }
730  return;
731 }
732 
733 bool OpenRover::sendCommand(int param1, int param2)
734 {
735  unsigned char write_buffer[SERIAL_OUT_PACKAGE_LENGTH];
736 
737  write_buffer[0] = SERIAL_START_BYTE;
738  write_buffer[1] = (unsigned char)motor_speeds_commanded_[LEFT_MOTOR_INDEX_]; // left motor
739  write_buffer[2] = (unsigned char)motor_speeds_commanded_[RIGHT_MOTOR_INDEX_]; // right motor
740  write_buffer[3] = (unsigned char)motor_speeds_commanded_[FLIPPER_MOTOR_INDEX_]; // flipper
741  write_buffer[4] = (unsigned char)param1; // Param 1: 10 to get data, 240 for low speed mode
742  write_buffer[5] = (unsigned char)param2; // Param 2:
743  // Calculate Checksum
744  write_buffer[6] =
745  (char)255 - (write_buffer[1] + write_buffer[2] + write_buffer[3] + write_buffer[4] + write_buffer[5]) % 255;
746 
747  if (!(serial_port_fd_ > 0))
748  {
749  ROS_INFO("Serial communication failed. Attempting to restart.");
750  if (!(openComs()))
751  {
752  ROS_WARN("Failed to restart serial communication.");
753  }
754  }
755 
757  {
758  char str_ex[50];
759  sprintf(str_ex, "Failed to send command: %02x,%02x,%02x,%02x,%02x,%02x,%02x", write_buffer[0], write_buffer[1],
760  write_buffer[2], write_buffer[3], write_buffer[4], write_buffer[5], write_buffer[6]);
761  throw std::string(str_ex);
762  }
763 
764  return true;
765 }
766 
768 { // only used after a send command with param1==10
769  unsigned char read_buffer[1];
770  unsigned char start_byte_read, checksum, read_checksum, data1, data2, dataNO;
771  int data;
772  if (!(serial_port_fd_ > 0))
773  {
774  ROS_INFO("Serial communication failed. Attempting to restart.");
775  if (!(openComs()))
776  {
777  ROS_WARN("Failed to restart serial communication.");
778  }
779  }
780 
781  int bits_read = read(serial_port_fd_, read_buffer, 1);
782  start_byte_read = read_buffer[0];
783 
784  read(serial_port_fd_, read_buffer, 1); // get param
785  dataNO = read_buffer[0];
786 
787  read(serial_port_fd_, read_buffer, 1); // get data1
788  data1 = read_buffer[0];
789 
790  read(serial_port_fd_, read_buffer, 1); // get data2
791  data2 = read_buffer[0];
792 
793  read(serial_port_fd_, read_buffer, 1); // get checksum
794  read_checksum = read_buffer[0];
795 
796  checksum = 255 - (dataNO + data1 + data2) % 255;
797 
798  if (!(SERIAL_START_BYTE == start_byte_read))
799  {
800  char str_ex[50];
801  sprintf(str_ex, "Received bad start byte. Received: %02x", start_byte_read);
802  tcflush(serial_port_fd_, TCIOFLUSH); // flush received buffer
803  throw std::string(str_ex);
804  }
805  else if (checksum != read_checksum)
806  {
807  char str_ex[50];
808  sprintf(str_ex, "Received bad CRC. Received: %02x,%02x,%02x,%02x,%02x", start_byte_read, dataNO, data1, data2,
809  read_checksum);
810  tcflush(serial_port_fd_, TCIOFLUSH); // flush received buffer
811  throw std::string(str_ex);
812  }
813  data = (data1 << 8) + data2;
814  return data;
815 }
816 
817 bool OpenRover::setParameterData(int param1, int param2)
818 {
819  try
820  {
821  if (!sendCommand(param1, param2))
822  {
823  throw;
824  }
825 
826  return true;
827  }
828  catch (std::string s)
829  {
830  std::string s2("setParameterData() failed. ");
831  throw(s2 + s);
832  }
833 }
834 
836 {
837  int data;
838 
839  try
840  {
841  if (!sendCommand(10, param))
842  {
843  throw;
844  }
845 
846  data = readCommand();
847 
848  if (0 > data)
849  {
850  throw;
851  }
852  return data;
853  }
854  catch (std::string s)
855  {
856  std::string s2("getParameterData() failed. "); // %i. ", param);
857  throw(s2 + s);
858  }
859 }
860 
862 {
863  ROS_INFO("Opening serial port");
864  struct termios serial_port_fd__options;
865 
866  serial_port_fd_ = ::open(port_.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
867  if (serial_port_fd_ < 0)
868  {
869  ROS_ERROR("Failed to open port: %s", strerror(errno));
870  return false;
871  }
872  if (0 > fcntl(serial_port_fd_, F_SETFL, 0))
873  {
874  ROS_ERROR("Failed to set port descriptor: %s", strerror(errno));
875  return false;
876  }
877  if (0 > tcgetattr(serial_port_fd_, &serial_port_fd__options))
878  {
879  ROS_ERROR("Failed to fetch port attributes: %s", strerror(errno));
880  return false;
881  }
882  if (0 > cfsetispeed(&serial_port_fd__options, B57600))
883  {
884  ROS_ERROR("Failed to set input baud: %s", strerror(errno));
885  return false;
886  }
887  if (0 > cfsetospeed(&serial_port_fd__options, B57600))
888  {
889  ROS_ERROR("Failed to set output baud: %s", strerror(errno));
890  return false;
891  }
892 
893  serial_port_fd__options.c_cflag |= (CREAD | CLOCAL | CS8);
894  serial_port_fd__options.c_cflag &= ~(PARODD | CRTSCTS | CSTOPB | PARENB);
895  serial_port_fd__options.c_iflag &= ~(IUCLC | IXANY | IMAXBEL | IXON | IXOFF | IUTF8 | ICRNL | INPCK); // input modes
896  serial_port_fd__options.c_oflag |= (NL0 | CR0 | TAB0 | BS0 | VT0 | FF0);
897  serial_port_fd__options.c_oflag &=
898  ~(OPOST | ONLCR | OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL | NL1 | CR1 | CR2 | TAB3 | BS1 | VT1 | FF1);
899  serial_port_fd__options.c_lflag |= (NOFLSH);
900  serial_port_fd__options.c_lflag &= ~(ICANON | IEXTEN | TOSTOP | ISIG | ECHOPRT | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE);
901  serial_port_fd__options.c_cc[VINTR] = 0x03; // INTR Character
902  serial_port_fd__options.c_cc[VQUIT] = 0x1C; // QUIT Character
903  serial_port_fd__options.c_cc[VERASE] = 0x7F; // ERASE Character
904  serial_port_fd__options.c_cc[VKILL] = 0x15; // KILL Character
905  serial_port_fd__options.c_cc[VEOF] = 0x04; // EOF Character
906  serial_port_fd__options.c_cc[VTIME] = 0x01; // Timeout in 0.1s of serial read
907  serial_port_fd__options.c_cc[VMIN] = 0; // SERIAL_IN_PACKAGE_LENGTH; //Min Number of bytes to read
908  serial_port_fd__options.c_cc[VSWTC] = 0x00;
909  serial_port_fd__options.c_cc[VSTART] = SERIAL_START_BYTE; // START Character
910  serial_port_fd__options.c_cc[VSTOP] = 0x13; // STOP character
911  serial_port_fd__options.c_cc[VSUSP] = 0x1A; // SUSP character
912  serial_port_fd__options.c_cc[VEOL] = 0x00; // EOL Character
913  serial_port_fd__options.c_cc[VREPRINT] = 0x12;
914  serial_port_fd__options.c_cc[VDISCARD] = 0x0F;
915  serial_port_fd__options.c_cc[VWERASE] = 0x17;
916  serial_port_fd__options.c_cc[VLNEXT] = 0x16;
917  serial_port_fd__options.c_cc[VEOL2] = 0x00;
918 
919  if (0 > tcsetattr(serial_port_fd_, TCSANOW, &serial_port_fd__options))
920  {
921  ROS_ERROR("Failed to set port attributes: %s", strerror(errno));
922  return false;
923  }
924  ::ioctl(serial_port_fd_, TIOCEXCL); // turn on exclusive mode
925 
926  ROS_INFO("Serial port opened");
927  is_serial_coms_open_ = true;
928  tcflush(serial_port_fd_, TCIOFLUSH); // flush received buffer
929 
930  return true;
931 }
932 
933 } // namespace openrover
934 
935 int main(int argc, char* argv[])
936 {
937  // Create ROS node
938  ros::init(argc, argv, "rr_openrover_basic_node");
939 
940  ros::NodeHandle nh("");
941  ros::NodeHandle nh_priv("~");
942  openrover::OpenRover openrover(nh, nh_priv);
943  /* if( !nh )
944  {
945  ROS_FATAL( "Failed to initialize NodeHandle" );
946  ros::shutdown( );
947  return -1;
948  }
949  if( !nh_priv )
950  {
951  ROS_FATAL( "Failed to initialize private NodeHandle" );
952  delete nh;
953  ros::shutdown( );
954  return -2;
955  }
956  if( !openrover )
957  {
958  ROS_FATAL( "Failed to initialize driver" );
959  delete nh_priv;
960  delete nh;
961  ros::shutdown( );
962  return -3;
963  }
964  */
965  if (!openrover.start())
966  {
967  ROS_FATAL("Failed to start the openrover driver");
969  }
970 
971  ros::Rate loop_rate(openrover::LOOP_RATE);
972 
973  while (ros::ok())
974  {
975  try
976  {
977  ros::spinOnce();
978  // Process Serial Buffers
979  openrover.serialManager();
980  loop_rate.sleep(); // sleeping greatly reduces CPU
981  }
982  catch (std::string s)
983  {
984  ROS_ERROR("%s", s.c_str());
985  }
986  catch (...)
987  {
988  ROS_ERROR("Unknown Exception occurred");
989  }
990  }
991  /*
992  delete openrover;
993  delete nh_priv;
994  delete nh;
995  */
996 
997  return 0;
998 }
void robotDataMediumCB(const ros::WallTimerEvent &e)
void robotDataSlowCB(const ros::WallTimerEvent &e)
msg
const int i_REG_MOTOR_FB_CURRENT_LEFT
Definition: constants.hpp:69
const int i_BATTERY_VOLTAGE_B
Definition: constants.hpp:101
const int i_REG_MOTOR_FLIPPER_ANGLE
Definition: constants.hpp:88
std::vector< unsigned char > serial_fast_buffer_
Definition: openrover.hpp:125
static tf::Quaternion createQuaternionFromRPY(double roll, double pitch, double yaw)
void robotDataFastCB(const ros::WallTimerEvent &e)
const int MOTOR_SPEED_ANGULAR_COEF_4WD_HS
Definition: constants.hpp:28
#define ROS_FATAL(...)
const int MOTOR_SPEED_LINEAR_COEF_F_HS
Definition: constants.hpp:17
std::vector< unsigned char > serial_slow_buffer_
Definition: openrover.hpp:127
const int LOOP_RATE
Definition: constants.hpp:8
const float ODOM_AXLE_TRACK_F
Definition: constants.hpp:13
const int i_REG_MOTOR_TEMP_RIGHT
Definition: constants.hpp:73
void publish(const boost::shared_ptr< M > &message) const
const int i_REG_POWER_BAT_VOLTAGE_A
Definition: constants.hpp:75
ros::NodeHandle & nh_priv_
Definition: openrover.hpp:63
const int i_ENCODER_INTERVAL_MOTOR_RIGHT
Definition: constants.hpp:78
OdomControl left_controller_
Definition: openrover.hpp:28
const int MEDIUM_SIZE
Definition: constants.hpp:129
const int i_REG_ROBOT_REL_SOC_A
Definition: constants.hpp:81
const float ODOM_AXLE_TRACK_2WD
Definition: constants.hpp:34
const int LEFT_MOTOR_INDEX_
Definition: openrover.hpp:92
rr_openrover_basic::SmartBatteryStatus interpret_battery_status(uint16_t bits)
ros::Publisher is_charging_pub
Definition: openrover.hpp:74
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:83
const int i_BATTERY_VOLTAGE_A
Definition: constants.hpp:100
const float ODOM_ENCODER_COEF_2WD
Definition: constants.hpp:33
ros::Publisher battery_status_a_pub
Definition: openrover.hpp:81
const int i_BATTERY_MODE_A
Definition: constants.hpp:95
XmlRpcServer s
int motor_speeds_commanded_[3]
Definition: openrover.hpp:91
const float ODOM_ENCODER_COEF_F
Definition: constants.hpp:12
std::string drive_type_
Definition: openrover.hpp:57
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
const int ENCODER_MIN
Definition: constants.hpp:50
ros::WallTimer medium_timer
Definition: openrover.hpp:67
const int i_ENCODER_INTERVAL_MOTOR_FLIPPER
Definition: constants.hpp:79
data
#define ROS_WARN_DELAYED_THROTTLE(rate,...)
ros::Publisher slow_rate_pub
Definition: openrover.hpp:80
void updateRobotData(int parameter)
bool publish_fast_rate_values_
Definition: openrover.hpp:45
int main(int argc, char *argv[])
const int MOTOR_SPEED_ANGULAR_COEF_F_HS
Definition: constants.hpp:18
const float ODOM_TRACTION_FACTOR_2WD
Definition: constants.hpp:36
const int i_REG_FLIPPER_FB_POSITION_POT2
Definition: constants.hpp:67
const int ROBOT_DATA_INDEX_FAST[]
Definition: constants.hpp:105
#define ROS_WARN(...)
bool publish_slow_rate_values_
Definition: openrover.hpp:47
const float ODOM_ANGULAR_COEF_4WD
Definition: constants.hpp:24
const int i_REG_MOTOR_FAULT_FLAG_LEFT
Definition: constants.hpp:71
const int RIGHT_MOTOR_INDEX_
Definition: openrover.hpp:93
const int ENCODER_MAX
Definition: constants.hpp:49
OdomControl right_controller_
Definition: openrover.hpp:29
ros::Publisher battery_status_b_pub
Definition: openrover.hpp:81
void timeoutCB(const ros::WallTimerEvent &e)
void cmdVelCB(const geometry_msgs::TwistStamped::ConstPtr &msg)
const int i_BATTERY_CURRENT_B
Definition: constants.hpp:103
const int i_REG_FLIPPER_FB_POSITION_POT1
Definition: constants.hpp:66
const int MOTOR_SPEED_MAX
Definition: constants.hpp:55
const int SERIAL_OUT_PACKAGE_LENGTH
Definition: constants.hpp:6
const float ODOM_AXLE_TRACK_4WD
Definition: constants.hpp:23
ros::Subscriber fan_speed_sub
Definition: openrover.hpp:84
const int FAST_SIZE
Definition: constants.hpp:128
ros::Publisher fast_rate_pub
Definition: openrover.hpp:78
const int i_BATTERY_MODE_B
Definition: constants.hpp:96
void fanSpeedCB(const std_msgs::Int32::ConstPtr &msg)
std::vector< unsigned char > serial_fan_buffer_
Definition: openrover.hpp:128
const int i_REG_POWER_B_CURRENT
Definition: constants.hpp:87
#define ROS_INFO(...)
const int i_BATTERY_TEMP_A
Definition: constants.hpp:97
const int i_REG_ROBOT_REL_SOC_B
Definition: constants.hpp:82
void start(bool use_control, PidGains pid_gains, int max, int min)
const int MOTOR_NEUTRAL
Definition: constants.hpp:54
const int i_BATTERY_TEMP_B
Definition: constants.hpp:98
ROSCPP_DECL bool ok()
const int i_ENCODER_INTERVAL_MOTOR_LEFT
Definition: constants.hpp:77
const int MOTOR_SPEED_ANGULAR_COEF_2WD_HS
Definition: constants.hpp:39
WallTimer createWallTimer(WallDuration period, void(T::*callback)(const WallTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
ros::Publisher vel_calc_pub
Definition: openrover.hpp:76
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
const int i_REG_POWER_BAT_VOLTAGE_B
Definition: constants.hpp:76
const int i_REG_MOTOR_FB_RPM_RIGHT
Definition: constants.hpp:65
const float ODOM_TRACTION_FACTOR_F
Definition: constants.hpp:15
bool sleep()
const int i_BATTERY_STATUS_A
Definition: constants.hpp:93
const int i_REG_MOTOR_TEMP_LEFT
Definition: constants.hpp:72
unsigned char run(bool e_stop_on, bool control_on, double commanded_vel, double measured_vel, double dt)
ros::WallTimer slow_timer
Definition: openrover.hpp:68
const float ODOM_ENCODER_COEF_4WD
Definition: constants.hpp:22
ros::Subscriber cmd_vel_sub
Definition: openrover.hpp:83
const int MOTOR_SPEED_LINEAR_COEF_4WD_HS
Definition: constants.hpp:27
ros::Publisher medium_rate_pub
Definition: openrover.hpp:79
ROSCPP_DECL void requestShutdown()
std::vector< unsigned char > serial_medium_buffer_
Definition: openrover.hpp:126
const int ROBOT_DATA_INDEX_SLOW[]
Definition: constants.hpp:119
const int ROBOT_DATA_INDEX_MEDIUM[]
Definition: constants.hpp:110
const int i_REG_PWR_TOTAL_CURRENT
Definition: constants.hpp:63
const float ODOM_ANGULAR_COEF_2WD
Definition: constants.hpp:35
bool getParam(const std::string &key, std::string &s) const
ros::WallTimer timeout_timer
Definition: openrover.hpp:69
const int SLOW_SIZE
Definition: constants.hpp:130
const int i_REG_POWER_A_CURRENT
Definition: constants.hpp:85
static Time now()
ros::WallTimer fast_timer
Definition: openrover.hpp:66
bool sendCommand(int param1, int param2)
const int MOTOR_DEADBAND
Definition: constants.hpp:53
ros::Publisher odom_enc_pub
Definition: openrover.hpp:72
const float ODOM_TRACTION_FACTOR_4WD
Definition: constants.hpp:25
OpenRover(ros::NodeHandle &nh, ros::NodeHandle &nh_priv)
int getParameterData(int parameter)
const int i_REG_MOTOR_FB_CURRENT_RIGHT
Definition: constants.hpp:70
bool setParameterData(int param1, int param2)
const int MOTOR_SPEED_MIN
Definition: constants.hpp:56
ros::Publisher motor_speeds_pub
Definition: openrover.hpp:75
const float ODOM_ANGULAR_COEF_F
Definition: constants.hpp:14
const int i_REG_MOTOR_FB_RPM_LEFT
Definition: constants.hpp:64
ROSCPP_DECL void spinOnce()
const int MOTOR_SPEED_LINEAR_COEF_2WD_HS
Definition: constants.hpp:38
const int i_BATTERY_STATUS_B
Definition: constants.hpp:94
void publishOdometry(float left_vel, float right_vel)
const int FLIPPER_MOTOR_INDEX_
Definition: openrover.hpp:94
geometry_msgs::Twist cmd_vel_commanded_
Definition: openrover.hpp:123
std::string port_
Definition: openrover.hpp:56
#define ROS_ERROR(...)
const unsigned char SERIAL_START_BYTE
Definition: constants.hpp:5
const int i_BATTERY_CURRENT_A
Definition: constants.hpp:102
const int i_BUILDNO
Definition: constants.hpp:84
#define ROS_DEBUG(...)


rr_openrover_basic
Author(s): Jack Kilian
autogenerated on Fri Jan 17 2020 03:18:17