Skip to content

Add UART support #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 24, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
250 changes: 213 additions & 37 deletions adafruit_bno055.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* Author(s): Radomir Dopieralski
"""
import time
import struct

from micropython import const
from adafruit_bus_device.i2c_device import I2CDevice
Expand Down Expand Up @@ -114,33 +115,10 @@ def __set__(self, obj, value):

class BNO055:
"""
Driver for the BNO055 9DOF IMU sensor.
Base class for the BNO055 9DOF IMU sensor.
"""

_temperature = _ReadOnlyUnaryStruct(0x34, "b")
_acceleration = _ScaledReadOnlyStruct(0x08, "<hhh", 1 / 100)
_magnetic = _ScaledReadOnlyStruct(0x0E, "<hhh", 1 / 16)
_gyro = _ScaledReadOnlyStruct(0x14, "<hhh", 0.001090830782496456)
_euler = _ScaledReadOnlyStruct(0x1A, "<hhh", 1 / 16)
_quaternion = _ScaledReadOnlyStruct(0x20, "<hhhh", 1 / (1 << 14))
_linear_acceleration = _ScaledReadOnlyStruct(0x28, "<hhh", 1 / 100)
_gravity = _ScaledReadOnlyStruct(0x2E, "<hhh", 1 / 100)

offsets_accelerometer = _ModeStruct(_OFFSET_ACCEL_REGISTER, "<hhh", CONFIG_MODE)
"""Calibration offsets for the accelerometer"""
offsets_magnetometer = _ModeStruct(_OFFSET_MAGNET_REGISTER, "<hhh", CONFIG_MODE)
"""Calibration offsets for the magnetometer"""
offsets_gyroscope = _ModeStruct(_OFFSET_GYRO_REGISTER, "<hhh", CONFIG_MODE)
"""Calibration offsets for the gyroscope"""

radius_accelerometer = _ModeStruct(_RADIUS_ACCEL_REGISTER, "<h", CONFIG_MODE)
"""Radius for accelerometer (cm?)"""
radius_magnetometer = _ModeStruct(_RADIUS_MAGNET_REGISTER, "<h", CONFIG_MODE)
"""Radius for magnetometer (cm?)"""

def __init__(self, i2c, address=0x28):
self.i2c_device = I2CDevice(i2c, address)
self.buffer = bytearray(2)
def __init__(self):
chip_id = self._read_register(_ID_REGISTER)
if chip_id != _CHIP_ID:
raise RuntimeError("bad chip id (%x != %x)" % (chip_id, _CHIP_ID))
Expand All @@ -152,18 +130,6 @@ def __init__(self, i2c, address=0x28):
self.mode = NDOF_MODE
time.sleep(0.01)

def _write_register(self, register, value):
self.buffer[0] = register
self.buffer[1] = value
with self.i2c_device as i2c:
i2c.write(self.buffer)

def _read_register(self, register):
self.buffer[0] = register
with self.i2c_device as i2c:
i2c.write_then_readinto(self.buffer, self.buffer, out_end=1, in_start=1)
return self.buffer[1]

def _reset(self):
"""Resets the sensor to default settings."""
self.mode = CONFIG_MODE
Expand Down Expand Up @@ -266,6 +232,10 @@ def temperature(self):
"""Measures the temperature of the chip in degrees Celsius."""
return self._temperature

@property
def _temperature(self):
raise NotImplementedError("Must be implemented.")

@property
def acceleration(self):
"""Gives the raw accelerometer readings, in m/s.
Expand All @@ -275,6 +245,10 @@ def acceleration(self):
return self._acceleration
return (None, None, None)

@property
def _acceleration(self):
raise NotImplementedError("Must be implemented.")

@property
def magnetic(self):
"""Gives the raw magnetometer readings in microteslas.
Expand All @@ -284,6 +258,10 @@ def magnetic(self):
return self._magnetic
return (None, None, None)

@property
def _magnetic(self):
raise NotImplementedError("Must be implemented.")

@property
def gyro(self):
"""Gives the raw gyroscope reading in radians per second.
Expand All @@ -293,6 +271,10 @@ def gyro(self):
return self._gyro
return (None, None, None)

@property
def _gyro(self):
raise NotImplementedError("Must be implemented.")

@property
def euler(self):
"""Gives the calculated orientation angles, in degrees.
Expand All @@ -302,6 +284,10 @@ def euler(self):
return self._euler
return (None, None, None)

@property
def _euler(self):
raise NotImplementedError("Must be implemented.")

@property
def quaternion(self):
"""Gives the calculated orientation as a quaternion.
Expand All @@ -311,6 +297,10 @@ def quaternion(self):
return self._quaternion
return (None, None, None, None)

@property
def _quaternion(self):
raise NotImplementedError("Must be implemented.")

@property
def linear_acceleration(self):
"""Returns the linear acceleration, without gravity, in m/s.
Expand All @@ -320,6 +310,10 @@ def linear_acceleration(self):
return self._linear_acceleration
return (None, None, None)

@property
def _linear_acceleration(self):
raise NotImplementedError("Must be implemented.")

@property
def gravity(self):
"""Returns the gravity vector, without acceleration in m/s.
Expand All @@ -328,3 +322,185 @@ def gravity(self):
if self.mode in [0x09, 0x0B, 0x0C]:
return self._gravity
return (None, None, None)

@property
def _gravity(self):
raise NotImplementedError("Must be implemented.")

def _write_register(self, register, value):
raise NotImplementedError("Must be implemented.")

def _read_register(self, register):
raise NotImplementedError("Must be implemented.")


class BNO055_I2C(BNO055):
"""
Driver for the BNO055 9DOF IMU sensor via I2C.
"""

_temperature = _ReadOnlyUnaryStruct(0x34, "b")
_acceleration = _ScaledReadOnlyStruct(0x08, "<hhh", 1 / 100)
_magnetic = _ScaledReadOnlyStruct(0x0E, "<hhh", 1 / 16)
_gyro = _ScaledReadOnlyStruct(0x14, "<hhh", 0.001090830782496456)
_euler = _ScaledReadOnlyStruct(0x1A, "<hhh", 1 / 16)
_quaternion = _ScaledReadOnlyStruct(0x20, "<hhhh", 1 / (1 << 14))
_linear_acceleration = _ScaledReadOnlyStruct(0x28, "<hhh", 1 / 100)
_gravity = _ScaledReadOnlyStruct(0x2E, "<hhh", 1 / 100)

offsets_accelerometer = _ModeStruct(_OFFSET_ACCEL_REGISTER, "<hhh", CONFIG_MODE)
"""Calibration offsets for the accelerometer"""
offsets_magnetometer = _ModeStruct(_OFFSET_MAGNET_REGISTER, "<hhh", CONFIG_MODE)
"""Calibration offsets for the magnetometer"""
offsets_gyroscope = _ModeStruct(_OFFSET_GYRO_REGISTER, "<hhh", CONFIG_MODE)
"""Calibration offsets for the gyroscope"""

radius_accelerometer = _ModeStruct(_RADIUS_ACCEL_REGISTER, "<h", CONFIG_MODE)
"""Radius for accelerometer (cm?)"""
radius_magnetometer = _ModeStruct(_RADIUS_MAGNET_REGISTER, "<h", CONFIG_MODE)
"""Radius for magnetometer (cm?)"""

def __init__(self, i2c, address=0x28):
self.buffer = bytearray(2)
self.i2c_device = I2CDevice(i2c, address)
super().__init__()

def _write_register(self, register, value):
self.buffer[0] = register
self.buffer[1] = value
with self.i2c_device as i2c:
i2c.write(self.buffer)

def _read_register(self, register):
self.buffer[0] = register
with self.i2c_device as i2c:
i2c.write_then_readinto(self.buffer, self.buffer, out_end=1, in_start=1)
return self.buffer[1]


class BNO055_UART(BNO055):
"""
Driver for the BNO055 9DOF IMU sensor via UART.
"""

def __init__(self, uart):
self._uart = uart
self._uart.baudrate = 115200
super().__init__()

def _write_register(self, register, data): # pylint: disable=arguments-differ
if not isinstance(data, bytes):
data = bytes([data])
self._uart.write(bytes([0xAA, 0x00, register, len(data)]) + data)
time.sleep(0.1)
resp = self._uart.read(self._uart.in_waiting)
if len(resp) < 2:
raise OSError("UART access error.")
if resp[0] != 0xEE or resp[1] != 0x01:
raise RuntimeError("UART write error: {}".format(resp[1]))

def _read_register(self, register, length=1): # pylint: disable=arguments-differ
self._uart.write(bytes([0xAA, 0x01, register, length]))
time.sleep(0.1)
resp = self._uart.read(self._uart.in_waiting)
if len(resp) < 2:
raise OSError("UART access error.")
if resp[0] != 0xBB:
raise RuntimeError("UART read error: {}".format(resp[1]))
if length > 1:
return resp[2:]
return int(resp[2])

@property
def _temperature(self):
return self._read_register(0x34)

@property
def _acceleration(self):
resp = struct.unpack("<hhh", self._read_register(0x08, 6))
return tuple([x / 100 for x in resp])

@property
def _magnetic(self):
resp = struct.unpack("<hhh", self._read_register(0x0E, 6))
return tuple([x / 16 for x in resp])

@property
def _gyro(self):
resp = struct.unpack("<hhh", self._read_register(0x0E, 6))
return tuple([x * 0.001090830782496456 for x in resp])

@property
def _euler(self):
resp = struct.unpack("<hhh", self._read_register(0x1A, 6))
return tuple([x / 16 for x in resp])

@property
def _quaternion(self):
resp = struct.unpack("<hhhh", self._read_register(0x20, 8))
return tuple([x / (1 << 14) for x in resp])

@property
def _linear_acceleration(self):
resp = struct.unpack("<hhh", self._read_register(0x28, 6))
return tuple([x / 100 for x in resp])

@property
def _gravity(self):
resp = struct.unpack("<hhh", self._read_register(0x2E, 6))
return tuple([x / 100 for x in resp])

@property
def offsets_accelerometer(self):
"""Calibration offsets for the accelerometer"""
return struct.unpack("<hhh", self._read_register(_OFFSET_ACCEL_REGISTER, 6))

@offsets_accelerometer.setter
def offsets_accelerometer(self, offsets):
data = bytearray(6)
struct.pack_into("<hhh", data, 0, *offsets)
self._write_register(_OFFSET_ACCEL_REGISTER, bytes(data))

@property
def offsets_magnetometer(self):
"""Calibration offsets for the magnetometer"""
return struct.unpack("<hhh", self._read_register(_OFFSET_MAGNET_REGISTER, 6))

@offsets_magnetometer.setter
def offsets_magnetometer(self, offsets):
data = bytearray(6)
struct.pack_into("<hhh", data, 0, *offsets)
self._write_register(_OFFSET_MAGNET_REGISTER, bytes(data))

@property
def offsets_gyroscope(self):
"""Calibration offsets for the gyroscope"""
return struct.unpack("<hhh", self._read_register(_OFFSET_GYRO_REGISTER, 6))

@offsets_gyroscope.setter
def offsets_gyroscope(self, offsets):
data = bytearray(6)
struct.pack_into("<hhh", data, 0, *offsets)
self._write_register(_OFFSET_GYRO_REGISTER, bytes(data))

@property
def radius_accelerometer(self):
"""Radius for accelerometer (cm?)"""
return struct.unpack("<h", self._read_register(_RADIUS_ACCEL_REGISTER, 2))[0]

@radius_accelerometer.setter
def radius_accelerometer(self, radius):
data = bytearray(2)
struct.pack_into("<h", data, 0, radius)
self._write_register(_RADIUS_ACCEL_REGISTER, bytes(data))

@property
def radius_magnetometer(self):
"""Radius for magnetometer (cm?)"""
return struct.unpack("<h", self._read_register(_RADIUS_MAGNET_REGISTER, 2))[0]

@radius_magnetometer.setter
def radius_magnetometer(self, radius):
data = bytearray(2)
struct.pack_into("<h", data, 0, radius)
self._write_register(_RADIUS_MAGNET_REGISTER, bytes(data))
7 changes: 6 additions & 1 deletion examples/bno055_simpletest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
import busio
import adafruit_bno055

# Use these lines for I2C
i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_bno055.BNO055(i2c)
sensor = adafruit_bno055.BNO055_I2C(i2c)

# User these lines for UART
#uart = busio.UART(board.TX, board.RX)
#sensor = adafruit_bno055.BNO055_UART(uart)

while True:
print("Temperature: {} degrees C".format(sensor.temperature))
Expand Down
2 changes: 1 addition & 1 deletion examples/bno055_webgl_demo/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
i2c = busio.I2C(board.SCL, board.SDA)

# Create the BNO sensor connection.
bno = adafruit_bno055.BNO055(i2c)
bno = adafruit_bno055.BNO055_I2C(i2c)

# Application configuration below. You probably don't need to change these values.

Expand Down