Revision 7393c00e

View differences:

firmware/demo/FeatherBase-BNO055_RGB_Haptics/FeatherBase-BNO055_RGB_Haptics.ino
1
/* 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);