PX4 Firmware
PX4 Autopilot Software http://px4.io
RoboClaw.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file RoboClaw.cpp
36  *
37  * RoboClaw Motor Driver
38  *
39  * references:
40  * http://downloads.orionrobotics.com/downloads/datasheets/motor_controller_robo_claw_R0401.pdf
41  *
42  */
43 
44 #include "RoboClaw.hpp"
45 #include <poll.h>
46 #include <stdio.h>
47 #include <math.h>
48 #include <string.h>
49 #include <fcntl.h>
50 #include <termios.h>
51 
52 #include <systemlib/err.h>
53 #include <systemlib/mavlink_log.h>
54 #include <arch/board/board.h>
55 
56 #include <uORB/Publication.hpp>
58 #include <drivers/drv_hrt.h>
59 #include <math.h>
60 
61 // The RoboClaw has a serial communication timeout of 10ms.
62 // Add a little extra to account for timing inaccuracy
63 #define TIMEOUT_US 10500
64 
65 // If a timeout occurs during serial communication, it will immediately try again this many times
66 #define TIMEOUT_RETRIES 1
67 
68 // If a timeout occurs while disarmed, it will try again this many times. This should be a higher number,
69 // because stopping when disarmed is pretty important.
70 #define STOP_RETRIES 10
71 
72 // Number of bytes returned by the Roboclaw when sending command 78, read both encoders
73 #define ENCODER_MESSAGE_SIZE 10
74 
75 // Number of bytes for commands 18 and 19, read speeds.
76 #define ENCODER_SPEED_MESSAGE_SIZE 7
77 
78 bool RoboClaw::taskShouldExit = false;
79 
80 RoboClaw::RoboClaw(const char *deviceName, const char *baudRateParam):
81  _uart(0),
82  _uart_set(),
83  _uart_timeout{.tv_sec = 0, .tv_usec = TIMEOUT_US},
84  _actuatorsSub(-1),
85  _lastEncoderCount{0, 0},
86  _encoderCounts{0, 0},
87  _motorSpeeds{0, 0}
88 
89 {
90  _param_handles.actuator_write_period_ms = param_find("RBCLW_WRITE_PER");
91  _param_handles.encoder_read_period_ms = param_find("RBCLW_READ_PER");
92  _param_handles.counts_per_rev = param_find("RBCLW_COUNTS_REV");
93  _param_handles.serial_baud_rate = param_find(baudRateParam);
94  _param_handles.address = param_find("RBCLW_ADDRESS");
95 
97 
98  // start serial port
99  _uart = open(deviceName, O_RDWR | O_NOCTTY);
100 
101  if (_uart < 0) { err(1, "could not open %s", deviceName); }
102 
103  int ret = 0;
104  struct termios uart_config {};
105  ret = tcgetattr(_uart, &uart_config);
106 
107  if (ret < 0) { err(1, "failed to get attr"); }
108 
109  uart_config.c_oflag &= ~ONLCR; // no CR for every LF
110  ret = cfsetispeed(&uart_config, _parameters.serial_baud_rate);
111 
112  if (ret < 0) { err(1, "failed to set input speed"); }
113 
114  ret = cfsetospeed(&uart_config, _parameters.serial_baud_rate);
115 
116  if (ret < 0) { err(1, "failed to set output speed"); }
117 
118  ret = tcsetattr(_uart, TCSANOW, &uart_config);
119 
120  if (ret < 0) { err(1, "failed to set attr"); }
121 
122  FD_ZERO(&_uart_set);
123 
124  // setup default settings, reset encoders
125  resetEncoders();
126 }
127 
129 {
132  close(_uart);
133 }
134 
136 {
137  // Make sure the Roboclaw is actually connected, so I don't just spam errors if it's not.
138  uint8_t rbuff[4];
139  int err_code = _transaction(CMD_READ_STATUS, nullptr, 0, &rbuff[0], sizeof(rbuff), false, true);
140 
141  if (err_code <= 0) {
142  PX4_ERR("Unable to connect to Roboclaw. Shutting down Roboclaw driver.");
143  return;
144  }
145 
146  // This main loop performs two different tasks, asynchronously:
147  // - Send actuator_controls_0 to the Roboclaw as soon as they are available
148  // - Read the encoder values at a constant rate
149  // To do this, the timeout on the poll() function is used.
150  // waitTime is the amount of time left (int microseconds) until the next time I should read from the encoders.
151  // It is updated at the end of every loop. Sometimes, if the actuator_controls_0 message came in right before
152  // I should have read the encoders, waitTime will be 0. This is fine. When waitTime is 0, poll() will return
153  // immediately with a timeout. (Or possibly with a message, if one happened to be available at that exact moment)
154  uint64_t encoderTaskLastRun = 0;
155  int waitTime = 0;
156 
157  uint64_t actuatorsLastWritten = 0;
158 
159  _actuatorsSub = orb_subscribe(ORB_ID(actuator_controls_0));
160  orb_set_interval(_actuatorsSub, _parameters.actuator_write_period_ms);
161 
162  _armedSub = orb_subscribe(ORB_ID(actuator_armed));
163  _paramSub = orb_subscribe(ORB_ID(parameter_update));
164 
165  pollfd fds[3];
166  fds[0].fd = _paramSub;
167  fds[0].events = POLLIN;
168  fds[1].fd = _actuatorsSub;
169  fds[1].events = POLLIN;
170  fds[2].fd = _armedSub;
171  fds[2].events = POLLIN;
172 
173  memset((void *) &_wheelEncoderMsg[0], 0, sizeof(_wheelEncoderMsg));
174  _wheelEncoderMsg[0].pulses_per_rev = _parameters.counts_per_rev;
175  _wheelEncoderMsg[1].pulses_per_rev = _parameters.counts_per_rev;
176 
177  while (!taskShouldExit) {
178 
179  int pret = poll(fds, sizeof(fds) / sizeof(pollfd), waitTime / 1000);
180 
181  bool actuators_timeout = int(hrt_absolute_time() - actuatorsLastWritten) > 2000 * _parameters.actuator_write_period_ms;
182 
183  if (fds[0].revents & POLLIN) {
184  orb_copy(ORB_ID(parameter_update), _paramSub, &_paramUpdate);
186  }
187 
188  // No timeout, update on either the actuator controls or the armed state
189  if (pret > 0 && (fds[1].revents & POLLIN || fds[2].revents & POLLIN || actuators_timeout)) {
190  orb_copy(ORB_ID(actuator_controls_0), _actuatorsSub, &_actuatorControls);
191  orb_copy(ORB_ID(actuator_armed), _armedSub, &_actuatorArmed);
192 
193  int drive_ret = 0, turn_ret = 0;
194 
196  || _actuatorArmed.force_failsafe || actuators_timeout;
197 
198  if (disarmed) {
199  // If disarmed, I want to be certain that the stop command gets through.
200  int tries = 0;
201 
202  while (tries < STOP_RETRIES && ((drive_ret = drive(0.0)) <= 0 || (turn_ret = turn(0.0)) <= 0)) {
203  PX4_ERR("Error trying to stop: Drive: %d, Turn: %d", drive_ret, turn_ret);
204  tries++;
205  px4_usleep(TIMEOUT_US);
206  }
207 
208  } else {
209  drive_ret = drive(_actuatorControls.control[actuator_controls_s::INDEX_THROTTLE]);
210  turn_ret = turn(_actuatorControls.control[actuator_controls_s::INDEX_YAW]);
211 
212  if (drive_ret <= 0 || turn_ret <= 0) {
213  PX4_ERR("Error controlling RoboClaw. Drive err: %d. Turn err: %d", drive_ret, turn_ret);
214  }
215  }
216 
217  actuatorsLastWritten = hrt_absolute_time();
218 
219  } else {
220  // A timeout occurred, which means that it's time to update the encoders
221  encoderTaskLastRun = hrt_absolute_time();
222 
223  if (readEncoder() > 0) {
224 
225  for (int i = 0; i < 2; i++) {
226  _wheelEncoderMsg[i].timestamp = encoderTaskLastRun;
227 
228  _wheelEncoderMsg[i].encoder_position = _encoderCounts[i];
229  _wheelEncoderMsg[i].speed = _motorSpeeds[i];
230 
231  if (_wheelEncodersAdv[i] == nullptr) {
232  int instance;
233  _wheelEncodersAdv[i] = orb_advertise_multi(ORB_ID(wheel_encoders), &_wheelEncoderMsg[i],
234  &instance, ORB_PRIO_DEFAULT);
235 
236  } else {
237  orb_publish(ORB_ID(wheel_encoders), _wheelEncodersAdv[i], &_wheelEncoderMsg[i]);
238  }
239  }
240 
241  } else {
242  PX4_ERR("Error reading encoders");
243  }
244  }
245 
246  waitTime = _parameters.encoder_read_period_ms * 1000 - (hrt_absolute_time() - encoderTaskLastRun);
247  waitTime = waitTime < 0 ? 0 : waitTime;
248  }
249 
253 }
254 
256 {
257 
258  uint8_t rbuff_pos[ENCODER_MESSAGE_SIZE];
259  // I am saving space by overlapping the two separate motor speeds, so that the final buffer will look like:
260  // [<speed 1> <speed 2> <status 2> <checksum 2>]
261  // And I just ignore all of the statuses and checksums. (The _transaction() function internally handles the
262  // checksum)
263  uint8_t rbuff_speed[ENCODER_SPEED_MESSAGE_SIZE + 4];
264 
265  bool success = false;
266 
267  for (int retry = 0; retry < TIMEOUT_RETRIES && !success; retry++) {
268  success = _transaction(CMD_READ_BOTH_ENCODERS, nullptr, 0, &rbuff_pos[0], ENCODER_MESSAGE_SIZE, false,
269  true) == ENCODER_MESSAGE_SIZE;
270  success = success && _transaction(CMD_READ_SPEED_1, nullptr, 0, &rbuff_speed[0], ENCODER_SPEED_MESSAGE_SIZE, false,
272  success = success && _transaction(CMD_READ_SPEED_2, nullptr, 0, &rbuff_speed[4], ENCODER_SPEED_MESSAGE_SIZE, false,
274  }
275 
276  if (!success) {
277  PX4_ERR("Error reading encoders");
278  return -1;
279  }
280 
281  uint32_t count;
282  uint32_t speed;
283  uint8_t *count_bytes;
284  uint8_t *speed_bytes;
285 
286  for (int motor = 0; motor <= 1; motor++) {
287  count = 0;
288  speed = 0;
289  count_bytes = &rbuff_pos[motor * 4];
290  speed_bytes = &rbuff_speed[motor * 4];
291 
292  // Data from the roboclaw is big-endian. This converts the bytes to an integer, regardless of the
293  // endianness of the system this code is running on.
294  for (int byte = 0; byte < 4; byte++) {
295  count = (count << 8) + count_bytes[byte];
296  speed = (speed << 8) + speed_bytes[byte];
297  }
298 
299  // The Roboclaw stores encoder counts as unsigned 32-bit ints. This can overflow, especially when starting
300  // at 0 and moving backward. The Roboclaw has overflow flags for this, but in my testing, they don't seem
301  // to work. This code detects overflow manually.
302  // These diffs are the difference between the count I just read from the Roboclaw and the last
303  // count that was read from the roboclaw for this motor. fwd_diff assumes that the wheel moved forward,
304  // and rev_diff assumes it moved backward. If the motor actually moved forward, then rev_diff will be close
305  // to 2^32 (UINT32_MAX). If the motor actually moved backward, then fwd_diff will be close to 2^32.
306  // To detect and account for overflow, I just assume that the smaller diff is correct.
307  // Strictly speaking, if the wheel rotated more than 2^31 encoder counts since the last time I checked, this
308  // will be wrong. But that's 1.7 million revolutions, so it probably won't come up.
309  uint32_t fwd_diff = count - _lastEncoderCount[motor];
310  uint32_t rev_diff = _lastEncoderCount[motor] - count;
311  // At this point, abs(diff) is always <= 2^31, so this cast from unsigned to signed is safe.
312  int32_t diff = fwd_diff <= rev_diff ? fwd_diff : -int32_t(rev_diff);
313  _encoderCounts[motor] += diff;
314  _lastEncoderCount[motor] = count;
315 
316  _motorSpeeds[motor] = speed;
317  }
318 
319  return 1;
320 }
321 
322 void RoboClaw::printStatus(char *string, size_t n)
323 {
324  snprintf(string, n, "pos1,spd1,pos2,spd2: %10.2f %10.2f %10.2f %10.2f\n",
325  double(getMotorPosition(MOTOR_1)),
326  double(getMotorSpeed(MOTOR_1)),
327  double(getMotorPosition(MOTOR_2)),
328  double(getMotorSpeed(MOTOR_2)));
329 }
330 
332 {
333  if (motor == MOTOR_1) {
334  return _encoderCounts[0];
335 
336  } else if (motor == MOTOR_2) {
337  return _encoderCounts[1];
338 
339  } else {
340  warnx("Unknown motor value passed to RoboClaw::getMotorPosition");
341  return NAN;
342  }
343 }
344 
346 {
347  if (motor == MOTOR_1) {
348  return _motorSpeeds[0];
349 
350  } else if (motor == MOTOR_2) {
351  return _motorSpeeds[1];
352 
353  } else {
354  warnx("Unknown motor value passed to RoboClaw::getMotorPosition");
355  return NAN;
356  }
357 }
358 
359 int RoboClaw::setMotorSpeed(e_motor motor, float value)
360 {
362 
363  // send command
364  if (motor == MOTOR_1) {
365  if (value > 0) {
366  command = CMD_DRIVE_FWD_1;
367 
368  } else {
369  command = CMD_DRIVE_REV_1;
370  }
371 
372  } else if (motor == MOTOR_2) {
373  if (value > 0) {
374  command = CMD_DRIVE_FWD_2;
375 
376  } else {
377  command = CMD_DRIVE_REV_2;
378  }
379 
380  } else {
381  return -1;
382  }
383 
384  return _sendUnsigned7Bit(command, value);
385 }
386 
387 int RoboClaw::setMotorDutyCycle(e_motor motor, float value)
388 {
389 
391 
392  // send command
393  if (motor == MOTOR_1) {
394  command = CMD_SIGNED_DUTYCYCLE_1;
395 
396  } else if (motor == MOTOR_2) {
397  command = CMD_SIGNED_DUTYCYCLE_2;
398 
399  } else {
400  return -1;
401  }
402 
403  return _sendSigned16Bit(command, value);
404 }
405 
406 int RoboClaw::drive(float value)
407 {
409  return _sendUnsigned7Bit(command, value);
410 }
411 
412 int RoboClaw::turn(float value)
413 {
415  return _sendUnsigned7Bit(command, value);
416 }
417 
419 {
421 }
422 
424 {
425  data = fabs(data);
426 
427  if (data > 1.0f) {
428  data = 1.0f;
429  }
430 
431  auto byte = (uint8_t)(data * INT8_MAX);
432  uint8_t recv_byte;
433  return _transaction(command, &byte, 1, &recv_byte, 1);
434 }
435 
437 {
438  if (data > 1.0f) {
439  data = 1.0f;
440 
441  } else if (data < -1.0f) {
442  data = -1.0f;
443  }
444 
445  auto buff = (uint16_t)(data * INT16_MAX);
446  uint8_t recv_buff;
447  return _transaction(command, (uint8_t *) &buff, 2, &recv_buff, 1);
448 }
449 
451 {
452  uint8_t recv_buff;
453  return _transaction(command, nullptr, 0, &recv_buff, 1);
454 }
455 
456 uint16_t RoboClaw::_calcCRC(const uint8_t *buf, size_t n, uint16_t init)
457 {
458  uint16_t crc = init;
459 
460  for (size_t byte = 0; byte < n; byte++) {
461  crc = crc ^ (((uint16_t) buf[byte]) << 8);
462 
463  for (uint8_t bit = 0; bit < 8; bit++) {
464  if (crc & 0x8000) {
465  crc = (crc << 1) ^ 0x1021;
466 
467  } else {
468  crc = crc << 1;
469  }
470  }
471  }
472 
473  return crc;
474 }
475 
476 int RoboClaw::_transaction(e_command cmd, uint8_t *wbuff, size_t wbytes,
477  uint8_t *rbuff, size_t rbytes, bool send_checksum, bool recv_checksum)
478 {
479  int err_code = 0;
480 
481  // WRITE
482 
483  tcflush(_uart, TCIOFLUSH); // flush buffers
484  uint8_t buf[wbytes + 4];
485  buf[0] = (uint8_t) _parameters.address;
486  buf[1] = cmd;
487 
488  if (wbuff) {
489  memcpy(&buf[2], wbuff, wbytes);
490  }
491 
492  wbytes = wbytes + (send_checksum ? 4 : 2);
493 
494  if (send_checksum) {
495  uint16_t sum = _calcCRC(buf, wbytes - 2);
496  buf[wbytes - 2] = (sum >> 8) & 0xFF;
497  buf[wbytes - 1] = sum & 0xFFu;
498  }
499 
500  int count = write(_uart, buf, wbytes);
501 
502  if (count < (int) wbytes) { // Did not successfully send all bytes.
503  PX4_ERR("Only wrote %d out of %d bytes", count, (int) wbytes);
504  return -1;
505  }
506 
507  // READ
508 
509  FD_ZERO(&_uart_set);
510  FD_SET(_uart, &_uart_set);
511 
512  uint8_t *rbuff_curr = rbuff;
513  size_t bytes_read = 0;
514 
515  // select(...) returns as soon as even 1 byte is available. read(...) returns immediately, no matter how many
516  // bytes are available. I need to keep reading until I get the number of bytes I expect.
517  while (bytes_read < rbytes) {
518  // select(...) may change this timeout struct (because it is not const). So I reset it every time.
519  _uart_timeout.tv_sec = 0;
520  _uart_timeout.tv_usec = TIMEOUT_US;
521  err_code = select(_uart + 1, &_uart_set, nullptr, nullptr, &_uart_timeout);
522 
523  // An error code of 0 means that select timed out, which is how the Roboclaw indicates an error.
524  if (err_code <= 0) {
525  return err_code;
526  }
527 
528  err_code = read(_uart, rbuff_curr, rbytes - bytes_read);
529 
530  if (err_code <= 0) {
531  return err_code;
532 
533  } else {
534  bytes_read += err_code;
535  rbuff_curr += err_code;
536  }
537  }
538 
539  //TODO: Clean up this mess of IFs and returns
540 
541  if (recv_checksum) {
542  if (bytes_read < 2) {
543  return -1;
544  }
545 
546  // The checksum sent back by the roboclaw is calculated based on the address and command bytes as well
547  // as the data returned.
548  uint16_t checksum_calc = _calcCRC(buf, 2);
549  checksum_calc = _calcCRC(rbuff, bytes_read - 2, checksum_calc);
550  uint16_t checksum_recv = (rbuff[bytes_read - 2] << 8) + rbuff[bytes_read - 1];
551 
552  if (checksum_calc == checksum_recv) {
553  return bytes_read;
554 
555  } else {
556  return -10;
557  }
558 
559  } else {
560  if (bytes_read == 1 && rbuff[0] == 0xFF) {
561  return 1;
562 
563  } else {
564  return -11;
565  }
566  }
567 }
568 
570 {
571  param_get(_param_handles.counts_per_rev, &_parameters.counts_per_rev);
572  param_get(_param_handles.encoder_read_period_ms, &_parameters.encoder_read_period_ms);
573  param_get(_param_handles.actuator_write_period_ms, &_parameters.actuator_write_period_ms);
574  param_get(_param_handles.address, &_parameters.address);
575 
576  if (_actuatorsSub > 0) {
577  orb_set_interval(_actuatorsSub, _parameters.actuator_write_period_ms);
578  }
579 
580  int baudRate;
581  param_get(_param_handles.serial_baud_rate, &baudRate);
582 
583  switch (baudRate) {
584  case 2400:
585  _parameters.serial_baud_rate = B2400;
586  break;
587 
588  case 9600:
589  _parameters.serial_baud_rate = B9600;
590  break;
591 
592  case 19200:
593  _parameters.serial_baud_rate = B19200;
594  break;
595 
596  case 38400:
597  _parameters.serial_baud_rate = B38400;
598  break;
599 
600  case 57600:
601  _parameters.serial_baud_rate = B57600;
602  break;
603 
604  case 115200:
605  _parameters.serial_baud_rate = B115200;
606  break;
607 
608  case 230400:
609  _parameters.serial_baud_rate = B230400;
610  break;
611 
612  case 460800:
613  _parameters.serial_baud_rate = B460800;
614  break;
615 
616  default:
617  _parameters.serial_baud_rate = B2400;
618  }
619 }
actuator_armed_s _actuatorArmed
Definition: RoboClaw.hpp:202
void _parameters_update()
Definition: RoboClaw.cpp:569
int _sendNothing(e_command)
Definition: RoboClaw.cpp:450
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
Definition: uORB.cpp:90
struct timeval _uart_timeout
Definition: RoboClaw.hpp:195
float getMotorPosition(e_motor motor)
Definition: RoboClaw.cpp:331
int readEncoder()
read data from serial
Definition: RoboClaw.cpp:255
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
Definition: parameters.cpp:589
struct RoboClaw::@20 _parameters
static bool taskShouldExit
Definition: RoboClaw.hpp:67
parameter_update_s _paramUpdate
Definition: RoboClaw.hpp:205
int _uart
Definition: RoboClaw.hpp:193
int32_t _motorSpeeds[2]
Definition: RoboClaw.hpp:212
int orb_set_interval(int handle, unsigned interval)
Definition: uORB.cpp:126
actuator_controls_s _actuatorControls
Definition: RoboClaw.hpp:199
RoboClaw(const char *deviceName, const char *baudRateParam)
constructor
Definition: RoboClaw.cpp:80
int setMotorSpeed(e_motor motor, float value)
set the speed of a motor, rev/sec
Definition: RoboClaw.cpp:359
LidarLite * instance
Definition: ll40ls.cpp:65
e_motor
motors
Definition: RoboClaw.hpp:76
High-resolution timer with callouts and timekeeping.
int _actuatorsSub
actuator controls subscription
Definition: RoboClaw.hpp:198
int turn(float value)
Turn.
Definition: RoboClaw.cpp:412
static void read(bootloader_app_shared_t *pshared)
int orb_subscribe(const struct orb_metadata *meta)
Definition: uORB.cpp:75
#define ENCODER_SPEED_MESSAGE_SIZE
Definition: RoboClaw.cpp:76
wheel_encoders_s _wheelEncoderMsg[2]
Definition: RoboClaw.hpp:208
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
#define TIMEOUT_US
Definition: RoboClaw.cpp:63
float getMotorSpeed(e_motor motor)
Definition: RoboClaw.cpp:345
#define TIMEOUT_RETRIES
Definition: RoboClaw.cpp:66
orb_advert_t _wheelEncodersAdv[2]
Definition: RoboClaw.hpp:207
void init()
Activates/configures the hardware registers.
int resetEncoders()
reset the encoders
Definition: RoboClaw.cpp:418
void printStatus(char *string, size_t n)
print status
Definition: RoboClaw.cpp:322
uint8_t * data
Definition: dataman.cpp:149
int orb_unsubscribe(int handle)
Definition: uORB.cpp:85
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
#define warnx(...)
Definition: err.h:95
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
#define ENCODER_MESSAGE_SIZE
Definition: RoboClaw.cpp:73
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
Definition: uORB.cpp:70
#define err(eval,...)
Definition: err.h:83
__EXPORT param_t param_find(const char *name)
Look up a parameter by name.
Definition: parameters.cpp:370
int _paramSub
Definition: RoboClaw.hpp:204
static void write(bootloader_app_shared_t *pshared)
int setMotorDutyCycle(e_motor motor, float value)
set the duty cycle of a motor
Definition: RoboClaw.cpp:387
int _sendUnsigned7Bit(e_command command, float data)
Definition: RoboClaw.cpp:423
int _sendSigned16Bit(e_command command, float data)
Definition: RoboClaw.cpp:436
uint32_t _lastEncoderCount[2]
Definition: RoboClaw.hpp:210
int _transaction(e_command cmd, uint8_t *wbuff, size_t wbytes, uint8_t *rbuff, size_t rbytes, bool send_checksum=true, bool recv_checksum=false)
Perform a round-trip write and read.
Definition: RoboClaw.cpp:476
static uint16_t _calcCRC(const uint8_t *buf, size_t n, uint16_t init=0)
Definition: RoboClaw.cpp:456
int64_t _encoderCounts[2]
Definition: RoboClaw.hpp:211
#define STOP_RETRIES
Definition: RoboClaw.cpp:70
int drive(float value)
Drive both motors.
Definition: RoboClaw.cpp:406
int _armedSub
Definition: RoboClaw.hpp:201
virtual ~RoboClaw()
deconstructor
Definition: RoboClaw.cpp:128
fd_set _uart_set
Definition: RoboClaw.hpp:194
orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)
Definition: uORB.cpp:53
struct RoboClaw::@21 _param_handles
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
void taskMain()
Definition: RoboClaw.cpp:135