Extended and refactored library for BNO055, an intelligent 9-axis absolute orientation sensor by Bosch Sensortec. It includes ACC, MAG and GYRO sensors and Cortex-M0 processor.

Fork of BNO055_fusion by Kenji Arai

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BNO055.cpp Source File

BNO055.cpp

00001 /*
00002  * mbed library program
00003  *  BNO055 Intelligent 9-axis absolute orientation sensor
00004  *  by Bosch Sensortec
00005  *
00006  * Copyright (c) 2015,'17 Kenji Arai / JH1PJL
00007  *  http://www.page.sannet.ne.jp/kenjia/index.html
00008  *  http://mbed.org/users/kenjiArai/
00009  *      Created: March     30th, 2015
00010  *      Revised: August    23rd, 2017
00011  */
00012 
00013 #include "mbed.h"
00014 #include "BNO055.h"
00015 
00016 
00017 #if MBED_MAJOR_VERSION == 2
00018 #define WAIT_MS(x)       wait_ms(x)
00019 #elif  MBED_MAJOR_VERSION == 5
00020 #define WAIT_MS(x)       Thread::wait(x)
00021 #else
00022 #error "Running on Unknown OS"
00023 #endif
00024 
00025 BNO055::BNO055 (PinName p_sda, PinName p_scl, PinName p_reset, uint8_t addr, uint8_t mode):
00026     _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p), _res(p_reset)
00027 {
00028     chip_addr = addr;
00029     chip_mode = mode;
00030     initialize_reset_pin();
00031     initialize ();
00032 }
00033 
00034 BNO055::BNO055 (PinName p_sda, PinName p_scl, PinName p_reset) :
00035     _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p), _res(p_reset)
00036 {
00037     chip_addr = BNO055_G_CHIP_ADDR;
00038     chip_mode = MODE_NDOF;
00039     initialize_reset_pin();
00040     initialize ();
00041 }
00042 
00043 BNO055::BNO055 (I2C& p_i2c, PinName p_reset, uint8_t addr, uint8_t mode) :
00044     _i2c(p_i2c), _res(p_reset)
00045 {
00046     chip_addr = addr;
00047     chip_mode = mode;
00048     initialize_reset_pin();
00049     initialize ();
00050 }
00051 
00052 BNO055::BNO055 (I2C& p_i2c, PinName p_reset) :
00053     _i2c(p_i2c), _res(p_reset)
00054 {
00055     chip_addr = BNO055_G_CHIP_ADDR;
00056     chip_mode = MODE_NDOF;
00057     initialize_reset_pin();
00058     initialize ();
00059 }
00060 
00061 /////////////// Read data & normalize /////////////////////
00062 void BNO055::get_euler_angles(BNO055_EULER_TypeDef *result)
00063 {
00064     int16_t h,p,r;
00065 
00066     select_page(0);
00067     dt[0] = BNO055_EULER_H_LSB;
00068     _i2c.write(chip_addr, dt, 1, true);
00069     _i2c.read(chip_addr, dt, 6, false);
00070     h = dt[1] << 8 | dt[0];
00071     r = dt[3] << 8 | dt[2];
00072     p = dt[5] << 8 | dt[4];
00073 
00074     if (use_degrees()) {
00075         result->h = (double)h / 16;
00076         result->p = (double)p / 16;
00077         result->r = (double)r / 16;
00078     } else {
00079         result->h = (double)h / 900;
00080         result->p = (double)p / 900;
00081         result->r = (double)r / 900;
00082     }
00083 }
00084 
00085 void BNO055::get_quaternion(BNO055_QUATERNION_TypeDef *result)
00086 {
00087     int16_t w,x,y,z;
00088 
00089     select_page(0);
00090     dt[0] = BNO055_QUATERNION_W_LSB;
00091     _i2c.write(chip_addr, dt, 1, true);
00092     _i2c.read(chip_addr, dt, 8, false);
00093     w = (dt[1] << 8 | dt[0]);
00094     x = (dt[3] << 8 | dt[2]);
00095     y = (dt[5] << 8 | dt[4]);
00096     z = (dt[7] << 8 | dt[6]);
00097 
00098     result->w = double(w) / 16384.0f;
00099     result->x = double(x) / 16384.0f;
00100     result->y = double(y) / 16384.0f;
00101     result->z = double(z) / 16384.0f;
00102 }
00103 
00104 void BNO055::get_linear_accel(BNO055_VECTOR_TypeDef *result)
00105 {
00106     int16_t x,y,z;
00107 
00108     select_page(0);
00109     dt[0] = BNO055_LINEAR_ACC_X_LSB;
00110     _i2c.write(chip_addr, dt, 1, true);
00111     _i2c.read(chip_addr, dt, 6, false);
00112     x = dt[1] << 8 | dt[0];
00113     y = dt[3] << 8 | dt[2];
00114     z = dt[5] << 8 | dt[4];
00115 
00116     if (use_mss()) {
00117         result->x = (double)x / 100;
00118         result->y = (double)y / 100;
00119         result->z = (double)z / 100;
00120     } else {
00121         result->x = (double)x;
00122         result->y = (double)y;
00123         result->z = (double)z;
00124     }
00125 }
00126 
00127 void BNO055::get_gravity(BNO055_VECTOR_TypeDef *result)
00128 {
00129     int16_t x,y,z;
00130 
00131     select_page(0);
00132     dt[0] = BNO055_GRAVITY_X_LSB;
00133     _i2c.write(chip_addr, dt, 1, true);
00134     _i2c.read(chip_addr, dt, 6, false);
00135     x = dt[1] << 8 | dt[0];
00136     y = dt[3] << 8 | dt[2];
00137     z = dt[5] << 8 | dt[4];
00138 
00139     if (use_mss()) {
00140         result->x = (double)x / 100;
00141         result->y = (double)y / 100;
00142         result->z = (double)z / 100;
00143     } else {
00144         result->x = (double)x;
00145         result->y = (double)y;
00146         result->z = (double)z;
00147     }
00148 }
00149 
00150 void BNO055::get_mag(BNO055_VECTOR_TypeDef *result)
00151 {
00152     int16_t x,y,z;
00153 
00154     select_page(0);
00155     dt[0] = BNO055_MAG_X_LSB;
00156     _i2c.write(chip_addr, dt, 1, true);
00157     _i2c.read(chip_addr, dt, 6, false);
00158     x = dt[1] << 8 | dt[0];
00159     y = dt[3] << 8 | dt[2];
00160     z = dt[5] << 8 | dt[4];
00161 
00162     result->x = (double)x;
00163     result->y = (double)y;
00164     result->z = (double)z;
00165 }
00166 
00167 void BNO055::get_accel(BNO055_VECTOR_TypeDef *result)
00168 {
00169     int16_t x,y,z;
00170 
00171     select_page(0);
00172     dt[0] = BNO055_ACC_X_LSB;
00173     _i2c.write(chip_addr, dt, 1, true);
00174     _i2c.read(chip_addr, dt, 6, false);
00175     x = dt[1] << 8 | dt[0];
00176     y = dt[3] << 8 | dt[2];
00177     z = dt[5] << 8 | dt[4];
00178 
00179     if (use_mss()) {
00180         result->x = (double)x / 100;
00181         result->y = (double)y / 100;
00182         result->z = (double)z / 100;
00183     } else {
00184         result->x = (double)x;
00185         result->y = (double)y;
00186         result->z = (double)z;
00187     }
00188 }
00189 
00190 void BNO055::get_gyro(BNO055_VECTOR_TypeDef *result)
00191 {
00192     int16_t x,y,z;
00193 
00194     select_page(0);
00195     dt[0] = BNO055_GYR_X_LSB;
00196     _i2c.write(chip_addr, dt, 1, true);
00197     _i2c.read(chip_addr, dt, 6, false);
00198     x = dt[1] << 8 | dt[0];
00199     y = dt[3] << 8 | dt[2];
00200     z = dt[5] << 8 | dt[4];
00201     if (use_dps()) {
00202         result->x = (double)x / 16;
00203         result->y = (double)y / 16;
00204         result->z = (double)z / 16;
00205     } else {
00206         result->x = (double)x / 900;
00207         result->y = (double)y / 900;
00208         result->z = (double)z / 900;
00209     }
00210 }
00211 
00212 void BNO055::get_chip_temperature(BNO055_TEMPERATURE_TypeDef *result)
00213 {
00214     select_page(0);
00215 
00216     uint8_t use_celsius_result = use_celsius();
00217 
00218     dt[0] = BNO055_TEMP_SOURCE;
00219     dt[1] = 0;
00220     _i2c.write(chip_addr, dt, 2, false);
00221     WAIT_MS(1); // Do I need to wait?
00222     dt[0] = BNO055_TEMP;
00223     _i2c.write(chip_addr, dt, 1, true);
00224     _i2c.read(chip_addr, dt, 1, false);
00225 
00226     if (use_celsius_result) {
00227         result->acc_chip = (int8_t)dt[0];
00228     } else {
00229         result->acc_chip = (int8_t)dt[0] * 2;
00230     }
00231 
00232     dt[0] = BNO055_TEMP_SOURCE;
00233     dt[1] = 1;
00234     _i2c.write(chip_addr, dt, 2, false);
00235     WAIT_MS(1); // Do I need to wait?
00236     dt[0] = BNO055_TEMP;
00237     _i2c.write(chip_addr, dt, 1, true);
00238     _i2c.read(chip_addr, dt, 1, false);
00239 
00240     if (use_celsius_result) {
00241         result->gyr_chip = (int8_t)dt[0];
00242     } else {
00243         result->gyr_chip = (int8_t)dt[0] * 2;
00244     }
00245 }
00246 
00247 /////////////// Initialize ////////////////////////////////
00248 void BNO055::initialize (void)
00249 {
00250 #if defined(TARGET_STM32L152RE)
00251     _i2c.frequency(100000);
00252 #else
00253     _i2c.frequency(400000);
00254 #endif
00255     page_flag = 0xff;
00256     select_page(0);
00257     // Check Acc & Mag & Gyro are available of not
00258     get_id();
00259     // Set initial data
00260     set_initial_dt_to_regs();
00261     // Unit selection
00262     unit_selection();
00263     // Set fusion mode
00264     change_fusion_mode(chip_mode);
00265 }
00266 
00267 void BNO055::initialize_reset_pin(void)
00268 {
00269     _res = 1;
00270     WAIT_MS(700); // Need to wait at least 650mS
00271 }
00272 
00273 void BNO055::unit_selection(void)
00274 {
00275     select_page(0);
00276     dt[0] = BNO055_UNIT_SEL;
00277     dt[1] = UNIT_ORI_WIN + UNIT_ACC_MSS + UNIT_GYR_DPS + UNIT_EULER_DEG + UNIT_TEMP_C;
00278     _i2c.write(chip_addr, dt, 2, false);
00279 }
00280 
00281 bool BNO055::use_degrees()
00282 {
00283     if (unit_flag_is_set(UNIT_EULER_RAD)) {
00284         return false;
00285     }
00286     return true;
00287 }
00288 
00289 bool BNO055::use_mss()
00290 {
00291     if (unit_flag_is_set(UNIT_ACC_MG)) {
00292         return false;
00293     }
00294     return true;
00295 }
00296 
00297 bool BNO055::use_dps()
00298 {
00299     if (unit_flag_is_set(UNIT_GYR_RPS)) {
00300         return false;
00301     }
00302     return true;
00303 }
00304 
00305 bool BNO055::use_celsius()
00306 {
00307     if (unit_flag_is_set(UNIT_TEMP_F)) {
00308         return false;
00309     }
00310     return true;
00311 }
00312 
00313 bool BNO055::unit_flag_is_set(uint8_t flag)
00314 {
00315     select_page(0);
00316     dt[0] = BNO055_UNIT_SEL;
00317     _i2c.write(chip_addr, dt, 1, true);
00318     _i2c.read(chip_addr, dt, 1, false);
00319     if (dt[0] & flag) {
00320         return true;
00321     }
00322     return false;
00323 }
00324 
00325 uint8_t BNO055::select_page(uint8_t page)
00326 {
00327     if (page != page_flag){
00328         dt[0] = BNO055_PAGE_ID;
00329         if (page == 1) {
00330             dt[1] = 1;  // select page 1
00331         } else {
00332             dt[1] = 0;  // select page 0
00333         }
00334         _i2c.write(chip_addr, dt, 2, false);
00335         dt[0] = BNO055_PAGE_ID;
00336         _i2c.write(chip_addr, dt, 1, true);
00337         _i2c.read(chip_addr, dt, 1, false);
00338         page_flag = dt[0];
00339     }
00340     return page_flag;
00341 }
00342 
00343 uint8_t BNO055::reset(void)
00344 {
00345      _res = 0;
00346      WAIT_MS(1);   // Reset 1mS
00347      _res = 1;
00348      WAIT_MS(700); // Need to wait at least 650mS
00349 #if defined(TARGET_STM32L152RE)
00350     _i2c.frequency(400000);
00351 #else
00352     _i2c.frequency(400000);
00353 #endif
00354     _i2c.stop();
00355     page_flag = 0xff;
00356     select_page(0);
00357     get_id();
00358     if (chip_id != I_AM_BNO055_CHIP){
00359         return 1;
00360     } else {
00361         initialize();
00362         return 0;
00363     }
00364 }
00365 
00366 ////// Set initialize data to related registers ///////////
00367 void BNO055::set_initial_dt_to_regs(void)
00368 {
00369     // select_page(0);
00370     // current setting is only used default values
00371 }
00372 
00373 /////////////// Check Who am I? ///////////////////////////
00374 void BNO055::get_id(void)
00375 {
00376     select_page(0);
00377     // ID
00378     dt[0] = BNO055_CHIP_ID;
00379     _i2c.write(chip_addr, dt, 1, true);
00380     _i2c.read(chip_addr, dt, 7, false);
00381     chip_id = dt[0];
00382     if (chip_id == I_AM_BNO055_CHIP) {
00383         ready_flag = 1;
00384     } else {
00385         ready_flag = 0;
00386     }
00387     acc_id = dt[1];
00388     if (acc_id == I_AM_BNO055_ACC) {
00389         ready_flag |= 2;
00390     }
00391     mag_id = dt[2];
00392     if (mag_id == I_AM_BNO055_MAG) {
00393         ready_flag |= 4;
00394     }
00395     gyr_id = dt[3];
00396     if (mag_id == I_AM_BNO055_MAG) {
00397         ready_flag |= 8;
00398     }
00399     bootldr_rev_id = dt[5]<< 8 | dt[4];
00400     sw_rev_id = dt[6];
00401 }
00402 
00403 void BNO055::read_id_inf(BNO055_ID_INF_TypeDef *id)
00404 {
00405     id->chip_id = chip_id;
00406     id->acc_id = acc_id;
00407     id->mag_id = mag_id;
00408     id->gyr_id = gyr_id;
00409     id->bootldr_rev_id = bootldr_rev_id;
00410     id->sw_rev_id = sw_rev_id;
00411 }
00412 
00413 /////////////// Check chip ready or not  //////////////////
00414 uint8_t BNO055::chip_ready(void)
00415 {
00416     if (ready_flag == 0x0f) {
00417         return 1;
00418     }
00419     return 0;
00420 }
00421 
00422 /////////////// Read Calibration status  //////////////////
00423 uint8_t BNO055::read_calib_status(void)
00424 {
00425     select_page(0);
00426     dt[0] = BNO055_CALIB_STAT;
00427     _i2c.write(chip_addr, dt, 1, true);
00428     _i2c.read(chip_addr, dt, 1, false);
00429     return dt[0];
00430 }
00431 
00432 /////////////// Change Fusion mode  ///////////////////////
00433 void BNO055::change_fusion_mode(uint8_t mode)
00434 {
00435     uint8_t current_mode;
00436 
00437     select_page(0);
00438     current_mode = get_operating_mode();
00439     switch (mode) {
00440         case CONFIGMODE:
00441             dt[0] = BNO055_OPR_MODE;
00442             dt[1] = mode;
00443             _i2c.write(chip_addr, dt, 2, false);
00444             WAIT_MS(19);    // wait 19mS
00445             break;
00446         case MODE_IMU:
00447         case MODE_COMPASS:
00448         case MODE_M4G:
00449         case MODE_NDOF_FMC_OFF:
00450         case MODE_NDOF:
00451             if (current_mode != CONFIGMODE) {   // Can we change the mode directry?
00452                 dt[0] = BNO055_OPR_MODE;
00453                 dt[1] = CONFIGMODE;
00454                 _i2c.write(chip_addr, dt, 2, false);
00455                 WAIT_MS(19);    // wait 19mS
00456             }
00457             dt[0] = BNO055_OPR_MODE;
00458             dt[1] = mode;
00459             _i2c.write(chip_addr, dt, 2, false);
00460             WAIT_MS(7);    // wait 7mS
00461             break;
00462         default:
00463             break;
00464     }
00465 }
00466 
00467 uint8_t BNO055::get_operating_mode(void)
00468 {
00469     select_page(0);
00470     dt[0] = BNO055_OPR_MODE;
00471     _i2c.write(chip_addr, dt, 1, true);
00472     _i2c.read(chip_addr, dt, 1, false);
00473     return dt[0];
00474 }
00475 
00476 /////////////// Set Mouting position  /////////////////////
00477 void BNO055::set_mounting_position(uint8_t position)
00478 {
00479     uint8_t remap_config;
00480     uint8_t remap_sign;
00481     uint8_t current_mode;
00482 
00483     current_mode = get_operating_mode();
00484     change_fusion_mode(CONFIGMODE);
00485     switch (position) {
00486         case MT_P0:
00487             remap_config = 0x21;
00488             remap_sign = 0x04;
00489             break;
00490         case MT_P2:
00491             remap_config = 0x24;
00492             remap_sign = 0x06;
00493             break;
00494         case MT_P3:
00495             remap_config = 0x21;
00496             remap_sign = 0x02;
00497             break;
00498         case MT_P4:
00499             remap_config = 0x24;
00500             remap_sign = 0x03;
00501             break;
00502         case MT_P5:
00503             remap_config = 0x21;
00504             remap_sign = 0x01;
00505             break;
00506         case MT_P6:
00507             remap_config = 0x21;
00508             remap_sign = 0x07;
00509             break;
00510         case MT_P7:
00511             remap_config = 0x24;
00512             remap_sign = 0x05;
00513             break;
00514         case MT_P1:
00515         default:
00516             remap_config = 0x24;
00517             remap_sign = 0x00;
00518             break;
00519     }
00520     dt[0] = BNO055_AXIS_MAP_CONFIG;
00521     dt[1] = remap_config;
00522     dt[2] = remap_sign;
00523     _i2c.write(chip_addr, dt, 3, false);
00524     change_fusion_mode(current_mode);
00525 }
00526 
00527 /////////////// I2C Freq. /////////////////////////////////
00528 void BNO055::frequency(int hz)
00529 {
00530     _i2c.frequency(hz);
00531 }
00532 
00533 /////////////// Read/Write specific register //////////////
00534 uint8_t BNO055::read_reg0(uint8_t addr)
00535 {
00536     select_page(0);
00537     dt[0] = addr;
00538     _i2c.write(chip_addr, dt, 1, true);
00539     _i2c.read(chip_addr, dt, 1, false);
00540     return (uint8_t)dt[0];
00541 }
00542 
00543 uint8_t BNO055::write_reg0(uint8_t addr, uint8_t data)
00544 {
00545     uint8_t current_mode;
00546     uint8_t d;
00547 
00548     current_mode = get_operating_mode();
00549     change_fusion_mode(CONFIGMODE);
00550     dt[0] = addr;
00551     dt[1] = data;
00552     _i2c.write(chip_addr, dt, 2, false);
00553     d = dt[0];
00554     change_fusion_mode(current_mode);
00555     return d;
00556 }
00557 
00558 uint8_t BNO055::read_reg1(uint8_t addr)
00559 {
00560     select_page(1);
00561     dt[0] = addr;
00562     _i2c.write(chip_addr, dt, 1, true);
00563     _i2c.read(chip_addr, dt, 1, false);
00564     return (uint8_t)dt[0];
00565 }
00566 
00567 uint8_t BNO055::write_reg1(uint8_t addr, uint8_t data)
00568 {
00569     uint8_t current_mode;
00570     uint8_t d;
00571 
00572     current_mode = get_operating_mode();
00573     change_fusion_mode(CONFIGMODE);
00574     select_page(1);
00575     dt[0] = addr;
00576     dt[1] = data;
00577     _i2c.write(chip_addr, dt, 2, false);
00578     d = dt[0];
00579     change_fusion_mode(current_mode);
00580     return d;
00581 }