![]() |
Forum Index : Microcontroller and PC projects : BNO055: The best position sensor BUT!!
Page 1 of 2 ![]() ![]() |
|||||
Author | Message | ||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10310 |
The BNO055 is a nine axis position sensor like others on the market BUT it also has on-chip a 32-bit processor that does all the hard calculations for you, so you can read off the absolute orientation with no calcs needed on the Micromite. Applications of the device are numerous: Digital level Tilt compensated compass Attitude indicator Pedometer etc. etc. I'll start by dealing with the BUT You can buy it off Adafruit but it is expensive You can also buy two versions from the usual ebay/Alieexpress suppliers. One version should be completely avoided. It cannot be configured for I2C operation. Picture at the bottom. The one to buy is this one ![]() but you will probably receive one looking like this (three out of three for me) Note that the zero ohm resistor to the right of the picture is in a different place. As received it shorts out VCC to GND ![]() The vendors supply a 32KHz crystal which can be fitted to provide the BNO055's internal processor with a more accurate clock (by default uses internal RC) but I haven't got this to work on the PCBs supplied ( a simple I2C command is supposed to enable it) so it is probably best omitted. I suspect the load capacitors for the crystal are completely the wrong value. After these changes are done using the chip is simplicity itself. My main program is: i2c open 100,1000 pause 500 id = readByte(CHIP_ID_ADDR) if id <> BNO055_ID THEN print "Chip not found" else PRINT "OK" endif writeByte(OPR_MODE_ADDR,&B1100) 'turn on fusion mode writeByte(UNIT_SEL_ADDR,&B0) 'set output in degrees pause 50 do pause 500 readEUL loop end The code to read the orientation (Euler angles) is: sub readEUL local a$ local float i,j,k i2c write BNO055_ADDRESS,1,1,EULER_H_LSB_ADDR pause 10 i2c read BNO055_ADDRESS,0,6,a$ i=intconv(left$(a$,2),1)/16 j=intconv(mid$(a$,3,2),1)/16 k=intconv(right$(a$,2),1)/16 print "Heading :".i," Roll: ",j," Pitch :",k end sub and there is one sneaky subroutine that loads the incoming bytes into an integer as a signed value Function intconv(s$, p%) as integer local integer l,k,j,i=len(s$) k=peek(varaddr j) for l=1 to i poke byte k+l-1,asc(mid$(s$,l,1)) next l if p% then if (asc(mid$(s$,i,1)) and &H80) then for l=i to 7 poke byte k+l,&HFF next l endif endif intconv=j End Function Assuming the wiring is correct the program will then report the absolute orientation of the sensor every half second Wiring is: VCC - 3.3V GND - GND ATX (also labelled TX-SDA) - Micromite I2C-DATA LRX (also labelled RX-SCL) - Micromite I2C-CLOCK I2C (also labelled COM3-I2c_SEL) - GND The I2C pin selects the part address. Full listing including all the address constants Option explicit option default NONE CONST BNO055_ADDRESS_A = &H28 'connectI2C-SEL to GND CONST BNO055_ADDRESS_B = &H29 'connectI2C-SEL to VCC CONST BNO055_ID = &HA0 CONST PAGE_ID_ADDR = &H07 ' PAGE0 REGISTER DEFINITION START CONST CHIP_ID_ADDR = &H00 CONST ACCEL_REV_ID_ADDR = &H01 CONST MAG_REV_ID_ADDR = &H02 CONST GYRO_REV_ID_ADDR = &H03 CONST SW_REV_ID_LSB_ADDR = &H04 CONST SW_REV_ID_MSB_ADDR = &H05 CONST BL_REV_ID_ADDR = &H06 ' Accel data register CONST ACCEL_DATA_X_LSB_ADDR = &H08 CONST ACCEL_DATA_X_MSB_ADDR = &H09 CONST ACCEL_DATA_Y_LSB_ADDR = &H0A CONST ACCEL_DATA_Y_MSB_ADDR = &H0B CONST ACCEL_DATA_Z_LSB_ADDR = &H0C CONST ACCEL_DATA_Z_MSB_ADDR = &H0D ' Mag data register CONST MAG_DATA_X_LSB_ADDR= &H0E CONST MAG_DATA_X_MSB_ADDR= &H0F CONST MAG_DATA_Y_LSB_ADDR= &H10 CONST MAG_DATA_Y_MSB_ADDR= &H11 CONST MAG_DATA_Z_LSB_ADDR= &H12 CONST MAG_DATA_Z_MSB_ADDR= &H13 ' Gyro data registers CONST GYRO_DATA_X_LSB_ADDR = &H14 CONST GYRO_DATA_X_MSB_ADDR = &H15 CONST GYRO_DATA_Y_LSB_ADDR = &H16 CONST GYRO_DATA_Y_MSB_ADDR = &H17 CONST GYRO_DATA_Z_LSB_ADDR = &H18 CONST GYRO_DATA_Z_MSB_ADDR = &H19 ' Euler data registers CONST EULER_H_LSB_ADDR = &H1A CONST EULER_H_MSB_ADDR = &H1B CONST EULER_R_LSB_ADDR = &H1C CONST EULER_R_MSB_ADDR = &H1D CONST EULER_P_LSB_ADDR = &H1E CONST EULER_P_MSB_ADDR = &H1F ' Quaternion data registers CONST QUATERNION_DATA_W_LSB_ADDR = &H20 CONST QUATERNION_DATA_W_MSB_ADDR = &H21 CONST QUATERNION_DATA_X_LSB_ADDR = &H22 CONST QUATERNION_DATA_X_MSB_ADDR = &H23 CONST QUATERNION_DATA_Y_LSB_ADDR = &H24 CONST QUATERNION_DATA_Y_MSB_ADDR = &H25 CONST QUATERNION_DATA_Z_LSB_ADDR = &H26 CONST QUATERNION_DATA_Z_MSB_ADDR = &H27 ' Linear acceleration data registers CONST LINEAR_ACCEL_DATA_X_LSB_ADDR = &H28 CONST LINEAR_ACCEL_DATA_X_MSB_ADDR = &H29 CONST LINEAR_ACCEL_DATA_Y_LSB_ADDR = &H2A CONST LINEAR_ACCEL_DATA_Y_MSB_ADDR = &H2B CONST LINEAR_ACCEL_DATA_Z_LSB_ADDR = &H2C CONST LINEAR_ACCEL_DATA_Z_MSB_ADDR = &H2D ' Gravity data registers CONST GRAVITY_DATA_X_LSB_ADDR = &H2E CONST BNO055_GRAVITY_DATA_X_MSB_ADDR = &H2F CONST GRAVITY_DATA_Y_LSB_ADDR = &H30 CONST GRAVITY_DATA_Y_MSB_ADDR = &H31 CONST GRAVITY_DATA_Z_LSB_ADDR = &H32 CONST GRAVITY_DATA_Z_MSB_ADDR = &H33 ' Temperature data register CONST TEMP_ADDR = &H34 ' Status registers CONST CALIB_STAT_ADDR = &H35 CONST SELFTEST_RESULT_ADDR = &H36 CONST INTR_STAT_ADDR = &H37 CONST SYS_CLK_STAT_ADDR = &H38 CONST SYS_STAT_ADDR= &H39 CONST SYS_ERR_ADDR = &H3A ' Unit selection register CONST UNIT_SEL_ADDR= &H3B CONST DATA_SELECT_ADDR = &H3C ' Mode registers CONST OPR_MODE_ADDR= &H3D CONST PWR_MODE_ADDR= &H3E CONST SYS_TRIGGER_ADDR = &H3F CONST TEMP_SOURCE_ADDR = &H40 ' Axis remap registers CONST AXIS_MAP_CONFIG_ADDR = &H41 CONST AXIS_MAP_SIGN_ADDR = &H42 ' SIC registers CONST SIC_MATRIX_0_LSB_ADDR = &H43 CONST SIC_MATRIX_0_MSB_ADDR = &H44 CONST SIC_MATRIX_1_LSB_ADDR = &H45 CONST SIC_MATRIX_1_MSB_ADDR = &H46 CONST SIC_MATRIX_2_LSB_ADDR = &H47 CONST SIC_MATRIX_2_MSB_ADDR = &H48 CONST SIC_MATRIX_3_LSB_ADDR = &H49 CONST SIC_MATRIX_3_MSB_ADDR = &H4A CONST SIC_MATRIX_4_LSB_ADDR = &H4B CONST SIC_MATRIX_4_MSB_ADDR = &H4C CONST BNO055_SIC_MATRIX_5_LSB_ADDR = &H4D CONST SIC_MATRIX_5_MSB_ADDR = &H4E CONST SIC_MATRIX_6_LSB_ADDR = &H4F CONST SIC_MATRIX_6_MSB_ADDR = &H50 CONST SIC_MATRIX_7_LSB_ADDR = &H51 CONST SIC_MATRIX_7_MSB_ADDR = &H52 CONST SIC_MATRIX_8_LSB_ADDR = &H53 CONST SIC_MATRIX_8_MSB_ADDR = &H54 ' Accelerometer Offset registers CONST ACCEL_OFFSET_X_LSB_ADDR = &H55 CONST ACCEL_OFFSET_X_MSB_ADDR = &H56 CONST ACCEL_OFFSET_Y_LSB_ADDR = &H57 CONST ACCEL_OFFSET_Y_MSB_ADDR = &H58 CONST ACCEL_OFFSET_Z_LSB_ADDR = &H59 CONST ACCEL_OFFSET_Z_MSB_ADDR = &H5A ' Magnetometer Offset registers CONST MAG_OFFSET_X_LSB_ADDR = &H5B CONST MAG_OFFSET_X_MSB_ADDR = &H5C CONST MAG_OFFSET_Y_LSB_ADDR = &H5D CONST MAG_OFFSET_Y_MSB_ADDR = &H5E CONST MAG_OFFSET_Z_LSB_ADDR = &H5F CONST MAG_OFFSET_Z_MSB_ADDR = &H60 ' Gyroscope Offset register s CONST GYRO_OFFSET_X_LSB_ADDR = &H61 CONST GYRO_OFFSET_X_MSB_ADDR = &H62 CONST GYRO_OFFSET_Y_LSB_ADDR = &H63 CONST GYRO_OFFSET_Y_MSB_ADDR = &H64 CONST GYRO_OFFSET_Z_LSB_ADDR = &H65 CONST GYRO_OFFSET_Z_MSB_ADDR = &H66 ' Radius registers CONST ACCEL_RADIUS_LSB_ADDR = &H67 CONST ACCEL_RADIUS_MSB_ADDR = &H68 CONST MAG_RADIUS_LSB_ADDR = &H69 CONST MAG_RADIUS_MSB_ADDR = &H6A ' Power Mode Settings CONST POWER_MODE_NORMAL = &H00 CONST POWER_MODE_LOWPOWER = &H01 CONST POWER_MODE_SUSPEND = &H02 ' Operation mode settings CONST OPERATION_MODE_CONFIG = &H00 CONST OPERATION_MODE_ACCONLY = &H01 CONST OPERATION_MODE_MAGONLY = &H02 CONST OPERATION_MODE_GYRONLY = &H03 CONST OPERATION_MODE_ACCMAG = &H04 CONST OPERATION_MODE_ACCGYRO = &H05 CONST OPERATION_MODE_MAGGYRO = &H06 CONST OPERATION_MODE_AMG = &H07 CONST OPERATION_MODE_IMUPLUS = &H08 CONST OPERATION_MODE_COMPASS = &H09 CONST OPERATION_MODE_M4G = &H0A CONST OPERATION_MODE_NDOF_FMC_OFF = &H0B CONST OPERATION_MODE_NDOF = &H0C CONST REMAP_CONFIG_P0 = &H21 CONST REMAP_CONFIG_P1 = &H24 ' default CONST REMAP_CONFIG_P2 = &H24 CONST REMAP_CONFIG_P3 = &H21 CONST REMAP_CONFIG_P4 = &H24 CONST REMAP_CONFIG_P5 = &H21 CONST REMAP_CONFIG_P6 = &H21 CONST REMAP_CONFIG_P7 = &H24 CONST REMAP_SIGN_P0 = &H04 CONST REMAP_SIGN_P1 = &H00 ' default CONST REMAP_SIGN_P2 = &H06 CONST REMAP_SIGN_P3 = &H02 CONST REMAP_SIGN_P4 = &H03 CONST REMAP_SIGN_P5 = &H01 CONST REMAP_SIGN_P6 = &H07 CONST REMAP_SIGN_P7 = &H05 DIM INTEGER id DIM INTEGER BNO055_ADDRESS = BNO055_ADDRESS_A ' i2c open 100,1000 pause 500 id = readByte(CHIP_ID_ADDR) if id <> BNO055_ID THEN print "Chip not found" else PRINT "OK" endif writeByte(OPR_MODE_ADDR,&B1100) 'turn on fusion mode writeByte(UNIT_SEL_ADDR,&B0) 'set output in degrees pause 50 do pause 500 readEUL loop end sub writeByte(reg%,value%) i2c write BNO055_ADDRESS,0,2,reg%,value% end sub ' function readByte(reg%) as integer i2c write BNO055_ADDRESS,1,1,reg% pause 100 i2c read BNO055_ADDRESS,0,1,readByte end function sub readEUL local a$ local float i,j,k i2c write BNO055_ADDRESS,1,1,EULER_H_LSB_ADDR pause 10 i2c read BNO055_ADDRESS,0,6,a$ i=intconv(left$(a$,2),1)/16 j=intconv(mid$(a$,3,2),1)/16 k=intconv(right$(a$,2),1)/16 print "Heading :".i," Roll: ",j," Pitch :",k end sub sub readQUAT local a$ local float qw,qx,qy,qz,s=1<<14 i2c write BNO055_ADDRESS,1,1,QUATERNION_DATA_W_LSB_ADDR pause 10 i2c read BNO055_ADDRESS,0,8,a$ qw=intconv(left$(a$,2),1)/s qx=intconv(mid$(a$,3,2),1)/s qy=intconv(mid$(a$,5,2),1)/s qz=intconv(right$(a$,2),1)/s print qw," ",qx," ",qy," ",qz end sub Function intconv(s$, p%) as integer local integer l,k,j,i=len(s$) k=peek(varaddr j) for l=1 to i poke byte k+l-1,asc(mid$(s$,l,1)) next l if p% then if (asc(mid$(s$,i,1)) and &H80) then for l=i to 7 poke byte k+l,&HFF next l endif endif intconv=j End Function ![]() |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
Looks good Peter, I have tried to get your previous compass to work using the Navigation PCB and GY-91 but had trouble with the calibration. The calibration routine ran and I substituted the values into the code but the compass was not accurate. Any chance of some compass code for this module, it is a bit beyond me. Paul. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10310 |
That is the beauty of this device - there is almost no code to write as it does it all for you. Just put it into "COMPASS" mode, waggle it about until it says it is calibrated (which it does automatically) and start reading the heading. Code example attached below, but remember you are unlikely to see any sort of linear change in heading on the electronics bench. You should see repeat-ability in fixed orientations and of course the change should be monotonic but don't expect south to be 180 degrees from north unless you are in a electrically very quiet environment. Note calibration continues after you get the flag and values will change until fully settled down. Option explicit option default NONE CONST BNO055_ADDRESS_A = &H28 'connectI2C-SEL to GND CONST BNO055_ADDRESS_B = &H29 'connectI2C-SEL to VCC CONST BNO055_ID = &HA0 CONST PAGE_ID_ADDR = &H07 ' PAGE0 REGISTER DEFINITION START CONST CHIP_ID_ADDR = &H00 CONST ACCEL_REV_ID_ADDR = &H01 CONST MAG_REV_ID_ADDR = &H02 CONST GYRO_REV_ID_ADDR = &H03 CONST SW_REV_ID_LSB_ADDR = &H04 CONST SW_REV_ID_MSB_ADDR = &H05 CONST BL_REV_ID_ADDR = &H06 ' Accel data register CONST ACCEL_DATA_X_LSB_ADDR = &H08 CONST ACCEL_DATA_X_MSB_ADDR = &H09 CONST ACCEL_DATA_Y_LSB_ADDR = &H0A CONST ACCEL_DATA_Y_MSB_ADDR = &H0B CONST ACCEL_DATA_Z_LSB_ADDR = &H0C CONST ACCEL_DATA_Z_MSB_ADDR = &H0D ' Mag data register CONST MAG_DATA_X_LSB_ADDR= &H0E CONST MAG_DATA_X_MSB_ADDR= &H0F CONST MAG_DATA_Y_LSB_ADDR= &H10 CONST MAG_DATA_Y_MSB_ADDR= &H11 CONST MAG_DATA_Z_LSB_ADDR= &H12 CONST MAG_DATA_Z_MSB_ADDR= &H13 ' Gyro data registers CONST GYRO_DATA_X_LSB_ADDR = &H14 CONST GYRO_DATA_X_MSB_ADDR = &H15 CONST GYRO_DATA_Y_LSB_ADDR = &H16 CONST GYRO_DATA_Y_MSB_ADDR = &H17 CONST GYRO_DATA_Z_LSB_ADDR = &H18 CONST GYRO_DATA_Z_MSB_ADDR = &H19 ' Euler data registers CONST EULER_H_LSB_ADDR = &H1A CONST EULER_H_MSB_ADDR = &H1B CONST EULER_R_LSB_ADDR = &H1C CONST EULER_R_MSB_ADDR = &H1D CONST EULER_P_LSB_ADDR = &H1E CONST EULER_P_MSB_ADDR = &H1F ' Quaternion data registers CONST QUATERNION_DATA_W_LSB_ADDR = &H20 CONST QUATERNION_DATA_W_MSB_ADDR = &H21 CONST QUATERNION_DATA_X_LSB_ADDR = &H22 CONST QUATERNION_DATA_X_MSB_ADDR = &H23 CONST QUATERNION_DATA_Y_LSB_ADDR = &H24 CONST QUATERNION_DATA_Y_MSB_ADDR = &H25 CONST QUATERNION_DATA_Z_LSB_ADDR = &H26 CONST QUATERNION_DATA_Z_MSB_ADDR = &H27 ' Linear acceleration data registers CONST LINEAR_ACCEL_DATA_X_LSB_ADDR = &H28 CONST LINEAR_ACCEL_DATA_X_MSB_ADDR = &H29 CONST LINEAR_ACCEL_DATA_Y_LSB_ADDR = &H2A CONST LINEAR_ACCEL_DATA_Y_MSB_ADDR = &H2B CONST LINEAR_ACCEL_DATA_Z_LSB_ADDR = &H2C CONST LINEAR_ACCEL_DATA_Z_MSB_ADDR = &H2D ' Gravity data registers CONST GRAVITY_DATA_X_LSB_ADDR = &H2E CONST BNO055_GRAVITY_DATA_X_MSB_ADDR = &H2F CONST GRAVITY_DATA_Y_LSB_ADDR = &H30 CONST GRAVITY_DATA_Y_MSB_ADDR = &H31 CONST GRAVITY_DATA_Z_LSB_ADDR = &H32 CONST GRAVITY_DATA_Z_MSB_ADDR = &H33 ' Temperature data register CONST TEMP_ADDR = &H34 ' Status registers CONST CALIB_STAT_ADDR = &H35 CONST SELFTEST_RESULT_ADDR = &H36 CONST INTR_STAT_ADDR = &H37 CONST SYS_CLK_STAT_ADDR = &H38 CONST SYS_STAT_ADDR= &H39 CONST SYS_ERR_ADDR = &H3A ' Unit selection register CONST UNIT_SEL_ADDR= &H3B CONST DATA_SELECT_ADDR = &H3C ' Mode registers CONST OPR_MODE_ADDR= &H3D CONST PWR_MODE_ADDR= &H3E CONST SYS_TRIGGER_ADDR = &H3F CONST TEMP_SOURCE_ADDR = &H40 ' Axis remap registers CONST AXIS_MAP_CONFIG_ADDR = &H41 CONST AXIS_MAP_SIGN_ADDR = &H42 ' SIC registers CONST SIC_MATRIX_0_LSB_ADDR = &H43 CONST SIC_MATRIX_0_MSB_ADDR = &H44 CONST SIC_MATRIX_1_LSB_ADDR = &H45 CONST SIC_MATRIX_1_MSB_ADDR = &H46 CONST SIC_MATRIX_2_LSB_ADDR = &H47 CONST SIC_MATRIX_2_MSB_ADDR = &H48 CONST SIC_MATRIX_3_LSB_ADDR = &H49 CONST SIC_MATRIX_3_MSB_ADDR = &H4A CONST SIC_MATRIX_4_LSB_ADDR = &H4B CONST SIC_MATRIX_4_MSB_ADDR = &H4C CONST BNO055_SIC_MATRIX_5_LSB_ADDR = &H4D CONST SIC_MATRIX_5_MSB_ADDR = &H4E CONST SIC_MATRIX_6_LSB_ADDR = &H4F CONST SIC_MATRIX_6_MSB_ADDR = &H50 CONST SIC_MATRIX_7_LSB_ADDR = &H51 CONST SIC_MATRIX_7_MSB_ADDR = &H52 CONST SIC_MATRIX_8_LSB_ADDR = &H53 CONST SIC_MATRIX_8_MSB_ADDR = &H54 ' Accelerometer Offset registers CONST ACCEL_OFFSET_X_LSB_ADDR = &H55 CONST ACCEL_OFFSET_X_MSB_ADDR = &H56 CONST ACCEL_OFFSET_Y_LSB_ADDR = &H57 CONST ACCEL_OFFSET_Y_MSB_ADDR = &H58 CONST ACCEL_OFFSET_Z_LSB_ADDR = &H59 CONST ACCEL_OFFSET_Z_MSB_ADDR = &H5A ' Magnetometer Offset registers CONST MAG_OFFSET_X_LSB_ADDR = &H5B CONST MAG_OFFSET_X_MSB_ADDR = &H5C CONST MAG_OFFSET_Y_LSB_ADDR = &H5D CONST MAG_OFFSET_Y_MSB_ADDR = &H5E CONST MAG_OFFSET_Z_LSB_ADDR = &H5F CONST MAG_OFFSET_Z_MSB_ADDR = &H60 ' Gyroscope Offset register s CONST GYRO_OFFSET_X_LSB_ADDR = &H61 CONST GYRO_OFFSET_X_MSB_ADDR = &H62 CONST GYRO_OFFSET_Y_LSB_ADDR = &H63 CONST GYRO_OFFSET_Y_MSB_ADDR = &H64 CONST GYRO_OFFSET_Z_LSB_ADDR = &H65 CONST GYRO_OFFSET_Z_MSB_ADDR = &H66 ' Radius registers CONST ACCEL_RADIUS_LSB_ADDR = &H67 CONST ACCEL_RADIUS_MSB_ADDR = &H68 CONST MAG_RADIUS_LSB_ADDR = &H69 CONST MAG_RADIUS_MSB_ADDR = &H6A ' Power Mode Settings CONST POWER_MODE_NORMAL = &H00 CONST POWER_MODE_LOWPOWER = &H01 CONST POWER_MODE_SUSPEND = &H02 ' Operation mode settings CONST OPERATION_MODE_CONFIG = &H00 CONST OPERATION_MODE_ACCONLY = &H01 CONST OPERATION_MODE_MAGONLY = &H02 CONST OPERATION_MODE_GYRONLY = &H03 CONST OPERATION_MODE_ACCMAG = &H04 CONST OPERATION_MODE_ACCGYRO = &H05 CONST OPERATION_MODE_MAGGYRO = &H06 CONST OPERATION_MODE_AMG = &H07 CONST OPERATION_MODE_IMUPLUS = &H08 CONST OPERATION_MODE_COMPASS = &H09 CONST OPERATION_MODE_M4G = &H0A CONST OPERATION_MODE_NDOF_FMC_OFF = &H0B CONST OPERATION_MODE_NDOF = &H0C CONST REMAP_CONFIG_P0 = &H21 CONST REMAP_CONFIG_P1 = &H24 ' default CONST REMAP_CONFIG_P2 = &H24 CONST REMAP_CONFIG_P3 = &H21 CONST REMAP_CONFIG_P4 = &H24 CONST REMAP_CONFIG_P5 = &H21 CONST REMAP_CONFIG_P6 = &H21 CONST REMAP_CONFIG_P7 = &H24 CONST REMAP_SIGN_P0 = &H04 CONST REMAP_SIGN_P1 = &H00 ' default CONST REMAP_SIGN_P2 = &H06 CONST REMAP_SIGN_P3 = &H02 CONST REMAP_SIGN_P4 = &H03 CONST REMAP_SIGN_P5 = &H01 CONST REMAP_SIGN_P6 = &H07 CONST REMAP_SIGN_P7 = &H05 ' DIM INTEGER id DIM INTEGER BNO055_ADDRESS = BNO055_ADDRESS_A ' i2c open 100,1000 resetBNO setMode(OPERATION_MODE_CONFIG) pause 50 writeByte(UNIT_SEL_ADDR,&B0) 'set output in degrees setMode(OPERATION_MODE_COMPASS) 'turn on fusion mode compass pause 50 Print "Move in figures of 8 until calibrated" do pause 500 readEUL loop end ' sub resetBNO 'reset the sensor writeByte(SYS_TRIGGER_ADDR, &H20) timer=0 do pause 10 loop until readByte(CHIP_ID_ADDR)=BNO055_ID or timer>4000 if timer> 4000 then print "BNO055 not found" end ENDIF pause 50 end sub ' sub setMode(value%) 'set to a specific operation mode (see values above) writeByte(OPR_MODE_ADDR,value%) timer=0 do pause 10 loop until readByte(CHIP_ID_ADDR)=BNO055_ID or timer>4000 if timer> 4000 then print "BNO055 not found" end ENDIF pause 50 end sub ' sub writeByte(reg%,value%) 'write a single register i2c write BNO055_ADDRESS,0,2,reg%,value% end sub ' function readByte(reg%) as integer 'read a single register i2c write BNO055_ADDRESS,1,1,reg% pause 100 i2c read BNO055_ADDRESS,0,1,readByte end function sub readEUL 'read in the Euler angles local a$ local float i,j,k i2c write BNO055_ADDRESS,1,1,EULER_H_LSB_ADDR pause 10 i2c read BNO055_ADDRESS,0,6,a$ i=intconv(left$(a$,2),1)/16 j=intconv(mid$(a$,3,2),1)/16 k=intconv(right$(a$,2),1)/16 if(readByte(CALIB_STAT_ADDR) AND &HC0 = &HC0) then print "Heading :",i ' print "Heading :",i," Roll: ",j," Pitch :",k, " Calibration :",bin$(readByte(CALIB_STAT_ADDR)) end sub sub readQUAT 'read in the quaternions local a$ local float qw,qx,qy,qz,s=1<<14 i2c write BNO055_ADDRESS,1,1,QUATERNION_DATA_W_LSB_ADDR pause 10 i2c read BNO055_ADDRESS,0,8,a$ qw=intconv(left$(a$,2),1)/s qx=intconv(mid$(a$,3,2),1)/s qy=intconv(mid$(a$,5,2),1)/s qz=intconv(right$(a$,2),1)/s print qw," ",qx," ",qy," ",qz end sub Function intconv(s$, p%) as integer 'convert values to signed integers local integer l,k,j,i=len(s$) k=peek(varaddr j) for l=1 to i poke byte k+l-1,asc(mid$(s$,l,1)) next l if p% then if (asc(mid$(s$,i,1)) and &H80) then for l=i to 7 poke byte k+l,&HFF next l endif endif intconv=j End Function |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
Thanks Peter Paul. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
@ Matherp, Sorry to trouble you. I have got the device working and it seems to read accurately, however there is a problem. I uncommented the line so I could see the values on the screen. The calibration value is zero for the first eleven prints and then changes to 100. I assume this means it is calibrated. The heading seems to read OK but after about 40 seconds I get an error on line 273 Not Enough Memory. Paul. Edit. The code seems to be stuck in this loop do pause 500 readEUL loop end Edit. After having another look I think it is meant to keep looping to print out the heading. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10310 |
You shouldn't be seeing that. What MM are you running on? If Pic-cromite or MMX please try a standard MM or MM+ and post the results. Also, please try it with just the bin$ clause removed |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
Running on a 28 pin Micromite Backpack. Will remove the bin$ line soon. Paul. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
any use? Pure bit/maths solution and fast http://www.fruitoftheshed.com/MMBasic.Sign-Extend-an-Integer.ashx?HL=sign,extend |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10310 |
I've sent an email to Geoff linking this thread as that shouldn't be happening and suggests a memory leak of some sort |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
I commented the line ' print "Heading :",i," Roll: ",j," Pitch :",k, " Calibration :",bin$(readByte(CALIB_STAT_ADDR)) But it makes no difference. The line above that is.... if(readByte(CALIB_STAT_ADDR) AND &HC0 = &HC0) then print "Heading :",i but it does not print the "Heading" all I get when I run the code is... and about 30 seconds later the "Not enough menory" error. Paul. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3292 |
There are a lot of things that can cause out of memory errors but it is unlikely to be a memory leak due to the way that memory is cleaned up after each command is executed. It is not feasible to reverse engineer this program, can you distil this into a short program (<10 lines) that demonstrates the fault? Geoff Graham - http://geoffg.net |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
Ok I found the problem, in the loop do pause 500 readEUL loop I added these lines Text 175,60, " HEADING ",CM, 1, 3,RGB(blue),RGB(cyan) Text 110,150, Heading$,CM, 1, 3,RGB(blue),RGB(cyan) Text 240,155, "Degrees",CM,1,2,RGB(Blue),RGB(Cyan) So it would print to the TFT screen and that causes the problem.WHY? Paul. Edit. I also added a line to the 'Sub EUL' Heading$ = Str$(i,3) "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
Paul, I finally got the courage up enough to re-solder the chips on my board. I wasn't able to create any memory problems on a 28 pin 'mite with LCD attached. This code has the LCD print statements you added as well as a MEMORY command which outputs to the console. OPTION EXPLICIT OPTION DEFAULT NONE CONST BNO055_ADDRESS_A = &H28 'connectI2C-SEL to GND CONST BNO055_ADDRESS_B = &H29 'connectI2C-SEL to VCC CONST BNO055_ID = &HA0 CONST PAGE_ID_ADDR = &H07 ' PAGE0 REGISTER DEFINITION START CONST CHIP_ID_ADDR = &H00 CONST ACCEL_REV_ID_ADDR = &H01 CONST MAG_REV_ID_ADDR = &H02 CONST GYRO_REV_ID_ADDR = &H03 CONST SW_REV_ID_LSB_ADDR = &H04 CONST SW_REV_ID_MSB_ADDR = &H05 CONST BL_REV_ID_ADDR = &H06 ' Accel data register CONST ACCEL_DATA_X_LSB_ADDR = &H08 CONST ACCEL_DATA_X_MSB_ADDR = &H09 CONST ACCEL_DATA_Y_LSB_ADDR = &H0A CONST ACCEL_DATA_Y_MSB_ADDR = &H0B CONST ACCEL_DATA_Z_LSB_ADDR = &H0C CONST ACCEL_DATA_Z_MSB_ADDR = &H0D ' Mag data register CONST MAG_DATA_X_LSB_ADDR= &H0E CONST MAG_DATA_X_MSB_ADDR= &H0F CONST MAG_DATA_Y_LSB_ADDR= &H10 CONST MAG_DATA_Y_MSB_ADDR= &H11 CONST MAG_DATA_Z_LSB_ADDR= &H12 CONST MAG_DATA_Z_MSB_ADDR= &H13 ' Gyro data registers CONST GYRO_DATA_X_LSB_ADDR = &H14 CONST GYRO_DATA_X_MSB_ADDR = &H15 CONST GYRO_DATA_Y_LSB_ADDR = &H16 CONST GYRO_DATA_Y_MSB_ADDR = &H17 CONST GYRO_DATA_Z_LSB_ADDR = &H18 CONST GYRO_DATA_Z_MSB_ADDR = &H19 ' Euler data registers CONST EULER_H_LSB_ADDR = &H1A CONST EULER_H_MSB_ADDR = &H1B CONST EULER_R_LSB_ADDR = &H1C CONST EULER_R_MSB_ADDR = &H1D CONST EULER_P_LSB_ADDR = &H1E CONST EULER_P_MSB_ADDR = &H1F ' Quaternion data registers CONST QUATERNION_DATA_W_LSB_ADDR = &H20 CONST QUATERNION_DATA_W_MSB_ADDR = &H21 CONST QUATERNION_DATA_X_LSB_ADDR = &H22 CONST QUATERNION_DATA_X_MSB_ADDR = &H23 CONST QUATERNION_DATA_Y_LSB_ADDR = &H24 CONST QUATERNION_DATA_Y_MSB_ADDR = &H25 CONST QUATERNION_DATA_Z_LSB_ADDR = &H26 CONST QUATERNION_DATA_Z_MSB_ADDR = &H27 ' Linear acceleration data registers CONST LINEAR_ACCEL_DATA_X_LSB_ADDR = &H28 CONST LINEAR_ACCEL_DATA_X_MSB_ADDR = &H29 CONST LINEAR_ACCEL_DATA_Y_LSB_ADDR = &H2A CONST LINEAR_ACCEL_DATA_Y_MSB_ADDR = &H2B CONST LINEAR_ACCEL_DATA_Z_LSB_ADDR = &H2C CONST LINEAR_ACCEL_DATA_Z_MSB_ADDR = &H2D ' Gravity data registers CONST GRAVITY_DATA_X_LSB_ADDR = &H2E CONST BNO055_GRAVITY_DATA_X_MSB_ADDR = &H2F CONST GRAVITY_DATA_Y_LSB_ADDR = &H30 CONST GRAVITY_DATA_Y_MSB_ADDR = &H31 CONST GRAVITY_DATA_Z_LSB_ADDR = &H32 CONST GRAVITY_DATA_Z_MSB_ADDR = &H33 ' Temperature data register CONST TEMP_ADDR = &H34 ' Status registers CONST CALIB_STAT_ADDR = &H35 CONST SELFTEST_RESULT_ADDR = &H36 CONST INTR_STAT_ADDR = &H37 CONST SYS_CLK_STAT_ADDR = &H38 CONST SYS_STAT_ADDR= &H39 CONST SYS_ERR_ADDR = &H3A ' Unit selection register CONST UNIT_SEL_ADDR= &H3B CONST DATA_SELECT_ADDR = &H3C ' Mode registers CONST OPR_MODE_ADDR= &H3D CONST PWR_MODE_ADDR= &H3E CONST SYS_TRIGGER_ADDR = &H3F CONST TEMP_SOURCE_ADDR = &H40 ' Axis remap registers CONST AXIS_MAP_CONFIG_ADDR = &H41 CONST AXIS_MAP_SIGN_ADDR = &H42 ' SIC registers CONST SIC_MATRIX_0_LSB_ADDR = &H43 CONST SIC_MATRIX_0_MSB_ADDR = &H44 CONST SIC_MATRIX_1_LSB_ADDR = &H45 CONST SIC_MATRIX_1_MSB_ADDR = &H46 CONST SIC_MATRIX_2_LSB_ADDR = &H47 CONST SIC_MATRIX_2_MSB_ADDR = &H48 CONST SIC_MATRIX_3_LSB_ADDR = &H49 CONST SIC_MATRIX_3_MSB_ADDR = &H4A CONST SIC_MATRIX_4_LSB_ADDR = &H4B CONST SIC_MATRIX_4_MSB_ADDR = &H4C CONST BNO055_SIC_MATRIX_5_LSB_ADDR = &H4D CONST SIC_MATRIX_5_MSB_ADDR = &H4E CONST SIC_MATRIX_6_LSB_ADDR = &H4F CONST SIC_MATRIX_6_MSB_ADDR = &H50 CONST SIC_MATRIX_7_LSB_ADDR = &H51 CONST SIC_MATRIX_7_MSB_ADDR = &H52 CONST SIC_MATRIX_8_LSB_ADDR = &H53 CONST SIC_MATRIX_8_MSB_ADDR = &H54 ' Accelerometer Offset registers CONST ACCEL_OFFSET_X_LSB_ADDR = &H55 CONST ACCEL_OFFSET_X_MSB_ADDR = &H56 CONST ACCEL_OFFSET_Y_LSB_ADDR = &H57 CONST ACCEL_OFFSET_Y_MSB_ADDR = &H58 CONST ACCEL_OFFSET_Z_LSB_ADDR = &H59 CONST ACCEL_OFFSET_Z_MSB_ADDR = &H5A ' Magnetometer Offset registers CONST MAG_OFFSET_X_LSB_ADDR = &H5B CONST MAG_OFFSET_X_MSB_ADDR = &H5C CONST MAG_OFFSET_Y_LSB_ADDR = &H5D CONST MAG_OFFSET_Y_MSB_ADDR = &H5E CONST MAG_OFFSET_Z_LSB_ADDR = &H5F CONST MAG_OFFSET_Z_MSB_ADDR = &H60 ' Gyroscope Offset register s CONST GYRO_OFFSET_X_LSB_ADDR = &H61 CONST GYRO_OFFSET_X_MSB_ADDR = &H62 CONST GYRO_OFFSET_Y_LSB_ADDR = &H63 CONST GYRO_OFFSET_Y_MSB_ADDR = &H64 CONST GYRO_OFFSET_Z_LSB_ADDR = &H65 CONST GYRO_OFFSET_Z_MSB_ADDR = &H66 ' Radius registers CONST ACCEL_RADIUS_LSB_ADDR = &H67 CONST ACCEL_RADIUS_MSB_ADDR = &H68 CONST MAG_RADIUS_LSB_ADDR = &H69 CONST MAG_RADIUS_MSB_ADDR = &H6A ' Power Mode Settings CONST POWER_MODE_NORMAL = &H00 CONST POWER_MODE_LOWPOWER = &H01 CONST POWER_MODE_SUSPEND = &H02 ' Operation mode settings CONST OPERATION_MODE_CONFIG = &H00 CONST OPERATION_MODE_ACCONLY = &H01 CONST OPERATION_MODE_MAGONLY = &H02 CONST OPERATION_MODE_GYRONLY = &H03 CONST OPERATION_MODE_ACCMAG = &H04 CONST OPERATION_MODE_ACCGYRO = &H05 CONST OPERATION_MODE_MAGGYRO = &H06 CONST OPERATION_MODE_AMG = &H07 CONST OPERATION_MODE_IMUPLUS = &H08 CONST OPERATION_MODE_COMPASS = &H09 CONST OPERATION_MODE_M4G = &H0A CONST OPERATION_MODE_NDOF_FMC_OFF = &H0B CONST OPERATION_MODE_NDOF = &H0C CONST REMAP_CONFIG_P0 = &H21 CONST REMAP_CONFIG_P1 = &H24 ' default CONST REMAP_CONFIG_P2 = &H24 CONST REMAP_CONFIG_P3 = &H21 CONST REMAP_CONFIG_P4 = &H24 CONST REMAP_CONFIG_P5 = &H21 CONST REMAP_CONFIG_P6 = &H21 CONST REMAP_CONFIG_P7 = &H24 CONST REMAP_SIGN_P0 = &H04 CONST REMAP_SIGN_P1 = &H00 ' default CONST REMAP_SIGN_P2 = &H06 CONST REMAP_SIGN_P3 = &H02 CONST REMAP_SIGN_P4 = &H03 CONST REMAP_SIGN_P5 = &H01 CONST REMAP_SIGN_P6 = &H07 CONST REMAP_SIGN_P7 = &H05 ' DIM INTEGER id DIM INTEGER BNO055_ADDRESS = BNO055_ADDRESS_A DIM Heading$ ' I2C OPEN 100,1000 resetBNO setMode(OPERATION_MODE_CONFIG) PAUSE 50 writeByte(UNIT_SEL_ADDR,&B0) 'set output in degrees setMode(OPERATION_MODE_COMPASS) 'turn on fusion mode compass PAUSE 50 PRINT "Move in figures of 8 until calibrated" CLS DO PAUSE 500 readEUL TEXT 175,60, " HEADING ",CM, 1, 3,RGB(BLUE),RGB(CYAN) TEXT 110,150, Heading$,CM, 1, 3,RGB(BLUE),RGB(CYAN) TEXT 240,155, "Degrees",CM,1,2,RGB(BLUE),RGB(CYAN) PRINT CHR$(27)+"[2J"+CHR$(27)+"[1;1H ",Heading$ MEMORY LOOP END ' SUB resetBNO 'reset the sensor writeByte(SYS_TRIGGER_ADDR, &H20) TIMER=0 DO PAUSE 10 LOOP UNTIL readByte(CHIP_ID_ADDR)=BNO055_ID OR TIMER>4000 IF TIMER> 4000 THEN PRINT "BNO055 not found" END ENDIF PAUSE 50 END SUB ' SUB setMode(value%) 'set to a specific operation mode (see values above) writeByte(OPR_MODE_ADDR,value%) TIMER=0 DO PAUSE 10 LOOP UNTIL readByte(CHIP_ID_ADDR)=BNO055_ID OR TIMER>4000 IF TIMER> 4000 THEN PRINT "BNO055 not found" END ENDIF PAUSE 50 END SUB ' SUB writeByte(reg%,value%) 'write a single register I2C WRITE BNO055_ADDRESS,0,2,reg%,value% END SUB ' FUNCTION readByte(reg%) AS INTEGER 'read a single register I2C WRITE BNO055_ADDRESS,1,1,reg% PAUSE 100 I2C READ BNO055_ADDRESS,0,1,readByte END FUNCTION SUB readEUL 'read in the Euler angles LOCAL a$ LOCAL FLOAT i,j,k I2C WRITE BNO055_ADDRESS,1,1,EULER_H_LSB_ADDR PAUSE 10 I2C READ BNO055_ADDRESS,0,6,a$ i=intconv(LEFT$(a$,2),1)/16 j=intconv(MID$(a$,3,2),1)/16 k=intconv(RIGHT$(a$,2),1)/16 IF(readByte(CALIB_STAT_ADDR) AND &HC0 = &HC0) THEN PRINT "Heading :",i ' print "Heading :",i," Roll: ",j," Pitch :",k, " Calibration :",bin$(readByte(CALIB_STAT_ADDR)) Heading$ = STR$(i,3,1) END SUB SUB readQUAT 'read in the quaternions LOCAL a$ LOCAL FLOAT qw,qx,qy,qz,s=1<<14 I2C WRITE BNO055_ADDRESS,1,1,QUATERNION_DATA_W_LSB_ADDR PAUSE 10 I2C READ BNO055_ADDRESS,0,8,a$ qw=intconv(LEFT$(a$,2),1)/s qx=intconv(MID$(a$,3,2),1)/s qy=intconv(MID$(a$,5,2),1)/s qz=intconv(RIGHT$(a$,2),1)/s PRINT qw," ",qx," ",qy," ",qz END SUB FUNCTION intconv(s$, p%) AS INTEGER 'convert values to signed integers LOCAL INTEGER l,k,j,i=LEN(s$) k=PEEK(VARADDR j) FOR l=1 TO i POKE BYTE k+l-1,ASC(MID$(s$,l,1)) NEXT l IF p% THEN IF (ASC(MID$(s$,i,1)) AND &H80) THEN FOR l=i TO 7 POKE BYTE k+l,&HFF NEXT l ENDIF ENDIF intconv=j END FUNCTION I don't have my device on long enough leads to get a good idea about it's abilities. I was able to confirm that my days of soldering those micro chips are over. I am waiting on an appointment with a neurologist to confirm my GP's diagnosis. "It's 'Essential Tremor', something that happens to the elderly". I'm not that bloody old! Unfortunately, the drugs that help it will not help my Asthma so I am stuck with it. Jim VK7JH MMedit |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
Well I don't know what is happening. The backpack was previously used for another project with no problems. With my code it runs for about 30 seconds before the error. I have checked it at intervals and I see the free RAM slowly dropping until the error when I have 3K free. The error appears at this line FUNCTION intconv(s$, p%) AS INTEGER 'convert values to signed integers so it must run out of memory in the 'SUB readEUL". As soon as I comment out the TEXT lines that print to the screen it runs OK. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
time for a re-flash - get the MM to a known state I have had really weird behaviour - inexplicable oddness with no rhyme or reason... Flash it and it's all OK. Might not fix it in your case but like I said... known state - it's one thing you can rule out. Two specific examples are a local variable that simply wasn't being recognised and another was a FOR-NEXT loop that wouldn't count backwards... Try that - nothing to lose. |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
@ CaptainBoing Good suggestion will do first thing in the morning. Paul. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
@ CaptainBoing Thanks all, re flashing did the trick, something for me to remember when odd things happen. Paul. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
glad you got it sorted. |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10310 |
If you have a BNO055 up and working and you have a 100 or 144 pin Micromite eXtreme and you have a 4.3" SSD1963 and you have uploaded the latest firmware. Then you can play with my Attitude indicator code. Set up the display using the new buffered driver OPTION LCDPANEL SSD1963_4_16_buff, L, RDpin and run the code. The code tests the internal sensor fusion algorithm in the BNO055 and compares it with the open source sensor fusion that I have included in the Micromite firmware. There is no comparison to my mind; the open source firmware running in double precision on the PIC32MZ is much much better and it allows you to tune the sensitivity of the fusion algorithm to optimise for your specific application (see the appendix in the Micromite eXtreme manual) . You can choose the fusion algorithm in the demo program using the constant "FUSION" 0 = BNO055 internal 1 = Micromite eXtreme Mahony 2 = Micromite eXtreme Madgwick Update rate on the display is about 18 frames per second 2018-02-17_042145_BNO055-AI.zip |
||||
palcal![]() Guru ![]() Joined: 12/10/2011 Location: AustraliaPosts: 1993 |
Thanks for that Peter will try it out when I get a spare minute. At the moment my daughter is here with a whip watching me shovel 5 metres of hardwood chip out of the trailer. Paul. "It is better to be ignorant and ask a stupid question than to be plain Stupid and not ask at all" |
||||
Page 1 of 2 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |