Fawkes API  Fawkes Development Version
imu_cruizcore_xg1010.cpp
1 
2 /***************************************************************************
3  * imu_cruizcore_xg1010.cpp - Retrieve IMU data from CruizCore XG1010
4  *
5  * Created: Sun Jun 22 21:44:17 2014
6  * Copyright 2008-2014 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Library General Public License for more details.
18  *
19  * Read the full text in the LICENSE.GPL file in the doc directory.
20  */
21 
22 #include "imu_cruizcore_xg1010.h"
23 
24 #include <core/threading/mutex.h>
25 #include <core/threading/mutex_locker.h>
26 
27 #include <tf/types.h>
28 #include <utils/math/angle.h>
29 #ifdef USE_TIMETRACKER
30 # include <utils/time/tracker.h>
31 #endif
32 #include <utils/time/tracker_macros.h>
33 
34 #include <boost/bind.hpp>
35 
36 #include <cstdlib>
37 #include <cstdio>
38 #include <cstring>
39 #include <unistd.h>
40 
41 using namespace fawkes;
42 
43 #define RECONNECT_INTERVAL 2000
44 
45 /** @class CruizCoreXG1010AcquisitionThread "imu_cruizcore_xg1010.h"
46  * IMU acquisition thread for CruizCore XG1010 gyros.
47  * @author Tim Niemueller
48  */
49 
50 
51 /// @cond OLD_BOOST_COMPAT
52 
53 #if BOOST_VERSION < 104800
54 
55 // The default maximum number of bytes to transfer in a single operation.
56 enum { default_max_transfer_size = 65536 };
57 
58 class transfer_exactly_t
59 {
60  public:
61  typedef std::size_t result_type;
62 
63  explicit transfer_exactly_t(std::size_t size)
64  : size_(size) {}
65 
66  template <typename Error>
67  std::size_t operator()(const Error& err, std::size_t bytes_transferred)
68  {
69  return (!!err || bytes_transferred >= size_) ? 0 :
70  (size_ - bytes_transferred < default_max_transfer_size
71  ? size_ - bytes_transferred : std::size_t(default_max_transfer_size));
72  }
73 
74  private:
75  std::size_t size_;
76 };
77 
78 inline transfer_exactly_t transfer_exactly(std::size_t size)
79 {
80  return transfer_exactly_t(size);
81 }
82 #endif
83 
84 /// @endcond
85 
86 
87 /** Constructor.
88  * @param cfg_name short name of configuration group
89  * @param cfg_prefix configuration path prefix
90  * @param continuous true to run continuous, false otherwise
91  */
93  std::string &cfg_prefix,
94  bool continuous)
95  : IMUAcquisitionThread(cfg_name.c_str(), continuous, cfg_name, cfg_prefix),
96  serial_(io_service_), io_service_work_(io_service_), deadline_(io_service_)
97 {
98  set_name("CruizCoreXG1010(%s)", cfg_name.c_str());
99 }
100 
101 void
103 {
104  deadline_.expires_at(boost::posix_time::pos_infin);
105  check_deadline();
106 
107  cfg_serial_ = config->get_string((cfg_prefix_ + "device").c_str());
108  cfg_baud_rate_ = config->get_uint((cfg_prefix_ + "baud_rate").c_str());
109  cfg_freq_ = config->get_uint((cfg_prefix_ + "data_frequency").c_str());
110 
111  if (cfg_freq_ != 25 && cfg_freq_ != 50 && cfg_freq_ != 100) {
112  throw Exception("Invalid data frequency, must be 25, 50, or 100");
113  }
114  if (cfg_baud_rate_ != 115200 && cfg_baud_rate_ != 57600 &&
115  cfg_baud_rate_ != 38400 && cfg_baud_rate_ != 28800 &&
116  cfg_baud_rate_ != 19200 && cfg_baud_rate_ != 9600 && cfg_baud_rate_ != 4800)
117  {
118  throw Exception("Invalid baud rate");
119  }
120 
121  if ( (cfg_freq_ > 25 && cfg_baud_rate_ < 9600) ||
122  (cfg_freq_ > 50 && cfg_baud_rate_ < 19200) )
123  {
124  throw Exception("Baud rate too low for frequency");
125  }
126 
127  // wait up to two expected packets
128  receive_timeout_ = (1000 / cfg_freq_) * 2;
129  //logger->log_debug(name(), "Receive timeout: %u ms", receive_timeout_);
130 
131  // No acceleration data available, set to -1
132  linear_acceleration_[0] = -1.;
133 
134  // from XG1010 data sheet
136 
137  open_device();
138 
140 
141 #ifdef USE_TIMETRACKER
142  tt_ = new TimeTracker();
143  tt_loopcount_ = 0;
144  ttc_full_loop_ = tt_->add_class("Full Loop");
145  ttc_read_ = tt_->add_class("Read");
146  ttc_catch_up_ = tt_->add_class("Catch up");
147  ttc_parse_ = tt_->add_class("Parse");
148 #endif
149 }
150 
151 
152 void
154 {
155  close_device();
157 #ifdef USE_TIMETRACKER
158  delete tt_;
159 #endif
160 }
161 
162 
163 void
165 {
166  TIMETRACK_START(ttc_full_loop_);
167 
168  if (serial_.is_open()) {
169 
170  // reset data for the case that we timeout or fail
171  angular_velocity_[2] = 0;
172  orientation_[0] = orientation_[1] = orientation_[2] = orientation_[3] = 0.;
173 
174  try {
175  TIMETRACK_START(ttc_read_);
176  deadline_.expires_from_now(boost::posix_time::milliseconds(receive_timeout_));
177 
178  ec_ = boost::asio::error::would_block;
179  bytes_read_ = 0;
180 
181  size_t to_read = CRUIZCORE_XG1010_PACKET_SIZE;
182  // if there is partial data in the buffer we are running behind
183  // read off old packet, catch up later will trigger if we had more data
184  if (input_buffer_.size() > 0) {
185  const size_t bsize = input_buffer_.size();
186  size_t full_frames = bsize / CRUIZCORE_XG1010_PACKET_SIZE;
187  size_t remaining =
188  CRUIZCORE_XG1010_PACKET_SIZE - (bsize - full_frames * CRUIZCORE_XG1010_PACKET_SIZE);
189  to_read = remaining;
190  }
191 
192  //logger->log_debug(name(), "Read %zu bytes", to_read);
193  boost::asio::async_read(serial_, input_buffer_,
194 #if BOOST_VERSION >= 104800
195  boost::asio::transfer_exactly(to_read),
196  (boost::lambda::var(ec_) = boost::lambda::_1,
197  boost::lambda::var(bytes_read_) = boost::lambda::_2));
198 #else
199  transfer_exactly(to_read),
200  boost::bind(
201  &CruizCoreXG1010AcquisitionThread::handle_read,
202  this,
203  boost::asio::placeholders::error,
204  boost::asio::placeholders::bytes_transferred
205  ));
206 #endif
207 
208  do io_service_.run_one(); while (ec_ == boost::asio::error::would_block);
209 
210  //logger->log_debug(name(), "Done");
211 
212  TIMETRACK_END(ttc_read_);
213 
214  data_mutex_->lock();
215  timestamp_->stamp();
216  data_mutex_->unlock();
217 
218  if (ec_) {
219  if (ec_.value() == boost::system::errc::operation_canceled) {
220  logger->log_error(name(), "Data timeout, will try to reconnect");
221  } else {
222  logger->log_warn(name(), "Data read error: %s\n", ec_.message().c_str());
223  }
224  data_mutex_->lock();
225  new_data_ = true;
226  data_mutex_->unlock();
227  close_device();
228  } else {
229  TIMETRACK_START(ttc_catch_up_);
230  bytes_read_ = 0;
231  bool catch_up = false;
232  size_t read_size = 0;
233  do {
234  ec_ = boost::asio::error::would_block;
235 
236  size_t to_read = CRUIZCORE_XG1010_PACKET_SIZE;
237  if (catch_up) {
238  deadline_.expires_from_now(boost::posix_time::milliseconds(receive_timeout_));
239  size_t full_frames = read_size / CRUIZCORE_XG1010_PACKET_SIZE;
240  size_t remaining = CRUIZCORE_XG1010_PACKET_SIZE - (read_size - full_frames * CRUIZCORE_XG1010_PACKET_SIZE);
241  to_read = remaining;
242  } else {
243  deadline_.expires_from_now(boost::posix_time::microseconds(10));
244  }
245  catch_up = false;
246 
247  bytes_read_ = 0;
248 
249  //logger->log_debug(name(), "Catch up read %zu bytes", to_read);
250  boost::asio::async_read(serial_, input_buffer_,
251 #if BOOST_VERSION >= 104800
252  boost::asio::transfer_exactly(to_read),
253  (boost::lambda::var(ec_) = boost::lambda::_1,
254  boost::lambda::var(bytes_read_) = boost::lambda::_2));
255 #else
256  transfer_exactly(to_read),
257  boost::bind(
258  &CruizCoreXG1010AcquisitionThread::handle_read,
259  this,
260  boost::asio::placeholders::error,
261  boost::asio::placeholders::bytes_transferred
262  ));
263 #endif
264 
265  do io_service_.run_one(); while (ec_ == boost::asio::error::would_block);
266 
267  if (bytes_read_ > 0) {
268  read_size += bytes_read_;
269  catch_up = (read_size % CRUIZCORE_XG1010_PACKET_SIZE != 0);
270  ec_ = boost::system::error_code();
271  }
272  } while (bytes_read_ > 0);
273  }
274 
275  TIMETRACK_END(ttc_catch_up_);
276 
277  if (ec_ && ec_.value() != boost::system::errc::operation_canceled) {
278  logger->log_warn(name(), "Data read error: %s\n", ec_.message().c_str());
279 
280  data_mutex_->lock();
281  new_data_ = true;
282  data_mutex_->unlock();
283  close_device();
284  } else {
285  if (input_buffer_.size() >= CRUIZCORE_XG1010_PACKET_SIZE) {
286  TIMETRACK_START(ttc_parse_);
287  if (input_buffer_.size() > CRUIZCORE_XG1010_PACKET_SIZE) {
288  input_buffer_.consume(input_buffer_.size() - CRUIZCORE_XG1010_PACKET_SIZE);
289  }
290  std::istream in_stream(&input_buffer_);
291  in_stream.read((char *)in_packet_, CRUIZCORE_XG1010_PACKET_SIZE);
292 
293  /*
294  printf("Packet (%zu): ", bytes_read_);
295  for (size_t i = 0; i < bytes_read_; ++i) {
296  printf("%x ", in_packet_[i] & 0xff);
297  }
298  printf("\n");
299  */
300 
301  try {
302  parse_packet();
303  } catch (Exception &e) {
304  logger->log_warn(name(), e);
305  try {
306  resync();
307  logger->log_info(name(), "Successfully resynced");
308  } catch (Exception &e) {
309  logger->log_warn(name(), "Resync failed, trying to re-open");
310  close_device();
311  }
312  }
313  TIMETRACK_END(ttc_parse_);
314  } else {
315  logger->log_warn(name(), "*** INVALID number of bytes in buffer: %zu\n", input_buffer_.size());
316  }
317  }
318  } catch (boost::system::system_error &e) {
319  if (e.code() == boost::asio::error::eof) {
320  close_device();
321  logger->log_warn(name(),
322  "CruizCoreXG1010 connection lost, trying to re-open");
323  } else {
324  logger->log_warn(name(), "CruizCore failed read: %s", e.what());
325  }
326  }
327  } else {
328  try {
329  open_device();
330  logger->log_warn(name(), "Reconnected to device");
331  } catch (Exception &e) {
332  // ignore, keep trying
333  usleep(RECONNECT_INTERVAL * 1000);
334  }
335  }
336 
338 
339  yield();
340  TIMETRACK_END(ttc_full_loop_);
341 #ifdef USE_TIMETRACKER
342  if (++tt_loopcount_ >= 50) {
343  tt_loopcount_ = 0;
344  tt_->print_to_stdout();
345  }
346 #endif
347 }
348 
349 
350 void
351 CruizCoreXG1010AcquisitionThread::open_device()
352 {
353  try {
354  input_buffer_.consume(input_buffer_.size());
355 
356  serial_.open(cfg_serial_);
357  // according to CruizCore R1050K (sensor in XG1010) technical manual
358  serial_.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
359  serial_.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
360  serial_.set_option(boost::asio::serial_port::baud_rate(cfg_baud_rate_));
361 
362  send_init_packet(/* enable transfer */ true);
363 
364  resync();
365  } catch (boost::system::system_error &e) {
366  throw Exception("CruizCore-XG1010 failed I/O: %s", e.what());
367  }
368 }
369 
370 
371 void
372 CruizCoreXG1010AcquisitionThread::send_init_packet(bool enable_transfer)
373 {
374  /* Format according to Technical Manual of R1050K for XG1010
375  Field Command Separator Example
376  INIT $MIA COMMA (,) $MIA,
377  FORMAT F, I or A COMMA (,) I,
378  BAUD RATE B,BAUDRATE COMMA (,) B,115200,
379  OUTPUT RATE R COMMA (,) R,100,
380  TYPE D or R COMMA (,) D,
381  OUTPUT Y or N COMMA (,) Y,
382  FLASH Y or N COMMA (,) Y,
383  CHECKSUM SUM of COMMAND ASTERISK(*) *C4
384  */
385  char *cmd_packet;
386  if (asprintf(&cmd_packet, "$MIA,I,B,%u,R,%u,D,%s,N* ", cfg_baud_rate_, cfg_freq_,
387  enable_transfer ? "Y" : "N") == -1)
388  {
389  throw Exception("Failed to create command packet");
390  }
391 
392  size_t cmd_packet_len = strlen(cmd_packet);
393 
394  // calculate checksum
395  unsigned int checksum = 0;
396  for(size_t i = 1; i < cmd_packet_len - 3; ++i ) checksum += cmd_packet[i];
397  checksum &= 0xFF;
398 
399  char checksum_str[3];
400  snprintf(checksum_str, 3, "%X", checksum);
401  cmd_packet[cmd_packet_len - 2] = checksum_str[0];
402  cmd_packet[cmd_packet_len - 1] = checksum_str[1];
403 
404  std::string cmd_packet_s(cmd_packet, cmd_packet_len);
405  free(cmd_packet);
406 
407  logger->log_debug(name(), "Sending init packet: %s", cmd_packet_s.c_str());
408 
409  boost::asio::write(serial_, boost::asio::buffer(cmd_packet_s.c_str(), cmd_packet_len));
410 
411 }
412 
413 void
414 CruizCoreXG1010AcquisitionThread::resync()
415 {
416  /*
417  // the idea here would be to:
418  // 1. stop data transfer
419  // 2. read all remaining data, i.e. flush serial line
420  // 3. start data transfer again
421  // 4. synchronize with packet stream
422  // the only problem being that once the transfer has been stopped it
423  // cannot be enabled again, this seems to be a bug in the CruizCore XG1010.
424 
425  // stop transfer and sniff off any data still arriving
426  send_init_packet(/ enable transfer / false);
427  try {
428  do {
429  ec_ = boost::asio::error::would_block;
430  deadline_.expires_from_now(boost::posix_time::milliseconds(receive_timeout_));
431  bytes_read_ = 0;
432 
433  boost::asio::async_read(serial_, input_buffer_,
434 #if BOOST_VERSION >= 104800
435  (boost::lambda::var(ec_) = boost::lambda::_1,
436  boost::lambda::var(bytes_read_) = boost::lambda::_2));
437 #else
438  boost::bind(
439  &CruizCoreXG1010AcquisitionThread::handle_read,
440  this,
441  boost::asio::placeholders::error,
442  boost::asio::placeholders::bytes_transferred
443  ));
444 #endif
445 
446  do io_service_.run_one(); while (ec_ == boost::asio::error::would_block);
447 
448  input_buffer_.consume(input_buffer_.size());
449 
450  logger->log_warn(name(), "EC: %s\n", ec_.message().c_str());
451  } while (!ec_ && bytes_read_ > 0);
452  } catch (boost::system::system_error &e) {
453  // ignore, just assume done, if there really is an error we'll
454  // catch it later on
455  }
456 
457  send_init_packet(/ enable transfer / true);
458  */
459 
460 #if BOOST_VERSION >= 104700
461  tcflush(serial_.lowest_layer().native_handle(), TCIOFLUSH);
462 #else
463  tcflush(serial_.lowest_layer().native(), TCIOFLUSH);
464 #endif
465 
466  // Try 10 times
467  const int NUM_TRIES = 10;
468  for (int t = 1; t <= NUM_TRIES; ++t) {
469  try {
470  ec_ = boost::asio::error::would_block;
471  bytes_read_ = 0;
472 
473  deadline_.expires_from_now(boost::posix_time::milliseconds(receive_timeout_ * 10));
474  boost::asio::async_read_until(serial_, input_buffer_, std::string("\xff\xff"),
475 #if BOOST_VERSION >= 104800
476  (boost::lambda::var(ec_) = boost::lambda::_1,
477  boost::lambda::var(bytes_read_) = boost::lambda::_2));
478 #else
479  boost::bind(
480  &CruizCoreXG1010AcquisitionThread::handle_read,
481  this,
482  boost::asio::placeholders::error,
483  boost::asio::placeholders::bytes_transferred
484  ));
485 #endif
486 
487  do io_service_.run_one(); while (ec_ == boost::asio::error::would_block);
488 
489  if (ec_) {
490  if (ec_.value() == boost::system::errc::operation_canceled) {
491  throw Exception("Timeout (1) on initial synchronization");
492  } else {
493  throw Exception("Error (1) on initial synchronization: %s", ec_.message().c_str());
494  }
495  }
496 
497  input_buffer_.consume(bytes_read_ - 2);
498 
499  deadline_.expires_from_now(boost::posix_time::milliseconds(receive_timeout_));
500  ec_ = boost::asio::error::would_block;
501  bytes_read_ = 0;
502  boost::asio::async_read(serial_, input_buffer_,
503 #if BOOST_VERSION >= 104800
504  boost::asio::transfer_exactly(CRUIZCORE_XG1010_PACKET_SIZE - 2),
505  (boost::lambda::var(ec_) = boost::lambda::_1,
506  boost::lambda::var(bytes_read_) = boost::lambda::_2));
507 #else
508  transfer_exactly(CRUIZCORE_XG1010_PACKET_SIZE - 2),
509  boost::bind(
510  &CruizCoreXG1010AcquisitionThread::handle_read,
511  this,
512  boost::asio::placeholders::error,
513  boost::asio::placeholders::bytes_transferred
514  ));
515 #endif
516 
517  do io_service_.run_one(); while (ec_ == boost::asio::error::would_block);
518 
519  if (ec_) {
520  if (ec_.value() == boost::system::errc::operation_canceled) {
521  throw Exception("Timeout (2) on initial synchronization");
522  } else {
523  throw Exception("Error (2) on initial synchronization: %s", ec_.message().c_str());
524  }
525  }
526 
527  std::istream in_stream(&input_buffer_);
528  in_stream.read((char *)in_packet_, CRUIZCORE_XG1010_PACKET_SIZE);
529 
530  parse_packet();
531  } catch (Exception &e) {
532  if (t == NUM_TRIES) {
533  e.append("Resync failed after %d tries", NUM_TRIES);
534  throw;
535  }
536  //else {
537  //logger->log_warn(name(), "Resync retry %i failed, retrying %i more time%s",
538  // t, NUM_TRIES - t, (NUM_TRIES - t == 1) ? "" : "s");
539  //}
540  }
541  }
542  deadline_.expires_at(boost::posix_time::pos_infin);
543 }
544 
545 
546 void
547 CruizCoreXG1010AcquisitionThread::close_device()
548 {
549  serial_.close();
550 }
551 
552 void
553 CruizCoreXG1010AcquisitionThread::parse_packet()
554 {
555  /*
556  printf("Packet: ");
557  for (size_t i = 0; i < CRUIZCORE_XG1010_PACKET_SIZE; ++i) {
558  printf("%x ", in_packet_[i] & 0xff);
559  }
560  printf("\n");
561  */
562 
563  if( in_packet_[0] != 0xFF || in_packet_[1] != 0xFF ) {
564  throw Exception("Failed to parse packet, invalid header");
565  }
566 
567  short int rate = ( in_packet_[2] & 0xFF) | ((in_packet_[3] << 8) & 0xFF00);
568  short int angle = ( in_packet_[4] & 0xFF) | ((in_packet_[5] << 8) & 0XFF00);
569 
570  int checksum = 0xffff + rate + angle;
571  if(((unsigned char)(checksum & 0xFF) != in_packet_[6]) ||
572  ((unsigned char)((checksum>>8) & 0xFF) != in_packet_[7]))
573  {
574  /*
575  printf("Packet: ");
576  for (size_t i = 0; i < CRUIZCORE_XG1010_PACKET_SIZE; ++i) {
577  printf("%x ", in_packet_[i] & 0xff);
578  }
579  printf("\n");
580  */
581  throw Exception("Failed to parse packet, checksum mismatch");
582  }
583 
584  data_mutex_->lock();
585  new_data_ = true;
586 
587  angular_velocity_[2] = -deg2rad(rate / 100.f);
588 
589  tf::Quaternion q = tf::create_quaternion_from_yaw(-deg2rad(angle / 100.f));
590  orientation_[0] = q.x();
591  orientation_[1] = q.y();
592  orientation_[2] = q.z();
593  orientation_[3] = q.w();
594 
595  data_mutex_->unlock();
596 }
597 
598 
599 /** Check whether the deadline has passed.
600  * We compare the deadline against
601  * the current time since a new asynchronous operation may have moved the
602  * deadline before this actor had a chance to run.
603  */
604 void
605 CruizCoreXG1010AcquisitionThread::check_deadline()
606 {
607  if (deadline_.expires_at() <= boost::asio::deadline_timer::traits_type::now()) {
608  serial_.cancel();
609  deadline_.expires_at(boost::posix_time::pos_infin);
610  }
611 
612 #if BOOST_VERSION >= 104800
613  deadline_.async_wait(boost::lambda::bind(&CruizCoreXG1010AcquisitionThread::check_deadline, this));
614 #else
615  deadline_.async_wait(boost::bind(&CruizCoreXG1010AcquisitionThread::check_deadline, this));
616 #endif
617 }
float angular_velocity_[3]
Pre-allocated angular velocities as array, 3 entries ordered (x,y,z).
CruizCoreXG1010AcquisitionThread(std::string &cfg_name, std::string &cfg_prefix, bool continuous)
Constructor.
float orientation_[4]
Pre-allocated orientation quaternion as array, 4 entries ordered (x,y,z,w).
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
virtual void init()
Initialize the thread.
Fawkes library namespace.
void unlock()
Unlock the mutex.
Definition: mutex.cpp:135
IMU acqusition thread.
fawkes::Time * timestamp_
Time when the most recent data was received.
virtual void loop()
Code to execute in the thread.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:44
void set_name(const char *format,...)
Set name of thread.
Definition: thread.cpp:761
Base class for exceptions in Fawkes.
Definition: exception.h:36
bool new_data_
Set to true in your loop if new data is available.
virtual void finalize()
Finalize the thread.
std::string cfg_prefix_
Configuration path prefix.
virtual void loop()
Code to execute in the thread.
Time tracking utility.
Definition: tracker.h:38
const char * name() const
Get name of thread.
Definition: thread.h:95
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
double angular_velocity_covariance_[9]
Pre-allocated angular velocity covariance, row major matrix ordered x, y, z.
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
void yield()
Yield the processor to another thread or process.
Definition: thread.cpp:902
fawkes::Mutex * data_mutex_
Lock while writing to distances or echoes array or marking new data.
virtual void finalize()
Finalize the thread.
void lock()
Lock this mutex.
Definition: mutex.cpp:89
Time & stamp()
Set this time to the current time.
Definition: time.cpp:783
virtual unsigned int get_uint(const char *path)=0
Get value from configuration which is of type unsigned int.
bool cfg_continuous_
True if running continuous.
float deg2rad(float deg)
Convert an angle given in degrees to radians.
Definition: angle.h:37
float linear_acceleration_[3]
Pre-allocated linear acceleration as array, 3 entries ordered (x,y,z).
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:44
virtual void init()
Initialize the thread.
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:341
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.