From bd752a3dbc961fe76b346d74bc6b399dcf09103a Mon Sep 17 00:00:00 2001 From: lady ada Date: Fri, 4 Sep 2020 14:33:07 -0400 Subject: [PATCH 1/6] move reset() to soft_reset() and check packet types on reset --- adafruit_bno080/__init__.py | 37 +++++++++++++++++++++++++++---------- adafruit_bno080/i2c.py | 23 +++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/adafruit_bno080/__init__.py b/adafruit_bno080/__init__.py index 0e245b2..4e549e3 100644 --- a/adafruit_bno080/__init__.py +++ b/adafruit_bno080/__init__.py @@ -29,7 +29,7 @@ from struct import unpack_from, pack_into from collections import namedtuple -from time import sleep, monotonic, monotonic_ns +import time from micropython import const # TODO: Remove on release @@ -132,16 +132,16 @@ def _elapsed(start_time): - return monotonic() - start_time + return time.monotonic() - start_time def elapsed_time(func): """Print the runtime of the decorated function""" def wrapper_timer(*args, **kwargs): - start_time = monotonic_ns() # 1 + start_time = time.monotonic_ns() # 1 value = func(*args, **kwargs) - end_time = monotonic_ns() # 2 + end_time = time.monotonic_ns() # 2 run_time = end_time - start_time # 3 print("Finished", func.__name__, "in", (run_time / 1000000.0), "ms") return value @@ -248,7 +248,7 @@ def __str__(self): _BNO_CHANNEL_INPUT_SENSOR_REPORTS, ]: if self.report_id in reports: - outstr += "DBG::\t\t \tReport Type: %s(%d)\n" % ( + outstr += "DBG::\t\t \tReport Type: %s (0x%x)\n" % ( reports[self.report_id], self.report_id, ) @@ -351,11 +351,12 @@ def __init__(self, debug=False): def initialize(self): """Initialize the sensor""" - self.reset() + self.soft_reset() if not self._check_id(): raise RuntimeError("Could not read ID") for report_type in _ENABLED_SENSOR_REPORTS: self._enable_feature(report_type) + time.sleep(0.1) @property def magnetic(self): @@ -436,7 +437,7 @@ def _wait_for_packet_type(self, channel_number, report_id=None, timeout=5.0): else: report_id_str = "" self._dbg("** Waiting for packet on channel", channel_number, report_id_str) - start_time = monotonic() + start_time = time.monotonic() while _elapsed(start_time) < timeout: new_packet = self._wait_for_packet() @@ -452,7 +453,7 @@ def _wait_for_packet_type(self, channel_number, report_id=None, timeout=5.0): raise RuntimeError("Timed out waiting for a packet on channel", channel_number) def _wait_for_packet(self, timeout=_PACKET_READ_TIMEOUT): - start_time = monotonic() + start_time = time.monotonic() while _elapsed(start_time) < timeout: if not self._data_ready: continue @@ -618,9 +619,25 @@ def _read_header(self): def _data_ready(self): raise RuntimeError("Not implemented") - def reset(self): + def soft_reset(self): """Reset the sensor to an initial unconfigured state""" - raise RuntimeError("Not implemented") + print("Resetting...", end="") + data = bytearray(1) + data[0] = 1 + seq = self._send_packet(BNO_CHANNEL_EXE, data) + + for i in range(3): + time.sleep(0.5) + packet = self._read_packet() + #print(packet) + if i == 0 and packet.channel_number != _BNO_CHANNEL_SHTP_COMMAND: + raise RuntimeError("Expected an SHTP announcement") + if i == 1 and packet.channel_number != BNO_CHANNEL_EXE: + raise RuntimeError("Expected a reset reply") + if i == 2 and packet.channel_number != _BNO_CHANNEL_CONTROL: + raise RuntimeError("Expected a control announcement") + print("OK!"); + # all is good! def _send_packet(self, channel, data): raise RuntimeError("Not implemented") diff --git a/adafruit_bno080/i2c.py b/adafruit_bno080/i2c.py index 9c383b5..a24549a 100644 --- a/adafruit_bno080/i2c.py +++ b/adafruit_bno080/i2c.py @@ -6,7 +6,7 @@ Subclass of `adafruit_bno080.BNO080` to use I2C """ -from time import sleep +import time from struct import pack_into import adafruit_bus_device.i2c_device as i2c_device from . import BNO080, BNO_CHANNEL_EXE, DATA_BUFFER_SIZE, const, Packet @@ -27,24 +27,6 @@ def __init__(self, i2c_bus, address=_BNO080_DEFAULT_ADDRESS, debug=False): self.bus_device_obj = i2c_device.I2CDevice(i2c_bus, address) super().__init__(debug) - def reset(self): - """Reset the sensor to an initial unconfigured state""" - # TODO: Update to use _wait_for_packet_type? - data = bytearray(1) - data[0] = 1 - self._send_packet(BNO_CHANNEL_EXE, data) - sleep(0.050) - - sleep(1) - data_read = True - while data_read: - data_read = self._read_packet() # pylint:disable=assignment-from-no-return - - sleep(0.050) - data_read = True - while data_read: - data_read = self._read_packet() # pylint:disable=assignment-from-no-return - def _send_packet(self, channel, data): data_length = len(data) write_length = data_length + 4 @@ -62,6 +44,7 @@ def _send_packet(self, channel, data): i2c.write(self._data_buffer, end=write_length) self._sequence_number[channel] = (self._sequence_number[channel] + 1) % 256 + return self._sequence_number[channel] # returns true if available data was read # the sensor will always tell us how much there is, so no need to track it ourselves @@ -69,7 +52,7 @@ def _send_packet(self, channel, data): def _read_packet(self): # TODO: MAGIC NUMBER? - sleep(0.001) # + time.sleep(0.001) # # TODO: this can be `_read_header` or know it's done by `_data_ready` with self.bus_device_obj as i2c: i2c.readinto(self._data_buffer, end=4) # this is expecting a header? From c90551383cc7cddfecb7209d526bbc8aece6925b Mon Sep 17 00:00:00 2001 From: lady ada Date: Fri, 4 Sep 2020 14:55:21 -0400 Subject: [PATCH 2/6] add hardware reset, and retries for resetting --- adafruit_bno080/__init__.py | 26 +++++++++++++++++++++++--- adafruit_bno080/i2c.py | 8 ++++---- examples/bno080_simpletest.py | 7 ++++--- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/adafruit_bno080/__init__.py b/adafruit_bno080/__init__.py index 4e549e3..b017fee 100644 --- a/adafruit_bno080/__init__.py +++ b/adafruit_bno080/__init__.py @@ -31,6 +31,7 @@ from collections import namedtuple import time from micropython import const +import digitalio # TODO: Remove on release from .debug import channels, reports @@ -332,8 +333,9 @@ class BNO080: """ - def __init__(self, debug=False): + def __init__(self, reset=None, debug=False): self._debug = debug + self._reset = reset self._dbg("********** __init__ *************") self._data_buffer = bytearray(DATA_BUFFER_SIZE) self._packet_slices = [] @@ -351,6 +353,7 @@ def __init__(self, debug=False): def initialize(self): """Initialize the sensor""" + self.hard_reset() self.soft_reset() if not self._check_id(): raise RuntimeError("Could not read ID") @@ -619,16 +622,33 @@ def _read_header(self): def _data_ready(self): raise RuntimeError("Not implemented") + def hard_reset(self): + """Hardware reset the sensor to an initial unconfigured state""" + if not self._reset: + return + self._reset.direction = digitalio.Direction.OUTPUT + self._reset.value = True + time.sleep(0.01) + self._reset.value = False + time.sleep(0.01) + self._reset.value = True + time.sleep(0.1) + def soft_reset(self): """Reset the sensor to an initial unconfigured state""" print("Resetting...", end="") data = bytearray(1) data[0] = 1 seq = self._send_packet(BNO_CHANNEL_EXE, data) + time.sleep(0.1) for i in range(3): - time.sleep(0.5) - packet = self._read_packet() + while True: # retry reading packets until ready! + packet = self._read_packet() + if packet: + break + time.sleep(0.1) + #print(packet) if i == 0 and packet.channel_number != _BNO_CHANNEL_SHTP_COMMAND: raise RuntimeError("Expected an SHTP announcement") diff --git a/adafruit_bno080/i2c.py b/adafruit_bno080/i2c.py index a24549a..9974720 100644 --- a/adafruit_bno080/i2c.py +++ b/adafruit_bno080/i2c.py @@ -23,9 +23,9 @@ class BNO080_I2C(BNO080): """ - def __init__(self, i2c_bus, address=_BNO080_DEFAULT_ADDRESS, debug=False): + def __init__(self, i2c_bus, reset=None, address=_BNO080_DEFAULT_ADDRESS, debug=False): self.bus_device_obj = i2c_device.I2CDevice(i2c_bus, address) - super().__init__(debug) + super().__init__(reset, debug) def _send_packet(self, channel, data): data_length = len(data) @@ -57,7 +57,7 @@ def _read_packet(self): with self.bus_device_obj as i2c: i2c.readinto(self._data_buffer, end=4) # this is expecting a header? self._dbg("") - self._dbg("READing packet") + self._dbg("SHTP READ packet header: ", [hex(x) for x in self._data_buffer[0:4]]) header = Packet.header_from_buffer(self._data_buffer) packet_byte_count = header.packet_byte_count @@ -67,7 +67,7 @@ def _read_packet(self): self._sequence_number[channel_number] = sequence_number if packet_byte_count == 0: self._dbg("SKIPPING NO PACKETS AVAILABLE IN i2c._read_packet") - return False # remove header size from read length + return None packet_byte_count -= 4 self._dbg( "channel", diff --git a/examples/bno080_simpletest.py b/examples/bno080_simpletest.py index 61a2108..b670339 100644 --- a/examples/bno080_simpletest.py +++ b/examples/bno080_simpletest.py @@ -1,14 +1,15 @@ # SPDX-FileCopyrightText: 2020 Bryan Siepert, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense -from time import sleep +import time import board import busio from adafruit_bno080.i2c import BNO080_I2C - +from digitalio import DigitalInOut i2c = busio.I2C(board.SCL, board.SDA) -bno = BNO080_I2C(i2c) +reset_pin = DigitalInOut(board.G0) +bno = BNO080_I2C(i2c, reset=reset_pin) while True: From 23bd06d6ca8e6cad296c0f7ce385f6aab2cc9ee0 Mon Sep 17 00:00:00 2001 From: lady ada Date: Fri, 4 Sep 2020 15:01:33 -0400 Subject: [PATCH 3/6] a packet exception --- adafruit_bno080/__init__.py | 13 +++++++++---- adafruit_bno080/i2c.py | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/adafruit_bno080/__init__.py b/adafruit_bno080/__init__.py index b017fee..78bfd04 100644 --- a/adafruit_bno080/__init__.py +++ b/adafruit_bno080/__init__.py @@ -132,6 +132,11 @@ REPORT_STATUS = ["Unreliable", "Accuracy low", "Accuracy medium", "Accuracy high"] +class PacketError(Exception): + """Raised when the packet couldnt be parsed""" + pass + + def _elapsed(start_time): return time.monotonic() - start_time @@ -359,7 +364,6 @@ def initialize(self): raise RuntimeError("Could not read ID") for report_type in _ENABLED_SENSOR_REPORTS: self._enable_feature(report_type) - time.sleep(0.1) @property def magnetic(self): @@ -644,10 +648,11 @@ def soft_reset(self): for i in range(3): while True: # retry reading packets until ready! - packet = self._read_packet() - if packet: + try: + packet = self._read_packet() break - time.sleep(0.1) + except PacketError: + time.sleep(0.1) #print(packet) if i == 0 and packet.channel_number != _BNO_CHANNEL_SHTP_COMMAND: diff --git a/adafruit_bno080/i2c.py b/adafruit_bno080/i2c.py index 9974720..9882d5f 100644 --- a/adafruit_bno080/i2c.py +++ b/adafruit_bno080/i2c.py @@ -9,7 +9,7 @@ import time from struct import pack_into import adafruit_bus_device.i2c_device as i2c_device -from . import BNO080, BNO_CHANNEL_EXE, DATA_BUFFER_SIZE, const, Packet +from . import BNO080, BNO_CHANNEL_EXE, DATA_BUFFER_SIZE, const, Packet, PacketError # should be removeable; I _think_ something else should be able to prep the buffers? @@ -67,7 +67,7 @@ def _read_packet(self): self._sequence_number[channel_number] = sequence_number if packet_byte_count == 0: self._dbg("SKIPPING NO PACKETS AVAILABLE IN i2c._read_packet") - return None + raise PacketError("No packet available") packet_byte_count -= 4 self._dbg( "channel", From de77dabea86b2036a86da29cf285fe5924b8491d Mon Sep 17 00:00:00 2001 From: lady ada Date: Fri, 4 Sep 2020 16:25:52 -0400 Subject: [PATCH 4/6] manually enable reports --- adafruit_bno080/__init__.py | 106 ++++++++++++++++++---------------- adafruit_bno080/i2c.py | 19 +++++- examples/bno080_simpletest.py | 13 ++++- 3 files changed, 83 insertions(+), 55 deletions(-) diff --git a/adafruit_bno080/__init__.py b/adafruit_bno080/__init__.py index 78bfd04..320546b 100644 --- a/adafruit_bno080/__init__.py +++ b/adafruit_bno080/__init__.py @@ -67,18 +67,18 @@ # Calibrated Acceleration (m/s2) -_BNO_REPORT_ACCELEROMETER = const(0x01) +BNO_REPORT_ACCELEROMETER = const(0x01) # Calibrated gyroscope (rad/s). -_BNO_REPORT_GYROSCOPE = const(0x02) +BNO_REPORT_GYROSCOPE = const(0x02) # Magnetic field calibrated (in µTesla). The fully calibrated magnetic field measurement. -_BNO_REPORT_MAGNETIC_FIELD = const(0x03) +BNO_REPORT_MAGNETIC_FIELD = const(0x03) # Linear acceleration (m/s2). Acceleration of the device with gravity removed -_BNO_REPORT_LINEAR_ACCELERATION = const(0x04) +BNO_REPORT_LINEAR_ACCELERATION = const(0x04) # Rotation Vector -_BNO_REPORT_ROTATION_VECTOR = const(0x05) -_BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR = const(0x09) -_BNO_REPORT_STEP_COUNTER = const(0x11) -_BNO_REPORT_SHAKE_DETECTOR = const(0x19) +BNO_REPORT_ROTATION_VECTOR = const(0x05) +BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR = const(0x09) +BNO_REPORT_STEP_COUNTER = const(0x11) +BNO_REPORT_SHAKE_DETECTOR = const(0x19) _DEFAULT_REPORT_INTERVAL = const(50000) # in microseconds = 50ms @@ -112,15 +112,15 @@ _BNO_CMD_TIMESTAMP_REBASE: 5, } # length is probably deterministic, like axes * 2 +4 -_ENABLED_SENSOR_REPORTS = { - _BNO_REPORT_ACCELEROMETER: (_Q_POINT_8_SCALAR, 3, 10), - _BNO_REPORT_GYROSCOPE: (_Q_POINT_9_SCALAR, 3, 10), - _BNO_REPORT_MAGNETIC_FIELD: (_Q_POINT_4_SCALAR, 3, 10), - _BNO_REPORT_LINEAR_ACCELERATION: (_Q_POINT_8_SCALAR, 3, 10), - _BNO_REPORT_ROTATION_VECTOR: (_Q_POINT_14_SCALAR, 4, 14,), - _BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR: (_Q_POINT_12_SCALAR, 4, 14), - _BNO_REPORT_STEP_COUNTER: (1, 1, 12), - _BNO_REPORT_SHAKE_DETECTOR: (1, 1, 6), +_AVAIL_SENSOR_REPORTS = { + BNO_REPORT_ACCELEROMETER: (_Q_POINT_8_SCALAR, 3, 10), + BNO_REPORT_GYROSCOPE: (_Q_POINT_9_SCALAR, 3, 10), + BNO_REPORT_MAGNETIC_FIELD: (_Q_POINT_4_SCALAR, 3, 10), + BNO_REPORT_LINEAR_ACCELERATION: (_Q_POINT_8_SCALAR, 3, 10), + BNO_REPORT_ROTATION_VECTOR: (_Q_POINT_14_SCALAR, 4, 14,), + BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR: (_Q_POINT_12_SCALAR, 4, 14), + BNO_REPORT_STEP_COUNTER: (1, 1, 12), + BNO_REPORT_SHAKE_DETECTOR: (1, 1, 6), } DATA_BUFFER_SIZE = const(512) # data buffer size. obviously eats ram @@ -158,7 +158,7 @@ def wrapper_timer(*args, **kwargs): def _parse_sensor_report_data(report_bytes): data_offset = 4 # this may not always be true report_id = report_bytes[0] - scalar, count, _report_length = _ENABLED_SENSOR_REPORTS[report_id] + scalar, count, _report_length = _AVAIL_SENSOR_REPORTS[report_id] results = [] @@ -204,7 +204,7 @@ def parse_sensor_id(buffer): def _report_length(report_id): if report_id < 0xF0: # it's a sensor report - return _ENABLED_SENSOR_REPORTS[report_id][2] + return _AVAIL_SENSOR_REPORTS[report_id][2] return _REPORT_LENGTHS[report_id] @@ -362,53 +362,62 @@ def initialize(self): self.soft_reset() if not self._check_id(): raise RuntimeError("Could not read ID") - for report_type in _ENABLED_SENSOR_REPORTS: - self._enable_feature(report_type) @property def magnetic(self): """A tuple of the current magnetic field measurements on the X, Y, and Z axes""" self._process_available_packets() # decorator? - return self._readings[_BNO_REPORT_MAGNETIC_FIELD] - + try: + return self._readings[BNO_REPORT_MAGNETIC_FIELD] + except KeyError: + raise RuntimeError("No magfield report found, is it enabled?") from None @property def quaternion(self): """A quaternion representing the current rotation vector""" self._process_available_packets() - return self._readings[_BNO_REPORT_ROTATION_VECTOR] + return self._readings[BNO_REPORT_ROTATION_VECTOR] @property def geomagnetic_quaternion(self): """A quaternion representing the current geomagnetic rotation vector""" self._process_available_packets() - return self._readings[_BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR] + return self._readings[BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR] @property def steps(self): """The number of steps detected since the sensor was initialized""" self._process_available_packets() - return self._readings[_BNO_REPORT_STEP_COUNTER] + return self._readings[BNO_REPORT_STEP_COUNTER] @property def linear_acceleration(self): """A tuple representing the current linear acceleration values on the X, Y, and Z axes in meters per second squared""" self._process_available_packets() - return self._readings[_BNO_REPORT_LINEAR_ACCELERATION] + try: + return self._readings[BNO_REPORT_LINEAR_ACCELERATION] + except KeyError: + raise RuntimeError("No lin. accel report found, is it enabled?") from None @property def acceleration(self): """A tuple representing the acceleration measurements on the X, Y, and Z axes in meters per second squared""" self._process_available_packets() - return self._readings[_BNO_REPORT_ACCELEROMETER] + try: + return self._readings[BNO_REPORT_ACCELEROMETER] + except KeyError: + raise RuntimeError("No accel report found, is it enabled?") from None @property def gyro(self): """A tuple representing Gyro's rotation measurements on the X, Y, and Z axes in radians per second""" self._process_available_packets() - return self._readings[_BNO_REPORT_GYROSCOPE] + try: + return self._readings[BNO_REPORT_GYROSCOPE] + except KeyError: + raise RuntimeError("No gyro report found, is it enabled?") from None @property def shake(self): @@ -419,20 +428,24 @@ def shake(self): this property is not guaranteed to reflect the shake state at the moment it is read """ self._process_available_packets() - shake_detected = self._readings[_BNO_REPORT_SHAKE_DETECTOR] + shake_detected = self._readings[BNO_REPORT_SHAKE_DETECTOR] # clear on read if shake_detected: - self._readings[_BNO_REPORT_SHAKE_DETECTOR] = False + self._readings[BNO_REPORT_SHAKE_DETECTOR] = False # # decorator? def _process_available_packets(self): processed_count = 0 while self._data_ready: - new_packet = self._read_packet() + print("reading a packet") + try: + new_packet = self._read_packet() + except PacketError: + continue self._handle_packet(new_packet) processed_count += 1 self._dbg("") - self._dbg("Processesd", processed_count, "packets") + #print("Processed", processed_count, "packets") self._dbg("") # we'll probably need an exit here for fast sensor rates self._dbg("") @@ -511,14 +524,14 @@ def _process_report(self, report_id, report_bytes): print(outstr) self._dbg("") - if report_id == _BNO_REPORT_STEP_COUNTER: + if report_id == BNO_REPORT_STEP_COUNTER: self._readings[report_id] = _parse_step_couter_report(report_bytes) return - if report_id == _BNO_REPORT_SHAKE_DETECTOR: + if report_id == BNO_REPORT_SHAKE_DETECTOR: shake_detected = _parse_shake_report(report_bytes) # shake not previously detected - auto cleared by 'shake' property - if not self._readings[_BNO_REPORT_SHAKE_DETECTOR]: - self._readings[_BNO_REPORT_SHAKE_DETECTOR] = shake_detected + if not self._readings[BNO_REPORT_SHAKE_DETECTOR]: + self._readings[BNO_REPORT_SHAKE_DETECTOR] = shake_detected return sensor_data = _parse_sensor_report_data(report_bytes) @@ -541,10 +554,11 @@ def _get_feature_enable_report( pack_into(" 5: self._dbg("channel number out of range:", header.channel_number) # data_length, packet_byte_count) diff --git a/examples/bno080_simpletest.py b/examples/bno080_simpletest.py index b670339..aa16634 100644 --- a/examples/bno080_simpletest.py +++ b/examples/bno080_simpletest.py @@ -4,21 +4,27 @@ import time import board import busio +import adafruit_bno080 from adafruit_bno080.i2c import BNO080_I2C from digitalio import DigitalInOut -i2c = busio.I2C(board.SCL, board.SDA) +i2c = busio.I2C(board.SCL, board.SDA, frequency=400000) reset_pin = DigitalInOut(board.G0) bno = BNO080_I2C(i2c, reset=reset_pin) +bno.enable_feature(adafruit_bno080.BNO_REPORT_ACCELEROMETER) +#bno.enable_feature(adafruit_bno080.BNO_REPORT_GYROSCOPE) +#bno.enable_feature(adafruit_bno080.BNO_REPORT_MAGNETIC_FIELD) + while True: - # print("Acceleration:") + print("Acceleration:") 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)) print("") - # print("Gyro:") + """ + print("Gyro:") 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)) print("") @@ -65,3 +71,4 @@ print("") sleep(0.5) + """ From 12bf82e3e322b30f93c7bfc7e90accda59db69f6 Mon Sep 17 00:00:00 2001 From: lady ada Date: Fri, 4 Sep 2020 16:40:16 -0400 Subject: [PATCH 5/6] needs more time to boot --- adafruit_bno080/__init__.py | 7 ++++--- adafruit_bno080/i2c.py | 10 ++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/adafruit_bno080/__init__.py b/adafruit_bno080/__init__.py index 320546b..045b705 100644 --- a/adafruit_bno080/__init__.py +++ b/adafruit_bno080/__init__.py @@ -638,21 +638,22 @@ def hard_reset(self): """Hardware reset the sensor to an initial unconfigured state""" if not self._reset: return + #print("Hard resetting...") self._reset.direction = digitalio.Direction.OUTPUT self._reset.value = True time.sleep(0.01) self._reset.value = False time.sleep(0.01) self._reset.value = True - time.sleep(0.1) + time.sleep(0.5) def soft_reset(self): """Reset the sensor to an initial unconfigured state""" - print("Resetting...", end="") + print("Soft resetting...", end="") data = bytearray(1) data[0] = 1 seq = self._send_packet(BNO_CHANNEL_EXE, data) - time.sleep(0.1) + time.sleep(0.5) for i in range(3): while True: # retry reading packets until ready! diff --git a/adafruit_bno080/i2c.py b/adafruit_bno080/i2c.py index 8d543e9..ed5ed72 100644 --- a/adafruit_bno080/i2c.py +++ b/adafruit_bno080/i2c.py @@ -51,14 +51,8 @@ def _send_packet(self, channel, data): def _read_header(self): """Reads the first 4 bytes available as a header""" - while True: - with self.bus_device_obj as i2c: - try: - i2c.readinto(self._data_buffer, end=4) # this is expecting a header - break - except RuntimeError: - time.sleep(0.1) - pass + with self.bus_device_obj as i2c: + i2c.readinto(self._data_buffer, end=4) # this is expecting a header packet_header = Packet.header_from_buffer(self._data_buffer) self._dbg(packet_header) return packet_header From 1e254f2a0dd59c4b295b0b83907e88cb48394f07 Mon Sep 17 00:00:00 2001 From: lady ada Date: Fri, 4 Sep 2020 17:16:45 -0400 Subject: [PATCH 6/6] require manually enabling. works a treat on feather m4 --- adafruit_bno080/__init__.py | 27 ++++++++++++++++++++------- examples/bno080_simpletest.py | 28 ++++++++++++++++------------ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/adafruit_bno080/__init__.py b/adafruit_bno080/__init__.py index 045b705..baffa9e 100644 --- a/adafruit_bno080/__init__.py +++ b/adafruit_bno080/__init__.py @@ -371,23 +371,33 @@ def magnetic(self): return self._readings[BNO_REPORT_MAGNETIC_FIELD] except KeyError: raise RuntimeError("No magfield report found, is it enabled?") from None + @property def quaternion(self): """A quaternion representing the current rotation vector""" self._process_available_packets() - return self._readings[BNO_REPORT_ROTATION_VECTOR] + try: + return self._readings[BNO_REPORT_ROTATION_VECTOR] + except KeyError: + raise RuntimeError("No quaternion report found, is it enabled?") from None @property def geomagnetic_quaternion(self): """A quaternion representing the current geomagnetic rotation vector""" self._process_available_packets() - return self._readings[BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR] + try: + return self._readings[BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR] + except KeyError: + raise RuntimeError("No geomag quaternion report found, is it enabled?") from None @property def steps(self): """The number of steps detected since the sensor was initialized""" self._process_available_packets() - return self._readings[BNO_REPORT_STEP_COUNTER] + try: + return self._readings[BNO_REPORT_STEP_COUNTER] + except KeyError: + raise RuntimeError("No steps report found, is it enabled?") from None @property def linear_acceleration(self): @@ -428,10 +438,13 @@ def shake(self): this property is not guaranteed to reflect the shake state at the moment it is read """ self._process_available_packets() - shake_detected = self._readings[BNO_REPORT_SHAKE_DETECTOR] - # clear on read - if shake_detected: - self._readings[BNO_REPORT_SHAKE_DETECTOR] = False + try: + shake_detected = self._readings[BNO_REPORT_SHAKE_DETECTOR] + # clear on read + if shake_detected: + self._readings[BNO_REPORT_SHAKE_DETECTOR] = False + except KeyError: + raise RuntimeError("No shake report found, is it enabled?") from None # # decorator? def _process_available_packets(self): diff --git a/examples/bno080_simpletest.py b/examples/bno080_simpletest.py index aa16634..ed15062 100644 --- a/examples/bno080_simpletest.py +++ b/examples/bno080_simpletest.py @@ -8,22 +8,27 @@ from adafruit_bno080.i2c import BNO080_I2C from digitalio import DigitalInOut -i2c = busio.I2C(board.SCL, board.SDA, frequency=400000) -reset_pin = DigitalInOut(board.G0) -bno = BNO080_I2C(i2c, reset=reset_pin) +i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) +reset_pin = DigitalInOut(board.D5) +bno = BNO080_I2C(i2c, reset=reset_pin, debug=False) bno.enable_feature(adafruit_bno080.BNO_REPORT_ACCELEROMETER) -#bno.enable_feature(adafruit_bno080.BNO_REPORT_GYROSCOPE) -#bno.enable_feature(adafruit_bno080.BNO_REPORT_MAGNETIC_FIELD) +bno.enable_feature(adafruit_bno080.BNO_REPORT_GYROSCOPE) +bno.enable_feature(adafruit_bno080.BNO_REPORT_MAGNETIC_FIELD) +bno.enable_feature(adafruit_bno080.BNO_REPORT_LINEAR_ACCELERATION) +bno.enable_feature(adafruit_bno080.BNO_REPORT_ROTATION_VECTOR) +bno.enable_feature(adafruit_bno080.BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR) +bno.enable_feature(adafruit_bno080.BNO_REPORT_STEP_COUNTER) +bno.enable_feature(adafruit_bno080.BNO_REPORT_SHAKE_DETECTOR) while True: - + time.sleep(0.1) + print("Acceleration:") 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)) print("") - """ print("Gyro:") 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)) @@ -45,13 +50,14 @@ % (linear_accel_x, linear_accel_y, linear_accel_z) ) print("") + print("Rotation Vector Quaternion:") quat_i, quat_j, quat_k, quat_real = bno.quaternion # pylint:disable=no-member - print( "I: %0.6f J: %0.6f K: %0.6f Real: %0.6f" % (quat_i, quat_j, quat_k, quat_real) ) print("") + print("Geomagnetic Rotation Vector Quaternion:") ( geo_quat_i, @@ -59,16 +65,14 @@ geo_quat_k, geo_quat_real, ) = bno.geomagnetic_quaternion # pylint:disable=no-member - print( "I: %0.6f J: %0.6f K: %0.6f Real: %0.6f" % (quat_i, quat_j, quat_k, quat_real) ) print("") + print("Steps detected:", bno.steps) print("") + if bno.shake: print("SHAKE DETECTED!") print("") - - sleep(0.5) - """