Skip to content
Snippets Groups Projects
ahrs_library.py 4.2 KiB
Newer Older
import smbus
import time
import math
from ahrs.filters import Madgwick

class IMUReader:
    def __init__(self):
        self.bus = smbus.SMBus(1)  # I2C bus
        self.DEVICE_ADDRESS = 0x68  # MPU6050 device address
        self.mpu_init()

        self.filter = Madgwick()
        self.orientation = [0.0, 0.0, 0.0, 1.0]  # Initial quaternion

    def mpu_init(self):
        PWR_MGMT_1 = 0x6B
        SMPLRT_DIV = 0x19
        CONFIG = 0x1A
        GYRO_CONFIG = 0x1B
        ACCEL_CONFIG = 0x1C
        INT_ENABLE = 0x38

        # Write to sample rate register
        self.bus.write_byte_data(self.DEVICE_ADDRESS, SMPLRT_DIV, 7)
        # Write to power management register to wake up the MPU6050
        self.bus.write_byte_data(self.DEVICE_ADDRESS, PWR_MGMT_1, 1)
        # Write to configuration register
        self.bus.write_byte_data(self.DEVICE_ADDRESS, CONFIG, 0)
        # Write to gyroscope configuration register
        self.bus.write_byte_data(self.DEVICE_ADDRESS, GYRO_CONFIG, 24)
        # Write to accelerometer configuration register
        self.bus.write_byte_data(self.DEVICE_ADDRESS, ACCEL_CONFIG, 0)
        # Enable interrupts
        self.bus.write_byte_data(self.DEVICE_ADDRESS, INT_ENABLE, 1)

    def read_raw_data(self, addr):
        # Read two bytes of data from the given address
        high = self.bus.read_byte_data(self.DEVICE_ADDRESS, addr)
        low = self.bus.read_byte_data(self.DEVICE_ADDRESS, addr + 1)
        value = (high << 8) | low
        if value > 32768:
            value = value - 65536
        return value

    def read_data(self):
        ACCEL_XOUT_H = 0x3B
        ACCEL_YOUT_H = 0x3D
        ACCEL_ZOUT_H = 0x3F
        GYRO_XOUT_H = 0x43
        GYRO_YOUT_H = 0x45
        GYRO_ZOUT_H = 0x47

        # Read accelerometer data
        acc_x = self.read_raw_data(ACCEL_XOUT_H)
        acc_y = self.read_raw_data(ACCEL_YOUT_H)
        acc_z = self.read_raw_data(ACCEL_ZOUT_H)

        # Read gyroscope data
        gyro_x = self.read_raw_data(GYRO_XOUT_H)
        gyro_y = self.read_raw_data(GYRO_YOUT_H)
        gyro_z = self.read_raw_data(GYRO_ZOUT_H)

        ax_offset = 0.01467432
        ay_offset = -0.00603101
        az_offset = 0.06171924

        gx_offset = -0.17447328
        gy_offset = 0.08720611
        gz_offset = 0.16423664

        Ax = (acc_x / 16384.0) - ax_offset
        Ay = (acc_y / 16384.0) - ay_offset
        Az = (acc_z / 16384.0) - az_offset
        Ax = 9.81 * Ax
        Ay = 9.81 * Ay
        Az = 9.81 * Az

        Gx = (gyro_x / 131.0) - gx_offset
        Gy = (gyro_y / 131.0) - gy_offset
        Gz = (gyro_z / 131.0) - gz_offset   

        Gx = Gx / 180 * math.pi
        Gy = Gy / 180 * math.pi
        Gz = Gz / 180 * math.pi

        self.orientation = self.filter.updateIMU(self.orientation,
                                                 [Gx, Gy, Gz],
                                                 [Ax / 9.81, Ay / 9.81, Az / 9.81])
        return Ax, Ay, Az, Gx, Gy, Gz, self.orientation

    def start(self):
        print("Starting IMU data collection...")
        while True:
            Ax, Ay, Az, Gx, Gy, Gz, orientation = self.read_data()

            # Debugging: Raw data
            print(f"Raw Accelerometer: Ax={Ax:.2f}, Ay={Ay:.2f}, Az={Az:.2f}")
            print(f"Raw Gyroscope: Gx={Gx:.2f}, Gy={Gy:.2f}, Gz={Gz:.2f}")

            # Debugging: Orientation
            print(f"Orientation (quaternion): x={orientation[0]:.2f}, y={orientation[1]:.2f}, "
                  f"z={orientation[2]:.2f}, w={orientation[3]:.2f}")

            # Test stability
            print("Orientation (Euler angles):")
            roll = math.atan2(2.0 * (orientation[3] * orientation[0] + orientation[1] * orientation[2]),
                              1.0 - 2.0 * (orientation[0]**2 + orientation[1]**2))
            pitch = math.asin(2.0 * (orientation[3] * orientation[1] - orientation[2] * orientation[0]))
            yaw = math.atan2(2.0 * (orientation[3] * orientation[2] + orientation[0] * orientation[1]),
                             1.0 - 2.0 * (orientation[1]**2 + orientation[2]**2))
            print(f"Roll={roll:.2f}, Pitch={pitch:.2f}, Yaw={yaw:.2f}")

            time.sleep(0.5)


if __name__ == "__main__":
    imu_reader = IMUReader()
    imu_reader.start()