Nitro_fpv
Posts: 46
Joined: Tue Mar 30, 2021 11:56 am

BNO055 IMU with I2C

Mon Apr 12, 2021 6:02 pm

Hello
I think I have a twister in my brain?
I connected the BNO055 to the Pi PICO with I2C.
The communication also works, but only up to a maximum of freq = 4000?!
I also get all the values from the BNO055.
According to the data sheet it works up to 400 kHz.
Page 90:
https://cdn-shop.adafruit.com/datasheet ... 000_12.pdf
I think 400kHz is freq = 400000.
Did I use the I2C incorrectly?

The original code is actually for Pyboard 1.x, Pyboard D, ESPx.
I just changed the I2C for the PI PICO.

Here is the code:

Code: Select all

# bno055_test.py Simple test program for MicroPython bno055 driver

# Copyright (c) Peter Hinch 2019
# Released under the MIT licence.
from machine import Pin, I2C
import machine
import time
from bno055 import *
i2c = I2C(0, scl=Pin(13), sda=Pin(12), freq=4000)
imu = BNO055(i2c)
calibrated = False
while True:
    time.sleep(1)
    if not calibrated:
        calibrated = imu.calibrated()
        print('Calibration required: sys {} gyro {} accel {} mag {}'.format(*imu.cal_status()))
    print('Temperature {}°C'.format(imu.temperature()))
    print('Mag       x {:5.0f}    y {:5.0f}     z {:5.0f}'.format(*imu.mag()))
    print('Gyro      x {:5.0f}    y {:5.0f}     z {:5.0f}'.format(*imu.gyro()))
    print('Accel     x {:5.1f}    y {:5.1f}     z {:5.1f}'.format(*imu.accel()))
    print('Lin acc.  x {:5.1f}    y {:5.1f}     z {:5.1f}'.format(*imu.lin_acc()))
    print('Gravity   x {:5.1f}    y {:5.1f}     z {:5.1f}'.format(*imu.gravity()))
    print('Heading     {:4.0f} roll {:4.0f} pitch {:4.0f}'.format(*imu.euler()))
 
The I2C communication looks good:

Image

What am I doing wrong?


Nitro_fpv
Posts: 46
Joined: Tue Mar 30, 2021 11:56 am

Re: BNO055 IMU with I2C

Tue Apr 13, 2021 6:38 pm

Short version: According to the data sheet, the I2C board can handle 400 kHz.
The board also has built-in SCL and SDA pullups.
For me the whole thing only works with 4000 stable.

What am i doing wrong?

Code: Select all

from machine import Pin, I2C
i2c = I2C(0, scl=Pin(13), sda=Pin(12), freq=4000)

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Tue Apr 13, 2021 7:44 pm

It could be the BNO055 module, it could be MicroPython, it could be the pico-sdk, it could be hardware, it could be ...

I realize that this is the Pico MicroPython forum but you could considered using the pico-sdk to directly access a few of the registers on a BNO055 to see if it also has issues accessing the BNO055 at such low baudrates. If it does, then perhaps it's a pico-sdk issue. If not, further investigation will be needed.

Nitro_fpv
Posts: 46
Joined: Tue Mar 30, 2021 11:56 am

Re: BNO055 IMU with I2C

Tue Apr 13, 2021 7:49 pm

Ok, but unfortunately I can't do C, C ++ or assembly.

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Tue Apr 13, 2021 7:59 pm

Nitro_fpv wrote:
Tue Apr 13, 2021 7:49 pm
Ok, but unfortunately I can't do C, C ++ or assembly.
Well, I guess my suggestion isn't the best of ideas in this case.

User avatar
jbeale
Posts: 3855
Joined: Tue Nov 22, 2011 11:51 pm
Contact: Website

Re: BNO055 IMU with I2C

Thu Apr 15, 2021 2:16 am

I was playing around with I2C for the first time on a Pico, and I was able to confirm mine does work OK at 400 kHz, eg with:

Code: Select all

from machine import Pin, I2C
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
print(i2c.scan())
In my case the device is MAX30102. You mention there are pullups on SDA, SCL. One thing that can cause low frequency to work and higher frequency to not work is if there is too much capacitance, or the pullup resistance is too large, or the resistors are not connected to a power rail. For example, on the MAX30102 breakout board I'm using, there are three tiny, easy-to-miss solder pads on the back and you have to bridge two of them to select either 1.8V or 3.3V pullup. As it comes from the factory they're all open, so if you neglect to do that, then you don't have an onboard pullup at all. There may be a weak pullup from the host that would enable it to work at some slower speed, but not at the design frequency. Of course this is just speculation, but it's possible.

Another possibility: there is some delay required between certain read and/or write operations. Again in my case I noticed my device stopped working when I removed some print statements. Apparently they were providing a required delay time between some read or write operations. There were several and I have not tracked down which specific operation it was.

EDIT: Found it. If I comment out the 20 msec sleep in the code below

Code: Select all

val = list(i2c.readfrom_mem(Adr, LED1_PA, 2))
sleep_ms(20)  # <-- this sleep is required
val[0] = 0x1f  # set LED current pulse amplitude
val[1] = 0x1f
i2c.writeto_mem(Adr, LED1_PA, bytearray(val))
Then I get an error when it runs:

Code: Select all

Traceback (most recent call last):
  File "<stdin>", line 51, in <module>
OSError: 5
I never get that error if the sleep is included. Actually 1 ms was also ok, but removing it was not ok.
If you google Raspberry Pico OSError: 5 you'll see I'm not the only one, for example:
https://github.com/micropython/micropython/issues/6891

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Thu Apr 22, 2021 7:19 pm

A short test program implemented in C using the pico-sdk that tests to see if a BNO055 functions as expected at a baud rate of 400 kHz can be found here. The program doesn't do very much, it simply reads the CHIP_ID register continuously as fast as it can. The program functions as expected confirming that the BNO055 can operate at a baud rate of 400 kHz. The number of bits that can be transfered per second is 44304 which is far less that the theoretical maximum of 400000 bits per second and is related to the BNO055 stretching the I2C clock. With other devices like the BME280 a lot more data can be transferred per second.

sonnybalut
Posts: 18
Joined: Fri Apr 17, 2015 2:57 am

Re: BNO055 IMU with I2C

Mon Apr 26, 2021 7:23 pm

I also was having problem with oserror 5, I tested with 100 khz instead of 400 khz, so I added time delay and try/except statement. Here is a youtube demo (source in the description) -------> https://www.youtube.com/watch?v=uu4slYGSQPE

Thanks,
Sonny

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Mon Apr 26, 2021 9:23 pm

The BNO055 has a power-on-reset time of 650 milliseconds which means it's important to steer clear of using it for the first 650 milliseconds after power-on (see here.) I wonder if the MicroPython programs are having issues because they access the BNO055 too quickly after power-on.

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Tue Apr 27, 2021 8:43 pm

Curiosity got the better of me here and I had to give it a try in MicroPython too. The below program which accesses a BNO055 at a baud rate of 400 kHz works for me. Note that the program will not function without the one second delay. The BNO055 has a Cortex-M0 microcontroller and a relatively long power-on-reset time of 650 milliseconds.

Code: Select all

from machine import Pin, I2C
import time

# Power-on-reset time for the BNO055 is 650 ms. Give it time to start.
time.sleep(1)

i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
i = 0
while True:
    i += 1
    bytes = i2c.readfrom_mem(0x28, 0x00, 1)
    if i % 1136 == 0:
        print(i, hex(bytes[0]))

Nitro_fpv
Posts: 46
Joined: Tue Mar 30, 2021 11:56 am

Re: BNO055 IMU with I2C

Fri Apr 30, 2021 6:32 pm

Hello everybody

Thank you for all of your answers.
I'm sorry that I haven't been able to answer until now.
Up until now, I was doing technical assembly in a rather deserted place.
There is actually no internet connection there, we only had GSM!

I have now read through all of your answers with great interest.
fivdi, you really contributed to my finding the bug!

In the code I have a pause for initialization:

Code: Select all

while True:
    time.sleep(1)
    if not calibrated:
        calibrated = imu.calibrated()

However, through your test code:

Code: Select all

from machine import Pin, I2C
import time

# Power-on-reset time for the BNO055 is 650 ms. Give it time to start.
time.sleep(1)

i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
i = 0
while True:
    i += 1
    bytes = i2c.readfrom_mem(0x28, 0x00, 1)
    if i % 1136 == 0:
        print(i, hex(bytes[0]))

I swapped the pins I2C pins on the Pi PICO.
With scl=Pin(9), sda=Pin(8), 4000 go for me, with scl=Pin(5), sda=Pin(4), the full 400000 go!
Either my PI PICO has a hardware problem, or all PI Picos, which I don't think so.

Can you please test the scl=Pin(9), sda=Pin(8) and say whether you can do it there too?

Nitro_fpv
Posts: 46
Joined: Tue Mar 30, 2021 11:56 am

Re: BNO055 IMU with I2C

Fri Apr 30, 2021 7:01 pm

Now it has caught up with me again. The test code from fivdi works with 400000. With my code, an error message appears after about 1 second:

Code: Select all

Traceback (most recent call last):
  File "<stdin>", line 27, in <module>
  File "bno055_base.py", line 64, in <lambda>
  File "bno055_base.py", line 91, in scaled_tuple
  File "bno055_base.py", line 123, in _readn
OSError: 5

here my code:

Code: Select all

from machine import Pin, I2C, PWM
from time import sleep
sleep(1)
pwm = PWM(Pin(0))
pwm.freq(200)

def interpoliert(x, i_m, i_M, o_m, o_M):
    return max(min(o_M, (x - i_m) * (o_M - o_m) // (i_M - i_m) + o_m), o_m)

from bno055 import *
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=4000)
print("I2C Address      : "+hex(i2c.scan()[0]).upper()) # Display device address
print("I2C Configuration: "+str(i2c))                   # Display I2C config
imu = BNO055(i2c)
calibrated = False

KP = 40  #KP euler
KD = -10 #KD gyro
euler_rc = 180

while True:
    if not calibrated:
        calibrated = imu.calibrated()
#        print('Calibration required: sys {} gyro {} accel {} mag {}'.format(*imu.cal_status()))
    gyro = ('{2}'.format(*imu.gyro()))   #gyro yaw
    euler = ('{0}'.format(*imu.euler())) #euler yaw
    euler = float (euler)
    gyro = float (gyro)
    euler = euler - euler_rc
    balance_output = euler * KP + gyro * KD
    pwm_servo = (interpoliert(balance_output, -1000, 1000, 13080, 26190))
    pwm_servo = int (pwm_servo)
    pwm.duty_u16(pwm_servo)
    print(balance_output)

Library:

Code: Select all

# bno055.py MicroPython driver for Bosch cls nine degree of freedom inertial
# measurement unit module with sensor fusion.

# The MIT License (MIT)
#
# Copyright (c) 2017 Radomir Dopieralski for Adafruit Industries.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

# This is a port of the Adafruit CircuitPython driver to MicroPython, with
# modified/enhanced functionality.

# Original Author: Radomir Dopieralski
# Ported to MicroPython and extended by Peter Hinch
# This port copyright (c) Peter Hinch 2019

from micropython import const
from bno055_base import BNO055_BASE


CONFIG_MODE = 0x00
ACCONLY_MODE = 0x01
MAGONLY_MODE = 0x02
GYRONLY_MODE = 0x03
ACCMAG_MODE = 0x04
ACCGYRO_MODE = 0x05
MAGGYRO_MODE = 0x06
AMG_MODE = 0x07
IMUPLUS_MODE = 0x08
COMPASS_MODE = 0x09
M4G_MODE = 0x0a
NDOF_FMC_OFF_MODE = 0x0b
NDOF_MODE = 0x0c

ACC = 0x08  # Registers for configuration (page 1)
MAG = 0x09
GYRO = 0x0a

ACC_DATA = 0x08  # Data regsiters (page 0)
MAG_DATA = 0x0e
GYRO_DATA = 0x14
GRAV_DATA = 0x2e
LIN_ACC_DATA = 0x28
EULER_DATA = 0x1a
QUAT_DATA = 0x20

_PAGE_REGISTER = const(0x07)
_AXIS_MAP_SIGN = const(0x42)
_AXIS_MAP_CONFIG = const(0x41)

class BNO055(BNO055_BASE):

    acc_range = (2, 4, 8, 16)  # G
    acc_bw = (8, 16, 31, 62, 125, 250, 500, 1000)
    gyro_range = (2000, 1000, 500, 250, 125)  # dps
    gyro_bw = (523, 230, 116, 47, 23, 12, 64, 32)  # bandwidth (Hz)
    mag_rate = (2, 6, 8, 10, 15, 20, 25, 30)  # rate (Hz)

    @classmethod
    def _tuple_to_int(cls, dev, v):  # Convert (range, bw) to register value
        try:
            if dev == ACC:
                msg = 'Illegal accel range {} or bandwidth {}'
                return cls.acc_range.index(v[0]) | (cls.acc_bw.index(v[1]) << 2)
            elif dev == GYRO:
                msg = 'Illegal gyro range {} or bandwidth {}'
                return cls.gyro_range.index(v[0]) | (cls.gyro_bw.index(v[1]) << 3)
            elif dev == MAG:
                msg = 'Illegal magnetometer rate {}'
                return cls.mag_rate.index(v[0])
        except ValueError:
            raise ValueError(msg.format(*v))

    # Return the current config in human readable form
    @classmethod
    def _int_to_tuple(cls, dev, v):
        try:
            if dev == ACC:
                return (cls.acc_range[v & 3], cls.acc_bw[v >> 2])
            elif dev == GYRO:
                return (cls.gyro_range[v & 7], cls.gyro_bw[v >> 3])
            elif dev == MAG:
                return (cls.mag_rate[v],)
        except IndexError:
            return False  # Can occur e.g. initial config of magnetometer
        raise ValueError('Unknown device.', dev)

    # Convert two bytes to signed integer (little endian) Can be used in an interrupt handler
    @staticmethod
    def _bytes_toint(lsb, msb):
        if not msb & 0x80:
            return msb << 8 | lsb  # +ve
        return - (((msb ^ 255) << 8) | (lsb ^ 255) + 1)

    @staticmethod
    def _argcheck(arg, name):
        if len(arg) != 3 or not (isinstance(arg, list) or isinstance(arg, tuple)):
            raise ValueError(name + ' must be a 3 element list or tuple')

    # Transposition (x, y, z) 0 == x 1 == y 2 == z hence (0, 1, 2) is no change
    # Scaling (x, y, z) 0 == normal 1 == invert
    def __init__(self, i2c, address=0x28, crystal=True, transpose=(0, 1, 2), sign=(0, 0, 0)):
        self._argcheck(sign, 'Sign')
        if [x for x in sign if x not in (0, 1)]:
            raise ValueError('Sign values must be 0 or 1')
        self.sign = sign
        self._argcheck(transpose, 'Transpose')
        if set(transpose) != {0, 1, 2}:
            raise ValueError('Transpose indices must be unique and in range 0-2')
        self.transpose = transpose
        super().__init__(i2c, address, crystal)
        self.buf6 = bytearray(6)
        self.buf8 = bytearray(8)
        self.w = 0
        self.x = 0
        self.y = 0
        self.z = 0

    def orient(self):
        if self.transpose != (0, 1, 2):
            a = self.transpose
            self._write(_AXIS_MAP_CONFIG, (a[2] << 4) + (a[1] << 2) + a[0])
        if self.sign != (0, 0, 0):
            a = self.sign
            self._write(_AXIS_MAP_SIGN, a[2] + (a[1] << 1) + (a[0] << 2))

    # Configuration: if a tuple is passed, convert to int using function from bno055_help.py
    def config(self, dev, value=None):
        if dev not in (ACC, MAG, GYRO):
            raise ValueError('Unknown device:', dev)
        if isinstance(value, tuple):
            value = self._tuple_to_int(dev, value)  # Convert tuple to register value
        elif value is not None:
            raise ValueError('value must be a tuple or None.')
        last_mode = self.mode(CONFIG_MODE)
        self._write(_PAGE_REGISTER, 1)
        old_val = self._read(dev)
        if value is not None:
            self._write(dev, value)
        self._write(_PAGE_REGISTER, 0)
        self.mode(last_mode)
        return self._int_to_tuple(dev, old_val)

    # For use in ISR
    def iget(self, reg):
        if reg == 0x20:
            n = 4
            buf = self.buf8
        else:
            n = 3
            buf = self.buf6
        self._i2c.readfrom_mem_into(self.address, reg, buf)
        if n == 4:
            self.w = self._bytes_toint(buf[0], buf[1])
            i = 2
        else:
            self.w = 0
            i = 0
        self.x = self._bytes_toint(buf[i], buf[i+1])
        self.y = self._bytes_toint(buf[i+2], buf[i+3])
        self.z = self._bytes_toint(buf[i+4], buf[i+5])

Code: Select all

# bno055_base.py Minimal MicroPython driver for Bosch BNO055 nine degree of
# freedom inertial measurement unit module with sensor fusion.

# The MIT License (MIT)
#
# Copyright (c) 2017 Radomir Dopieralski for Adafruit Industries.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

# This is a port of the Adafruit CircuitPython driver to MicroPython, with
# modified/enhanced functionality.

# Original Author: Radomir Dopieralski
# Ported to MicroPython and extended by Peter Hinch
# This port copyright (c) Peter Hinch 2019

import utime as time
import ustruct
from micropython import const

_CHIP_ID = const(0xa0)

_CONFIG_MODE = const(0)
_NDOF_MODE = const(0x0c)

_POWER_NORMAL = const(0x00)
_POWER_LOW = const(0x01)
_POWER_SUSPEND = const(0x02)

_MODE_REGISTER = const(0x3d)
_PAGE_REGISTER = const(0x07)
_CALIBRATION_REGISTER = const(0x35)
_TRIGGER_REGISTER = const(0x3f)
_POWER_REGISTER = const(0x3e)
_ID_REGISTER = const(0x00)

class BNO055_BASE:

    def __init__(self, i2c, address=0x28, crystal=True, transpose=(0, 1, 2), sign=(0, 0, 0)):
        self._i2c = i2c
        self.address = address
        self.crystal = crystal
        self.mag = lambda : self.scaled_tuple(0x0e, 1/16)  # microteslas (x, y, z)
        self.accel = lambda : self.scaled_tuple(0x08, 1/100)  # m.s^-2
        self.lin_acc = lambda : self.scaled_tuple(0x28, 1/100)  # m.s^-2
        self.gravity = lambda : self.scaled_tuple(0x2e, 1/100)  # m.s^-2
        self.gyro = lambda : self.scaled_tuple(0x14, 1/16)  # deg.s^-1
        self.euler = lambda : self.scaled_tuple(0x1a, 1/16)  # degrees (heading, roll, pitch)
        self.quaternion = lambda : self.scaled_tuple(0x20, 1/(1<<14), bytearray(8), '<hhhh')  # (w, x, y, z)
        try:
            chip_id = self._read(_ID_REGISTER)
        except OSError:
            raise RuntimeError('No BNO055 chip detected.')
        if chip_id != _CHIP_ID:
            raise RuntimeError("bad chip id (%x != %x)" % (chip_id, _CHIP_ID))
        self.reset()

    def reset(self):
        self.mode(_CONFIG_MODE)
        try:
            self._write(_TRIGGER_REGISTER, 0x20)
        except OSError: # error due to the chip resetting
            pass
        # wait for the chip to reset (650 ms typ.)
        time.sleep_ms(700)
        self._write(_POWER_REGISTER, _POWER_NORMAL)
        self._write(_PAGE_REGISTER, 0x00)
        self._write(_TRIGGER_REGISTER, 0x80 if self.crystal else 0)
        time.sleep_ms(500 if self.crystal else 10)  # Crystal osc seems to take time to start.
        if hasattr(self, 'orient'):
            self.orient()  # Subclass
        self.mode(_NDOF_MODE)

    def scaled_tuple(self, addr, scale, buf=bytearray(6), fmt='<hhh'):
        return tuple(b*scale for b in ustruct.unpack(fmt, self._readn(buf, addr)))

    def temperature(self):
        t = self._read(0x34)  # Celcius signed (corrected from Adafruit)
        return t if t < 128 else t - 256

    # Return bytearray [sys, gyro, accel, mag] calibration data.
    def cal_status(self, s=bytearray(4)):
        cdata = self._read(_CALIBRATION_REGISTER)
        s[0] = (cdata >> 6) & 0x03  # sys
        s[1] = (cdata >> 4) & 0x03  # gyro
        s[2] = (cdata >> 2) & 0x03  # accel
        s[3] = cdata & 0x03  # mag
        return s

    def calibrated(self):
        s = self.cal_status()
        # https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/device-calibration
        return min(s[1:]) == 3 and s[0] > 0

    # read byte from register, return int
    def _read(self, memaddr, buf=bytearray(1)):  # memaddr = memory location within the I2C device
        self._i2c.readfrom_mem_into(self.address, memaddr, buf)
        return buf[0]

    # write byte to register
    def _write(self, memaddr, data, buf=bytearray(1)):
        buf[0] = data
        self._i2c.writeto_mem(self.address, memaddr, buf)

    # read n bytes, return buffer
    def _readn(self, buf, memaddr):  # memaddr = memory location within the I2C device
        self._i2c.readfrom_mem_into(self.address, memaddr, buf)
        return buf

    def mode(self, new_mode=None):
        old_mode = self._read(_MODE_REGISTER)
        if new_mode is not None:
            self._write(_MODE_REGISTER, _CONFIG_MODE)  # This is empirically necessary if the mode is to be changed
            time.sleep_ms(20)  # Datasheet table 3.6
            if new_mode != _CONFIG_MODE:
                self._write(_MODE_REGISTER, new_mode)
                time.sleep_ms(10)  # Table 3.6
        return old_mode

    def external_crystal(self):
        return bool(self._read(_TRIGGER_REGISTER) & 0x80)

What do you think of the error message?

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Sat May 01, 2021 12:18 pm

Nitro_fpv wrote:
Fri Apr 30, 2021 6:32 pm
I swapped the pins I2C pins on the Pi PICO.
With scl=Pin(9), sda=Pin(8), 4000 go for me, with scl=Pin(5), sda=Pin(4), the full 400000 go!
Either my PI PICO has a hardware problem, or all PI Picos, which I don't think so.

Can you please test the scl=Pin(9), sda=Pin(8) and say whether you can do it there too?

I gave this a try and it works as expected for me. Here is what it looks like with rshell:

Code: Select all

/home/pi/src/pico/mp> cat /pyboard/bno055_2.py
from machine import Pin, I2C
import time

# Power-on-reset time for the BNO055 is 650 ms. Give it time to start.
time.sleep(1)

i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=400000)
i = 0
while True:
    i += 1
    bytes = i2c.readfrom_mem(0x28, 0x00, 1)
    if i % 1136 == 0:
        print(i, hex(bytes[0]))

/home/pi/src/pico/mp> repl
Entering REPL. Use Control-X to exit.
>
MicroPython v1.15 on 2021-05-01; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> 
>>> import bno055_2
1136 0xa0
2272 0xa0
3408 0xa0
4544 0xa0
5680 0xa0
6816 0xa0
7952 0xa0
9088 0xa0
10224 0xa0
... 

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Sat May 01, 2021 1:27 pm

I can reproduce the error using the code at https://github.com/micropython-IMU/micropython-bno055.
However, I'm afraid I don't know what's causing the problem.

Code: Select all

Entering REPL. Use Control-X to exit.
>
MicroPython v1.15 on 2021-05-01; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> 
>>> import bno055_test
Calibration required: sys 0 gyro 0 accel 0 mag 0
Temperature 29°C
Mag       x    -8    y    -7     z   -33
Gyro      x    -0    y     0     z     0
Accel     x  -2.7    y   0.2     z   9.2
Lin acc.  x   0.0    y  -0.0     z  -0.2
Gravity   x  -2.8    y   0.2     z   9.4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bno055_test.py", line 26, in <module>
  File "bno055_base.py", line 64, in <lambda>
  File "bno055_base.py", line 91, in scaled_tuple
  File "bno055_base.py", line 125, in _readn
OSError: [Errno 5] EIO

Nitro_fpv
Posts: 46
Joined: Tue Mar 30, 2021 11:56 am

Re: BNO055 IMU with I2C

Sat May 01, 2021 3:43 pm

fivdi wrote:
Sat May 01, 2021 1:27 pm
I can reproduce the error using the code at https://github.com/micropython-IMU/micropython-bno055.
However, I'm afraid I don't know what's causing the problem.

Yes, I looked at the library, unfortunately I couldn't find anything that could trigger the problem.
However, I am not the professional for it either.
Thank you for your confirmation, I thought I was doing something wrong.

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Sat May 01, 2021 6:52 pm

The CircuitPython BNO055 library works well at 400 kHz: https://github.com/adafruit/Adafruit_Ci ... hon_BNO055

Nitro_fpv
Posts: 46
Joined: Tue Mar 30, 2021 11:56 am

Re: BNO055 IMU with I2C

Sat May 01, 2021 7:10 pm

fivdi wrote:
Sat May 01, 2021 6:52 pm
The CircuitPython BNO055 library works well at 400 kHz: https://github.com/adafruit/Adafruit_Ci ... hon_BNO055
Good to know.
Unfortunately I can't do a CircuitPython.
Is there a comparison list or something similar of the different code structure?
I just started with MicroPython: =)

fivdi
Posts: 388
Joined: Sun Sep 23, 2012 8:09 pm
Contact: Website

Re: BNO055 IMU with I2C

Sat May 01, 2021 7:42 pm

Nitro_fpv wrote:
Sat May 01, 2021 7:10 pm
Unfortunately I can't do a CircuitPython.
Is there a comparison list or something similar of the different code structure?
I just started with MicroPython: =)

If you can do MicroPython you can do CircuitPython and visa versa. To a large extent they are very similar.

See
https://learn.adafruit.com/getting-star ... cuitpython
https://github.com/adafruit/circuitpyth ... icropython

Nitro_fpv
Posts: 46
Joined: Tue Mar 30, 2021 11:56 am

Re: BNO055 IMU with I2C

Sat May 01, 2021 8:23 pm

fivdi wrote:
Sat May 01, 2021 7:42 pm

If you can do MicroPython you can do CircuitPython and visa versa. To a large extent they are very similar.

See
https://learn.adafruit.com/getting-star ... cuitpython
https://github.com/adafruit/circuitpyth ... icropython

Thank you very much, I'll read this through.

Return to “MicroPython”