imu.cpp
Go to the documentation of this file.
1 /*
2  * imu.hpp
3  *
4  * Copyright (c) 2014 Kumar Robotics. All rights reserved.
5  *
6  * This file is part of galt.
7  *
8  * Created on: 2/6/2014
9  * Author: gareth
10  */
11 
13 
14 #include <chrono>
15 #include <locale>
16 #include <tuple>
17 #include <algorithm>
18 #include <iostream>
19 #include <string>
20 #include <sstream>
21 #include <stdexcept>
22 #include <boost/assert.hpp>
23 
24 extern "C" {
25 #include <fcntl.h>
26 #include <getopt.h>
27 #include <poll.h>
28 #include <time.h>
29 #include <errno.h>
30 #include <termios.h>
31 #include <sys/ioctl.h>
32 #include <assert.h>
33 #include <unistd.h> // close
34 #include <string.h> // strerror
35 }
36 
37 #define kDefaultTimeout (300)
38 #define kBufferSize (10) // keep this small, or 1000Hz is not attainable
39 
40 #define u8(x) static_cast<uint8_t>((x))
41 
42 #define COMMAND_CLASS_BASE u8(0x01)
43 #define COMMAND_CLASS_3DM u8(0x0C)
44 #define COMMAND_CLASS_FILTER u8(0x0D)
45 
46 #define DATA_CLASS_IMU u8(0x80)
47 #define DATA_CLASS_FILTER u8(0x82)
48 
49 #define FUNCTION_APPLY u8(0x01)
50 
51 #define SELECTOR_IMU u8(0x01)
52 #define SELECTOR_FILTER u8(0x03)
53 
54 // base commands
55 #define DEVICE_PING u8(0x01)
56 #define DEVICE_IDLE u8(0x02)
57 #define DEVICE_RESUME u8(0x06)
58 
59 // 3DM and FILTER commands
60 #define COMMAND_GET_DEVICE_INFO u8(0x03)
61 #define COMMAND_GET_IMU_BASE_RATE u8(0x06)
62 #define COMMAND_GET_FILTER_BASE_RATE u8(0x0B)
63 #define COMMAND_IMU_MESSAGE_FORMAT u8(0x08)
64 #define COMAMND_FILTER_MESSAGE_FORMAT u8(0x0A)
65 #define COMMAND_ENABLE_DATA_STREAM u8(0x11)
66 #define COMMAND_FILTER_CONTROL_FLAGS u8(0x14)
67 #define COMMAND_UART_BAUD_RATE u8(0x40)
68 #define COMMAND_SET_HARD_IRON u8(0x3A)
69 #define COMMAND_SET_SOFT_IRON u8(0x3B)
70 #define COMMAND_ENABLE_MEASUREMENTS u8(0x41)
71 #define COMMAND_DEVICE_STATUS u8(0x64)
72 
73 // supported fields
74 #define FIELD_QUATERNION u8(0x03)
75 #define FIELD_ACCELEROMETER u8(0x04)
76 #define FIELD_GYROSCOPE u8(0x05)
77 #define FIELD_GYRO_BIAS u8(0x06)
78 #define FIELD_MAGNETOMETER u8(0x06)
79 #define FIELD_ANGLE_UNCERTAINTY u8(0x0A)
80 #define FIELD_BIAS_UNCERTAINTY u8(0x0B)
81 #define FIELD_BAROMETER u8(0x17)
82 #define FIELD_DEVICE_INFO u8(0x81)
83 #define FIELD_IMU_BASERATE u8(0x83)
84 #define FIELD_FILTER_BASERATE u8(0x8A)
85 #define FIELD_STATUS_REPORT u8(0x90)
86 #define FIELD_ACK_OR_NACK u8(0xF1)
87 
88 using namespace imu_3dm_gx4;
89 
90 // trim from start
91 static inline std::string ltrim(std::string s) {
92  s.erase(s.begin(),
93  std::find_if(s.begin(), s.end(),
94  std::not1(std::ptr_fun<int, int>(std::isspace))));
95  return s;
96 }
97 
98 // swap order of bytes if on a little endian platform
99 template <size_t sz> void to_device_order(uint8_t buffer[sz]) {
100 #ifdef HOST_LITTLE_ENDIAN
101  for (size_t i = 0; i < sz / 2; i++) {
102  std::swap(buffer[i], buffer[sz - i - 1]);
103  }
104 #endif
105 }
106 
107 template <> void to_device_order<1>(uint8_t buffer[1]) {}
108 
109 template <typename T> size_t encode(uint8_t *buffer, const T &t) {
110  static_assert(std::is_fundamental<T>::value,
111  "Only fundamental types may be encoded");
112 
113  const size_t szT = sizeof(T);
114  union {
115  T tc;
116  uint8_t bytes[szT];
117  };
118  tc = t;
119 
120  to_device_order<szT>(bytes);
121 
122  // append
123  for (size_t i = 0; i < szT; i++) {
124  buffer[i] = bytes[i];
125  }
126 
127  return szT;
128 }
129 
130 template <typename T, typename... Ts>
131 size_t encode(uint8_t *buffer, const T &t, const Ts &... ts) {
132  const size_t sz = encode(buffer, t);
133  // recurse
134  return sz + encode(buffer + sizeof(T), ts...);
135 }
136 
137 template <typename T> void decode(const uint8_t *buffer, size_t count,
138  T *output) {
139  const size_t szT = sizeof(T);
140  static_assert(std::is_fundamental<T>::value,
141  "Only fundamental types may be decoded");
142  union {
143  T tc;
144  uint8_t bytes[szT];
145  };
146 
147  for (size_t i = 0; i < count; i++) {
148  for (size_t j = 0; j < szT; j++) {
149  bytes[j] = buffer[j];
150  }
151  to_device_order<szT>(&bytes[0]);
152  output[i] = tc;
153 
154  buffer += szT;
155  }
156 }
157 
162 public:
163  PacketEncoder(Imu::Packet& p) : p_(p), fs_(0), enc_(false) {
164  p.length = 0;
165  }
166  virtual ~PacketEncoder() {
167  // no destruction without completion
168  assert(!enc_);
169  }
170 
171  void beginField(uint8_t desc) {
172  assert(!enc_);
173  assert(p_.length < sizeof(p_.payload) - 2); // 2 bytes per field minimum
174  fs_ = p_.length;
175  p_.payload[fs_+1] = desc;
176  p_.length += 2;
177  enc_ = true;
178  }
179 
180  template <typename ...Ts>
181  void append(const Ts& ...args) {
182  assert(enc_); // todo: check argument length here
183  p_.length += encode(p_.payload+p_.length, args...);
184  }
185 
186  void endField() {
187  assert(enc_);
188  p_.payload[fs_] = p_.length - fs_;
189  enc_ = false;
190  }
191 
192 private:
194  uint8_t fs_;
195  bool enc_;
196 };
197 
202 public:
203  PacketDecoder(const Imu::Packet& p) : p_(p), fs_(0), pos_(2) {
204  assert(p.length > 0);
205  }
206 
207  int fieldDescriptor() const {
208  if (fs_ > sizeof(p_.payload)-2) {
209  return -1;
210  }
211  if (p_.payload[fs_] == 0) {
212  return -1; // no field
213  }
214  return p_.payload[fs_ + 1]; // descriptor after length
215  }
216 
217  int fieldLength() const {
218  assert(fs_ < sizeof(p_.payload));
219  return p_.payload[fs_];
220  }
221 
222  bool fieldIsAckOrNack() const {
223  const int desc = fieldDescriptor();
224  if (desc == static_cast<int>(FIELD_ACK_OR_NACK)) {
225  return true;
226  }
227  return false;
228  }
229 
230  bool advanceTo(uint8_t field) {
231  for (int d; (d = fieldDescriptor()) > 0; advance()) {
232  if (d == static_cast<int>(field)) {
233  return true;
234  }
235  }
236  return false;
237  }
238 
239  void advance() {
240  fs_ += p_.payload[fs_];
241  pos_ = 2; // skip length and descriptor
242  }
243 
244  template <typename T>
245  void extract(size_t count, T* output) {
246  BOOST_VERIFY(fs_ + pos_ + sizeof(T) * count <= sizeof(p_.payload));
247  decode(&p_.payload[fs_ + pos_], count, output);
248  pos_ += sizeof(T) * count;
249  }
250 
251 private:
252  const Imu::Packet& p_;
253  uint8_t fs_;
254  uint8_t pos_;
255 };
256 
258  return descriptor == DATA_CLASS_IMU;
259 }
260 
262  return descriptor == DATA_CLASS_FILTER;
263 }
264 
265 int Imu::Packet::ackErrorCodeFor(const Packet &command) const {
266  PacketDecoder decoder(*this);
267  const uint8_t sentDesc = command.descriptor;
268  const uint8_t sentField = command.payload[1];
269 
270  if (sentDesc != this->descriptor) {
271  // not for this packet
272  return -1;
273  }
274 
275  // look for a matching ACK
276  for (int d; (d = decoder.fieldDescriptor()) > 0; decoder.advance()) {
277  if (decoder.fieldIsAckOrNack()) {
278  uint8_t cmd, code;
279  decoder.extract(1, &cmd);
280  decoder.extract(1, &code);
281  if (cmd == sentField) {
282  // match
283  return code;
284  }
285  }
286  }
287  // not an ACK/NACK
288  return -1;
289 }
290 
292  uint8_t byte1 = 0, byte2 = 0;
293 
294 #define add_byte(x) \
295  byte1 += (x); \
296  byte2 += byte1;
297 
298  add_byte(syncMSB);
299  add_byte(syncLSB);
301  add_byte(length);
302 
303  for (size_t i = 0; i < length; i++) {
304  add_byte(payload[i]);
305  }
306 #undef add_byte
307 
308  checksum = (static_cast<uint16_t>(byte1) << 8) + static_cast<uint16_t>(byte2);
309 #ifdef HOST_LITTLE_ENDIAN
310  uint8_t temp = checkLSB;
311  checkLSB = checkMSB;
312  checkMSB = temp;
313 #endif
314 }
315 
316 Imu::Packet::Packet(uint8_t desc)
318  checksum(0) {
319  memset(&payload, 0, sizeof(payload));
320 }
321 
322 std::string Imu::Packet::toString() const {
323  std::stringstream ss;
324  ss << std::hex;
325  ss << "SyncMSB: " << static_cast<int>(syncMSB) << "\n";
326  ss << "SyncLSB: " << static_cast<int>(syncLSB) << "\n";
327  ss << "Descriptor: " << static_cast<int>(descriptor) << "\n";
328  ss << "Length: " << static_cast<int>(length) << "\n";
329  ss << "Payload: ";
330  for (size_t s=0; s < length; s++) {
331  ss << static_cast<int>(payload[s]) << " ";
332  }
333  ss << "\nCheck MSB: " << static_cast<int>(checkMSB) << "\n";
334  ss << "Check LSB: " << static_cast<int>(checkLSB);
335  return ss.str();
336 }
337 
338 std::map <std::string, std::string> Imu::Info::toMap() const {
339  std::map<std::string, std::string> map;
340  map["Firmware version"] = std::to_string(firmwareVersion);
341  map["Model name"] = modelName;
342  map["Model number"] = modelNumber;
343  map["Serial number"] = serialNumber;
344  map["Device options"] = deviceOptions;
345  // omit lot number since it is empty
346  return map;
347 }
348 
349 std::map <std::string, unsigned int> Imu::DiagnosticFields::toMap() const {
350  std::map<std::string, unsigned int> map;
351  map["Model number"] = modelNumber;
352  map["Selector"] = selector;
353  map["Status flags"] = statusFlags;
354  map["System timer"] = systemTimer;
355  map["Num 1PPS Pulses"] = num1PPSPulses;
356  map["Last 1PPS Pulse"] = last1PPSPulse;
357  map["Imu stream enabled"] = imuStreamEnabled;
358  map["Filter stream enabled"] = filterStreamEnabled;
359  map["Imu packets dropped"] = imuPacketsDropped;
360  map["Filter packets dropped"] = filterPacketsDropped;
361  map["Com bytes written"] = comBytesWritten;
362  map["Com bytes read"] = comBytesRead;
363  map["Com num write overruns"] = comNumReadOverruns;
364  map["Com num read overruns"] = comNumReadOverruns;
365  map["Usb bytes written"] = usbBytesWritten;
366  map["Usb bytes read"] = usbBytesRead;
367  map["Usb num write overruns"] = usbNumWriteOverruns;
368  map["Usb num read overruns"] = usbNumReadOverruns;
369  map["Num imu parse errors"] = numIMUParseErrors;
370  map["Total imu messages"] = totalIMUMessages;
371  map["Last imu message"] = lastIMUMessage;
372  return map;
373 }
374 
375 Imu::command_error::command_error(const Packet& p, uint8_t code) :
376  std::runtime_error(generateString(p, code)) {}
377 
378 std::string Imu::command_error::generateString(const Packet& p, uint8_t code) {
379  std::stringstream ss;
380  ss << "Received NACK with error code " << std::hex << static_cast<int>(code);
381  ss << ". Command Packet:\n" << p.toString();
382  return ss.str();
383 }
384 
385 Imu::timeout_error::timeout_error(bool write, unsigned int to)
386 : std::runtime_error(generateString(write,to)) {}
387 
388 std::string Imu::timeout_error::generateString(bool write,
389  unsigned int to) {
390  std::stringstream ss;
391  ss << "Timed-out while " << ((write) ? "writing" : "reading") << ". ";
392  ss << "Time-out limit is " << to << "ms.";
393  return ss.str();
394 }
395 
396 Imu::Imu(const std::string &device, bool verbose) : device_(device), verbose_(verbose),
397  fd_(0),
399  srcIndex_(0), dstIndex_(0),
400  state_(Idle) {
401  // buffer for storing reads
402  buffer_.resize(kBufferSize);
403 }
404 
406 
407 void Imu::connect() {
408  if (fd_ > 0) {
409  throw std::runtime_error("Socket is already open");
410  }
411 
412  const char *path = device_.c_str();
413  fd_ = ::open(path, O_RDWR | O_NOCTTY | O_NDELAY); // read/write, no
414  // controlling terminal, non
415  // blocking access
416  if (fd_ < 0) {
417  throw std::runtime_error("Failed to open device : " + device_);
418  }
419 
420  // make sure it is non-blocking
421  if (fcntl(fd_, F_SETFL, FNONBLOCK) < 0) {
422  disconnect();
423  throw io_error(strerror(errno));
424  }
425 
426  struct termios toptions;
427  if (tcgetattr(fd_, &toptions) < 0) {
428  disconnect();
429  throw io_error(strerror(errno));
430  }
431 
432  // set default baud rate
433  cfsetispeed(&toptions, B115200);
434  cfsetospeed(&toptions, B115200);
435 
436  toptions.c_cflag &= ~PARENB; // no parity bit
437  toptions.c_cflag &= ~CSTOPB; // disable 2 stop bits (only one used instead)
438  toptions.c_cflag &= ~CSIZE; // disable any previous size settings
439  toptions.c_cflag |= HUPCL; // enable modem disconnect
440  toptions.c_cflag |= CS8; // bytes are 8 bits long
441 
442  toptions.c_cflag &= ~CRTSCTS; // no hardware RTS/CTS switch
443 
444  toptions.c_cflag |=
445  CREAD |
446  CLOCAL; // enable receiving of data, forbid control lines (CLOCAL)
447  toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // no software flow control
448  toptions.c_iflag &= ~(INLCR|ICRNL); // disable NL->CR and CR->NL
449 
450  // disable the following
451  // ICANON = input is read on a per-line basis
452  // ECHO/ECHOE = echo enabled
453  // ISIG = interrupt signals
454  toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
455  toptions.c_oflag &= ~OPOST; // disable pre-processing of input data
456  toptions.c_oflag &= ~(ONLCR|OCRNL); // disable NL->CR and CR->NL
457 
458  toptions.c_cc[VMIN] = 0; // no minimum number of bytes when reading
459  toptions.c_cc[VTIME] = 0; // no time blocking
460 
461  // TCSAFLUSH = make change after flushing i/o buffers
462  if (tcsetattr(fd_, TCSAFLUSH, &toptions) < 0) {
463  disconnect();
464  throw io_error(strerror(errno));
465  }
466 }
467 
469  if (fd_ > 0) {
470  // send the idle command first
471  idle(false); // we don't care about reply here
472  close(fd_);
473  }
474  fd_ = 0;
475 }
476 
477 bool Imu::termiosBaudRate(unsigned int baud) {
478  struct termios toptions;
479  if (tcgetattr(fd_, &toptions) < 0) {
480  return false;
481  }
482 
483  speed_t speed;
484  switch (baud) {
485  case 9600:
486  speed = B9600;
487  break;
488  case 19200:
489  speed = B19200;
490  break;
491  case 115200:
492  speed = B115200;
493  break;
494  case 230400:
495  speed = B230400;
496  break;
497  case 460800:
498  speed = B460800;
499  break;
500  case 921600:
501  speed = B921600;
502  break;
503  default:
504  throw std::invalid_argument("Invalid Baud Rate" );
505  }
506 
507  // modify only the baud rate
508  cfsetispeed(&toptions, speed);
509  cfsetospeed(&toptions, speed);
510 
511  if (tcsetattr(fd_, TCSAFLUSH, &toptions) < 0) {
512  return false;
513  }
514 
515  usleep(200000); // wait for connection to be negotiated
516  // found this length through experimentation
517  return true;
518 }
519 
520 void Imu::runOnce() {
521  int sig = pollInput(5);
522  if (sig < 0) {
523  // failure in poll/read, device disconnected
524  throw io_error(strerror(errno));
525  }
526 }
527 
528 void Imu::selectBaudRate(unsigned int baud) {
529  // baud rates supported by the 3DM-GX4-25
530  const size_t num_rates = 6;
531  unsigned int rates[num_rates] = {
532  9600, 19200, 115200, 230400, 460800, 921600
533  };
534 
535  if (!std::binary_search(rates, rates + num_rates, baud)) {
536  // invalid baud rate
537  std::stringstream ss;
538  ss << "Baud rate unsupported: " << baud;
539  throw std::invalid_argument(ss.str());
540  }
541 
542  Imu::Packet pp(COMMAND_CLASS_BASE); // was 0x02
543  {
544  PacketEncoder encoder(pp);
545  encoder.beginField(DEVICE_PING);
546  encoder.endField();
547  }
548  pp.calcChecksum();
549 
550  size_t i;
551  bool foundRate = false;
552  for (i = 0; i < num_rates; i++) {
553  if (verbose_){
554  std::cout << "Switching to baud rate " << rates[i] << std::endl;
555  }
556  if (!termiosBaudRate(rates[i])) {
557  throw io_error(strerror(errno));
558  }
559 
560  if (verbose_) {
561  std::cout << "Switched baud rate to " << rates[i] << std::endl;
562  std::cout << "Sending a ping packet.\n" << std::flush;
563  }
564 
565  // send ping and wait for first response
566  sendPacket(pp, 100);
567  try {
568  receiveResponse(pp, 500);
569  } catch (timeout_error&) {
570  if (verbose_) {
571  std::cout << "Timed out waiting for ping response.\n" << std::flush;
572  }
573  continue;
574  } catch (command_error&) {
575  if (verbose_) {
576  std::cout << "IMU returned error code for ping.\n" << std::flush;
577  }
578  continue;
579  } // do not catch io_error
580 
581  if (verbose_) {
582  std::cout << "Found correct baudrate.\n" << std::flush;
583  }
584 
585  // no error in receiveResponse, this is correct baud rate
586  foundRate = true;
587  break;
588  }
589 
590  if (!foundRate) {
591  throw std::runtime_error("Failed to reach device " + device_);
592  }
593 
594  // we are on the correct baud rate, now change to the new rate
595  Packet comm(COMMAND_CLASS_3DM); // was 0x07
596  {
597  PacketEncoder encoder(comm);
599  encoder.append(FUNCTION_APPLY);
600  encoder.append(static_cast<uint32_t>(baud));
601  encoder.endField();
602  assert(comm.length == 0x07);
603  }
604  comm.calcChecksum();
605 
606  try {
607  if (verbose_) {
608  std::cout << "Instructing device to change to " << baud << std::endl
609  << std::flush;
610  }
611  sendCommand(comm);
612  } catch (std::exception& e) {
613  std::stringstream ss;
614  ss << "Device rejected baud rate " << baud << ".\n";
615  ss << e.what();
616  throw std::runtime_error(ss.str());
617  }
618 
619  // device has switched baud rate, now we should also
620  if (!termiosBaudRate(baud)) {
621  throw io_error(strerror(errno));
622  }
623 
624  // ping
625  try {
626  ping();
627  } catch (std::exception& e) {
628  std::string err("Device did not respond to ping.\n");
629  err += e.what();
630  throw std::runtime_error(err);
631  }
632 }
633 
634 void Imu::ping() {
635  Imu::Packet p(COMMAND_CLASS_BASE); // was 0x02
636  PacketEncoder encoder(p);
637  encoder.beginField(DEVICE_PING);
638  encoder.endField();
639  p.calcChecksum();
640  assert(p.checkMSB == 0xE0 && p.checkLSB == 0xC6);
641  sendCommand(p);
642 }
643 
644 void Imu::idle(bool needReply) {
645  Imu::Packet p(COMMAND_CLASS_BASE); // was 0x02
646  PacketEncoder encoder(p);
647  encoder.beginField(DEVICE_IDLE);
648  encoder.endField();
649  p.calcChecksum();
650  assert(p.checkMSB == 0xE1 && p.checkLSB == 0xC7);
651  sendCommand(p, needReply);
652 }
653 
654 void Imu::resume() {
655  Imu::Packet p(COMMAND_CLASS_BASE); // was 0x02
656  PacketEncoder encoder(p);
657  encoder.beginField(DEVICE_RESUME);
658  encoder.endField();
659  p.calcChecksum();
660  assert(p.checkMSB == 0xE5 && p.checkLSB == 0xCB);
661  sendCommand(p);
662 }
663 
665  Imu::Packet p(COMMAND_CLASS_BASE); // was 0x02
666  PacketEncoder encoder(p);
668  encoder.endField();
669  p.calcChecksum();
670  assert(p.checkMSB == 0xE2 && p.checkLSB == 0xC8);
671 
672  sendCommand(p);
673  {
674  PacketDecoder decoder(packet_);
675  BOOST_VERIFY(decoder.advanceTo(FIELD_DEVICE_INFO));
676  char buffer[16];
677 
678  decoder.extract(1, &info.firmwareVersion);
679  // decode all strings and trim left whitespace
680  decoder.extract(sizeof(buffer), &buffer[0]);
681  info.modelName = ltrim(std::string(buffer,16));
682  decoder.extract(sizeof(buffer), &buffer[0]);
683  info.modelNumber = ltrim(std::string(buffer,16));
684  decoder.extract(sizeof(buffer), &buffer[0]);
685  info.serialNumber = ltrim(std::string(buffer,16));
686  decoder.extract(sizeof(buffer), &buffer[0]);
687  info.lotNumber = ltrim(std::string(buffer,16));
688  decoder.extract(sizeof(buffer), &buffer[0]);
689  info.deviceOptions = ltrim(std::string(buffer,16));
690  }
691 }
692 
693 void Imu::getIMUDataBaseRate(uint16_t &baseRate) {
694  Packet p(COMMAND_CLASS_3DM); // was 0x02
695  PacketEncoder encoder(p);
697  encoder.endField();
698  p.calcChecksum();
699 
700  sendCommand(p);
701  {
702  PacketDecoder decoder(packet_);
703  BOOST_VERIFY(decoder.advanceTo(FIELD_IMU_BASERATE));
704  decoder.extract(1, &baseRate);
705  }
706 }
707 
708 void Imu::getFilterDataBaseRate(uint16_t &baseRate) {
709  Packet p(COMMAND_CLASS_3DM); // was 0x02
710  PacketEncoder encoder(p);
712  encoder.endField();
713  p.calcChecksum();
714 
715  sendCommand(p);
716  decode(&packet_.payload[6], 1, &baseRate);
717 }
718 
721  PacketEncoder encoder(p);
723  encoder.append(static_cast<uint16_t>(6234)); // device model number
724  encoder.append(u8(0x02)); // diagnostic mode
725  encoder.endField();
726  p.calcChecksum();
727 
728  sendCommand(p);
729  {
730  PacketDecoder decoder(packet_);
731  BOOST_VERIFY(decoder.advanceTo(FIELD_STATUS_REPORT));
732 
733  decoder.extract(1, &fields.modelNumber);
734  decoder.extract(1, &fields.selector);
735  decoder.extract(4, &fields.statusFlags);
736  decoder.extract(2, &fields.imuStreamEnabled);
737  decoder.extract(13, &fields.imuPacketsDropped);
738  }
739 }
740 
741 void Imu::setIMUDataRate(uint16_t decimation,
742  const std::bitset<4>& sources) {
743  Imu::Packet p(COMMAND_CLASS_3DM); // was 0x04
744  PacketEncoder encoder(p);
745 
746  // valid field descriptors: accel, gyro, mag, pressure
747  static const uint8_t fieldDescs[] = { FIELD_ACCELEROMETER,
750  FIELD_BAROMETER };
751  assert(sizeof(fieldDescs) == sources.size());
752  std::vector<uint8_t> fields;
753 
754  for (size_t i=0; i < sources.size(); i++) {
755  if (sources[i]) {
756  fields.push_back(fieldDescs[i]);
757  }
758  }
760  encoder.append(FUNCTION_APPLY, u8(fields.size()));
761 
762  for (const uint8_t& field : fields) {
763  encoder.append(field, decimation);
764  }
765 
766  encoder.endField();
767  p.calcChecksum();
768  sendCommand(p);
769 }
770 
771 void Imu::setFilterDataRate(uint16_t decimation, const std::bitset<4>& sources) {
772  Imu::Packet p(COMMAND_CLASS_3DM); // was 0x04
773  PacketEncoder encoder(p);
774 
775  static const uint8_t fieldDescs[] = { FIELD_QUATERNION,
779  assert(sizeof(fieldDescs) == sources.size());
780  std::vector<uint8_t> fields;
781 
782  for (size_t i=0; i < sources.size(); i++) {
783  if (sources[i]) {
784  fields.push_back(fieldDescs[i]);
785  }
786  }
787 
789  encoder.append(FUNCTION_APPLY, u8(fields.size()));
790 
791  for (const uint8_t& field : fields) {
792  encoder.append(field, decimation);
793  }
794  encoder.endField();
795  p.calcChecksum();
796  sendCommand(p);
797 }
798 
799 void Imu::enableMeasurements(bool accel, bool magnetometer) {
801  PacketEncoder encoder(p);
803  uint16_t flag=0;
804  if (accel) {
805  flag |= 0x01;
806  }
807  if (magnetometer) {
808  flag |= 0x02;
809  }
810  encoder.append(FUNCTION_APPLY, flag);
811  encoder.endField();
812  p.calcChecksum();
813  sendCommand(p);
814 }
815 
816 void Imu::enableBiasEstimation(bool enabled) {
818  PacketEncoder encoder(p);
820  uint16_t flag = 0xFFFE;
821  if (enabled) {
822  flag = 0xFFFF;
823  }
824  encoder.append(FUNCTION_APPLY, flag);
825  encoder.endField();
826  p.calcChecksum();
827  sendCommand(p);
828 }
829 
830 void Imu::setHardIronOffset(float offset[3]) {
832  PacketEncoder encoder(p);
834  encoder.append(FUNCTION_APPLY, offset[0], offset[1], offset[2]);
835  encoder.endField();
836  assert(p.length == 0x0F);
837  p.calcChecksum();
838  sendCommand(p);
839 }
840 
841 void Imu::setSoftIronMatrix(float matrix[9]) {
843  PacketEncoder encoder(p);
845  encoder.append(FUNCTION_APPLY);
846  for (int i=0; i < 9; i++) {
847  encoder.append(matrix[i]);
848  }
849  encoder.endField();
850  assert(p.length == 0x27);
851  p.calcChecksum();
852  sendCommand(p);
853 }
854 
855 void Imu::enableIMUStream(bool enabled) {
857  PacketEncoder encoder(p);
860  encoder.append(u8(enabled));
861  encoder.endField();
862  p.calcChecksum();
863  if (enabled) {
864  assert(p.checkMSB == 0x04 && p.checkLSB == 0x1A);
865  }
866  sendCommand(p);
867 }
868 
869 void Imu::enableFilterStream(bool enabled) {
871  PacketEncoder encoder(p);
874  encoder.append(u8(enabled));
875  encoder.endField();
876  p.calcChecksum();
877  if (enabled) {
878  assert(p.checkMSB == 0x06 && p.checkLSB == 0x1E);
879  }
880  sendCommand(p);
881 }
882 
883 void
884 Imu::setIMUDataCallback(const std::function<void(const Imu::IMUData &)> &cb) {
885  imuDataCallback_ = cb;
886 }
887 
889  const std::function<void(const Imu::FilterData &)> &cb) {
890  filterDataCallback_ = cb;
891 }
892 
893 int Imu::pollInput(unsigned int to) {
894  // poll socket for inputs
895  struct pollfd p;
896  p.fd = fd_;
897  p.events = POLLIN;
898 
899  int rPoll = poll(&p, 1, to); // timeout is in millis
900  if (rPoll > 0) {
901  const ssize_t amt = ::read(fd_, &buffer_[0], buffer_.size());
902  if (amt > 0) {
903  return handleRead(amt);
904  } else if (amt == 0) {
905  // end-of-file, device disconnected
906  return -1;
907  }
908  } else if (rPoll == 0) {
909  return 0; // no socket can be read
910  }
911 
912  if (errno == EAGAIN || errno == EINTR) {
913  // treat these like timeout errors
914  return 0;
915  }
916 
917  // poll() or read() failed
918  return -1;
919 }
920 
927 std::size_t Imu::handleByte(const uint8_t& byte, bool& found) {
928  found = false;
929  if (state_ == Idle) {
930  // reset dstIndex_ to start of packet
931  dstIndex_ = 0;
932  if (byte == Imu::Packet::kSyncMSB) {
933  packet_.syncMSB = byte;
934  state_ = Reading;
935  // clear previous packet out
936  memset(&packet_.payload[0], 0, sizeof(packet_.payload));
937  } else {
938  // byte is no good, stay in idle
939  return 1;
940  }
941  }
942  else if (state_ == Reading) {
943  const size_t end = Packet::kHeaderLength + packet_.length;
944  // fill out fields of packet structure
945  if (dstIndex_ == 1) {
946  if (byte != Imu::Packet::kSyncLSB) {
947  // not a true header, throw away and go back to idle
948  state_ = Idle;
949  return 1;
950  }
951  packet_.syncLSB = byte;
952  }
953  else if (dstIndex_ == 2) {
954  packet_.descriptor = byte;
955  }
956  else if (dstIndex_ == 3) {
957  packet_.length = byte;
958  }
959  else if (dstIndex_ < end) {
961  }
962  else if (dstIndex_ == end) {
963  packet_.checkMSB = byte;
964  }
965  else if (dstIndex_ == end + 1) {
966  state_ = Idle; // finished packet
967  packet_.checkLSB = byte;
968 
969  // check checksum
970  const uint16_t sum = packet_.checksum;
972 
973  if (sum != packet_.checksum) {
974  // invalid, go back to waiting for a marker in the stream
975  std::cout << "Warning: Dropped packet with mismatched checksum\n"
976  << std::flush;
977  if (verbose_) {
978  std::cout << "Expected " << std::hex <<
979  static_cast<int>(packet_.checksum) << " but received " <<
980  static_cast<int>(sum) << std::endl;
981  std::cout << "Packet content:\n" << packet_.toString() << std::endl;
982  std::cout << "Queue content: \n";
983  for (const uint8_t& q : queue_) {
984  std::cout << static_cast<int>(q) << " ";
985  }
986  std::cout << "\n" << std::flush;
987  }
988  return 1;
989  } else {
990  // successfully read a packet
991  processPacket();
992  found = true;
993  return end+2;
994  }
995  }
996  }
997 
998  // advance to next byte in packet
999  dstIndex_++;
1000  return 0;
1001 }
1002 
1003 // parses packets out of the input buffer
1004 int Imu::handleRead(size_t bytes_transferred) {
1005  // read data into queue
1006  std::stringstream ss;
1007  ss << "Handling read : " << std::hex;
1008  for (size_t i = 0; i < bytes_transferred; i++) {
1009  queue_.push_back(buffer_[i]);
1010  ss << static_cast<int>(buffer_[i]) << " ";
1011  }
1012  ss << std::endl;
1013  if (verbose_) {
1014  std::cout << ss.str() << std::flush;
1015  }
1016 
1017  bool found = false;
1018  while (srcIndex_ < queue_.size() && !found) {
1019  const uint8_t head = queue_[srcIndex_];
1020  const size_t clear = handleByte(head, found);
1021  // pop 'clear' bytes from the queue
1022  for (size_t i=0; i < clear; i++) {
1023  queue_.pop_front();
1024  }
1025  if (clear) {
1026  // queue was shortened, return to head
1027  srcIndex_=0;
1028  } else {
1029  // continue up the queue
1030  srcIndex_++;
1031  }
1032  }
1033 
1034  // no packet
1035  return found;
1036 }
1037 
1039  IMUData data;
1040  FilterData filterData;
1041  PacketDecoder decoder(packet_);
1042 
1043  if (packet_.isIMUData()) {
1044  // process all fields in the packet
1045  for (int d; (d = decoder.fieldDescriptor()) > 0; decoder.advance()) {
1046  switch (u8(d)) {
1047  case FIELD_ACCELEROMETER:
1048  decoder.extract(3, &data.accel[0]);
1050  break;
1051  case FIELD_GYROSCOPE:
1052  decoder.extract(3, &data.gyro[0]);
1053  data.fields |= IMUData::Gyroscope;
1054  break;
1055  case FIELD_MAGNETOMETER:
1056  decoder.extract(3, &data.mag[0]);
1057  data.fields |= IMUData::Magnetometer;
1058  break;
1059  case FIELD_BAROMETER:
1060  decoder.extract(1, &data.pressure);
1061  data.fields |= IMUData::Barometer;
1062  break;
1063  default:
1064  std::stringstream ss;
1065  ss << "Unsupported field in IMU packet: " << std::hex << d;
1066  throw std::runtime_error(ss.str());
1067  break;
1068  }
1069  }
1070 
1071  if (imuDataCallback_) {
1072  imuDataCallback_(data);
1073  }
1074  } else if (packet_.isFilterData()) {
1075  for (int d; (d = decoder.fieldDescriptor()) > 0; decoder.advance()) {
1076  switch (u8(d)) {
1077  case FIELD_QUATERNION:
1078  decoder.extract(4, &filterData.quaternion[0]);
1079  decoder.extract(1, &filterData.quaternionStatus);
1080  filterData.fields |= FilterData::Quaternion;
1081  break;
1082  case FIELD_GYRO_BIAS:
1083  decoder.extract(3, &filterData.bias[0]);
1084  decoder.extract(1, &filterData.biasStatus);
1085  filterData.fields |= FilterData::Bias;
1086  break;
1088  decoder.extract(3, &filterData.angleUncertainty[0]);
1089  decoder.extract(1, &filterData.angleUncertaintyStatus);
1090  filterData.fields |= FilterData::AngleUnertainty;
1091  break;
1093  decoder.extract(3, &filterData.biasUncertainty[0]);
1094  decoder.extract(1, &filterData.biasUncertaintyStatus);
1095  filterData.fields |= FilterData::BiasUncertainty;
1096  break;
1097  default:
1098  std::stringstream ss;
1099  ss << "Unsupported field in filter packet: " << std::hex << d;
1100  throw std::runtime_error(ss.str());
1101  break;
1102  }
1103  }
1104 
1105  if (filterDataCallback_) {
1106  filterDataCallback_(filterData);
1107  }
1108  } else {
1109  // find any NACK fields and log them
1110  for (int d; (d = decoder.fieldDescriptor()) > 0; decoder.advance()) {
1111  if (decoder.fieldIsAckOrNack()) {
1112  uint8_t cmd_code[2]; // 0 = command echo, 1 = command code
1113  decoder.extract(2, &cmd_code[0]);
1114  if (cmd_code[1] != 0) {
1115  // error occurred
1116  std::cout << "Received NACK packet (class, command, code): ";
1117  std::cout << std::hex << static_cast<int>(packet_.descriptor) << ", ";
1118  std::cout << static_cast<int>(cmd_code[0]) << ", ";
1119  std::cout << static_cast<int>(cmd_code[1]) << "\n" << std::flush;
1120  }
1121  }
1122  }
1123  }
1124 }
1125 
1126 int Imu::writePacket(const Packet &p, unsigned int to) {
1127  using namespace std::chrono;
1128 
1129  // place into buffer
1130  std::vector<uint8_t> v;
1131  v.reserve(Packet::kHeaderLength + sizeof(Packet::payload) + 2);
1132 
1133  v.push_back(p.syncMSB);
1134  v.push_back(p.syncLSB);
1135  v.push_back(p.descriptor);
1136  v.push_back(p.length);
1137  for (size_t i = 0; i < p.length; i++) {
1138  v.push_back(p.payload[i]);
1139  }
1140  v.push_back(p.checkMSB);
1141  v.push_back(p.checkLSB);
1142 
1143  auto tstart = high_resolution_clock::now();
1144  auto tstop = tstart + milliseconds(to);
1145 
1146  size_t written = 0;
1147  while (written < v.size()) {
1148  const ssize_t amt = ::write(fd_, &v[written], v.size() - written);
1149  if (amt > 0) {
1150  written += amt;
1151  } else if (amt < 0) {
1152  if (errno == EAGAIN || errno == EINTR) {
1153  // blocked or interrupted - try again until timeout
1154  } else {
1155  return -1; // error while writing
1156  }
1157  }
1158 
1159  if (tstop < high_resolution_clock::now()) {
1160  return 0; // timed out
1161  }
1162  }
1163 
1164  return static_cast<int>(written); // wrote w/o issue
1165 }
1166 
1167 void Imu::sendPacket(const Packet &p, unsigned int to) {
1168  const int wrote = writePacket(p, to);
1169  if (wrote < 0) {
1170  throw io_error(strerror(errno));
1171  } else if (wrote == 0) {
1172  throw timeout_error(true,to);
1173  }
1174 }
1175 
1176 void Imu::receiveResponse(const Packet &command, unsigned int to) {
1177  // read back response
1178  const auto tstart = std::chrono::high_resolution_clock::now();
1179  const auto tend = tstart + std::chrono::milliseconds(to);
1180 
1181  while (std::chrono::high_resolution_clock::now() <= tend) {
1182  const int resp = pollInput(1);
1183  if (resp > 0) {
1184  // check if this is an ack
1185  const int ack = packet_.ackErrorCodeFor(command);
1186 
1187  if (ack == 0) {
1188  return; // success, exit
1189  } else if (ack > 0) {
1190  throw command_error(command, ack);
1191  } else {
1192  if (verbose_) {
1193  std::cout << "Not interested in this [N]ACK!\n";
1194  std::cout << packet_.toString() << "\n";
1195  }
1196  // this ack was not for us, keep spinning until timeout
1197  }
1198  } else if (resp < 0) {
1199  throw io_error(strerror(errno));
1200  } else {
1201  // resp == 0 keep reading until timeout
1202  }
1203  }
1204  if (verbose_) {
1205  std::cout << "Timed out reading response to:\n";
1206  std::cout << command.toString() << std::endl << std::flush;
1207  }
1208  // timed out
1209  throw timeout_error(false, to);
1210 }
1211 
1212 void Imu::sendCommand(const Packet &p, bool readReply) {
1213  if (verbose_) {
1214  std::cout << "Sending command:\n";
1215  std::cout << p.toString() << std::endl;
1216  }
1217  sendPacket(p, rwTimeout_);
1218  if (readReply) {
1220  }
1221 }
#define COMMAND_SET_HARD_IRON
Definition: imu.cpp:68
d
void setIMUDataRate(uint16_t decimation, const std::bitset< 4 > &sources)
setIMUDataRate Set imu data rate for different sources.
Definition: imu.cpp:741
#define FIELD_IMU_BASERATE
Definition: imu.cpp:83
#define DATA_CLASS_IMU
Definition: imu.cpp:46
void extract(size_t count, T *output)
Definition: imu.cpp:245
command_error(const Packet &p, uint8_t code)
Definition: imu.cpp:375
Packet packet_
Definition: imu.hpp:432
std::map< std::string, std::string > toMap() const
Device options (range of the sensor)
Definition: imu.cpp:338
#define DEVICE_IDLE
Definition: imu.cpp:56
void getDeviceInfo(Imu::Info &info)
getDeviceInfo Get hardware information about the device.
Definition: imu.cpp:664
#define COMMAND_IMU_MESSAGE_FORMAT
Definition: imu.cpp:63
#define FIELD_GYRO_BIAS
Definition: imu.cpp:77
bool advanceTo(uint8_t field)
Definition: imu.cpp:230
uint32_t usbNumReadOverruns
Definition: imu.hpp:19
uint8_t selector
Definition: imu.hpp:3
command_error Generated when device replies with NACK.
Definition: imu.hpp:213
Tool for decoding packets by iterating through fields.
Definition: imu.cpp:201
static constexpr uint8_t kSyncLSB
Definition: imu.hpp:4
#define FIELD_QUATERNION
Definition: imu.cpp:74
void setHardIronOffset(float offset[3])
setHardIronOffset Set the hard-iron bias vector for the magnetometer.
Definition: imu.cpp:830
std::string deviceOptions
Lot number - appears to be unused.
Definition: imu.hpp:118
virtual ~PacketEncoder()
Definition: imu.cpp:166
std::string modelNumber
Model name.
Definition: imu.hpp:115
#define COMMAND_UART_BAUD_RATE
Definition: imu.cpp:67
#define DEVICE_RESUME
Definition: imu.cpp:57
uint32_t totalIMUMessages
Definition: imu.hpp:21
void runOnce()
runOnce Poll for input and read packets if available.
Definition: imu.cpp:520
void connect()
connect Open a file descriptor to the serial device.
Definition: imu.cpp:407
int fieldLength() const
Definition: imu.cpp:217
uint32_t statusFlags
Definition: imu.hpp:4
uint8_t fs_
Definition: imu.cpp:253
#define COMMAND_CLASS_FILTER
Definition: imu.cpp:44
uint32_t systemTimer
Definition: imu.hpp:5
std::string modelName
Firmware version.
Definition: imu.hpp:114
uint32_t comBytesRead
Definition: imu.hpp:13
static constexpr uint8_t kSyncLSB
Definition: imu.hpp:48
uint32_t last1PPSPulse
Definition: imu.hpp:7
uint8_t length
Definition: imu.hpp:15
XmlRpcServer s
uint32_t usbNumWriteOverruns
Definition: imu.hpp:18
static constexpr uint8_t kSyncMSB
Definition: imu.hpp:47
const Imu::Packet & p_
Definition: imu.cpp:252
uint32_t lastIMUMessage
Definition: imu.hpp:22
data
#define FIELD_ACCELEROMETER
Definition: imu.cpp:75
int fieldDescriptor() const
Definition: imu.cpp:207
#define FIELD_GYROSCOPE
Definition: imu.cpp:76
uint32_t imuPacketsDropped
Definition: imu.hpp:10
int pollInput(unsigned int to)
Definition: imu.cpp:893
int writePacket(const Packet &p, unsigned int to)
Definition: imu.cpp:1126
void enableFilterStream(bool enabled)
enableFilterStream Enable/disable streaming of estimation filter data.
Definition: imu.cpp:869
std::map< std::string, unsigned int > toMap() const
Convert to map of human readable strings and integers.
Definition: imu.cpp:349
void append(const Ts &...args)
Definition: imu.cpp:181
const bool verbose_
Definition: imu.hpp:418
#define FUNCTION_APPLY
Definition: imu.cpp:49
static constexpr uint8_t kSyncMSB
Definition: imu.hpp:3
std::vector< uint8_t > buffer_
Definition: imu.hpp:422
uint32_t num1PPSPulses
Definition: imu.hpp:6
io_error Generated when a low-level IO command fails.
Definition: imu.hpp:223
void enableBiasEstimation(bool enabled)
enableBiasEstimation Enable gyroscope bias estimation
Definition: imu.cpp:816
#define COMMAND_SET_SOFT_IRON
Definition: imu.cpp:69
bool fieldIsAckOrNack() const
Definition: imu.cpp:222
void endField()
Definition: imu.cpp:186
uint16_t modelNumber
Definition: imu.hpp:2
const std::string device_
Definition: imu.hpp:417
void calcChecksum()
Calculate the packet checksum. Sets the checksum variable.
Definition: imu.cpp:291
void advance()
Definition: imu.cpp:239
DiagnosticFields struct (See 3DM documentation for these fields)
Definition: imu.hpp:129
bool isIMUData() const
True if this packet corresponds to an imu data message.
Definition: imu.cpp:257
uint16_t biasUncertaintyStatus
Definition: imu.hpp:203
#define DATA_CLASS_FILTER
Definition: imu.cpp:47
#define u8(x)
Definition: imu.cpp:40
uint32_t comBytesWritten
Definition: imu.hpp:12
#define COMAMND_FILTER_MESSAGE_FORMAT
Definition: imu.cpp:64
uint8_t checkLSB
Definition: imu.hpp:22
timeout_error(bool write, unsigned int to)
Definition: imu.cpp:385
#define FIELD_DEVICE_INFO
Definition: imu.cpp:82
Tool for encoding packets more easily by simply appending fields.
Definition: imu.cpp:161
void getDiagnosticInfo(Imu::DiagnosticFields &fields)
getDiagnosticInfo Get diagnostic information from the IMU.
Definition: imu.cpp:719
Imu::DiagnosticFields fields
Definition: imu_3dm_gx4.cpp:28
void sendPacket(const Packet &p, unsigned int to)
Definition: imu.cpp:1167
std::deque< uint8_t > queue_
Definition: imu.hpp:423
std::string generateString(bool write, unsigned int to)
Definition: imu.cpp:388
#define COMMAND_GET_FILTER_BASE_RATE
Definition: imu.cpp:62
std::function< void(const Imu::FilterData &)> filterDataCallback_
Called with IMU data is ready.
Definition: imu.hpp:429
#define FIELD_ACK_OR_NACK
Definition: imu.cpp:86
FilterData Estimator readings produced by the sensor.
Definition: imu.hpp:183
#define COMMAND_DEVICE_STATUS
Definition: imu.cpp:71
#define COMMAND_ENABLE_DATA_STREAM
Definition: imu.cpp:65
uint8_t filterStreamEnabled
Definition: imu.hpp:9
Imu::Packet & p_
Definition: imu.cpp:193
std::string lotNumber
Serial number.
Definition: imu.hpp:117
#define FIELD_BIAS_UNCERTAINTY
Definition: imu.cpp:80
uint32_t comNumReadOverruns
Definition: imu.hpp:15
#define COMMAND_CLASS_BASE
Definition: imu.cpp:42
enum imu_3dm_gx4::Imu::@0 state_
Called when filter data is ready.
uint8_t pos_
Definition: imu.cpp:254
bool termiosBaudRate(unsigned int baud)
Definition: imu.cpp:477
PacketDecoder(const Imu::Packet &p)
Definition: imu.cpp:203
virtual ~Imu()
~Imu Destructor
Definition: imu.cpp:405
int ackErrorCodeFor(const Packet &command) const
Extract the ACK code from this packet.
Definition: imu.cpp:265
uint8_t fs_
Definition: imu.cpp:194
IMUData IMU readings produced by the sensor.
Definition: imu.hpp:162
void disconnect()
disconnect Close the file descriptor, sending the IDLE command first.
Definition: imu.cpp:468
#define kDefaultTimeout
Definition: imu.cpp:37
#define kBufferSize
Definition: imu.cpp:38
void getFilterDataBaseRate(uint16_t &baseRate)
getFilterDataBaseRate Get the filter data base rate (should be 500)
Definition: imu.cpp:708
timeout_error Generated when read or write times out, usually indicates device hang up...
Definition: imu.hpp:231
#define add_byte(x)
uint8_t syncMSB
Definition: imu.hpp:8
PacketEncoder(Imu::Packet &p)
Definition: imu.cpp:163
void ping()
ping Ping the device.
Definition: imu.cpp:634
std::string toString() const
Make a &#39;human-readable&#39; version of the packet.
Definition: imu.cpp:322
uint8_t syncLSB
Definition: imu.hpp:9
uint8_t payload[255]
Definition: imu.hpp:61
Imu::Info info
Definition: imu_3dm_gx4.cpp:27
uint16_t angleUncertaintyStatus
Definition: imu.hpp:200
#define DEVICE_PING
Definition: imu.cpp:55
std::function< void(const Imu::IMUData &)> imuDataCallback_
Definition: imu.hpp:427
#define COMMAND_CLASS_3DM
Definition: imu.cpp:43
#define COMMAND_GET_DEVICE_INFO
Definition: imu.cpp:60
void receiveResponse(const Packet &command, unsigned int to)
Definition: imu.cpp:1176
bool isFilterData() const
True if this packet corresponds to a filter data message.
Definition: imu.cpp:261
std::size_t handleByte(const uint8_t &byte, bool &found)
Definition: imu.cpp:927
#define FIELD_MAGNETOMETER
Definition: imu.cpp:78
void beginField(uint8_t desc)
Definition: imu.cpp:171
void setFilterDataCallback(const std::function< void(const Imu::FilterData &)> &)
Set the onboard filter data callback.
Definition: imu.cpp:888
static constexpr uint8_t kHeaderLength
Definition: imu.hpp:46
bool enc_
Definition: imu.cpp:195
void decode(const uint8_t *buffer, size_t count, T *output)
Definition: imu.cpp:137
#define FIELD_BAROMETER
Definition: imu.cpp:81
std::string generateString(const Packet &p, uint8_t code)
Definition: imu.cpp:378
uint32_t filterPacketsDropped
Definition: imu.hpp:11
int handleRead(size_t)
Definition: imu.cpp:1004
void setSoftIronMatrix(float matrix[9])
setSoftIronMatrix Set the soft-iron matrix for the magnetometer.
Definition: imu.cpp:841
void setFilterDataRate(uint16_t decimation, const std::bitset< 4 > &sources)
setFilterDataRate Set estimator data rate for different sources.
Definition: imu.cpp:771
uint32_t numIMUParseErrors
Definition: imu.hpp:20
void resume()
resume Resume the device.
Definition: imu.cpp:654
uint8_t imuStreamEnabled
Definition: imu.hpp:8
uint16_t checksum
Definition: imu.hpp:24
#define SELECTOR_IMU
Definition: imu.cpp:51
unsigned int fields
Definition: imu.hpp:170
void to_device_order< 1 >(uint8_t buffer[1])
Definition: imu.cpp:107
unsigned int rwTimeout_
Definition: imu.hpp:420
void getIMUDataBaseRate(uint16_t &baseRate)
getIMUDataBaseRate Get the imu data base rate (should be 1000)
Definition: imu.cpp:693
uint8_t checkMSB
Definition: imu.hpp:21
size_t dstIndex_
Definition: imu.hpp:424
#define COMMAND_GET_IMU_BASE_RATE
Definition: imu.cpp:61
void setIMUDataCallback(const std::function< void(const Imu::IMUData &)> &)
Set the IMU data callback.
Definition: imu.cpp:884
#define FIELD_STATUS_REPORT
Definition: imu.cpp:85
void processPacket()
Definition: imu.cpp:1038
uint32_t usbBytesWritten
Definition: imu.hpp:16
void enableMeasurements(bool accel, bool magnetometer)
enableMeasurements Set which measurements to enable in the filter
Definition: imu.cpp:799
uint8_t descriptor
Definition: imu.hpp:14
#define COMMAND_FILTER_CONTROL_FLAGS
Definition: imu.cpp:66
void selectBaudRate(unsigned int baud)
selectBaudRate Select baud rate.
Definition: imu.cpp:528
static std::string ltrim(std::string s)
Definition: imu.cpp:91
size_t srcIndex_
Definition: imu.hpp:424
void enableIMUStream(bool enabled)
enableIMUStream Enable/disable streaming of IMU data
Definition: imu.cpp:855
void sendCommand(const Packet &p, bool readReply=true)
Definition: imu.cpp:1212
#define SELECTOR_FILTER
Definition: imu.cpp:52
Imu(const std::string &device, bool verbose)
Imu Constructor.
Definition: imu.cpp:396
#define FIELD_ANGLE_UNCERTAINTY
Definition: imu.cpp:79
#define COMMAND_ENABLE_MEASUREMENTS
Definition: imu.cpp:70
uint16_t firmwareVersion
Definition: imu.hpp:113
size_t encode(uint8_t *buffer, const T &t)
Definition: imu.cpp:109
Info Structure generated by the getDeviceInfo command.
Definition: imu.hpp:112
void idle(bool needReply=true)
idle Switch the device to idle mode.
Definition: imu.cpp:644
Packet(uint8_t desc=0)
Constructor.
Definition: imu.cpp:316
std::string serialNumber
Model number.
Definition: imu.hpp:116
uint32_t usbBytesRead
Definition: imu.hpp:17
void to_device_order(uint8_t buffer[sz])
Definition: imu.cpp:99
uint8_t payload[255]
Definition: imu.hpp:17


thormang3_imu_3dm_gx4
Author(s): Gareth Cross, SCH
autogenerated on Mon Jun 10 2019 15:26:53