Statistics
| Branch: | Revision:

brix5 / firmware / demo / FeatherBase-BNO055_RGB_Haptics / FeatherBase-BNO055_RGB_Haptics.ino @ 7393c00e

History | View | Annotate | Download (45.559 KB)

1 7393c00e Jan
/* vim:ts=2:sw=2:expandtab
2
3
  Mapping BNO055 Orientation to RGB WS2812 LEDs and DRV2605 Haptics
4
  on FeatherBase
5
  
6
  Based on BNO055_MS5637_t3 Basic Example Code by Kris Winer
7
8
  Original Winer Comments follow:
9
  
10
  date: October 19, 2014
11
  license: Beerware - Use this code however you'd like. If you
12
  find it useful you can buy me a beer some time.
13
14
  Demonstrates basic BNO055 functionality including parameterizing the register addresses,
15
  initializing the sensor, communicating with pressure sensor MS5637,
16
  getting properly scaled accelerometer, gyroscope, and magnetometer data out.
17
18
  Added display functions to allow display to on breadboard monitor.
19
20
  Addition of 9 DoF sensor fusion using open source Madgwick and Mahony filter algorithms.
21
  Can compare results to hardware 9 DoF sensor fusion carried out on the BNO055.
22
  Sketch runs on the 3.3 V 8 MHz Pro Mini and the Teensy 3.1.
23
24
  This sketch is intended specifically for the BNO055+MS5637 Add-On Shield for the Teensy 3.1.
25
  It uses SDA/SCL on pins 17/16, respectively, and it uses the Teensy 3.1-specific Wire library i2c_t3.h.
26
27
  The Add-on shield can also be used as a stand-alone breakout board for any Arduino, Teensy, or
28
  other microcontroller by closing the solder jumpers on the back of the board.
29
30
  The MS5637 is a simple but high resolution (24-bit) pressure sensor, which can be used in its high resolution
31
  mode but with power consumption of 20 microAmp, or in a lower resolution mode with power consumption of
32
  only 1 microAmp. The choice will depend on the application.
33
34
  All sensors communicate via I2C at 400 Hz or higher.
35
  SDA and SCL should have external pull-up resistors (to 3.3V).
36
  4K7 resistors are on the BNO055_MS5637 breakout board.
37
38
  Hardware setup:
39
  Breakout Board --------- Arduino/Teensy
40
  3V3 ---------------------- 3.3V
41
  SDA -----------------------A4/17
42
  SCL -----------------------A5/16
43
  GND ---------------------- GND
44
45
  Note: The BNO055_MS5637 breakout board is an I2C sensor and uses the Arduino Wire or Teensy i2c_t3.h library.
46
  Because the sensor is not 5V tolerant, we are using a 3.3 V 8 MHz Pro Mini or a 3.3 V Teensy 3.1.
47
  We have disabled the internal pull-ups used by the Wire library in the Wire.h/twi.c utility file.
48
  We are also using the 400 kHz fast I2C mode by setting the TWI_FREQ  to 400000L /twi.h utility file.
49
  The Teensy has no internal pullups and we are using the Wire.begin function of the i2c_t3.h library
50
  to select 400 Hz i2c speed.
51
*/
52
53
// Uncomment to use BNO055 on address 0x29 instead of 0x28
54
//#define ADO 1
55
56
// use DRV2605 Haptics
57
#define USE_DRV
58
59
#if defined(__MK20DX128__) || defined(__MK20DX256__)
60
#include "i2c_t3.h"
61
#else
62
#include "Wire.h"
63
#endif
64
#include <Adafruit_NeoPixel.h>
65
#ifdef __AVR__
66
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
67
#endif
68
69
#ifdef USE_DRV
70
#include <Adafruit_DRV2605.h>
71
Adafruit_DRV2605 drv;
72
73
#endif
74
75
// Which pin on the Arduino is connected to the NeoPixels?
76
// On a Trinket or Gemma we suggest changing this to 1:
77
#define LED_PIN    A1
78
79
// How many NeoPixels are attached to the Arduino?
80
#define LED_COUNT 2
81
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
82
83
//#include <Audio.h>
84
//AudioOutputI2S      audioOutput;        // audio shield: headphones & line-out
85
86
// Audio Code, Enable AudioOutputI2SQuad line to reproduce
87
// GUItool: begin automatically generated code
88
//AudioSynthWaveform       waveform0; //xy=192,380
89
//AudioSynthWaveform       waveform1; //xy=192,420
90
//AudioSynthWaveform       waveform2; //xy=192,460
91
//AudioSynthWaveform       waveform3; //xy=192,500
92
//AudioOutputI2SQuad       i2s_quad1;      //xy=385.8452453613281,443.1428527832031
93
//AudioConnection          patchCord0(waveform0, 0, i2s_quad1, 0);
94
//AudioConnection          patchCord1(waveform1, 0, i2s_quad1, 1);
95
//AudioConnection          patchCord2(waveform2, 0, i2s_quad1, 2);
96
//AudioConnection          patchCord3(waveform3, 0, i2s_quad1, 3);
97
//AudioControlSGTL5000     sgtl5000_2;     //xy=381.8453063964844,384.8571472167969
98
//AudioControlSGTL5000     sgtl5000_1;     //xy=382.2737731933594,345.14288330078125
99
// GUItool: end automatically generated code
100
101
//#include <SPI.h>
102
103
// BNO055 Register Map
104
// http://ae-bst.resource.bosch.com/media/products/dokumente/bno055/BST_BNO055_DS000_10_Release.pdf
105
//
106
// BNO055 Page 0
107
#define BNO055_CHIP_ID          0x00    // should be 0xA0              
108
#define BNO055_ACC_ID           0x01    // should be 0xFB              
109
#define BNO055_MAG_ID           0x02    // should be 0x32              
110
#define BNO055_GYRO_ID          0x03    // should be 0x0F              
111
#define BNO055_SW_REV_ID_LSB    0x04
112
#define BNO055_SW_REV_ID_MSB    0x05
113
#define BNO055_BL_REV_ID        0x06
114
#define BNO055_PAGE_ID          0x07
115
#define BNO055_ACC_DATA_X_LSB   0x08
116
#define BNO055_ACC_DATA_X_MSB   0x09
117
#define BNO055_ACC_DATA_Y_LSB   0x0A
118
#define BNO055_ACC_DATA_Y_MSB   0x0B
119
#define BNO055_ACC_DATA_Z_LSB   0x0C
120
#define BNO055_ACC_DATA_Z_MSB   0x0D
121
#define BNO055_MAG_DATA_X_LSB   0x0E
122
#define BNO055_MAG_DATA_X_MSB   0x0F
123
#define BNO055_MAG_DATA_Y_LSB   0x10
124
#define BNO055_MAG_DATA_Y_MSB   0x11
125
#define BNO055_MAG_DATA_Z_LSB   0x12
126
#define BNO055_MAG_DATA_Z_MSB   0x13
127
#define BNO055_GYR_DATA_X_LSB   0x14
128
#define BNO055_GYR_DATA_X_MSB   0x15
129
#define BNO055_GYR_DATA_Y_LSB   0x16
130
#define BNO055_GYR_DATA_Y_MSB   0x17
131
#define BNO055_GYR_DATA_Z_LSB   0x18
132
#define BNO055_GYR_DATA_Z_MSB   0x19
133
#define BNO055_EUL_HEADING_LSB  0x1A
134
#define BNO055_EUL_HEADING_MSB  0x1B
135
#define BNO055_EUL_ROLL_LSB     0x1C
136
#define BNO055_EUL_ROLL_MSB     0x1D
137
#define BNO055_EUL_PITCH_LSB    0x1E
138
#define BNO055_EUL_PITCH_MSB    0x1F
139
#define BNO055_QUA_DATA_W_LSB   0x20
140
#define BNO055_QUA_DATA_W_MSB   0x21
141
#define BNO055_QUA_DATA_X_LSB   0x22
142
#define BNO055_QUA_DATA_X_MSB   0x23
143
#define BNO055_QUA_DATA_Y_LSB   0x24
144
#define BNO055_QUA_DATA_Y_MSB   0x25
145
#define BNO055_QUA_DATA_Z_LSB   0x26
146
#define BNO055_QUA_DATA_Z_MSB   0x27
147
#define BNO055_LIA_DATA_X_LSB   0x28
148
#define BNO055_LIA_DATA_X_MSB   0x29
149
#define BNO055_LIA_DATA_Y_LSB   0x2A
150
#define BNO055_LIA_DATA_Y_MSB   0x2B
151
#define BNO055_LIA_DATA_Z_LSB   0x2C
152
#define BNO055_LIA_DATA_Z_MSB   0x2D
153
#define BNO055_GRV_DATA_X_LSB   0x2E
154
#define BNO055_GRV_DATA_X_MSB   0x2F
155
#define BNO055_GRV_DATA_Y_LSB   0x30
156
#define BNO055_GRV_DATA_Y_MSB   0x31
157
#define BNO055_GRV_DATA_Z_LSB   0x32
158
#define BNO055_GRV_DATA_Z_MSB   0x33
159
#define BNO055_TEMP             0x34
160
#define BNO055_CALIB_STAT       0x35
161
#define BNO055_ST_RESULT        0x36
162
#define BNO055_INT_STATUS       0x37
163
#define BNO055_SYS_CLK_STATUS   0x38
164
#define BNO055_SYS_STATUS       0x39
165
#define BNO055_SYS_ERR          0x3A
166
#define BNO055_UNIT_SEL         0x3B
167
#define BNO055_OPR_MODE         0x3D
168
#define BNO055_PWR_MODE         0x3E
169
#define BNO055_SYS_TRIGGER      0x3F
170
#define BNO055_TEMP_SOURCE      0x40
171
#define BNO055_AXIS_MAP_CONFIG  0x41
172
#define BNO055_AXIS_MAP_SIGN    0x42
173
#define BNO055_ACC_OFFSET_X_LSB 0x55
174
#define BNO055_ACC_OFFSET_X_MSB 0x56
175
#define BNO055_ACC_OFFSET_Y_LSB 0x57
176
#define BNO055_ACC_OFFSET_Y_MSB 0x58
177
#define BNO055_ACC_OFFSET_Z_LSB 0x59
178
#define BNO055_ACC_OFFSET_Z_MSB 0x5A
179
#define BNO055_MAG_OFFSET_X_LSB 0x5B
180
#define BNO055_MAG_OFFSET_X_MSB 0x5C
181
#define BNO055_MAG_OFFSET_Y_LSB 0x5D
182
#define BNO055_MAG_OFFSET_Y_MSB 0x5E
183
#define BNO055_MAG_OFFSET_Z_LSB 0x5F
184
#define BNO055_MAG_OFFSET_Z_MSB 0x60
185
#define BNO055_GYR_OFFSET_X_LSB 0x61
186
#define BNO055_GYR_OFFSET_X_MSB 0x62
187
#define BNO055_GYR_OFFSET_Y_LSB 0x63
188
#define BNO055_GYR_OFFSET_Y_MSB 0x64
189
#define BNO055_GYR_OFFSET_Z_LSB 0x65
190
#define BNO055_GYR_OFFSET_Z_MSB 0x66
191
#define BNO055_ACC_RADIUS_LSB   0x67
192
#define BNO055_ACC_RADIUS_MSB   0x68
193
#define BNO055_MAG_RADIUS_LSB   0x69
194
#define BNO055_MAG_RADIUS_MSB   0x6A
195
//
196
// BNO055 Page 1
197
#define BNO055_PAGE_ID          0x07
198
#define BNO055_ACC_CONFIG       0x08
199
#define BNO055_MAG_CONFIG       0x09
200
#define BNO055_GYRO_CONFIG_0    0x0A
201
#define BNO055_GYRO_CONFIG_1    0x0B
202
#define BNO055_ACC_SLEEP_CONFIG 0x0C
203
#define BNO055_GYR_SLEEP_CONFIG 0x0D
204
#define BNO055_INT_MSK          0x0F
205
#define BNO055_INT_EN           0x10
206
#define BNO055_ACC_AM_THRES     0x11
207
#define BNO055_ACC_INT_SETTINGS 0x12
208
#define BNO055_ACC_HG_DURATION  0x13
209
#define BNO055_ACC_HG_THRESH    0x14
210
#define BNO055_ACC_NM_THRESH    0x15
211
#define BNO055_ACC_NM_SET       0x16
212
#define BNO055_GYR_INT_SETTINGS 0x17
213
#define BNO055_GYR_HR_X_SET     0x18
214
#define BNO055_GYR_DUR_X        0x19
215
#define BNO055_GYR_HR_Y_SET     0x1A
216
#define BNO055_GYR_DUR_Y        0x1B
217
#define BNO055_GYR_HR_Z_SET     0x1C
218
#define BNO055_GYR_DUR_Z        0x1D
219
#define BNO055_GYR_AM_THRESH    0x1E
220
#define BNO055_GYR_AM_SET       0x1F
221
222
// Using the BNO055_MS5637 breakout board/Teensy 3.1 Add-On Shield, ADO is set to 1 by default
223
#if ADO
224
#define BNO055_ADDRESS 0x29   //  Device address of BNO055 when ADO = 1
225
#define MS5637_ADDRESS   0x76   //  Address of MS5637 altimeter
226
#else
227
#define BNO055_ADDRESS 0x28   //  Device address of BNO055 when ADO = 0
228
#define MS5637_ADDRESS   0x76   //  Address of MS5637 altimeter
229
#endif
230
231
#define SerialDebug true      // set to true to get Serial output for debugging
232
233
// Set initial input parameters
234
enum Ascale {  // ACC Full Scale
235
  AFS_2G = 0,
236
  AFS_4G,
237
  AFS_8G,
238
  AFS_18G
239
};
240
241
enum Abw { // ACC Bandwidth
242
  ABW_7_81Hz = 0,
243
  ABW_15_63Hz,
244
  ABW_31_25Hz,
245
  ABW_62_5Hz,
246
  ABW_125Hz,
247
  ABW_250Hz,
248
  ABW_500Hz,
249
  ABW_1000Hz,    //0x07
250
};
251
252
enum APwrMode { // ACC Pwr Mode
253
  NormalA = 0,
254
  SuspendA,
255
  LowPower1A,
256
  StandbyA,
257
  LowPower2A,
258
  DeepSuspendA
259
};
260
261
enum Gscale {  // gyro full scale
262
  GFS_2000DPS = 0,
263
  GFS_1000DPS,
264
  GFS_500DPS,
265
  GFS_250DPS,
266
  GFS_125DPS    // 0x04
267
};
268
269
enum GPwrMode { // GYR Pwr Mode
270
  NormalG = 0,
271
  FastPowerUpG,
272
  DeepSuspendedG,
273
  SuspendG,
274
  AdvancedPowerSaveG
275
};
276
277
enum Gbw { // gyro bandwidth
278
  GBW_523Hz = 0,
279
  GBW_230Hz,
280
  GBW_116Hz,
281
  GBW_47Hz,
282
  GBW_23Hz,
283
  GBW_12Hz,
284
  GBW_64Hz,
285
  GBW_32Hz
286
};
287
288
enum OPRMode {  // BNO-55 operation modes
289
  CONFIGMODE = 0x00,
290
  // Sensor Mode
291
  ACCONLY,
292
  MAGONLY,
293
  GYROONLY,
294
  ACCMAG,
295
  ACCGYRO,
296
  MAGGYRO,
297
  AMG,            // 0x07
298
  // Fusion Mode
299
  IMU,
300
  COMPASS,
301
  M4G,
302
  NDOF_FMC_OFF,
303
  NDOF            // 0x0C
304
};
305
306
enum PWRMode {
307
  Normalpwr = 0,
308
  Lowpower,
309
  Suspendpwr
310
};
311
312
enum Modr {         // magnetometer output data rate
313
  MODR_2Hz = 0,
314
  MODR_6Hz,
315
  MODR_8Hz,
316
  MODR_10Hz,
317
  MODR_15Hz,
318
  MODR_20Hz,
319
  MODR_25Hz,
320
  MODR_30Hz
321
};
322
323
enum MOpMode { // MAG Op Mode
324
  LowPower = 0,
325
  Regular,
326
  EnhancedRegular,
327
  HighAccuracy
328
};
329
330
enum MPwrMode { // MAG power mode
331
  Normal = 0,
332
  Sleep,
333
  Suspend,
334
  ForceMode
335
};
336
337
#define ADC_256  0x00 // define pressure and temperature conversion rates
338
#define ADC_512  0x02
339
#define ADC_1024 0x04
340
#define ADC_2048 0x06
341
#define ADC_4096 0x08
342
#define ADC_8192 0x0A
343
#define ADC_D1   0x40
344
#define ADC_D2   0x50
345
346
// Specify sensor configuration
347
uint8_t OSR = ADC_8192;       // set pressure amd temperature oversample rate
348
//
349
uint8_t GPwrMode = Normal;    // Gyro power mode
350
uint8_t Gscale = GFS_250DPS;  // Gyro full scale
351
//uint8_t Godr = GODR_250Hz;    // Gyro sample rate
352
uint8_t Gbw = GBW_23Hz;       // Gyro bandwidth
353
//
354
uint8_t Ascale = AFS_2G;      // Accel full scale
355
//uint8_t Aodr = AODR_250Hz;    // Accel sample rate
356
uint8_t APwrMode = Normal;    // Accel power mode
357
uint8_t Abw = ABW_31_25Hz;    // Accel bandwidth, accel sample rate divided by ABW_divx
358
//
359
//uint8_t Mscale = MFS_4Gauss;  // Select magnetometer full-scale resolution
360
uint8_t MOpMode = HighAccuracy;    // Select magnetometer perfomance mode
361
uint8_t MPwrMode = Normal;    // Select magnetometer power mode
362
uint8_t Modr = MODR_10Hz;     // Select magnetometer ODR when in BNO055 bypass mode
363
364
uint8_t PWRMode = Normal ;    // Select BNO055 power mode
365
uint8_t OPRMode = NDOF;        // specify operation mode for sensors
366
uint8_t status;               // BNO055 data status register
367
float aRes, gRes, mRes;       // scale resolutions per LSB for the sensors
368
369
// Pin definitions
370
int intPin = 13;  // These can be changed, 2 and 3 are the Arduinos ext int pins
371
int myLed = 9;
372
373
uint16_t Pcal[8];         // calibration constants from MS5637 PROM registers
374
unsigned char nCRC;       // calculated check sum to ensure PROM integrity
375
uint32_t D1 = 0, D2 = 0;  // raw MS5637 pressure and temperature data
376
double dT, OFFSET, SENS, OFFSET2, SENS2;  // First order and second order corrections for raw S5637 temperature and pressure data
377
int16_t accelCount[3];  // Stores the 16-bit signed accelerometer sensor output
378
int16_t gyroCount[3];   // Stores the 16-bit signed gyro sensor output
379
int16_t magCount[3];    // Stores the 16-bit signed magnetometer sensor output
380
int16_t quatCount[4];   // Stores the 16-bit signed quaternion output
381
int16_t EulCount[3];    // Stores the 16-bit signed Euler angle output
382
int16_t LIACount[3];    // Stores the 16-bit signed linear acceleration output
383
int16_t GRVCount[3];    // Stores the 16-bit signed gravity vector output
384
float gyroBias[3] = {0, 0, 0}, accelBias[3] = {0, 0, 0}, magBias[3] = {0, 0, 0};  // Bias corrections for gyro, accelerometer, and magnetometer
385
int16_t tempGCount, tempMCount;      // temperature raw count output of mag and gyro
386
float   Gtemperature, Mtemperature;  // Stores the BNO055 gyro and LIS3MDL mag internal chip temperatures in degrees Celsius
387
double Temperature, Pressure;        // stores MS5637 pressures sensor pressure and temperature
388
389
// global constants for 9 DoF fusion and AHRS (Attitude and Heading Reference System)
390
float GyroMeasError = PI * (40.0f / 180.0f);   // gyroscope measurement error in rads/s (start at 40 deg/s)
391
float GyroMeasDrift = PI * (0.0f  / 180.0f);   // gyroscope measurement drift in rad/s/s (start at 0.0 deg/s/s)
392
// There is a tradeoff in the beta parameter between accuracy and response speed.
393
// In the original Madgwick study, beta of 0.041 (corresponding to GyroMeasError of 2.7 degrees/s) was found to give optimal accuracy.
394
// However, with this value, the LSM9SD0 response time is about 10 seconds to a stable initial quaternion.
395
// Subsequent changes also require a longish lag time to a stable output, not fast enough for a quadcopter or robot car!
396
// By increasing beta (GyroMeasError) by about a factor of fifteen, the response time constant is reduced to ~2 sec
397
// I haven't noticed any reduction in solution accuracy. This is essentially the I coefficient in a PID control sense;
398
// the bigger the feedback coefficient, the faster the solution converges, usually at the expense of accuracy.
399
// In any case, this is the free parameter in the Madgwick filtering and fusion scheme.
400
float beta = sqrt(3.0f / 4.0f) * GyroMeasError;   // compute beta
401
float zeta = sqrt(3.0f / 4.0f) * GyroMeasDrift;   // compute zeta, the other free parameter in the Madgwick scheme usually set to a small or zero value
402
#define Kp 2.0f * 5.0f // these are the free parameters in the Mahony filter and fusion scheme, Kp for proportional feedback, Ki for integral
403
#define Ki 0.0f
404
405
uint32_t delt_t = 0, count = 0, sumCount = 0;  // used to control display output rate
406
float pitch, yaw, roll;
407
float Pitch, Yaw, Roll;
408
float LIAx, LIAy, LIAz, GRVx, GRVy, GRVz;
409
float deltat = 0.0f, sum = 0.0f;          // integration interval for both filter schemes
410
uint32_t lastUpdate = 0, firstUpdate = 0; // used to calculate integration interval
411
uint32_t Now = 0;                         // used to calculate integration interval
412
413
float ax, ay, az, gx, gy, gz, mx, my, mz; // variables to hold latest sensor data values
414
float q[4] = {1.0f, 0.0f, 0.0f, 0.0f};    // vector to hold quaternion
415
float quat[4] = {1.0f, 0.0f, 0.0f, 0.0f};    // vector to hold quaternion
416
float eInt[3] = {0.0f, 0.0f, 0.0f};       // vector to hold integral error for Mahony method
417
418
void setup()
419
{
420
  //  Wire.begin();
421
  //  TWBR = 12;  // 400 kbit/sec I2C speed for Pro Mini
422
  // Setup for Master mode, pins 16/17, external pullups, 400kHz for Teensy 3.1
423
#if defined(__MK20DX128__) || defined(__MK20DX256__)
424
  Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_INT, 400000);
425
#else
426
  Wire.begin();
427
#endif
428
429
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
430
  strip.show();            // Turn OFF all pixels ASAP
431
  strip.setBrightness(100); // Set BRIGHTNESS to about 1/5 (max = 255)
432
433
#ifdef USE_DRV
434
  drv.selectLibrary(6);
435
  drv.useLRA();
436
  drv.setMode(DRV2605_MODE_REALTIME);
437
  pinMode(A3, OUTPUT);
438
  digitalWrite(A3, HIGH);
439
#endif
440
441
  delay(1000);
442
  Serial.begin(115200);
443
444
  // Set up the interrupt pin, its set as active high, push-pull
445
  pinMode(intPin, INPUT);
446
  pinMode(myLed, OUTPUT);
447
  digitalWrite(myLed, HIGH);
448
449
  /*
450
    // scan for i2c devices
451
    byte error, address;
452
    int nDevices;
453
454
    Serial.println("Scanning...");
455
456
    nDevices = 0;
457
    for(address = 1; address < 127; address++ )
458
    {
459
      // The i2c_scanner uses the return value of
460
      // the Write.endTransmisstion to see if
461
      // a device did acknowledge to the address.
462
      Wire.beginTransmission(address);
463
      error = Wire.endTransmission();
464
465
      if (error == 0)
466
      {
467
        Serial.print("I2C device found at address 0x");
468
        if (address<16)
469
          Serial.print("0");
470
        Serial.print(address,HEX);
471
        Serial.println("  !");
472
473
        nDevices++;
474
      }
475
      else if (error==4)
476
      {
477
        Serial.print("Unknow error at address 0x");
478
        if (address<16)
479
          Serial.print("0");
480
        Serial.println(address,HEX);
481
      }
482
    }
483
    if (nDevices == 0)
484
      Serial.println("No I2C devices found\n");
485
    else
486
      Serial.println("done\n");
487
488
  */
489
490
  // Read the WHO_AM_I register, this is a good test of communication
491
  Serial.println("BNO055 9-axis motion sensor...");
492
  byte c = readByte(BNO055_ADDRESS, BNO055_CHIP_ID);  // Read WHO_AM_I register for BNO055
493
  Serial.print("BNO055 Address = 0x"); Serial.println(BNO055_ADDRESS, HEX);
494
  Serial.print("BNO055 WHO_AM_I = 0x"); Serial.println(BNO055_CHIP_ID, HEX);
495
  Serial.print("BNO055 "); Serial.print("I AM "); Serial.print(c, HEX); Serial.println(" I should be 0xA0");
496
497
  delay(500);
498
499
  // Read the WHO_AM_I register of the accelerometer, this is a good test of communication
500
  byte d = readByte(BNO055_ADDRESS, BNO055_ACC_ID);  // Read WHO_AM_I register for accelerometer
501
  Serial.print("BNO055 ACC "); Serial.print("I AM "); Serial.print(d, HEX); Serial.println(" I should be 0xFB");
502
503
  delay(500);
504
505
  // Read the WHO_AM_I register of the magnetometer, this is a good test of communication
506
  byte e = readByte(BNO055_ADDRESS, BNO055_MAG_ID);  // Read WHO_AM_I register for magnetometer
507
  Serial.print("BNO055 MAG "); Serial.print("I AM "); Serial.print(e, HEX); Serial.println(" I should be 0x32");
508
509
  delay(500);
510
511
  // Read the WHO_AM_I register of the gyroscope, this is a good test of communication
512
  byte f = readByte(BNO055_ADDRESS, BNO055_GYRO_ID);  // Read WHO_AM_I register for LIS3MDL
513
  Serial.print("BNO055 GYRO "); Serial.print("I AM "); Serial.print(f, HEX); Serial.println(" I should be 0x0F");
514
515
  delay(500);
516
517
  if (c == 0xA0) // BNO055 WHO_AM_I should always be 0xA0
518
  {
519
    Serial.println("BNO055 is online...");
520
521
    // Check software revision ID
522
    byte swlsb = readByte(BNO055_ADDRESS, BNO055_SW_REV_ID_LSB);
523
    byte swmsb = readByte(BNO055_ADDRESS, BNO055_SW_REV_ID_MSB);
524
    Serial.print("BNO055 SW Revision ID: "); Serial.print(swmsb, HEX); Serial.print("."); Serial.println(swlsb, HEX);
525
    Serial.println("Should be 03.04");
526
527
    // Check bootloader version
528
    byte blid = readByte(BNO055_ADDRESS, BNO055_BL_REV_ID);
529
    Serial.print("BNO055 bootloader Version: "); Serial.println(blid);
530
531
    // Check self-test results
532
    byte selftest = readByte(BNO055_ADDRESS, BNO055_ST_RESULT);
533
534
    if (selftest & 0x01) {
535
      Serial.println("accelerometer passed selftest");
536
    } else {
537
      Serial.println("accelerometer failed selftest");
538
    }
539
    if (selftest & 0x02) {
540
      Serial.println("magnetometer passed selftest");
541
    } else {
542
      Serial.println("magnetometer failed selftest");
543
    }
544
    if (selftest & 0x04) {
545
      Serial.println("gyroscope passed selftest");
546
    } else {
547
      Serial.println("gyroscope failed selftest");
548
    }
549
    if (selftest & 0x08) {
550
      Serial.println("MCU passed selftest");
551
    } else {
552
      Serial.println("MCU failed selftest");
553
    }
554
555
    delay(500);
556
557
    //delay(500);
558
559
    //accelgyroCalBNO055(accelBias, gyroBias);
560
561
    // Serial.println("Average accelerometer bias (mg) = "); Serial.println(accelBias[0]); Serial.println(accelBias[1]); Serial.println(accelBias[2]);
562
    //  Serial.println("Average gyro bias (dps) = "); Serial.println(gyroBias[0]); Serial.println(gyroBias[1]); Serial.println(gyroBias[2]);
563
564
    //delay(500);
565
566
    //magCalBNO055(magBias);
567
568
    //Serial.println("Average magnetometer bias (mG) = "); Serial.println(magBias[0]); Serial.println(magBias[1]); Serial.println(magBias[2]);
569
570
    // delay(500);
571
572
    // Check calibration status of the sensors
573
    uint8_t calstat = readByte(BNO055_ADDRESS, BNO055_CALIB_STAT);
574
    Serial.println("Not calibrated = 0, fully calibrated = 3");
575
    Serial.print("System calibration status "); Serial.println( (0xC0 & calstat) >> 6);
576
    Serial.print("Gyro   calibration status "); Serial.println( (0x30 & calstat) >> 4);
577
    Serial.print("Accel  calibration status "); Serial.println( (0x0C & calstat) >> 2);
578
    Serial.print("Mag    calibration status "); Serial.println( (0x03 & calstat) >> 0);
579
580
    initBNO055(); // Initialize the BNO055
581
    Serial.println("BNO055 initialized for sensor mode...."); // Initialize BNO055 for sensor read
582
583
  }
584
  else
585
  {
586
    Serial.print("Could not connect to BNO055: 0x");
587
    Serial.println(c, HEX);
588
    while (1) ; // Loop forever if communication doesn't happen
589
  }
590
}
591
592
void loop()
593
{
594
595
  readAccelData(accelCount);  // Read the x/y/z adc values
596
  // Now we'll calculate the accleration value into actual mg's
597
  ax = (float)accelCount[0] - accelBias[0];  // subtract off calculated accel bias
598
  ay = (float)accelCount[1] - accelBias[1];
599
  az = (float)accelCount[2] - accelBias[2];
600
601
  readGyroData(gyroCount);  // Read the x/y/z adc values
602
  // Calculate the gyro value into actual degrees per second
603
  gx = (float)gyroCount[0] / 16. - gyroBias[0]; // subtract off calculated gyro bias
604
  gy = (float)gyroCount[1] / 16. - gyroBias[1];
605
  gz = (float)gyroCount[2] / 16. - gyroBias[2];
606
607
  readMagData(magCount);  // Read the x/y/z adc values
608
  // Calculate the magnetometer values in milliGauss
609
  mx = (float)magCount[0] / 1.6 - magBias[0]; // get actual magnetometer value in mGauss
610
  my = (float)magCount[1] / 1.6 - magBias[1];
611
  mz = (float)magCount[2] / 1.6 - magBias[2];
612
613
  readQuatData(quatCount);  // Read the x/y/z adc values
614
  // Calculate the quaternion values
615
  quat[0] = (float)(quatCount[0]) / 16384.;
616
  quat[1] = (float)(quatCount[1]) / 16384.;
617
  quat[2] = (float)(quatCount[2]) / 16384.;
618
  quat[3] = (float)(quatCount[3]) / 16384.;
619
620
  readEulData(EulCount);  // Read the x/y/z adc values
621
  // Calculate the Euler angles values in degrees
622
  Yaw = (float)EulCount[0] / 16.;
623
  Roll = (float)EulCount[1] / 16.;
624
  Pitch = (float)EulCount[2] / 16.;
625
626
  readLIAData(LIACount);  // Read the x/y/z adc values
627
  // Calculate the linear acceleration (sans gravity) values in mg
628
  LIAx = (float)LIACount[0];
629
  LIAy = (float)LIACount[1];
630
  LIAz = (float)LIACount[2];
631
632
  readGRVData(GRVCount);  // Read the x/y/z adc values
633
  // Calculate the linear acceleration (sans gravity) values in mg
634
  GRVx = (float)GRVCount[0];
635
  GRVy = (float)GRVCount[1];
636
  GRVz = (float)GRVCount[2];
637
638
  Now = micros();
639
  deltat = ((Now - lastUpdate) / 1000000.0f); // set integration time by time elapsed since last filter update
640
  lastUpdate = Now;
641
642
  sum += deltat; // sum for averaging filter update rate
643
  sumCount++;
644
645
  // Sensors x, y, and z-axes  for the three sensor: accel, gyro, and magnetometer are all aligned, so
646
  // no allowance for any orientation mismatch in feeding the output to the quaternion filter is required.
647
  // For the BNO055, the sensor forward is along the x-axis just like
648
  // in the LSM9DS0 and MPU9250 sensors. This rotation can be modified to allow any convenient orientation convention.
649
  // This is ok by aircraft orientation standards!
650
  // Pass gyro rate as rad/s
651
  // MadgwickQuaternionUpdate(ax, ay, az, gx*PI/180.0f, gy*PI/180.0f, gz*PI/180.0f,  mx,  my,  mz);
652
  //  MahonyQuaternionUpdate(ax, ay, az, gx*PI/180.0f, gy*PI/180.0f, gz*PI/180.0f, mx, my, mz);
653
654
  // Serial print and/or display at 0.5 s rate independent of data rates
655
  delt_t = millis() - count;
656
  if (delt_t > 100) { // update LCD once per half-second independent of read rate
657
658
    // check BNO-055 error status at 2 Hz rate
659
    uint8_t errstat = readByte(BNO055_ADDRESS, BNO055_CALIB_STAT);
660
    if (errstat == 0x01) {
661
      uint8_t syserr = readByte(BNO055_ADDRESS, BNO055_SYS_ERR);
662
      if (syserr == 0x01) Serial.println("Peripheral initialization error");
663
      if (syserr == 0x02) Serial.println("System initialization error");
664
      if (syserr == 0x03) Serial.println("Self test result failed");
665
      if (syserr == 0x04) Serial.println("Register map value out of range");
666
      if (syserr == 0x05) Serial.println("Register map address out of range");
667
      if (syserr == 0x06) Serial.println("Register map write error");
668
      if (syserr == 0x07) Serial.println("BNO low power mode no available for selected operation mode");
669
      if (syserr == 0x08) Serial.println("Accelerometer power mode not available");
670
      if (syserr == 0x09) Serial.println("Fusion algorithm configuration error");
671
      if (syserr == 0x0A) Serial.println("Sensor configuration error");
672
    }
673
674
    //    Serial.print("ax = "); Serial.print((int)ax);
675
    //    Serial.print(" ay = "); Serial.print((int)ay);
676
    //    Serial.print(" az = "); Serial.print((int)az); Serial.println(" mg");
677
    //    Serial.print("gx = "); Serial.print( gx, 2);
678
    //    Serial.print(" gy = "); Serial.print( gy, 2);
679
    //    Serial.print(" gz = "); Serial.print( gz, 2); Serial.println(" deg/s");
680
    //    Serial.print("mx = "); Serial.print( (int)mx );
681
    //    Serial.print(" my = "); Serial.print( (int)my );
682
    //    Serial.print(" mz = "); Serial.print( (int)mz ); Serial.println(" mG");
683
    //
684
    //    Serial.print("qx = "); Serial.print(q[0]);
685
    //    Serial.print(" qy = "); Serial.print(q[1]);
686
    //    Serial.print(" qz = "); Serial.print(q[2]);
687
    //    Serial.print(" qw = "); Serial.println(q[3]);
688
    //    Serial.print("quatw = "); Serial.print(quat[0]);
689
    //    Serial.print(" quatx = "); Serial.print(quat[1]);
690
    //    Serial.print(" quaty = "); Serial.print(quat[2]);
691
    //    Serial.print(" quatz = "); Serial.println(quat[3]);
692
693
    tempGCount = readGyroTempData();  // Read the gyro adc values
694
    Gtemperature = (float) tempGCount; // Gyro chip temperature in degrees Centigrade
695
    // Print gyro die temperature in degrees Centigrade
696
    //    Serial.print("Gyro temperature is ");  Serial.print(Gtemperature, 1);  Serial.println(" degrees C"); // Print T values to tenths of a degree C
697
698
    // Define output variables from updated quaternion---these are Tait-Bryan angles, commonly used in aircraft orientation.
699
    // In this coordinate system, the positive z-axis is down toward Earth.
700
    // Yaw is the angle between Sensor x-axis and Earth magnetic North (or true North if corrected for local declination, looking down on the sensor positive yaw is counterclockwise.
701
    // Pitch is angle between sensor x-axis and Earth ground plane, toward the Earth is positive, up toward the sky is negative.
702
    // Roll is angle between sensor y-axis and Earth ground plane, y-axis up is positive roll.
703
    // These arise from the definition of the homogeneous rotation matrix constructed from quaternions.
704
    // Tait-Bryan angles as well as Euler angles are non-commutative; that is, the get the correct orientation the rotations must be
705
    // applied in the correct order which for this configuration is yaw, pitch, and then roll.
706
    // For more see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles which has additional links.
707
    yaw   = atan2(2.0f * (q[1] * q[2] + q[0] * q[3]), q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3]);
708
    pitch = -asin(2.0f * (q[1] * q[3] - q[0] * q[2]));
709
    roll  = atan2(2.0f * (q[0] * q[1] + q[2] * q[3]), q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]);
710
    pitch *= 180.0f / PI;
711
    yaw   *= 180.0f / PI;
712
    //   yaw   -= 13.8f; // Declination at Danville, California is 13 degrees 48 minutes and 47 seconds on 2014-04-04
713
    roll  *= 180.0f / PI;
714
715
    //    Serial.print("Software Yaw, Pitch, Roll: ");
716
    //    Serial.print(yaw, 2);
717
    //    Serial.print(", ");
718
    //    Serial.print(pitch, 2);
719
    //    Serial.print(", ");
720
    //    Serial.println(roll, 2);
721
    //
722
    //    Serial.print("Hardware Yaw, Pitch, Roll: ");
723
    //    Serial.print(Yaw, 2);
724
    //    Serial.print(", ");
725
    //    Serial.print(Pitch, 2);
726
    //    Serial.print(", ");
727
    //    Serial.println(Roll, 2);
728
    //
729
    //    Serial.print("Hardware x, y, z linear acceleration: ");
730
    //    Serial.print(LIAx, 2);
731
    //    Serial.print(", ");
732
    //    Serial.print(LIAy, 2);
733
    //    Serial.print(", ");
734
    //    Serial.println(LIAz, 2);
735
736
    Serial.print("Hardware x, y, z gravity vector: ");
737
    Serial.print(GRVx, 2);
738
    Serial.print(", ");
739
    Serial.print(GRVy, 2);
740
    Serial.print(", ");
741
    Serial.println(GRVz, 2);
742
743
    Serial.print("rate = "); Serial.print((float)sumCount / sum, 2); Serial.println(" Hz");
744
    uint8_t r = map (GRVx, -1000, 1000, 0, 255);
745
    uint8_t g = map (GRVy, -1000, 1000, 0, 255);
746
    uint8_t b = map (GRVz, -1000, 1000, 0, 255);
747
    Serial.print("LED Data: ");
748
    Serial.print(r);
749
    Serial.print(", ");
750
    Serial.print(g);
751
    Serial.print(", ");
752
    Serial.println(b);
753
    strip.setPixelColor(0, r, g, b); // Set pixel 'c' to value 'color'
754
    strip.setPixelColor(1, 255-r, 255-g, 255-b); // Set pixel 'c' to value 'color'
755
    strip.show();            // Turn OFF all pixels ASAP
756
757
    digitalWrite(myLed, !digitalRead(myLed));
758
    count = millis();
759
    sumCount = 0;
760
    sum = 0;
761
762
#ifdef USE_DRV
763
    drv.setRealtimeValue(map(GRVx, -1000, 1000, 0, 127));
764
#endif
765
  }
766
767
}
768
769
//===================================================================================================================
770
//====== Set of useful function to access acceleration. gyroscope, magnetometer, and temperature data
771
//===================================================================================================================
772
773
void readAccelData(int16_t * destination)
774
{
775
  uint8_t rawData[6];  // x/y/z accel register data stored here
776
  readBytes(BNO055_ADDRESS, BNO055_ACC_DATA_X_LSB, 6, &rawData[0]);  // Read the six raw data registers into data array
777
  destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ;      // Turn the MSB and LSB into a signed 16-bit value
778
  destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
779
  destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
780
}
781
782
void readGyroData(int16_t * destination)
783
{
784
  uint8_t rawData[6];  // x/y/z gyro register data stored here
785
  readBytes(BNO055_ADDRESS, BNO055_GYR_DATA_X_LSB, 6, &rawData[0]);  // Read the six raw data registers sequentially into data array
786
  destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ;       // Turn the MSB and LSB into a signed 16-bit value
787
  destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
788
  destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
789
}
790
791
int8_t readGyroTempData()
792
{
793
  return readByte(BNO055_ADDRESS, BNO055_TEMP);  // Read the two raw data registers sequentially into data array
794
}
795
796
void readMagData(int16_t * destination)
797
{
798
  uint8_t rawData[6];  // x/y/z gyro register data stored here
799
  readBytes(BNO055_ADDRESS, BNO055_MAG_DATA_X_LSB, 6, &rawData[0]);  // Read the six raw data registers sequentially into data array
800
  destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ;       // Turn the MSB and LSB into a signed 16-bit value
801
  destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
802
  destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
803
}
804
805
void readQuatData(int16_t * destination)
806
{
807
  uint8_t rawData[8];  // x/y/z gyro register data stored here
808
  readBytes(BNO055_ADDRESS, BNO055_QUA_DATA_W_LSB, 8, &rawData[0]);  // Read the six raw data registers sequentially into data array
809
  destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ;       // Turn the MSB and LSB into a signed 16-bit value
810
  destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
811
  destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
812
  destination[3] = ((int16_t)rawData[7] << 8) | rawData[6] ;
813
}
814
815
void readEulData(int16_t * destination)
816
{
817
  uint8_t rawData[6];  // x/y/z gyro register data stored here
818
  readBytes(BNO055_ADDRESS, BNO055_EUL_HEADING_LSB, 6, &rawData[0]);  // Read the six raw data registers sequentially into data array
819
  destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ;       // Turn the MSB and LSB into a signed 16-bit value
820
  destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
821
  destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
822
}
823
824
void readLIAData(int16_t * destination)
825
{
826
  uint8_t rawData[6];  // x/y/z gyro register data stored here
827
  readBytes(BNO055_ADDRESS, BNO055_LIA_DATA_X_LSB, 6, &rawData[0]);  // Read the six raw data registers sequentially into data array
828
  destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ;       // Turn the MSB and LSB into a signed 16-bit value
829
  destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
830
  destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
831
}
832
833
void readGRVData(int16_t * destination)
834
{
835
  uint8_t rawData[6];  // x/y/z gyro register data stored here
836
  readBytes(BNO055_ADDRESS, BNO055_GRV_DATA_X_LSB, 6, &rawData[0]);  // Read the six raw data registers sequentially into data array
837
  destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ;       // Turn the MSB and LSB into a signed 16-bit value
838
  destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
839
  destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
840
}
841
842
void initBNO055() {
843
  // Select page 1 to configure sensors
844
  writeByte(BNO055_ADDRESS, BNO055_PAGE_ID, 0x01);
845
  // Configure ACC
846
  writeByte(BNO055_ADDRESS, BNO055_ACC_CONFIG, APwrMode << 5 | Abw << 3 | Ascale );
847
  // Configure GYR
848
  writeByte(BNO055_ADDRESS, BNO055_GYRO_CONFIG_0, Gbw << 3 | Gscale );
849
  writeByte(BNO055_ADDRESS, BNO055_GYRO_CONFIG_1, GPwrMode);
850
  // Configure MAG
851
  writeByte(BNO055_ADDRESS, BNO055_MAG_CONFIG, MPwrMode << 4 | MOpMode << 2 | Modr );
852
853
  // Select page 0 to read sensors
854
  writeByte(BNO055_ADDRESS, BNO055_PAGE_ID, 0x00);
855
856
  // Select BNO055 gyro temperature source
857
  writeByte(BNO055_ADDRESS, BNO055_TEMP_SOURCE, 0x01 );
858
859
  // Select BNO055 sensor units (temperature in degrees C, rate in dps, accel in mg)
860
  writeByte(BNO055_ADDRESS, BNO055_UNIT_SEL, 0x01 );
861
862
  // Select BNO055 system power mode
863
  writeByte(BNO055_ADDRESS, BNO055_PWR_MODE, PWRMode );
864
865
  // Select BNO055 system operation mode
866
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, OPRMode );
867
}
868
869
void accelgyroCalBNO055(float * dest1, float * dest2)
870
{
871
  uint8_t data[6]; // data array to hold accelerometer and gyro x, y, z, data
872
  uint16_t ii = 0, sample_count = 0;
873
  int32_t gyro_bias[3]  = {0, 0, 0}, accel_bias[3] = {0, 0, 0};
874
875
  Serial.println("Accel/Gyro Calibration: Put device on a level surface and keep motionless! Wait......");
876
  delay(1000);
877
878
  // Select page 0 to read sensors
879
  writeByte(BNO055_ADDRESS, BNO055_PAGE_ID, 0x00);
880
  // Select BNO055 system operation mode as NDOF for calibration
881
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, CONFIGMODE );
882
  delay(25);
883
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, NDOF );
884
885
  // In NDF fusion mode, accel full scale is at +/- 4g, ODR is 62.5 Hz
886
  sample_count = 256;
887
  for (ii = 0; ii < sample_count; ii++) {
888
    int16_t accel_temp[3] = {0, 0, 0};
889
    readBytes(BNO055_ADDRESS, BNO055_ACC_DATA_X_LSB, 6, &data[0]);  // Read the six raw data registers into data array
890
    accel_temp[0] = (int16_t) (((int16_t)data[1] << 8) | data[0]) ; // Form signed 16-bit integer for each sample in FIFO
891
    accel_temp[1] = (int16_t) (((int16_t)data[3] << 8) | data[2]) ;
892
    accel_temp[2] = (int16_t) (((int16_t)data[5] << 8) | data[4]) ;
893
    accel_bias[0]  += (int32_t) accel_temp[0];
894
    accel_bias[1]  += (int32_t) accel_temp[1];
895
    accel_bias[2]  += (int32_t) accel_temp[2];
896
    delay(20);  // at 62.5 Hz ODR, new accel data is available every 16 ms
897
  }
898
  accel_bias[0]  /= (int32_t) sample_count;  // get average accel bias in mg
899
  accel_bias[1]  /= (int32_t) sample_count;
900
  accel_bias[2]  /= (int32_t) sample_count;
901
902
  if (accel_bias[2] > 0L) {
903
    accel_bias[2] -= (int32_t) 1000; // Remove gravity from the z-axis accelerometer bias calculation
904
  }
905
  else {
906
    accel_bias[2] += (int32_t) 1000;
907
  }
908
909
  dest1[0] = (float) accel_bias[0];  // save accel biases in mg for use in main program
910
  dest1[1] = (float) accel_bias[1];  // accel data is 1 LSB/mg
911
  dest1[2] = (float) accel_bias[2];
912
913
  // In NDF fusion mode, gyro full scale is at +/- 2000 dps, ODR is 32 Hz
914
  for (ii = 0; ii < sample_count; ii++) {
915
    int16_t gyro_temp[3] = {0, 0, 0};
916
    readBytes(BNO055_ADDRESS, BNO055_GYR_DATA_X_LSB, 6, &data[0]);  // Read the six raw data registers into data array
917
    gyro_temp[0] = (int16_t) (((int16_t)data[1] << 8) | data[0]) ;  // Form signed 16-bit integer for each sample in FIFO
918
    gyro_temp[1] = (int16_t) (((int16_t)data[3] << 8) | data[2]) ;
919
    gyro_temp[2] = (int16_t) (((int16_t)data[5] << 8) | data[4]) ;
920
    gyro_bias[0]  += (int32_t) gyro_temp[0];
921
    gyro_bias[1]  += (int32_t) gyro_temp[1];
922
    gyro_bias[2]  += (int32_t) gyro_temp[2];
923
    delay(35);  // at 32 Hz ODR, new gyro data available every 31 ms
924
  }
925
  gyro_bias[0]  /= (int32_t) sample_count;  // get average gyro bias in counts
926
  gyro_bias[1]  /= (int32_t) sample_count;
927
  gyro_bias[2]  /= (int32_t) sample_count;
928
929
  dest2[0] = (float) gyro_bias[0] / 16.; // save gyro biases in dps for use in main program
930
  dest2[1] = (float) gyro_bias[1] / 16.; // gyro data is 16 LSB/dps
931
  dest2[2] = (float) gyro_bias[2] / 16.;
932
933
  // Return to config mode to write accelerometer biases in offset register
934
  // This offset register is only used while in fusion mode when accelerometer full-scale is +/- 4g
935
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, CONFIGMODE );
936
  delay(25);
937
938
  //write biases to accelerometer offset registers ad 16 LSB/dps
939
  writeByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_X_LSB, (int16_t)accel_bias[0] & 0xFF);
940
  writeByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_X_MSB, ((int16_t)accel_bias[0] >> 8) & 0xFF);
941
  writeByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_Y_LSB, (int16_t)accel_bias[1] & 0xFF);
942
  writeByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_Y_MSB, ((int16_t)accel_bias[1] >> 8) & 0xFF);
943
  writeByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_Z_LSB, (int16_t)accel_bias[2] & 0xFF);
944
  writeByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_Z_MSB, ((int16_t)accel_bias[2] >> 8) & 0xFF);
945
946
  // Check that offsets were properly written to offset registers
947
  //  Serial.println("Average accelerometer bias = ");
948
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_X_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_X_LSB)));
949
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_Y_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_Y_LSB)));
950
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_Z_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_ACC_OFFSET_Z_LSB)));
951
952
  //write biases to gyro offset registers
953
  writeByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_X_LSB, (int16_t)gyro_bias[0] & 0xFF);
954
  writeByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_X_MSB, ((int16_t)gyro_bias[0] >> 8) & 0xFF);
955
  writeByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_Y_LSB, (int16_t)gyro_bias[1] & 0xFF);
956
  writeByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_Y_MSB, ((int16_t)gyro_bias[1] >> 8) & 0xFF);
957
  writeByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_Z_LSB, (int16_t)gyro_bias[2] & 0xFF);
958
  writeByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_Z_MSB, ((int16_t)gyro_bias[2] >> 8) & 0xFF);
959
960
  // Select BNO055 system operation mode
961
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, OPRMode );
962
963
  // Check that offsets were properly written to offset registers
964
  //  Serial.println("Average gyro bias = ");
965
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_X_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_X_LSB)));
966
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_Y_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_Y_LSB)));
967
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_Z_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_GYR_OFFSET_Z_LSB)));
968
969
  Serial.println("Accel/Gyro Calibration done!");
970
}
971
972
void magCalBNO055(float * dest1)
973
{
974
  uint8_t data[6]; // data array to hold accelerometer and gyro x, y, z, data
975
  uint16_t ii = 0, sample_count = 0;
976
  int32_t mag_bias[3] = {0, 0, 0};
977
  int16_t mag_max[3] = {0, 0, 0}, mag_min[3] = {0, 0, 0};
978
979
  Serial.println("Mag Calibration: Wave device in a figure eight until done!");
980
  delay(4000);
981
982
  // Select page 0 to read sensors
983
  writeByte(BNO055_ADDRESS, BNO055_PAGE_ID, 0x00);
984
  // Select BNO055 system operation mode as NDOF for calibration
985
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, CONFIGMODE );
986
  delay(25);
987
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, NDOF );
988
989
  // In NDF fusion mode, mag data is in 16 LSB/microTesla, ODR is 20 Hz in forced mode
990
  sample_count = 256;
991
  for (ii = 0; ii < sample_count; ii++) {
992
    int16_t mag_temp[3] = {0, 0, 0};
993
    readBytes(BNO055_ADDRESS, BNO055_MAG_DATA_X_LSB, 6, &data[0]);  // Read the six raw data registers into data array
994
    mag_temp[0] = (int16_t) (((int16_t)data[1] << 8) | data[0]) ;   // Form signed 16-bit integer for each sample in FIFO
995
    mag_temp[1] = (int16_t) (((int16_t)data[3] << 8) | data[2]) ;
996
    mag_temp[2] = (int16_t) (((int16_t)data[5] << 8) | data[4]) ;
997
    for (int jj = 0; jj < 3; jj++) {
998
      if (mag_temp[jj] > mag_max[jj]) mag_max[jj] = mag_temp[jj];
999
      if (mag_temp[jj] < mag_min[jj]) mag_min[jj] = mag_temp[jj];
1000
    }
1001
    delay(55);  // at 20 Hz ODR, new mag data is available every 50 ms
1002
  }
1003
1004
  //   Serial.println("mag x min/max:"); Serial.println(mag_max[0]); Serial.println(mag_min[0]);
1005
  //   Serial.println("mag y min/max:"); Serial.println(mag_max[1]); Serial.println(mag_min[1]);
1006
  //   Serial.println("mag z min/max:"); Serial.println(mag_max[2]); Serial.println(mag_min[2]);
1007
1008
  mag_bias[0]  = (mag_max[0] + mag_min[0]) / 2; // get average x mag bias in counts
1009
  mag_bias[1]  = (mag_max[1] + mag_min[1]) / 2; // get average y mag bias in counts
1010
  mag_bias[2]  = (mag_max[2] + mag_min[2]) / 2; // get average z mag bias in counts
1011
1012
  dest1[0] = (float) mag_bias[0] / 1.6;  // save mag biases in mG for use in main program
1013
  dest1[1] = (float) mag_bias[1] / 1.6;  // mag data is 1.6 LSB/mg
1014
  dest1[2] = (float) mag_bias[2] / 1.6;
1015
1016
  // Return to config mode to write mag biases in offset register
1017
  // This offset register is only used while in fusion mode when magnetometer sensitivity is 16 LSB/microTesla
1018
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, CONFIGMODE );
1019
  delay(25);
1020
1021
  //write biases to accelerometer offset registers as 16 LSB/microTesla
1022
  writeByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_X_LSB, (int16_t)mag_bias[0] & 0xFF);
1023
  writeByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_X_MSB, ((int16_t)mag_bias[0] >> 8) & 0xFF);
1024
  writeByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_Y_LSB, (int16_t)mag_bias[1] & 0xFF);
1025
  writeByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_Y_MSB, ((int16_t)mag_bias[1] >> 8) & 0xFF);
1026
  writeByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_Z_LSB, (int16_t)mag_bias[2] & 0xFF);
1027
  writeByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_Z_MSB, ((int16_t)mag_bias[2] >> 8) & 0xFF);
1028
1029
  // Check that offsets were properly written to offset registers
1030
  //  Serial.println("Average magnetometer bias = ");
1031
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_X_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_X_LSB)));
1032
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_Y_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_Y_LSB)));
1033
  //  Serial.println((int16_t)((int16_t)readByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_Z_MSB) << 8 | readByte(BNO055_ADDRESS, BNO055_MAG_OFFSET_Z_LSB)));
1034
  // Select BNO055 system operation mode
1035
  writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, OPRMode );
1036
1037
  Serial.println("Mag Calibration done!");
1038
}
1039
1040
// I2C communication with the MS5637 is a little different from that with the BNO055 and most other sensors
1041
// For the MS5637, we write commands, and the MS5637 sends data in response, rather than directly reading
1042
// MS5637 registers
1043
1044
// I2C read/write functions for the BNO055 sensor
1045
1046
void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
1047
{
1048
  Wire.beginTransmission(address);  // Initialize the Tx buffer
1049
  Wire.write(subAddress);           // Put slave register address in Tx buffer
1050
  Wire.write(data);                 // Put data in Tx buffer
1051
  Wire.endTransmission();           // Send the Tx buffer
1052
}
1053
1054
uint8_t readByte(uint8_t address, uint8_t subAddress)
1055
{
1056
  uint8_t data; // `data` will store the register data
1057
  Wire.beginTransmission(address);         // Initialize the Tx buffer
1058
  Wire.write(subAddress);                     // Put slave register address in Tx buffer
1059
  //    Wire.endTransmission(I2C_NOSTOP);        // Send the Tx buffer, but send a restart to keep connection alive
1060
  Wire.endTransmission(false);             // Send the Tx buffer, but send a restart to keep connection alive
1061
  //    Wire.requestFrom(address, 1);  // Read one byte from slave register address
1062
  Wire.requestFrom(address, (size_t) 1);   // Read one byte from slave register address
1063
  data = Wire.read();                      // Fill Rx buffer with result
1064
  return data;                             // Return data read from slave register
1065
}
1066
1067
void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
1068
{
1069
  Wire.beginTransmission(address);   // Initialize the Tx buffer
1070
  Wire.write(subAddress);            // Put slave register address in Tx buffer
1071
  //    Wire.endTransmission(I2C_NOSTOP);  // Send the Tx buffer, but send a restart to keep connection alive
1072
  Wire.endTransmission(false);       // Send the Tx buffer, but send a restart to keep connection alive
1073
  uint8_t i = 0;
1074
  //        Wire.requestFrom(address, count);  // Read bytes from slave register address
1075
  Wire.requestFrom(address, (size_t) count);  // Read bytes from slave register address
1076
  while (Wire.available()) {
1077
    dest[i++] = Wire.read();
1078
  }         // Put read results in the Rx buffer
1079
}