@@ -159,30 +159,48 @@ def _ensure_imu_initialized(self):
159159 if not self ._initialized or self ._imu_driver is not None :
160160 return self ._imu_driver is not None
161161
162- # Try QMI8658 first (Waveshare board)
163162 if self ._i2c_bus :
164163 try :
165- from drivers .imu_sensor .qmi8658 import QMI8658
166- chip_id = self ._i2c_bus .readfrom_mem (self ._i2c_address , 0x00 , 1 )[0 ] # PARTID register
164+ print ("Try QMI8658 first (Waveshare board)" )
165+ # PARTID register:
166+ chip_id = self ._i2c_bus .readfrom_mem (self ._i2c_address , 0x00 , 1 )[0 ]
167+ print (f"{ chip_id = :#04x} " )
167168 if chip_id == 0x05 : # QMI8685_PARTID
168169 self ._imu_driver = _QMI8658Driver (self ._i2c_bus , self ._i2c_address )
169170 self ._register_qmi8658_sensors ()
170171 self ._load_calibration ()
172+ print ("Use QMI8658, ok" )
171173 return True
172- except :
173- pass
174+ except Exception as e :
175+ print ( "No QMI8658:" , e )
174176
175- # Try WSEN_ISDS (fri3d_2024) or LSM6DSO (fri3d_2026)
176177 try :
177- from drivers .imu_sensor .wsen_isds import Wsen_Isds
178- chip_id = self ._i2c_bus .readfrom_mem (self ._i2c_address , 0x0F , 1 )[0 ] # WHO_AM_I register - could also use Wsen_Isds.get_chip_id()
179- if chip_id == 0x6A or chip_id == 0x6C : # WSEN_ISDS WHO_AM_I 0x6A (Fri3d 2024) or 0x6C (Fri3d 2026)
178+ print ("Try WSEN_ISDS (fri3d_2024) or LSM6DSO (fri3d_2026)" )
179+ # WHO_AM_I register - could also use Wsen_Isds.get_chip_id():
180+ chip_id = self ._i2c_bus .readfrom_mem (self ._i2c_address , 0x0F , 1 )[0 ]
181+ print (f"{ chip_id = :#04x} " )
182+ # WSEN_ISDS WHO_AM_I 0x6A (Fri3d 2024) or 0x6C (Fri3d 2026):
183+ if chip_id == 0x6A or chip_id == 0x6C :
180184 self ._imu_driver = _WsenISDSDriver (self ._i2c_bus , self ._i2c_address )
181185 self ._register_wsen_isds_sensors ()
182186 self ._load_calibration ()
187+ print ("Use WSEN_ISDS/LSM6DSO, ok" )
183188 return True
184- except :
185- pass
189+ except Exception as e :
190+ print ("No WSEN_ISDS or LSM6DSO:" , e )
191+
192+ try :
193+ print ("Try MPU6886 (M5Stack FIRE)" )
194+ chip_id = self ._i2c_bus .readfrom_mem (self ._i2c_address , 0x75 , 1 )[0 ]
195+ print (f"{ chip_id = :#04x} " )
196+ if chip_id == 0x19 :
197+ self ._imu_driver = _MPU6886Driver (self ._i2c_bus , self ._i2c_address )
198+ self ._register_mpu6886_sensors ()
199+ self ._load_calibration ()
200+ print ("Use MPU6886, ok" )
201+ return True
202+ except Exception as e :
203+ print ("No MPU6886:" , e )
186204
187205 return False
188206
@@ -575,7 +593,39 @@ def _register_qmi8658_sensors(self):
575593 power_ma = 0
576594 )
577595 ]
578-
596+
597+ def _register_mpu6886_sensors (self ):
598+ """Register MPU6886 sensors in sensor list."""
599+ self ._sensor_list = [
600+ Sensor (
601+ name = "MPU6886 Accelerometer" ,
602+ sensor_type = TYPE_ACCELEROMETER ,
603+ vendor = "InvenSense" ,
604+ version = 1 ,
605+ max_range = "±16g" ,
606+ resolution = "0.0024 m/s²" ,
607+ power_ma = 0.2 ,
608+ ),
609+ Sensor (
610+ name = "MPU6886 Gyroscope" ,
611+ sensor_type = TYPE_GYROSCOPE ,
612+ vendor = "InvenSense" ,
613+ version = 1 ,
614+ max_range = "±256 deg/s" ,
615+ resolution = "0.002 deg/s" ,
616+ power_ma = 0.7 ,
617+ ),
618+ Sensor (
619+ name = "MPU6886 Temperature" ,
620+ sensor_type = TYPE_IMU_TEMPERATURE ,
621+ vendor = "InvenSense" ,
622+ version = 1 ,
623+ max_range = "-40°C to +85°C" ,
624+ resolution = "0.05°C" ,
625+ power_ma = 0 ,
626+ ),
627+ ]
628+
579629 def _register_wsen_isds_sensors (self ):
580630 """Register WSEN_ISDS sensors in sensor list."""
581631 self ._sensor_list = [
@@ -813,6 +863,92 @@ def set_calibration(self, accel_offsets, gyro_offsets):
813863 self .gyro_offset = list (gyro_offsets )
814864
815865
866+ class _MPU6886Driver (_IMUDriver ):
867+ """Wrapper for MPU6886 IMU (Waveshare board)."""
868+
869+ def __init__ (self , i2c_bus , address ):
870+ from drivers .imu_sensor .mpu6886 import MPU6886
871+
872+ self .sensor = MPU6886 (i2c_bus , address = address )
873+ # Software calibration offsets (MPU6886 has no built-in calibration)
874+ self .accel_offset = [0.0 , 0.0 , 0.0 ]
875+ self .gyro_offset = [0.0 , 0.0 , 0.0 ]
876+
877+ def read_temperature (self ):
878+ """Read temperature in °C."""
879+ return self .sensor .temperature
880+
881+ def read_acceleration (self ):
882+ """Read acceleration in m/s² (converts from G)."""
883+ ax , ay , az = self .sensor .acceleration
884+ # Convert G to m/s² and apply calibration
885+ return (
886+ (ax * _GRAVITY ) - self .accel_offset [0 ],
887+ (ay * _GRAVITY ) - self .accel_offset [1 ],
888+ (az * _GRAVITY ) - self .accel_offset [2 ],
889+ )
890+
891+ def read_gyroscope (self ):
892+ """Read gyroscope in deg/s (already in correct units)."""
893+ gx , gy , gz = self .sensor .gyro
894+ # Apply calibration
895+ return (
896+ gx - self .gyro_offset [0 ],
897+ gy - self .gyro_offset [1 ],
898+ gz - self .gyro_offset [2 ],
899+ )
900+
901+ def calibrate_accelerometer (self , samples ):
902+ """Calibrate accelerometer (device must be stationary)."""
903+ sum_x , sum_y , sum_z = 0.0 , 0.0 , 0.0
904+
905+ for _ in range (samples ):
906+ ax , ay , az = self .sensor .acceleration
907+ sum_x += ax * _GRAVITY
908+ sum_y += ay * _GRAVITY
909+ sum_z += az * _GRAVITY
910+ time .sleep_ms (10 )
911+
912+ if FACING_EARTH == FACING_EARTH :
913+ sum_z *= - 1
914+
915+ # Average offsets (assuming Z-axis should read +9.8 m/s²)
916+ self .accel_offset [0 ] = sum_x / samples
917+ self .accel_offset [1 ] = sum_y / samples
918+ self .accel_offset [2 ] = (sum_z / samples ) - _GRAVITY
919+
920+ return tuple (self .accel_offset )
921+
922+ def calibrate_gyroscope (self , samples ):
923+ """Calibrate gyroscope (device must be stationary)."""
924+ sum_x , sum_y , sum_z = 0.0 , 0.0 , 0.0
925+
926+ for _ in range (samples ):
927+ gx , gy , gz = self .sensor .gyro
928+ sum_x += gx
929+ sum_y += gy
930+ sum_z += gz
931+ time .sleep_ms (10 )
932+
933+ # Average offsets (should be 0 when stationary)
934+ self .gyro_offset [0 ] = sum_x / samples
935+ self .gyro_offset [1 ] = sum_y / samples
936+ self .gyro_offset [2 ] = sum_z / samples
937+
938+ return tuple (self .gyro_offset )
939+
940+ def get_calibration (self ):
941+ """Get current calibration."""
942+ return {"accel_offsets" : self .accel_offset , "gyro_offsets" : self .gyro_offset }
943+
944+ def set_calibration (self , accel_offsets , gyro_offsets ):
945+ """Set calibration from saved values."""
946+ if accel_offsets :
947+ self .accel_offset = list (accel_offsets )
948+ if gyro_offsets :
949+ self .gyro_offset = list (gyro_offsets )
950+
951+
816952class _WsenISDSDriver (_IMUDriver ):
817953 """Wrapper for WSEN_ISDS IMU (Fri3d badge)."""
818954
0 commit comments