libyggdrasil  v1.0.0
six_axis_sensor.hpp
Go to the documentation of this file.
1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * _____.___. .___ .__.__ *
3  * \__ | | ____ ____ __| _/___________ _____|__| | *
4  * / | |/ ___\ / ___\ / __ |\_ __ \__ \ / ___/ | | *
5  * \____ / /_/ > /_/ > /_/ | | | \// __ \_\___ \| | |__ *
6  * / ______\___ /\___ /\____ | |__| (____ /____ >__|____/ *
7  * \/ /_____//_____/ \/ \/ \/ *
8  * - Yggdrasil - *
9  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
10  * This software can be used by students and other personal of the *
11  * Bern University of Applied Sciences under the terms of the MIT *
12  * license. *
13  * For other persons this software is under the terms of the GNU *
14  * General Public License version 2. *
15  * *
16  * Copyright © 2021, Bern University of Applied Sciences. *
17  * All rights reserved. *
18  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26 #pragma once
27 
29 #include <cpp/common/types.hpp>
30 #include <cpp/common/math.hpp>
31 
32 namespace bsp::ygg::prph {
33 
37  class SixAxisSensor {
38  public:
39 
43  struct Coordinate {
44  float x, y, z;
45  };
46 
50  struct Orientation {
51  float roll;
52  float pitch;
53  };
54 
58  enum class AccelFullScaleRange : u8 {
59  _2G = 0x03,
60  _4G = 0x02,
61  _8G = 0x01,
62  _16G = 0x00
63  };
64 
69  enum class GyroFullScaleRange : u8 {
70  _2000DPS = 0x00,
71  _1000DPS = 0x01,
72  _500DPS = 0x02,
73  _250DPS = 0x03,
74  _125DPS = 0x04,
75  _62_5DPS = 0x05,
76  _31_25DPS = 0x06,
77  _15_125DPS = 0x07
78  };
79 
83  enum class AccelOutputDataRange : u8 {
84  _8000Hz = 0x03,
85  _4000Hz = 0x04,
86  _2000Hz = 0x05,
87  _1000Hz = 0x06,
88  _500Hz = 0x0F,
89  _200Hz = 0x07,
90  _100Hz = 0x08,
91  _50Hz = 0x09,
92  _25Hz = 0x0A,
93  _12_5Hz = 0x0B,
94  _6_25Hz = 0x0C,
95  _3_125Hz = 0x0D,
96  _1_5625Hz = 0x0E
97  };
98 
102  enum class GyroOutputDataRange : u8 {
103  _8000Hz = 0x03,
104  _4000Hz = 0x04,
105  _2000Hz = 0x05,
106  _1000Hz = 0x06,
107  _500Hz = 0x0F,
108  _200Hz = 0x07,
109  _100Hz = 0x08,
110  _50Hz = 0x09,
111  _25Hz = 0x0A,
112  _12_5Hz = 0x0B,
113  };
114 
115  SixAxisSensor() = delete;
116 
131  SixAxisSensor::s_accelScale = accelScale;
132  SixAxisSensor::s_gyroScale = gyroScale;
133 
134  selectBank(0);
135 
136  {
137  u8 retries = 0;
138  do {
139  if( bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::WHO_AM_I)) == DeviceID){
140  break;
141  }
142  else {
143  retries++;
144  if(retries > 10) return false;
145  }
146  } while (true);
147  }
148 
149  {
150  // Enable hyroscope and accelerometer in low noise mode
151  auto pwrMgmt0 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::PWR_MGMT0));
152  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::PWR_MGMT0), pwrMgmt0 | 0x0F);
153 
154  // Set gyro scale and data rate
155  auto gyroConfig0 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::GYRO_CONFIG0));
156  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::GYRO_CONFIG0), gyroConfig0 | enumValue(gyroOdr) | (enumValue(gyroScale) << 5));
157 
158  // Set accel scale and data rate
159  auto accelConfig0 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::ACCEL_CONFIG0));
160  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::ACCEL_CONFIG0), accelConfig0 | enumValue(accelOdr) | (enumValue(accelScale) << 5));
161 
162  // Set temperature low pass filter to a minimum and use first order filter for gyro
163  auto gyroConfig1 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::GYRO_CONFIG1));
164  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::GYRO_CONFIG1), gyroConfig1 | 0xD0);
165 
166  // Setup interrupt pins
167  auto intConfig0 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::INT_CONFIG));
168  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::INT_CONFIG), intConfig0 | 0x18 | 0x03);
169 
170  // Enable async interrupt reset
171  auto intConfig1 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::INT_CONFIG1));
172  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::INT_CONFIG1), intConfig1 & ~0x10);
173 
174  // Route data ready interrupt to INT1
175  auto intSource0 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::INT_SOURCE0));
176  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::INT_SOURCE0), intSource0 | 0x08);
177 
178  // Route AGC interrupt to INT2
179  auto intSource3 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::INT_SOURCE3));
180  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::INT_SOURCE3), intSource3 | 0x01);
181 
182  selectBank(4);
183 
184  // Set inversion matrix to X and Y inverted, Z not inverted
185  auto apexConfig5 = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank4::APEX_CONFIG5));
186  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank4::APEX_CONFIG5), (apexConfig5 & ~(0b111)) | 0x011);
187 
188  selectBank(0);
189  }
190 
191  return true;
192  }
193 
200  struct GyroData {
201  ByteSwapped<i16> x, y, z;
202  };
203 
204  auto [x, y, z] = bsp::I2CA::read<GyroData>(DeviceAddress, enumValue(RegisterBank0::GYRO_DATA_X1));
205 
206  return { transformGyroAxisData(x), transformGyroAxisData(y), transformGyroAxisData(z) };
207  }
208 
215  struct AccelData {
216  ByteSwapped<i16> x, y, z;
217  };
218 
219  auto [x, y, z] = bsp::I2CA::read<AccelData>(DeviceAddress, enumValue(RegisterBank0::ACCEL_DATA_X1));
220 
221  return { transformAccelAxisData(x), transformAccelAxisData(y), transformAccelAxisData(z) };
222  }
223 
229  static float getTemperature() {
230  auto data = bsp::I2CA::read<ByteSwapped<i16>>(DeviceAddress, enumValue(RegisterBank0::TEMP_DATA1));
231 
232  return (float(data) / 132.48F) + 25;
233  }
234 
235 
243  Orientation orientation = {0};
245 
246  float gp = sqrt(x*x + y*y + z*z);
247  orientation.roll = asin(y/gp) * 180 / math::Pi<float>;
248  orientation.pitch = asin(x/gp) * 180 / math::Pi<float>;
249 
250  if(z < 0){
251  if(x < 0) orientation.pitch = - 180 - orientation.pitch;
252  else orientation.pitch = 180 - orientation.pitch;
253  if(y < 0) orientation.roll = - 180 - orientation.roll;
254  else orientation.roll = 180 - orientation.roll;
255  }
256 
257  orientation.roll *= -1;
258 
259  return orientation;
260 
261  }
262 
263 
264  private:
265 
269  enum class RegisterBank0 : u8 {
270  DEVICE_CONFIG = 0x11,
271  DRIVE_CONFIG = 0x13,
272  INT_CONFIG = 0x14,
273  FIFO_CONFIG = 0x16,
274  TEMP_DATA1 = 0x1D,
275  TEMP_DATA0 = 0x1E,
276  ACCEL_DATA_X1 = 0x1F,
277  ACCEL_DATA_X0 = 0x20,
278  ACCEL_DATA_Y1 = 0x21,
279  ACCEL_DATA_Y0 = 0x22,
280  ACCEL_DATA_Z1 = 0x23,
281  ACCEL_DATA_Z0 = 0x24,
282  GYRO_DATA_X1 = 0x25,
283  GYRO_DATA_X0 = 0x26,
284  GYRO_DATA_Y1 = 0x27,
285  GYRO_DATA_Y0 = 0x28,
286  GYRO_DATA_Z1 = 0x29,
287  GYRO_DATA_Z0 = 0x2A,
288  TMST_FSYNCH = 0x2B,
289  TMST_FSYNCL = 0x2C,
290  INT_STATUS = 0x2D,
291  FIFO_COUNTH = 0x2E,
292  FIFO_COUNTL = 0x2F,
293  FIFO_DATA = 0x30,
294  APEX_DATA0 = 0x31,
295  APEX_DATA1 = 0x32,
296  APEX_DATA2 = 0x33,
297  APEX_DATA3 = 0x34,
298  APEX_DATA4 = 0x35,
299  APEX_DATA5 = 0x36,
300  INT_STATUS2 = 0x37,
301  INT_STATUS3 = 0x38,
302  SIGNAL_PATH_RESET = 0x4B,
303  INTF_CONFIG0 = 0x4C,
304  INTF_CONFIG1 = 0x4D,
305  PWR_MGMT0 = 0x4E,
306  GYRO_CONFIG0 = 0x4F,
307  ACCEL_CONFIG0 = 0x50,
308  GYRO_CONFIG1 = 0x51,
309  GYRO_ACCEL_CONFIG0 = 0x52,
310  ACCEL_CONFIG1 = 0x53,
311  TMST_CONFIG = 0x54,
312  APEX_CONFIG0 = 0x56,
313  SMD_CONFIG = 0x57,
314  FIFO_CONFIG1 = 0x5F,
315  FIFO_CONFIG2 = 0x60,
316  FIFO_CONFIG3 = 0x61,
317  FSYNC_CONFIG = 0x62,
318  INT_CONFIG0 = 0x63,
319  INT_CONFIG1 = 0x64,
320  INT_SOURCE0 = 0x65,
321  INT_SOURCE1 = 0x66,
322  INT_SOURCE3 = 0x68,
323  INT_SOURCE4 = 0x69,
324  FIFO_LOST_PKT0 = 0x6C,
325  FIFO_LOST_PKT1 = 0x6D,
326  SELF_TEST_CONFIG = 0x70,
327  WHO_AM_I = 0x75,
328  REG_BANK_SEL = 0x76
329  };
330 
334  enum class RegisterBank1 : u8 {
335  SENSOR_CONFIG0 = 0x03,
336  GYRO_CONFIG_STATIC2 = 0x0B,
337  GYRO_CONFIG_STATIC3 = 0x0C,
338  GYRO_CONFIG_STATIC4 = 0x0D,
339  GYRO_CONFIG_STATIC5 = 0x0E,
340  GYRO_CONFIG_STATIC6 = 0x0F,
341  GYRO_CONFIG_STATIC7 = 0x10,
342  GYRO_CONFIG_STATIC8 = 0x11,
343  GYRO_CONFIG_STATIC9 = 0x12,
344  GYRO_CONFIG_STATIC10 = 0x13,
345  XG_ST_DATA = 0x5F,
346  YG_ST_DATA = 0x60,
347  ZG_ST_DATA = 0x61,
348  TMSTVAL0 = 0x62,
349  TMSTVAL1 = 0x63,
350  TMSTVAL2 = 0x64,
351  INTF_CONFIG4 = 0x7A,
352  INTF_CONFIG5 = 0x7B,
353  INTF_CONFIG6 = 0x7C
354  };
355 
359  enum class RegisterBank2 : u8 {
360  ACCEL_CONFIG_STATIC2 = 0x03,
361  ACCEL_CONFIG_STATIC3 = 0x04,
362  ACCEL_CONFIG_STATIC4 = 0x05,
363  XA_ST_DATA = 0x3B,
364  YA_ST_DATA = 0x3C,
365  ZA_ST_DATA = 0x3D
366  };
367 
371  enum class RegisterBank4 : u8 {
372  GYRO_ON_OFF_CONFIG = 0x0E,
373  APEX_CONFIG1 = 0x40,
374  APEX_CONFIG2 = 0x41,
375  APEX_CONFIG3 = 0x42,
376  APEX_CONFIG4 = 0x43,
377  APEX_CONFIG5 = 0x44,
378  APEX_CONFIG6 = 0x45,
379  APEX_CONFIG7 = 0x46,
380  APEX_CONFIG8 = 0x47,
381  APEX_CONFIG9 = 0x48,
382  ACCEL_WOM_X_THR = 0x4A,
383  ACCEL_WOM_Y_THR = 0x4B,
384  ACCEL_WOM_Z_THR = 0x4C,
385  INT_SOURCE6 = 0x4D,
386  INT_SOURCE7 = 0x4E,
387  INT_SOURCE8 = 0x4F,
388  INT_SOURCE9 = 0x50,
389  INT_SOURCE10 = 0x51,
390  OFFSET_USER0 = 0x77,
391  OFFSET_USER1 = 0x78,
392  OFFSET_USER2 = 0x79,
393  OFFSET_USER3 = 0x7A,
394  OFFSET_USER4 = 0x7B,
395  OFFSET_USER5 = 0x7C,
396  OFFSET_USER6 = 0x7D,
397  OFFSET_USER7 = 0x7E,
398  OFFSET_USER8 = 0x7F
399  };
400 
401  constexpr static inline auto DeviceAddress = 0xD2;
402  constexpr static inline auto DeviceID = 0x42;
403 
404  static inline AccelFullScaleRange s_accelScale;
405  static inline GyroFullScaleRange s_gyroScale;
406 
412  static void selectBank(u8 bank) {
413  auto bankSelect = bsp::I2CA::read<u8>(DeviceAddress, enumValue(RegisterBank0::REG_BANK_SEL));
414  bsp::I2CA::write<u8>(DeviceAddress, enumValue(RegisterBank0::REG_BANK_SEL), (bankSelect & 0xF8) | bank);
415  }
416 
422  static inline float transformGyroAxisData(i16 data) {
423  return (float(data) / 0xFFFF) * (2000 / (enumValue(SixAxisSensor::s_gyroScale) + 1));
424  }
425 
431  static inline float transformAccelAxisData(i16 data) {
432  return (float(data) / 0xFFFF) * (16 / (enumValue(SixAxisSensor::s_accelScale) + 1));
433  }
434  };
435 
436 }
bsp::ygg::prph::SixAxisSensor::AccelFullScaleRange::_8G
@ _8G
Range from -8G to 8G.
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange
GyroOutputDataRange
Gyroscope data rate.
Definition: six_axis_sensor.hpp:102
bsp::ygg::prph::SixAxisSensor::init
static bool init(AccelFullScaleRange accelScale=AccelFullScaleRange::_2G, GyroFullScaleRange gyroScale=GyroFullScaleRange::_250DPS, AccelOutputDataRange accelOdr=AccelOutputDataRange::_1000Hz, GyroOutputDataRange gyroOdr=GyroOutputDataRange::_1000Hz)
Initializes the ICM-42605 Six Axis Sensor.
Definition: six_axis_sensor.hpp:127
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange
GyroFullScaleRange
Gyroscope range.
Definition: six_axis_sensor.hpp:69
u8
uint8_t u8
Unsigned integer definitions.
Definition: types.h:36
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_500Hz
@ _500Hz
500 measurements per second
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_100Hz
@ _100Hz
100 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange::_15_125DPS
@ _15_125DPS
Range from -15.125DPS to 15.125DPS with highest precision.
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_200Hz
@ _200Hz
200 measurements per second
bsp::ygg::prph::SixAxisSensor::Coordinate::z
float z
Definition: six_axis_sensor.hpp:44
i16
int16_t i16
Definition: types.h:47
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_3_125Hz
@ _3_125Hz
3.125 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange::_1000DPS
@ _1000DPS
Range from -1000DPS to 1000DPS.
bsp::ygg::prph::SixAxisSensor::AccelFullScaleRange
AccelFullScaleRange
Accelerometer range.
Definition: six_axis_sensor.hpp:58
types.hpp
Commonly used type definitions and helper templates.
bsp::ygg::prph::SixAxisSensor::getBoardOrientation
static Orientation getBoardOrientation()
Get yggdrasil's current orientation.
Definition: six_axis_sensor.hpp:242
bsp::ygg::prph::SixAxisSensor::Orientation::pitch
float pitch
Rotation around y-axis.
Definition: six_axis_sensor.hpp:52
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_25Hz
@ _25Hz
25 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange::_31_25DPS
@ _31_25DPS
Range from -31.25DPS to 31.25DPS.
bsp::enumValue
auto enumValue(T value)
Casts a scoped enum type into its underlying value.
Definition: utils.hpp:151
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_6_25Hz
@ _6_25Hz
6.25 measurements per second
bsp::ygg::prph::SixAxisSensor::Orientation
Absolute board orientation.
Definition: six_axis_sensor.hpp:50
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_25Hz
@ _25Hz
25 measurements per second
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_4000Hz
@ _4000Hz
4000 measurements per second
bsp::ygg::prph::SixAxisSensor::SixAxisSensor
SixAxisSensor()=delete
bsp::ygg::prph::SixAxisSensor::AccelFullScaleRange::_16G
@ _16G
Range from -16G to 16G with lowest precision.
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_100Hz
@ _100Hz
100 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_12_5Hz
@ _12_5Hz
12.5 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_8000Hz
@ _8000Hz
8000 measurements per second
bsp::ygg::prph::SixAxisSensor::AccelFullScaleRange::_2G
@ _2G
Range from -2G to 2G with highest precision.
bsp::ygg::prph::SixAxisSensor::getAcceleration
static Coordinate getAcceleration()
Get yggdrasil's current acceleration from the accelerometer.
Definition: six_axis_sensor.hpp:214
bsp::ByteSwapped
Helper class to store the data of a given type in reverse order.
Definition: utils.hpp:162
bsp::ygg::prph::SixAxisSensor::Coordinate::y
float y
Definition: six_axis_sensor.hpp:44
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange::_125DPS
@ _125DPS
Range from -125DPS to 125DPS.
bsp::ygg::prph::SixAxisSensor::Coordinate::x
float x
Definition: six_axis_sensor.hpp:44
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange::_500DPS
@ _500DPS
Range from -500DPS to 500DPS.
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_200Hz
@ _200Hz
200 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange::_250DPS
@ _250DPS
Range from -250DPS to 250DPS.
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange
AccelOutputDataRange
Accelerometer data rate.
Definition: six_axis_sensor.hpp:83
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_8000Hz
@ _8000Hz
8000 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_50Hz
@ _50Hz
50 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_2000Hz
@ _2000Hz
2000 measurements per second
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_50Hz
@ _50Hz
50 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange::_2000DPS
@ _2000DPS
Range from -2000DPS to 2000DPS with lowest precision.
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_2000Hz
@ _2000Hz
2000 measurements per second
bsp::ygg::prph::SixAxisSensor::getRotation
static Coordinate getRotation()
Get yggdrasil's current orientation from the gyroscope.
Definition: six_axis_sensor.hpp:199
attributes.hpp
Commonly used C++ and GNU attributes.
bsp::ygg::prph::SixAxisSensor
6 axis sensor driver ICM-42605
Definition: six_axis_sensor.hpp:37
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_4000Hz
@ _4000Hz
4000 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_500Hz
@ _500Hz
500 measurements per second
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_12_5Hz
@ _12_5Hz
12.5 measurements per second
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_1000Hz
@ _1000Hz
1000 measurements per second
bsp::ygg::prph::SixAxisSensor::Orientation::roll
float roll
Rotation around x-axis.
Definition: six_axis_sensor.hpp:51
bsp::ygg::prph::SixAxisSensor::AccelFullScaleRange::_4G
@ _4G
Range from -4G to 4G.
bsp::ygg::prph::SixAxisSensor::Coordinate
Coordinates.
Definition: six_axis_sensor.hpp:43
math.hpp
Commonly used math functions.
bsp::ygg::prph
Definition: color_sensor.hpp:32
bsp::ygg::prph::SixAxisSensor::GyroOutputDataRange::_1000Hz
@ _1000Hz
1000 measurements per second
bsp::ygg::prph::SixAxisSensor::getTemperature
static float getTemperature()
Get the internal temperature of the ICM-42605 sensor.
Definition: six_axis_sensor.hpp:229
bsp::ygg::prph::SixAxisSensor::AccelOutputDataRange::_1_5625Hz
@ _1_5625Hz
1.5625 measurements per second
bsp::ygg::prph::SixAxisSensor::GyroFullScaleRange::_62_5DPS
@ _62_5DPS
Range from -62.5DPS to 65.5DPS.