adafruit / Adafruit_CircuitPython_BNO08x

Helper library for the Hillcrest Laboratories BNO080 IMU
MIT License
22 stars 29 forks source link

Issues with reads over I2c #36

Closed DandrewsDev closed 1 year ago

DandrewsDev commented 1 year ago

I am seeing a number of issues working with this library and sensor when reading over I2c. Seems that there is some serious clock stretching issues with this sensor.

        ********** Packet *************
DBG::        HEADER:
DBG::        Data Len: 19
DBG::        Channel: INPUT_SENSOR_REPORTS (3)
DBG::           ** UNKNOWN Report Type **: 0x7b
DBG::        Sequence number: 2

DBG::        Data:
DBG::       [0x04] 0x7B 0x20 0x00 0x00
DBG::       [0x08] 0x00 0x05 0x0A 0x00
DBG::       [0x0C] 0x00 0x01 0x16 0xFF
DBG::       [0x10] 0x38 0x02 0xF6 0x39
DBG::       [0x14] 0x10 0x44 0x32
        *******************************

Here is some example of the code I am working with.

import adafruit_bno08x
from adafruit_bno08x.i2c import BNO08X_I2C

bno = BNO08X_I2C(i2c)
bno.enable_feature(BNO_REPORT_ROTATION_VECTOR)
bno.enable_feature(BNO_REPORT_ACCELEROMETER)
bno.enable_feature(BNO_REPORT_GYROSCOPE)

accel_x, accel_y, accel_z = bno.acceleration  # pylint:disable=no-member
print("X: %0.6f  Y: %0.6f Z: %0.6f  m/s^2" % (accel_x, accel_y, accel_z))
gyro_x, gyro_y, gyro_z = bno.gyro  # pylint:disable=no-member
print("X: %0.6f  Y: %0.6f Z: %0.6f rads/s" % (gyro_x, gyro_y, gyro_z))

I have been getting good measurements when its not throwing errors. To help fix these errors I've adjust the I2c bus speed in /boot/config.txt. Currently its set to 20khz.

dtparam=i2c_arm_baudrate=20000

The more I lower that speed, the less and less I see errors. However it is having a massive impact on the rate at which I can poll the sensor. At the 20khz I am now limited to around 18 samples per second for Acc/Gyro/Quat data.

I am unable to use a UART here as the 1 hardware UART is already in use. And doing a software UART seems to have very similar issues with errors being thrown.

Is SPI my best option here? Will it suffer the same issues as I2c and UART? Most of the examples and documentation I've seen for this sensor show I2c. I'd like to get around 100 samples a second for Acc/Gyro/Quat data. Is there anything I can try where that sort of data rate seems likely?

caternuson commented 1 year ago

Yep, it's def a clock stretcher, which never plays nice on a Pi.

Before giving up I2C, try software based I2C using the i2c-gpio overlay. https://github.com/raspberrypi/firmware/blob/5f40391c32ca871c8491b4d78c1e60f0c28120f5/boot/overlays/README#L1731

DandrewsDev commented 1 year ago

Okay so I gave software I2c a shot, and ran into a totally different issue.

Traceback (most recent call last):
  File "/home/pi/accTest/acc.py", line 18, in <module>
    bno.enable_feature(BNO_REPORT_ROTATION_VECTOR)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bno08x/__init__.py", line 985, in enable_feature
    raise RuntimeError("Was not able to enable feature", feature_id)
RuntimeError: ('Was not able to enable feature', 5)
import adafruit_bitbangio

i2c = adafruit_bitbangio.I2C(board.D19, board.D26)

bno = BNO08X_I2C(i2c)
bno.enable_feature(BNO_REPORT_ROTATION_VECTOR)

So to check, I tried an i2c scan, using that same bitbang I2c connection. I2C addresses found: ['0x4a']. Which is correct. So the connection is working and seeing the device, but data to and from seems to be a problem.

DandrewsDev commented 1 year ago

I went ahead and wired up my sensor for SPI, and am running into a different issue.

Sample code Im running

from time import sleep
import board
import busio
from digitalio import DigitalInOut, Direction
from adafruit_bno08x.spi import BNO08X_SPI

spi = busio.SPI(board.SCK, MISO=board.MISO, MOSI=board.MOSI)

cs = DigitalInOut(board.D5)
cs.direction = Direction.OUTPUT

int_pin = DigitalInOut(board.D13)
int_pin.direction = Direction.INPUT

wake_pin = DigitalInOut(board.D6)
wake_pin.direction = Direction.INPUT

reset_pin = DigitalInOut(board.D6)
reset_pin.direction = Direction.INPUT

bno = BNO08X_SPI(spi, cs, int_pin, wake_pin, reset_pin, debug=True)

while True:
    print("getting quats")
    quat = bno.quaternion  # pylint:disable=no-member
    print("Rotation Vector Quaternion:")
    print(
        "I: %0.6f  J: %0.6f K: %0.6f  Real: %0.6f" % (quat.i, quat.j, quat.k, quat.real)
    )
    print("")
    sleep(0.5)

And error message.

DBG::        ********** __init__ *************
Hard resetting...
Done!
Traceback (most recent call last):
  File "/home/pi/accTest/spiAcc.py", line 23, in <module>
    bno = BNO08X_SPI(spi, cs, int_pin, wake_pin, reset_pin, debug=True)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bno08x/spi.py", line 40, in __init__
    super().__init__(resetpin, debug)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bno08x/__init__.py", line 513, in __init__
    self.initialize()
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bno08x/__init__.py", line 518, in initialize
    self.hard_reset()
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bno08x/spi.py", line 56, in hard_reset
    self._read_packet()
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bno08x/spi.py", line 103, in _read_packet
    self._read_header()
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bno08x/spi.py", line 98, in _read_header
    spi.readinto(self._data_buffer, end=4, write_value=0x00)
  File "/usr/local/lib/python3.9/dist-packages/busio.py", line 390, in readinto
    return self._spi.readinto(buf, start, end, write_value=write_value)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_blinka/microcontroller/generic_linux/spi.py", line 101, in readinto
    self._spi.max_speed_hz = self.baudrate
  File "/usr/local/lib/python3.9/dist-packages/Adafruit_PureIO/spi.py", line 323, in max_speed_hz
    self._ioctl(SPI._IOC_WR_MAX_SPEED_HZ, max_speed_hz)
  File "/usr/local/lib/python3.9/dist-packages/Adafruit_PureIO/spi.py", line 223, in _ioctl
    arg = struct.pack("=" + structure, data)
struct.error: required argument is not an integer

I've checked my wiring vs the spec 3 or 4 times now and everything looks good.

I saw a comment somewhere "# need to limit clock to 3Mhz" for this SPI device. But not mention of where or how to se that clock speed limit. So that might be my issue there. But I've now tried I2c, software I2c, and SPI and am unable to get it to spit back data at anything more than 20 samples a second.

caternuson commented 1 year ago

How about the suggestion here: https://learn.adafruit.com/adafruit-9-dof-orientation-imu-fusion-breakout-bno085?view=all#python-computer-wiring-3072324 to go back to hardware I2C and up the clock speed to 400kHz?

DandrewsDev commented 1 year ago

Well thats something I had tried before I started lowering the I2C clock speed. It was throwing basically identical errors to those I had reported initially of UNKNOWN Report Type.

I however tried that exact setup again. And then ran into the same issues. But I had a handful of these sensors sitting around so I tried another on I2C with the same settings, and setup as the first. And no problems. Able to get around 250 samples per second of full data without issue.

Closing for now as its currently working fairly well over hardware I2C at 400kHz, with a second sensor.