Files

212 lines
8.5 KiB
Python
Raw Permalink Normal View History

2026-07-06 17:31:02 -06:00
import busio
import adafruit_bno055
import time
class ImuMode:
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
class IMU:
def __init__(self, scl_pin, sda_pin, mode, mag_offset=None, gyro_offset=None, accel_offset=None):
i2c = busio.I2C(scl_pin, sda_pin)
self._imu = adafruit_bno055.BNO055_I2C(i2c)
print(self._imu.axis_remap)
self._imu.axis_remap = (0, 1, 2, 0, -1, -1)
self._imu.mode = adafruit_bno055.ACCMAG_MODE
time.sleep(1)
self._imu.mode = adafruit_bno055.NDOF_MODE
if mag_offset:
self._imu.offsets_magnetometer = mag_offset
if gyro_offset:
self._imu.offsets_gyroscope = gyro_offset
if accel_offset:
self._imu.offsets_accelerometer = accel_offset
self._accel_update_time = [0, 0, 0, 0]
self.accel_updated = False
self._acceleration = [0, 0, 0]
self._linear_acceleration = [0, 0, 0]
self._gravity = [0, 0, 0]
self._mag_update_time = [0, 0, 0, 0]
self.mag_updated = False
self._mag = [0, 0, 0]
self._gyro_update_time = [0, 0, 0, 0]
self.gyro_updated = False
self._gyro = [0, 0, 0]
self._euler_update_time = [0, 0, 0, 0]
self.euler_updated = False
self._euler = [0, 0, 0]
self._quat_update_time = [0, 0, 0, 0]
self.quat_updated = False
self._quat = [0, 0, 0, 0]
#self._do_calibration()
def _do_calibration(self):
print("Magnetometer: Perform the figure-eight calibration dance.")
while not self._imu.calibration_status[3] == 3:
# Calibration Dance Step One: Magnetometer
# Move sensor away from magnetic interference or shields
# Perform the figure-eight until calibrated
print(f"Mag Calib Status: {100 / 3 * self._imu.calibration_status[3]:3.0f}%")
time.sleep(1)
print("... CALIBRATED")
time.sleep(1)
print("Accelerometer: Perform the six-step calibration dance.")
while not self._imu.calibration_status[2] == 3:
# Calibration Dance Step Two: Accelerometer
# Place sensor board into six stable positions for a few seconds each:
# 1) x-axis right, y-axis up, z-axis away
# 2) x-axis up, y-axis left, z-axis away
# 3) x-axis left, y-axis down, z-axis away
# 4) x-axis down, y-axis right, z-axis away
# 5) x-axis left, y-axis right, z-axis up
# 6) x-axis right, y-axis left, z-axis down
# Repeat the steps until calibrated
print(f"Accel Calib Status: {100 / 3 * self._imu.calibration_status[2]:3.0f}%")
time.sleep(1)
print("... CALIBRATED")
time.sleep(1)
print("Gyroscope: Perform the hold-in-place calibration dance.")
while not self._imu.calibration_status[1] == 3:
# Calibration Dance Step Three: Gyroscope
# Place sensor in any stable position for a few seconds
# (Accelerometer calibration may also calibrate the gyro)
print(f"Gyro Calib Status: {100 / 3 * self._imu.calibration_status[1]:3.0f}%")
time.sleep(1)
print("... CALIBRATED")
time.sleep(1)
print("\nCALIBRATION COMPLETED")
print("Insert these preset offset values into project code:")
print(f" Offsets_Magnetometer: {self._imu.offsets_magnetometer}")
print(f" Offsets_Gyroscope: {self._imu.offsets_gyroscope}")
print(f" Offsets_Accelerometer: {self._imu.offsets_accelerometer}")
def update(self, utc):
if self._acceleration != self._imu.acceleration:
2026-07-06 18:53:28 -06:00
self._acceleration = self._imu.acceleration[:]
self._linear_acceleration = self._imu.linear_acceleration[:]
self._gravity = self._imu.gravity[:]
2026-07-06 17:31:02 -06:00
self._accel_update_time = utc
self.accel_updated = True
def get_accel_message(self):
if not self.accel_updated:
return
self.accel_updated = False
message = bytearray(b'\xd4\x53\x2a\xfa')
message += self._accel_update_time[0].to_bytes(1, 'little')
message += self._accel_update_time[1].to_bytes(1, 'little')
message += self._accel_update_time[2].to_bytes(1, 'little')
message += self._accel_update_time[3].to_bytes(4, 'little')
value_list = list(self._acceleration)
for idx in range(len(value_list)):
neg = int(value_list[idx] < 0)
val = abs(round(value_list[idx]*1000000))
message += neg.to_bytes(1, 'little')
message += val.to_bytes(4, 'little')
value_list = list(self._linear_acceleration)
for idx in range(len(value_list)):
neg = int(value_list[idx] < 0)
val = abs(round(value_list[idx]*1000000))
message += neg.to_bytes(1, 'little')
message += val.to_bytes(4, 'little')
value_list = list(self._gravity)
for idx in range(len(value_list)):
neg = int(value_list[idx] < 0)
val = abs(round(value_list[idx]*1000000))
message += neg.to_bytes(1, 'little')
message += val.to_bytes(4, 'little')
message += b'\x00\x00'
return message
def get_mag_message(self):
if not self.mag_updated:
return
self.mag_updated = False
message = bytearray(b'\xd4\x53\x2a\x39')
message += self._mag_update_time[0].to_bytes(1, 'little')
message += self._mag_update_time[1].to_bytes(1, 'little')
message += self._mag_update_time[2].to_bytes(1, 'little')
message += self._mag_update_time[3].to_bytes(4, 'little')
value_list = list(self._mag)
for idx in range(len(value_list)):
neg = int(value_list[idx] < 0)
message += neg.to_bytes(1, 'little')
val = abs(round(value_list[idx]*1000))
message += val.to_bytes(4, 'little')
message += b'\x00\x00'
return message
def get_gyro_message(self):
if not self.gyro_updated:
return
self.gyro_updated = False
message = bytearray(b'\xd4\x53\x2a\xa7')
message += self._gyro_update_time[0].to_bytes(1, 'little')
message += self._gyro_update_time[1].to_bytes(1, 'little')
message += self._gyro_update_time[2].to_bytes(1, 'little')
message += self._gyro_update_time[3].to_bytes(4, 'little')
value_list = list(self._gyro)
for idx in range(len(value_list)):
neg = int(value_list[idx] < 0)
message += neg.to_bytes(1, 'little')
val = abs(round(value_list[idx]*1000000))
message += val.to_bytes(8, 'little')
message += b'\x00\x00'
return message
def get_euler_message(self):
if not self.euler_updated:
return
self.euler_updated = False
message = bytearray(b'\xd4\x53\x2a\x5e')
message += self._euler_update_time[0].to_bytes(1, 'little')
message += self._euler_update_time[1].to_bytes(1, 'little')
message += self._euler_update_time[2].to_bytes(1, 'little')
message += self._euler_update_time[3].to_bytes(4, 'little')
value_list = list(self._euler)
for idx in range(len(value_list)):
neg = int(value_list[idx] < 0)
message += neg.to_bytes(1, 'little')
val = abs(round(value_list[idx]*1000))
message += val.to_bytes(4, 'little')
message += b'\x00\x00'
return message
def get_quaternion_message(self):
if not self.quat_updated:
return
self.quat_updated = False
message = bytearray(b'\xd4\x53\x2a\xba')
message += self._quat_update_time[0].to_bytes(1, 'little')
message += self._quat_update_time[1].to_bytes(1, 'little')
message += self._quat_update_time[2].to_bytes(1, 'little')
message += self._quat_update_time[3].to_bytes(4, 'little')
value_list = list(self._quat)
for idx in range(len(value_list)):
neg = int(value_list[idx] < 0)
val = abs(round(value_list[idx]*1000000))
message += neg.to_bytes(1, 'little')
message += val.to_bytes(4, 'little')
message += b'\x00\x00'
return message