Statistics
| Branch: | Revision:

adafruit_bno055 / Adafruit_BNO055.cpp @ 67f3cff5

History | View | Annotate | Download (12.791 KB)

1
/***************************************************************************
2
  This is a library for the BNO055 orientation sensor
3

4
  Designed specifically to work with the Adafruit BNO055 Breakout.
5

6
  Pick one up today in the adafruit shop!
7
  ------> http://www.adafruit.com/products
8

9
  These sensors use I2C to communicate, 2 pins are required to interface.
10

11
  Adafruit invests time and resources providing this open source code,
12
  please support Adafruit andopen-source hardware by purchasing products
13
  from Adafruit!
14

15
  Written by KTOWN for Adafruit Industries.
16

17
  MIT license, all text above must be included in any redistribution
18
 ***************************************************************************/
19

    
20
#if ARDUINO >= 100
21
 #include "Arduino.h"
22
#else
23
 #include "WProgram.h"
24
#endif
25

    
26
#include <math.h>
27
#include <limits.h>
28

    
29
#include "Adafruit_BNO055.h"
30

    
31
/***************************************************************************
32
 CONSTRUCTOR
33
 ***************************************************************************/
34
 
35
/**************************************************************************/
36
/*!
37
    @brief  Instantiates a new Adafruit_BNO055 class
38
*/
39
/**************************************************************************/
40
Adafruit_BNO055::Adafruit_BNO055(int32_t sensorID, uint8_t address)
41
{
42
  _sensorID = sensorID;
43
  _address = address;
44
}
45

    
46
/***************************************************************************
47
 PUBLIC FUNCTIONS
48
 ***************************************************************************/
49

    
50
/**************************************************************************/
51
/*!
52
    @brief  Sets up the HW
53
*/
54
/**************************************************************************/
55
bool Adafruit_BNO055::begin(adafruit_bno055_opmode_t mode)
56
{
57
  /* Enable I2C */
58
  Wire.begin();
59

    
60
  /* Make sure we have the right device */
61
  uint8_t id = read8(BNO055_CHIP_ID_ADDR);
62
  if(id != BNO055_ID)
63
  {
64
    delay(1000); // hold on for boot
65
    if(id != BNO055_ID) {
66
      return false;  // still not? ok bail
67
    }
68
  }
69

    
70
  /* Switch to config mode (just in case since this is the default) */
71
  setMode(OPERATION_MODE_CONFIG);
72

    
73
  /* Reset */
74
  write8(BNO055_SYS_TRIGGER_ADDR, 0x20); //reset the sensor
75
  while (read8(BNO055_CHIP_ID_ADDR) != BNO055_ID) //wait for boot
76
    delay(10);
77
  
78
  delay(50);
79
 
80
  /* Set to normal power mode */
81
  write8(BNO055_PWR_MODE_ADDR, POWER_MODE_NORMAL);
82
  delay(10);
83

    
84
  write8(BNO055_PAGE_ID_ADDR, 0);
85
  
86
  /* Set the output units */
87
  uint8_t unitsel = (0 << 7) | /* Orientation = Android */
88
                    (0 << 4) | /* Temperature = Celsius */
89
                    (0 << 2) | /* Euler = Degrees */
90
                    (1 << 1) | /* Gyro = Rads */
91
                    (0 << 0);  /* Accelerometer = m/s^2 */
92
  write8(BNO055_UNIT_SEL_ADDR, unitsel);
93

    
94
  write8(BNO055_SYS_TRIGGER_ADDR, 0x0);
95
  delay(10);
96
  /* Set the requested operating mode (see section 3.3) */
97
  setMode(mode);
98
  delay(20);
99

    
100
  return true;
101
}
102

    
103
/**************************************************************************/
104
/*!
105
    @brief  Puts the chip in the specified operating mode
106
*/
107
/**************************************************************************/
108
void Adafruit_BNO055::setMode(adafruit_bno055_opmode_t mode)
109
{
110
  _mode = mode;
111
  write8(BNO055_OPR_MODE_ADDR, _mode);
112
  delay(30);
113
}
114

    
115
/**************************************************************************/
116
/*!
117
    @brief  Use the external 32.768KHz crystal
118
*/
119
/**************************************************************************/
120
void Adafruit_BNO055::setExtCrystalUse(boolean usextal)
121
{
122
  adafruit_bno055_opmode_t modeback = _mode;
123

    
124
  /* Switch to config mode (just in case since this is the default) */
125
  setMode(OPERATION_MODE_CONFIG);
126
  delay(25);
127
  write8(BNO055_PAGE_ID_ADDR, 0);
128
  if (usextal) {
129
    write8(BNO055_SYS_TRIGGER_ADDR, 0x80);
130
  } else {
131
    write8(BNO055_SYS_TRIGGER_ADDR, 0x00);
132
  }
133
  delay(10);
134
  /* Set the requested operating mode (see section 3.3) */
135
  setMode(modeback);
136
  delay(20);
137
}
138

    
139

    
140
/**************************************************************************/
141
/*!
142
    @brief  Gets the latest system status info
143
*/
144
/**************************************************************************/
145
void Adafruit_BNO055::getSystemStatus(uint8_t *system_status, uint8_t *self_test_result, uint8_t *system_error)
146
{
147
  adafruit_bno055_opmode_t backupmode = _mode;
148

    
149
  setMode(OPERATION_MODE_CONFIG);
150
  delay(20);
151
  write8(BNO055_PAGE_ID_ADDR, 0);
152

    
153
  write8(BNO055_SYS_TRIGGER_ADDR, read8(BNO055_SYS_TRIGGER_ADDR) | 0x1);
154
  delay(1000);
155
  
156
  /* System Status (see section 4.3.58)
157
     ---------------------------------
158
     0 = Idle
159
     1 = System Error
160
     2 = Initializing Peripherals
161
     3 = System Iniitalization
162
     4 = Executing Self-Test
163
     5 = Sensor fusio algorithm running
164
     6 = System running without fusion algorithms */
165
  
166
  if (system_status != 0)
167
    *system_status    = read8(BNO055_SYS_STAT_ADDR);
168
  
169
  /* Self Test Results (see section )
170
     --------------------------------
171
     1 = test passed, 0 = test failed
172
  
173
     Bit 0 = Accelerometer self test
174
     Bit 1 = Magnetometer self test
175
     Bit 2 = Gyroscope self test
176
     Bit 3 = MCU self test
177

178
     0x0F = all good! */
179
  
180
  if (self_test_result != 0)
181
    *self_test_result = read8(BNO055_SELFTEST_RESULT_ADDR);
182

    
183
  /* System Error (see section 4.3.59)
184
     ---------------------------------
185
     0 = No error
186
     1 = Peripheral initialization error
187
     2 = System initialization error
188
     3 = Self test result failed
189
     4 = Register map value out of range
190
     5 = Register map address out of range
191
     6 = Register map write error
192
     7 = BNO low power mode not available for selected operat ion mode
193
     8 = Accelerometer power mode not available
194
     9 = Fusion algorithm configuration error
195
     A = Sensor configuration error */
196
  
197
  if (system_error != 0)
198
    *system_error     = read8(BNO055_SYS_ERR_ADDR);
199

    
200
  setMode(backupmode);
201
  delay(20);
202
}
203

    
204
/**************************************************************************/
205
/*!
206
    @brief  Gets the chip revision numbers
207
*/
208
/**************************************************************************/
209
void Adafruit_BNO055::getRevInfo(adafruit_bno055_rev_info_t* info)
210
{
211
  uint8_t a, b;
212

    
213
  memset(info, 0, sizeof(adafruit_bno055_rev_info_t));
214

    
215
  /* Check the accelerometer revision */
216
  info->accel_rev = read8(BNO055_ACCEL_REV_ID_ADDR);
217

    
218
  /* Check the magnetometer revision */
219
  info->mag_rev   = read8(BNO055_MAG_REV_ID_ADDR);
220

    
221
  /* Check the gyroscope revision */
222
  info->gyro_rev  = read8(BNO055_GYRO_REV_ID_ADDR);
223

    
224
  /* Check the SW revision */
225
  info->bl_rev    = read8(BNO055_BL_REV_ID_ADDR);
226
  
227
  a = read8(BNO055_SW_REV_ID_LSB_ADDR);
228
  b = read8(BNO055_SW_REV_ID_MSB_ADDR);
229
  info->sw_rev = (((uint16_t)b) << 8) | ((uint16_t)a);
230
}
231

    
232
/**************************************************************************/
233
/*!
234
    @brief  Gets teh temperature in degrees celsius
235
*/
236
/**************************************************************************/
237
int8_t Adafruit_BNO055::getTemp(void)
238
{
239
  int8_t temp = (int8_t)(read8(BNO055_TEMP_ADDR));
240
  return temp;
241
}
242

    
243
/**************************************************************************/
244
/*!
245
    @brief  Gets a vector reading from the specified source
246
*/
247
/**************************************************************************/
248
imu::Vector<3> Adafruit_BNO055::getVector(adafruit_vector_type_t vector_type)
249
{
250
  imu::Vector<3> xyz;
251
  uint8_t buffer[6];
252
  memset (buffer, 0, 6);
253
  
254
  int16_t x, y, z;
255
  x = y = z = 0;
256
  
257
  /* Read vector data (6 bytes) */
258
  readLen((adafruit_bno055_reg_t)vector_type, buffer, 6);
259
  x = (((uint16_t)buffer[1]) << 8) | ((uint16_t)buffer[0]);
260
  y = (((uint16_t)buffer[3]) << 8) | ((uint16_t)buffer[2]);
261
  z = (((uint16_t)buffer[5]) << 8) | ((uint16_t)buffer[4]);
262

    
263
  /* Convert the value to an appropriate range (section 3.6.4) */
264
  /* and assign the value to the Vector type */
265
  switch(vector_type)
266
  {
267
    case VECTOR_MAGNETOMETER:
268
      /* 1uT = 16 LSB */
269
      xyz[0] = ((double)x)/16.0;
270
      xyz[1] = ((double)y)/16.0;
271
      xyz[2] = ((double)z)/16.0;
272
      break;
273
    case VECTOR_GYROSCOPE:
274
      /* 1rps = 900 LSB */
275
      xyz[0] = ((double)x)/900.0;
276
      xyz[1] = ((double)y)/900.0;
277
      xyz[2] = ((double)z)/900.0;
278
      break;
279
    case VECTOR_EULER:
280
      /* 1 degree = 16 LSB */
281
      xyz[0] = ((double)x)/16.0;
282
      xyz[1] = ((double)y)/16.0;
283
      xyz[2] = ((double)z)/16.0;
284
      break;
285
    case VECTOR_ACCELEROMETER:
286
    case VECTOR_LINEARACCEL:
287
    case VECTOR_GRAVITY:
288
      /* 1m/s^2 = 100 LSB */
289
      xyz[0] = ((double)x)/100.0;
290
      xyz[1] = ((double)y)/100.0;
291
      xyz[2] = ((double)z)/100.0;
292
      break;
293
  }
294
  
295
  return xyz;
296
}
297

    
298
/**************************************************************************/
299
/*!
300
    @brief  Gets a quaternion reading from the specified source
301
*/
302
/**************************************************************************/
303
imu::Quaternion Adafruit_BNO055::getQuat(void)
304
{
305
  uint8_t buffer[8];
306
  memset (buffer, 0, 8);
307
  
308
  int16_t x, y, z, w;
309
  x = y = z = w = 0;
310
  
311
  /* Read quat data (8 bytes) */
312
  readLen(BNO055_QUATERNION_DATA_W_LSB_ADDR, buffer, 8);
313
  w = (((uint16_t)buffer[1]) << 8) | ((uint16_t)buffer[0]);
314
  x = (((uint16_t)buffer[3]) << 8) | ((uint16_t)buffer[2]);
315
  y = (((uint16_t)buffer[5]) << 8) | ((uint16_t)buffer[4]);
316
  z = (((uint16_t)buffer[7]) << 8) | ((uint16_t)buffer[6]);
317

    
318
  /* Assign to Quaternion */
319
  imu::Quaternion quat((double)w, (double)x, (double)y, (double)z);
320
  return quat;
321
}
322

    
323
/**************************************************************************/
324
/*!
325
    @brief  Provides the sensor_t data for this sensor
326
*/
327
/**************************************************************************/
328
void Adafruit_BNO055::getSensor(sensor_t *sensor)
329
{
330
  /* Clear the sensor_t object */
331
  memset(sensor, 0, sizeof(sensor_t));
332

    
333
  /* Insert the sensor name in the fixed length char array */
334
  strncpy (sensor->name, "BNO055", sizeof(sensor->name) - 1);
335
  sensor->name[sizeof(sensor->name)- 1] = 0;
336
  sensor->version     = 1;
337
  sensor->sensor_id   = _sensorID;
338
  sensor->type        = SENSOR_TYPE_ORIENTATION;
339
  sensor->min_delay   = 0;
340
  sensor->max_value   = 0.0F;
341
  sensor->min_value   = 0.0F;
342
  sensor->resolution  = 0.01F;
343
}
344

    
345
/**************************************************************************/
346
/*!
347
    @brief  Reads the sensor and returns the data as a sensors_event_t
348
*/
349
/**************************************************************************/
350
bool Adafruit_BNO055::getEvent(sensors_event_t *event)
351
{
352
  /* Clear the event */
353
  memset(event, 0, sizeof(sensors_event_t));
354

    
355
  event->version   = sizeof(sensors_event_t);
356
  event->sensor_id = _sensorID;
357
  event->type      = SENSOR_TYPE_ORIENTATION;
358
  event->timestamp = millis();
359

    
360
  /* Get a Euler angle sample for orientation */
361
  imu::Vector<3> euler = getVector(Adafruit_BNO055::VECTOR_EULER);
362
  event->orientation.x = euler.x();
363
  event->orientation.y = euler.y();
364
  event->orientation.z = euler.z();
365

    
366
  return true;
367
}
368

    
369
/***************************************************************************
370
 PRIVATE FUNCTIONS
371
 ***************************************************************************/
372

    
373
/**************************************************************************/
374
/*!
375
    @brief  Writes an 8 bit value over I2C
376
*/
377
/**************************************************************************/
378
bool Adafruit_BNO055::write8(adafruit_bno055_reg_t reg, byte value)
379
{
380
  Wire.beginTransmission(_address);
381
  #if ARDUINO >= 100
382
    Wire.write((uint8_t)reg);
383
    Wire.write((uint8_t)value);
384
  #else
385
    Wire.send(reg);
386
    Wire.send(value);
387
  #endif
388
  Wire.endTransmission();
389

    
390
  /* ToDo: Check for error! */
391
  return true;
392
}
393

    
394
/**************************************************************************/
395
/*!
396
    @brief  Reads an 8 bit value over I2C
397
*/
398
/**************************************************************************/
399
byte Adafruit_BNO055::read8(adafruit_bno055_reg_t reg )
400
{
401
  byte value = 0;
402
  
403
  Wire.beginTransmission(_address);
404
  #if ARDUINO >= 100
405
    Wire.write((uint8_t)reg);
406
  #else
407
    Wire.send(reg);
408
  #endif
409
  Wire.endTransmission();
410
  Wire.requestFrom(_address, (byte)1);
411
  #if ARDUINO >= 100
412
    value = Wire.read();
413
  #else
414
    value = Wire.receive();
415
  #endif
416
  
417
  return value;
418
}
419

    
420
/**************************************************************************/
421
/*!
422
    @brief  Reads the specified number of bytes over I2C
423
*/
424
/**************************************************************************/
425
bool Adafruit_BNO055::readLen(adafruit_bno055_reg_t reg, byte * buffer, uint8_t len)
426
{
427
  Wire.beginTransmission(_address);
428
  #if ARDUINO >= 100
429
    Wire.write((uint8_t)reg);
430
  #else
431
    Wire.send(reg);
432
  #endif
433
  Wire.endTransmission();
434
  Wire.requestFrom(_address, (byte)len);
435

    
436
  /* Wait until data is available */
437
  while (Wire.available() < len);
438
    
439
  for (uint8_t i = 0; i < len; i++)
440
  {
441
    #if ARDUINO >= 100
442
      buffer[i] = Wire.read();
443
    #else
444
      buffer[i] = Wire.receive();
445
    #endif
446
  }
447
  
448
  /* ToDo: Check for errors! */
449
  return true;
450
}