driver.cpp
Go to the documentation of this file.
1 #include <ros/ros.h>
2 #include <ros/console.h>
3 #include <serial/serial.h>
4 #include <signal.h>
5 #include <string>
6 #include <sstream>
7 
8 
9 #define DELTAT(_nowtime,_thentime) ((_thentime>_nowtime)?((0xffffffff-_thentime)+_nowtime):(_nowtime-_thentime))
10 
11 
12 //
13 // cmd_vel subscriber
14 //
15 
16 // Define following to enable cmdvel debug output
17 #define _CMDVEL_DEBUG
18 
19 // Define following to enable motor test mode
20 // Runs both motors in forward direction at 10% of configured maximum (rpms in close_loop mode, power in open_loop mode)
21 // If configured correctly robot should translate forward in a straight line
22 //#define _CMDVEL_FORCE_RUN
23 
24 #include <geometry_msgs/Twist.h>
25 #include <nav_msgs/Odometry.h>
27 
28 
29 //
30 // odom publisher
31 //
32 
33 // Define following to enable odom debug output
34 #define _ODOM_DEBUG
35 
36 // Define following to publish additional sensor information
37 #define _ODOM_SENSORS
38 
39 // Define following to enable service for returning covariance
40 //#define _ODOM_COVAR_SERVER
41 
42 #define NORMALIZE(_z) atan2(sin(_z), cos(_z))
43 
44 #include <tf/tf.h>
45 #include <geometry_msgs/Quaternion.h>
47 #include <geometry_msgs/TransformStamped.h>
48 #include <nav_msgs/Odometry.h>
49 #ifdef _ODOM_SENSORS
50 #include <std_msgs/Float32.h>
51 #include <roboteq_diff_msgs/Duplex.h>
52 #endif
53 #ifdef _ODOM_COVAR_SERVER
54 #include "roboteq_diff_msgs/OdometryCovariances.h"
55 #include "rogoteq_diff_msgs/RequestOdometryCovariances.h"
56 #endif
57 
58 
59 
60 void mySigintHandler(int sig)
61 {
62  ROS_INFO("Received SIGINT signal, shutting down...");
63  ros::shutdown();
64 }
65 
66 
67 uint32_t millis()
68 {
69  ros::WallTime walltime = ros::WallTime::now();
70 // return (uint32_t)((walltime._sec*1000 + walltime.nsec/1000000.0) + 0.5);
71 // return (uint32_t)(walltime.toNSec()/1000000.0+0.5);
72  return (uint32_t)(walltime.toNSec()/1000000);
73 }
74 
75 class MainNode
76 {
77 
78 public:
79  MainNode();
80 
81 public:
82 
83  //
84  // cmd_vel subscriber
85  //
86  void cmdvel_callback( const geometry_msgs::Twist& twist_msg);
87  void cmdvel_setup();
88  void cmdvel_loop();
89  void cmdvel_run();
90 
91  //
92  // odom publisher
93  //
94  void odom_setup();
95  void odom_stream();
96  void odom_loop();
97  //void odom_hs_run();
98  void odom_ms_run();
99  void odom_ls_run();
100  void odom_publish();
101 #ifdef _ODOM_COVAR_SERVER
102  void odom_covar_callback(const roboteq_diff_msgs::RequestOdometryCovariancesRequest& req, roboteq_diff_msgs::RequestOdometryCovariancesResponse& res);
103 #endif
104 
105  int run();
106 
107 protected:
109 
111 
112  uint32_t starttime;
113  uint32_t hstimer;
114  uint32_t mstimer;
115  uint32_t lstimer;
116 
117  //
118  // cmd_vel subscriber
119  //
121 
122  //
123  // odom publisher
124  //
125  geometry_msgs::TransformStamped tf_msg;
127  nav_msgs::Odometry odom_msg;
129 
130 #ifdef _ODOM_SENSORS
131  std_msgs::Float32 voltage_msg;
133  roboteq_diff_msgs::Duplex current_msg;
135  std_msgs::Float32 energy_msg;
137  std_msgs::Float32 temperature_msg;
139 #endif
140 
141  // buffer for reading encoder counts
142  int odom_idx;
143  char odom_buf[24];
144 
145  // toss out initial encoder readings
147 
150 
151  float odom_x;
152  float odom_y;
153  float odom_yaw;
154  float odom_last_x;
155  float odom_last_y;
157 
158  uint32_t odom_last_time;
159 
160 #ifdef _ODOM_SENSORS
161  float voltage;
164  float energy;
165  float temperature;
167 #endif
168 
169  // settings
171  std::string odom_frame;
172  std::string base_frame;
173  std::string cmdvel_topic;
174  std::string odom_topic;
175  std::string port;
176  int baud;
177  bool open_loop;
179  double track_width;
182  double max_amps;
183  int max_rpm;
184 
185 };
186 
188  starttime(0),
189  hstimer(0),
190  mstimer(0),
191  odom_idx(0),
195  odom_x(0.0),
196  odom_y(0.0),
197  odom_yaw(0.0),
198  odom_last_x(0.0),
199  odom_last_y(0.0),
200  odom_last_yaw(0.0),
201  odom_last_time(0),
202 #ifdef _ODOM_SENSORS
203  voltage(0.0),
204  current_right(0.0),
205  current_left(0.0),
206  energy(0.0),
207  temperature(0.0),
209 #endif
210  pub_odom_tf(true),
211  open_loop(false),
212  baud(115200),
214  track_width(0),
215  encoder_ppr(0),
216  encoder_cpr(0),
217  max_amps(0.0),
218  max_rpm(0)
219 {
220 
221 
222  // CBA Read local params (from launch file)
223  ros::NodeHandle nhLocal("~");
224  nhLocal.param("pub_odom_tf", pub_odom_tf, true);
225  ROS_INFO_STREAM("pub_odom_tf: " << pub_odom_tf);
226  nhLocal.param<std::string>("odom_frame", odom_frame, "odom");
227  ROS_INFO_STREAM("odom_frame: " << odom_frame);
228  nhLocal.param<std::string>("base_frame", base_frame, "base_link");
229  ROS_INFO_STREAM("base_frame: " << base_frame);
230  nhLocal.param<std::string>("cmdvel_topic", cmdvel_topic, "cmd_vel");
231  ROS_INFO_STREAM("cmdvel_topic: " << cmdvel_topic);
232  nhLocal.param<std::string>("odom_topic", odom_topic, "odom");
233  ROS_INFO_STREAM("odom_topic: " << odom_topic);
234  nhLocal.param<std::string>("port", port, "/dev/ttyACM0");
235  ROS_INFO_STREAM("port: " << port);
236  nhLocal.param("baud", baud, 115200);
237  ROS_INFO_STREAM("baud: " << baud);
238  nhLocal.param("open_loop", open_loop, false);
239  ROS_INFO_STREAM("open_loop: " << open_loop);
240  nhLocal.param("wheel_circumference", wheel_circumference, 0.3192);
241  ROS_INFO_STREAM("wheel_circumference: " << wheel_circumference);
242  nhLocal.param("track_width", track_width, 0.4318);
243  ROS_INFO_STREAM("track_width: " << track_width);
244  nhLocal.param("encoder_ppr", encoder_ppr, 900);
245  ROS_INFO_STREAM("encoder_ppr: " << encoder_ppr);
246  nhLocal.param("encoder_cpr", encoder_cpr, 3600);
247  ROS_INFO_STREAM("encoder_cpr: " << encoder_cpr);
248  nhLocal.param("max_amps", max_amps, 5.0);
249  ROS_INFO_STREAM("max_amps: " << max_amps);
250  nhLocal.param("max_rpm", max_rpm, 100);
251  ROS_INFO_STREAM("max_rpm: " << max_rpm);
252 
253 }
254 
255 
256 //
257 // cmd_vel subscriber
258 //
259 
260 void MainNode::cmdvel_callback( const geometry_msgs::Twist& twist_msg)
261 {
262 
263  // wheel speed (m/s)
264  float right_speed = twist_msg.linear.x + track_width * twist_msg.angular.z / 2.0;
265  float left_speed = twist_msg.linear.x - track_width * twist_msg.angular.z / 2.0;
266 #ifdef _CMDVEL_DEBUG
267 ROS_DEBUG_STREAM("cmdvel speed right: " << right_speed << " left: " << left_speed);
268 #endif
269 
270  std::stringstream right_cmd;
271  std::stringstream left_cmd;
272 
273  if (open_loop)
274  {
275  // motor power (scale 0-1000)
276  int32_t right_power = right_speed / wheel_circumference * 60.0 / max_rpm * 1000.0;
277  int32_t left_power = left_speed / wheel_circumference * 60.0 / max_rpm * 1000.0;
278 #ifdef _CMDVEL_DEBUG
279 ROS_DEBUG_STREAM("cmdvel power right: " << right_power << " left: " << left_power);
280 #endif
281  right_cmd << "!G 1 " << right_power << "\r";
282  left_cmd << "!G 2 " << left_power << "\r";
283  }
284  else
285  {
286  // motor speed (rpm)
287  int32_t right_rpm = right_speed / wheel_circumference * 60.0;
288  int32_t left_rpm = left_speed / wheel_circumference * 60.0;
289 #ifdef _CMDVEL_DEBUG
290 ROS_DEBUG_STREAM("cmdvel rpm right: " << right_rpm << " left: " << left_rpm);
291 #endif
292  right_cmd << "!S 1 " << right_rpm << "\r";
293  left_cmd << "!S 2 " << left_rpm << "\r";
294  }
295 
296 
297 #ifndef _CMDVEL_FORCE_RUN
298  controller.write(right_cmd.str());
299  controller.write(left_cmd.str());
300  controller.flush();
301 #endif
302 }
303 
305 {
306 
307  // stop motors
308  controller.write("!G 1 0\r");
309  controller.write("!G 2 0\r");
310  controller.write("!S 1 0\r");
311  controller.write("!S 2 0\r");
312  controller.flush();
313 
314  // disable echo
315  controller.write("^ECHOF 1\r");
316  controller.flush();
317 
318  // enable watchdog timer (1000 ms)
319  controller.write("^RWD 1000\r");
320 
321  // set motor operating mode (1 for closed-loop speed)
322  if (open_loop)
323  {
324  // open-loop speed mode
325  controller.write("^MMOD 1 0\r");
326  controller.write("^MMOD 2 0\r");
327  }
328  else
329  {
330  // closed-loop speed mode
331  controller.write("^MMOD 1 1\r");
332  controller.write("^MMOD 2 1\r");
333  }
334 
335  // set motor amps limit (A * 10)
336  std::stringstream right_ampcmd;
337  std::stringstream left_ampcmd;
338  right_ampcmd << "^ALIM 1 " << (int)(max_amps * 10) << "\r";
339  left_ampcmd << "^ALIM 2 " << (int)(max_amps * 10) << "\r";
340  controller.write(right_ampcmd.str());
341  controller.write(left_ampcmd.str());
342 
343  // set max speed (rpm) for relative speed commands
344  std::stringstream right_rpmcmd;
345  std::stringstream left_rpmcmd;
346  right_rpmcmd << "^MXRPM 1 " << max_rpm << "\r";
347  left_rpmcmd << "^MXRPM 2 " << max_rpm << "\r";
348  controller.write(right_rpmcmd.str());
349  controller.write(left_rpmcmd.str());
350 
351  // set max acceleration rate (2000 rpm/s * 10)
352  controller.write("^MAC 1 20000\r");
353  controller.write("^MAC 2 20000\r");
354 
355  // set max deceleration rate (2000 rpm/s * 10)
356  controller.write("^MDEC 1 20000\r");
357  controller.write("^MDEC 2 20000\r");
358 
359  // set PID parameters (gain * 10)
360  controller.write("^KP 1 10\r");
361  controller.write("^KP 2 10\r");
362  controller.write("^KI 1 80\r");
363  controller.write("^KI 2 80\r");
364  controller.write("^KD 1 0\r");
365  controller.write("^KD 2 0\r");
366 
367  // set encoder mode (18 for feedback on motor1, 34 for feedback on motor2)
368  controller.write("^EMOD 1 18\r");
369  controller.write("^EMOD 2 34\r");
370 
371  // set encoder counts (ppr)
372  std::stringstream right_enccmd;
373  std::stringstream left_enccmd;
374  right_enccmd << "^EPPR 1 " << encoder_ppr << "\r";
375  left_enccmd << "^EPPR 2 " << encoder_ppr << "\r";
376  controller.write(right_enccmd.str());
377  controller.write(left_enccmd.str());
378 
379  controller.flush();
380 
381  ROS_INFO_STREAM("Subscribing to topic " << cmdvel_topic);
383 
384 }
385 
387 {
388 }
389 
391 {
392 #ifdef _CMDVEL_FORCE_RUN
393  if (open_loop)
394  {
395  controller.write("!G 1 100\r");
396  controller.write("!G 2 100\r");
397  }
398  else
399  {
400  std::stringstream right_cmd;
401  std::stringstream left_cmd;
402  right_cmd << "!S 1 " << (int)(max_rpm * 0.1) << "\r";
403  left_cmd << "!S 2 " << (int)(max_rpm * 0.1) << "\r";
404  controller.write(right_cmd.str());
405  controller.write(left_cmd.str());
406  }
407  controller.flush();
408 #endif
409 }
410 
411 
412 //
413 // odom publisher
414 //
415 
416 #ifdef _ODOM_COVAR_SERVER
417 void MainNode::odom_covar_callback(const roboteq_diff_msgs::RequestOdometryCovariancesRequest& req, roboteq_diff_msgs::RequestOdometryCovariancesResponse& res)
418 {
419  res.odometry_covariances.pose.pose.covariance[0] = 0.001;
420  res.odometry_covariances.pose.pose.covariance[7] = 0.001;
421  res.odometry_covariances.pose.pose.covariance[14] = 1000000;
422  res.odometry_covariances.pose.pose.covariance[21] = 1000000;
423  res.odometry_covariances.pose.pose.covariance[28] = 1000000;
424  res.odometry_covariances.pose.pose.covariance[35] = 1000;
425 
426  res.odometry_covariances.twist.twist.covariance[0] = 0.001;
427  res.odometry_covariances.twist.twist.covariance[7] = 0.001;
428  res.odometry_covariances.twist.twist.covariance[14] = 1000000;
429  res.odometry_covariances.twist.twist.covariance[21] = 1000000;
430  res.odometry_covariances.twist.twist.covariance[28] = 1000000;
431  res.odometry_covariances.twist.twist.covariance[35] = 1000;
432 }
433 #endif
434 
435 /*
436  position.pose.covariance = boost::assign::list_of(1e-3) (0) (0) (0) (0) (0)
437  (0) (1e-3) (0) (0) (0) (0)
438  (0) (0) (1e6) (0) (0) (0)
439  (0) (0) (0) (1e6) (0) (0)
440  (0) (0) (0) (0) (1e6) (0)
441  (0) (0) (0) (0) (0) (1e3) ;
442 
443  position.twist.covariance = boost::assign::list_of(1e-3) (0) (0) (0) (0) (0)
444  (0) (1e-3) (0) (0) (0) (0)
445  (0) (0) (1e6) (0) (0) (0)
446  (0) (0) (0) (1e6) (0) (0)
447  (0) (0) (0) (0) (1e6) (0)
448  (0) (0) (0) (0) (0) (1e3) ;
449 
450 To estimate velocity covariance you should know TICKSMM (128) and SIPCYCLE (100) parameters of your robot (written in your robots flash memory and not accessible with Aria). First parameter tells you how many encoder impulses (count) gets generated by your robot's forward movement of 1 mm. Second parameter tells you number of milliseconds between two consecutive Server Information Packets from your robot. The values in the parentheses are for P3-DX (ARCOS).
451 
452 So an error in determining velocity could come from missing an encoder impulse in a cycle. This would result in 1/TICKSMM/SIPCYCLE velocity error (mm/ms or m/s) for one wheel. For P3-DX parameters above, this value is 7.8125e-05. Note that you would err by the same absolute amount of velocity in the next cycle. Gearbox also plays a role in velocity error, but you would need to measure to find the exact amount. As a rule of thumb, I would at least double the previous amount in order to include gearbox error.
453 
454 Now that we have determined maximum error of a single wheel's (transversal) velocity, i.e. we expect 99.7% of errors to be less than this number, we can determine sigma = max_err/3 and C = sigma^2. Translational and rotational velocities are determined from left and right wheel velocities like this:
455 
456 v = (v_R + v_L)/2
457 
458 w = (v_R - v_L)/(2d)
459 
460 So the covariance for transversal velocity would be (1/2)^2 2C and the covariance for rotational velocity would be (1/(2d))^2 2C. The d parameter is 1/DiffConvFactor and is accessible from Aria (ArRobot::getDiffConvFactor()).
461 
462 */
463 
465 {
466 
467  if ( pub_odom_tf )
468  {
469  ROS_INFO("Broadcasting odom tf");
470 // odom_broadcaster.init(nh); // ???
471  }
472 
473  ROS_INFO_STREAM("Publishing to topic " << odom_topic);
474  odom_pub = nh.advertise<nav_msgs::Odometry>(odom_topic, 1000);
475 
476 #ifdef _ODOM_COVAR_SERVER
477  ROS_INFO("Advertising service on roboteq/odom_covar_srv");
478  odom_covar_server = nh.advertiseService("roboteq/odom_covar_srv", &MainNode::odom_covar_callback, this);
479 #endif
480 
481 #ifdef _ODOM_SENSORS
482  ROS_INFO("Publishing to topic roboteq/voltage");
483  voltage_pub = nh.advertise<std_msgs::Float32>("roboteq/voltage", 1000);
484  ROS_INFO("Publishing to topic roboteq/current");
485  current_pub = nh.advertise<roboteq_diff_msgs::Duplex>("roboteq/current", 1000);
486  ROS_INFO("Publishing to topic roboteq/energy");
487  energy_pub = nh.advertise<std_msgs::Float32>("roboteq/energy", 1000);
488  ROS_INFO("Publishing to topic roboteq/temperature");
489  temperature_pub = nh.advertise<std_msgs::Float32>("roboteq/temperature", 1000);
490 #endif
491 
492  tf_msg.header.seq = 0;
493  tf_msg.header.frame_id = odom_frame;
494  tf_msg.child_frame_id = base_frame;
495 
496  odom_msg.header.seq = 0;
497  odom_msg.header.frame_id = odom_frame;
498  odom_msg.child_frame_id = base_frame;
499 
500  odom_msg.pose.covariance.assign(0);
501  odom_msg.pose.covariance[0] = 0.001;
502  odom_msg.pose.covariance[7] = 0.001;
503  odom_msg.pose.covariance[14] = 1000000;
504  odom_msg.pose.covariance[21] = 1000000;
505  odom_msg.pose.covariance[28] = 1000000;
506  odom_msg.pose.covariance[35] = 1000;
507 
508  odom_msg.twist.covariance.assign(0);
509  odom_msg.twist.covariance[0] = 0.001;
510  odom_msg.twist.covariance[7] = 0.001;
511  odom_msg.twist.covariance[14] = 1000000;
512  odom_msg.twist.covariance[21] = 1000000;
513  odom_msg.twist.covariance[28] = 1000000;
514  odom_msg.twist.covariance[35] = 1000;
515 
516 #ifdef _ODOM_SENSORS
517 // voltage_msg.header.seq = 0;
518 // voltage_msg.header.frame_id = 0;
519 // current_msg.header.seq = 0;
520 // current_msg.header.frame_id = 0;
521 // energy_msg.header.seq = 0;
522 // energy_msg.header.frame_id = 0;
523 // temperature_msg.header.seq = 0;
524 // temperature_msg.header.frame_id = 0;
525 #endif
526 
527  // start encoder streaming
528  odom_stream();
529 
531 #ifdef _ODOM_SENSORS
533 #endif
534 }
535 
537 {
538 
539 #ifdef _ODOM_SENSORS
540  // start encoder and current output (30 hz)
541  // doubling frequency since one value is output at each cycle
542 // controller.write("# C_?CR_?BA_# 17\r");
543  // start encoder, current and voltage output (30 hz)
544  // tripling frequency since one value is output at each cycle
545  controller.write("# C_?CR_?BA_?V_# 11\r");
546 #else
547 // // start encoder output (10 hz)
548 // controller.write("# C_?CR_# 100\r");
549  // start encoder output (30 hz)
550  controller.write("# C_?CR_# 33\r");
551 // // start encoder output (50 hz)
552 // controller.write("# C_?CR_# 20\r");
553 #endif
554  controller.flush();
555 
556 }
557 
559 {
560 
561  uint32_t nowtime = millis();
562 
563  // if we haven't received encoder counts in some time then restart streaming
564  if( DELTAT(nowtime,odom_last_time) >= 1000 )
565  {
566  odom_stream();
567  odom_last_time = nowtime;
568  }
569 
570  // read sensor data stream from motor controller
571  if (controller.available())
572  {
573  char ch = 0;
574  if ( controller.read((uint8_t*)&ch, 1) == 0 )
575  return;
576  if (ch == '\r')
577  {
578  odom_buf[odom_idx] = 0;
579 #ifdef _ODOM_DEBUG
580 //ROS_DEBUG_STREAM( "line: " << odom_buf );
581 #endif
582  // CR= is encoder counts
583  if ( odom_buf[0] == 'C' && odom_buf[1] == 'R' && odom_buf[2] == '=' )
584  {
585  int delim;
586  for ( delim = 3; delim < odom_idx; delim++ )
587  {
588  if ( odom_encoder_toss > 0 )
589  {
591  break;
592  }
593  if (odom_buf[delim] == ':')
594  {
595  odom_buf[delim] = 0;
596  odom_encoder_right = (int32_t)strtol(odom_buf+3, NULL, 10);
597  odom_encoder_left = (int32_t)strtol(odom_buf+delim+1, NULL, 10);
598 #ifdef _ODOM_DEBUG
599 ROS_DEBUG_STREAM("encoder right: " << odom_encoder_right << " left: " << odom_encoder_left);
600 #endif
601  odom_publish();
602  break;
603  }
604  }
605  }
606 #ifdef _ODOM_SENSORS
607  // V= is voltages
608  else if ( odom_buf[0] == 'V' && odom_buf[1] == '=' )
609  {
610  int count = 0;
611  int start = 2;
612  for ( int delim = 2; delim <= odom_idx; delim++ )
613  {
614  if (odom_buf[delim] == ':' || odom_buf[delim] == 0)
615  {
616  odom_buf[delim] = 0;
617 /*
618  switch (count)
619  {
620  case 0:
621 // odom_internal_voltage = (float)strtol(odom_buf+start, NULL, 10) / 10.0;
622  break;
623  case 1:
624  voltage = (float)strtol(odom_buf+start, NULL, 10) / 10.0;
625  break;
626  case 2:
627 // odom_aux_voltage = (float)strtol(odom_buf+start, NULL, 1000.0);
628  break;
629  }
630 */
631  if ( count == 1 )
632  {
633  voltage = (float)strtol(odom_buf+start, NULL, 10) / 10.0;
634 #ifdef _ODOM_DEBUG
635 //ROS_DEBUG_STREAM("voltage: " << voltage);
636 #endif
637  break;
638  }
639  start = delim + 1;
640  count++;
641  }
642  }
643  }
644  // BA= is motor currents
645  else if ( odom_buf[0] == 'B' && odom_buf[1] == 'A' && odom_buf[2] == '=' )
646  {
647  int delim;
648  for ( delim = 3; delim < odom_idx; delim++ )
649  {
650  if (odom_buf[delim] == ':')
651  {
652  odom_buf[delim] = 0;
653  current_right = (float)strtol(odom_buf+3, NULL, 10) / 10.0;
654  current_left = (float)strtol(odom_buf+delim+1, NULL, 10) / 10.0;
655 #ifdef _ODOM_DEBUG
656 //ROS_DEBUG_STREAM("current right: " << current_right << " left: " << current_left);
657 #endif
658 
659  // determine delta time in seconds
660  float dt = (float)DELTAT(nowtime,current_last_time) / 1000.0;
661  current_last_time = nowtime;
662  energy += (current_right + current_left) * dt / 3600.0;
663  break;
664  }
665  }
666  }
667 #endif
668  odom_idx = 0;
669  }
670  else if ( odom_idx < (sizeof(odom_buf)-1) )
671  {
672  odom_buf[odom_idx++] = ch;
673  }
674  }
675 }
676 
677 //void MainNode::odom_hs_run()
678 //{
679 //}
680 
682 {
683 
684 #ifdef _ODOM_SENSORS
685 // current_msg.header.seq++;
686 // current_msg.header.stamp = ros::Time::now();
690 #endif
691 
692 }
693 
695 {
696 
697 #ifdef _ODOM_SENSORS
698 // voltage_msg.header.seq++;
699 // voltage_msg.header.stamp = ros::Time::now();
700  voltage_msg.data = voltage;
702 // energy_msg.header.seq++;
703 // energy_msg.header.stamp = ros::Time::now();
704  energy_msg.data = energy;
706 // temperature_msg.header.seq++;
707 // temperature_msg.header.stamp = ros::Time::now();
710 #endif
711 
712 }
713 
715 {
716 
717  // determine delta time in seconds
718  uint32_t nowtime = millis();
719  float dt = (float)DELTAT(nowtime,odom_last_time) / 1000.0;
720  odom_last_time = nowtime;
721 
722 #ifdef _ODOM_DEBUG
723 /*
724 ROS_DEBUG("right: ");
725 ROS_DEBUG(odom_encoder_right);
726 ROS_DEBUG(" left: ");
727 ROS_DEBUG(odom_encoder_left);
728 ROS_DEBUG(" dt: ");
729 ROS_DEBUG(dt);
730 ROS_DEBUG("");
731 */
732 #endif
733 
734  // determine deltas of distance and angle
735  float linear = ((float)odom_encoder_right / (float)encoder_cpr * wheel_circumference + (float)odom_encoder_left / (float)encoder_cpr * wheel_circumference) / 2.0;
736 // float angular = ((float)odom_encoder_right / (float)encoder_cpr * wheel_circumference - (float)odom_encoder_left / (float)encoder_cpr * wheel_circumference) / track_width * -1.0;
737  float angular = ((float)odom_encoder_right / (float)encoder_cpr * wheel_circumference - (float)odom_encoder_left / (float)encoder_cpr * wheel_circumference) / track_width;
738 #ifdef _ODOM_DEBUG
739 /*
740 ROS_DEBUG("linear: ");
741 ROS_DEBUG(linear);
742 ROS_DEBUG(" angular: ");
743 ROS_DEBUG(angular);
744 ROS_DEBUG("");
745 */
746 #endif
747 
748  // Update odometry
749  odom_x += linear * cos(odom_yaw); // m
750  odom_y += linear * sin(odom_yaw); // m
751  odom_yaw = NORMALIZE(odom_yaw + angular); // rad
752 #ifdef _ODOM_DEBUG
753 //ROS_DEBUG_STREAM( "odom x: " << odom_x << " y: " << odom_y << " yaw: " << odom_yaw );
754 #endif
755 
756  // Calculate velocities
757  float vx = (odom_x - odom_last_x) / dt;
758  float vy = (odom_y - odom_last_y) / dt;
759  float vyaw = (odom_yaw - odom_last_yaw) / dt;
760 #ifdef _ODOM_DEBUG
761 //ROS_DEBUG_STREAM( "velocity vx: " << odom_x << " vy: " << odom_y << " vyaw: " << odom_yaw );
762 #endif
766 #ifdef _ODOM_DEBUG
767 /*
768 ROS_DEBUG("vx: ");
769 ROS_DEBUG(vx);
770 ROS_DEBUG(" vy: ");
771 ROS_DEBUG(vy);
772 ROS_DEBUG(" vyaw: ");
773 ROS_DEBUG(vyaw);
774 ROS_DEBUG("");
775 */
776 #endif
777 
778  geometry_msgs::Quaternion quat = tf::createQuaternionMsgFromYaw(odom_yaw);
779 
780  if ( pub_odom_tf )
781  {
782  tf_msg.header.seq++;
783  tf_msg.header.stamp = ros::Time::now();
784  tf_msg.transform.translation.x = odom_x;
785  tf_msg.transform.translation.y = odom_y;
786  tf_msg.transform.translation.z = 0.0;
787  tf_msg.transform.rotation = quat;
789  }
790 
791  odom_msg.header.seq++;
792  odom_msg.header.stamp = ros::Time::now();
793  odom_msg.pose.pose.position.x = odom_x;
794  odom_msg.pose.pose.position.y = odom_y;
795  odom_msg.pose.pose.position.z = 0.0;
796  odom_msg.pose.pose.orientation = quat;
797  odom_msg.twist.twist.linear.x = vx;
798  odom_msg.twist.twist.linear.y = vy;
799  odom_msg.twist.twist.linear.z = 0.0;
800  odom_msg.twist.twist.angular.x = 0.0;
801  odom_msg.twist.twist.angular.y = 0.0;
802  odom_msg.twist.twist.angular.z = vyaw;
804 
805 }
806 
807 
809 {
810 
811  ROS_INFO("Beginning setup...");
812 
816  controller.setTimeout(timeout);
817 
818  // TODO: support automatic re-opening of port after disconnection
819  while ( ros::ok() )
820  {
821  ROS_INFO_STREAM("Opening serial port on " << port << " at " << baud << "..." );
822  try
823  {
824  controller.open();
825  if ( controller.isOpen() )
826  {
827  ROS_INFO("Successfully opened serial port");
828  break;
829  }
830  }
831  catch (serial::IOException e)
832  {
833  ROS_WARN_STREAM("serial::IOException: " << e.what());
834  }
835  ROS_WARN("Failed to open serial port");
836  sleep( 5 );
837  }
838 
839  cmdvel_setup();
840  odom_setup();
841 
842  starttime = millis();
843  hstimer = starttime;
844  mstimer = starttime;
845  lstimer = starttime;
846 
847 // ros::Rate loop_rate(10);
848 
849  ROS_INFO("Beginning looping...");
850 
851  while (ros::ok())
852  {
853 
854  cmdvel_loop();
855  odom_loop();
856 
857  uint32_t nowtime = millis();
858 //ROS_INFO_STREAM("loop nowtime: " << nowtime << " lstimer: " << lstimer << " delta: " << DELTAT(nowtime,lstimer) << " / " << (nowtime-lstimer));
859 //uint32_t delta = DELTAT(nowtime,lstimer);
860 //ROS_INFO_STREAM("loop nowtime: " << nowtime << " lstimer: " << lstimer << " delta: " << delta << " / " << (nowtime-lstimer));
861 
862 // // Handle 50 Hz publishing
863 // if (DELTAT(nowtime,hstimer) >= 20)
864  // Handle 30 Hz publishing
865  if (DELTAT(nowtime,hstimer) >= 33)
866  {
867  hstimer = nowtime;
868 // odom_hs_run();
869  }
870 
871  // Handle 10 Hz publishing
872  if (DELTAT(nowtime,mstimer) >= 100)
873  {
874  mstimer = nowtime;
875  cmdvel_run();
876  odom_ms_run();
877  }
878 
879  // Handle 1 Hz publishing
880  if (DELTAT(nowtime,lstimer) >= 1000)
881  {
882  lstimer = nowtime;
883  odom_ls_run();
884  }
885 
886  ros::spinOnce();
887 
888 // loop_rate.sleep();
889  }
890 
891  if ( controller.isOpen() )
892  controller.close();
893 
894  ROS_INFO("Exiting");
895 
896  return 0;
897 }
898 
899 int main(int argc, char **argv)
900 {
901 
902  ros::init(argc, argv, "main_node");
903 
904  MainNode node;
905 
906  // Override the default ros sigint handler.
907  // This must be set after the first NodeHandle is created.
908  signal(SIGINT, mySigintHandler);
909 
910  return node.run();
911 }
912 
int baud
Definition: driver.cpp:176
timeout
std::string port
Definition: driver.cpp:175
size_t available()
void odom_stream()
Definition: driver.cpp:536
#define NORMALIZE(_z)
Definition: driver.cpp:42
ros::Publisher voltage_pub
Definition: driver.cpp:132
#define DELTAT(_nowtime, _thentime)
Definition: driver.cpp:9
void publish(const boost::shared_ptr< M > &message) const
void odom_ls_run()
Definition: driver.cpp:694
char odom_buf[24]
Definition: driver.cpp:143
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
float current_right
Definition: driver.cpp:162
ros::Publisher energy_pub
Definition: driver.cpp:136
#define _ODOM_SENSORS
Definition: driver.cpp:37
void setTimeout(Timeout &timeout)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
float odom_last_y
Definition: driver.cpp:155
void setBaudrate(uint32_t baudrate)
void cmdvel_run()
Definition: driver.cpp:390
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
#define ROS_WARN(...)
std_msgs::Float32 temperature_msg
Definition: driver.cpp:137
geometry_msgs::TransformStamped tf_msg
Definition: driver.cpp:125
int encoder_ppr
Definition: driver.cpp:180
float odom_x
Definition: driver.cpp:151
int32_t odom_encoder_left
Definition: driver.cpp:148
std_msgs::Float32 energy_msg
Definition: driver.cpp:135
int max_rpm
Definition: driver.cpp:183
ros::Publisher temperature_pub
Definition: driver.cpp:138
double track_width
Definition: driver.cpp:179
float odom_last_x
Definition: driver.cpp:154
int run()
Definition: driver.cpp:808
ros::NodeHandle nh
Definition: driver.cpp:108
int main(int argc, char **argv)
Definition: driver.cpp:899
void cmdvel_callback(const geometry_msgs::Twist &twist_msg)
Definition: driver.cpp:260
float temperature
Definition: driver.cpp:165
float energy
Definition: driver.cpp:164
nav_msgs::Odometry odom_msg
Definition: driver.cpp:127
void odom_loop()
Definition: driver.cpp:558
#define ROS_INFO(...)
serial::Serial controller
Definition: driver.cpp:110
bool param(const std::string &param_name, T &param_val, const T &default_val) const
std_msgs::Float32 voltage_msg
Definition: driver.cpp:131
float current_left
Definition: driver.cpp:163
std::string odom_topic
Definition: driver.cpp:174
tf::TransformBroadcaster odom_broadcaster
Definition: driver.cpp:126
ROSCPP_DECL bool ok()
void sendTransform(const StampedTransform &transform)
uint32_t current_last_time
Definition: driver.cpp:166
virtual const char * what() const
int odom_idx
Definition: driver.cpp:142
std::string odom_frame
Definition: driver.cpp:171
static Timeout simpleTimeout(uint32_t timeout)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
float odom_yaw
Definition: driver.cpp:153
bool isOpen() const
ros::Subscriber cmdvel_sub
Definition: driver.cpp:120
#define ROS_WARN_STREAM(args)
#define ROS_DEBUG_STREAM(args)
ros::Publisher current_pub
Definition: driver.cpp:134
uint32_t lstimer
Definition: driver.cpp:115
void odom_setup()
Definition: driver.cpp:464
MainNode()
Definition: driver.cpp:187
void setPort(const std::string &port)
void cmdvel_loop()
Definition: driver.cpp:386
char odom_encoder_toss
Definition: driver.cpp:146
void mySigintHandler(int sig)
Definition: driver.cpp:60
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
#define ROS_INFO_STREAM(args)
static WallTime now()
uint32_t millis()
Definition: driver.cpp:67
uint32_t odom_last_time
Definition: driver.cpp:158
uint32_t starttime
Definition: driver.cpp:112
size_t read(uint8_t *buffer, size_t size)
ros::Publisher odom_pub
Definition: driver.cpp:128
static Time now()
ROSCPP_DECL void shutdown()
double max_amps
Definition: driver.cpp:182
int32_t odom_encoder_right
Definition: driver.cpp:149
std::string base_frame
Definition: driver.cpp:172
bool open_loop
Definition: driver.cpp:177
float odom_last_yaw
Definition: driver.cpp:156
float voltage
Definition: driver.cpp:161
uint32_t mstimer
Definition: driver.cpp:114
bool pub_odom_tf
Definition: driver.cpp:170
void odom_publish()
Definition: driver.cpp:714
ROSCPP_DECL void spinOnce()
std::string cmdvel_topic
Definition: driver.cpp:173
double wheel_circumference
Definition: driver.cpp:178
void odom_ms_run()
Definition: driver.cpp:681
int encoder_cpr
Definition: driver.cpp:181
void cmdvel_setup()
Definition: driver.cpp:304
roboteq_diff_msgs::Duplex current_msg
Definition: driver.cpp:133
size_t write(const uint8_t *data, size_t size)
float odom_y
Definition: driver.cpp:152
uint32_t hstimer
Definition: driver.cpp:113


roboteq_diff_driver
Author(s): Chad Attermann
autogenerated on Sat Feb 13 2021 03:36:06