robot-hat 3.3.2__tar.gz → 3.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robot_hat-3.3.2 → robot_hat-3.3.4}/.github/workflows/ci.yml +5 -5
- {robot_hat-3.3.2 → robot_hat-3.3.4}/.github/workflows/release.yml +2 -2
- {robot_hat-3.3.2 → robot_hat-3.3.4}/CHANGELOG.md +45 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/PKG-INFO +44 -8
- {robot_hat-3.3.2 → robot_hat-3.3.4}/README.md +43 -7
- {robot_hat-3.3.2 → robot_hat-3.3.4}/docs/localization_sensors.md +29 -10
- {robot_hat-3.3.2 → robot_hat-3.3.4}/docs/sense_hat_sensors.md +7 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/imu.py +23 -4
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/i2c/i2c_bus.py +78 -32
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/i2c/smbus_manager.py +1 -1
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/imu_abc.py +8 -1
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/imu.py +5 -1
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/motor/gpio_dc_motor.py +101 -22
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/motor/phase_motor.py +37 -8
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/pin.py +1 -4
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/imu/lsm6ds33.py +2 -1
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/imu/lsm9ds1.py +19 -9
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/imu/sh3001.py +8 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/base_motor_service.py +61 -13
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/motor_service.py +12 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/servo_service.py +56 -40
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/servos/gpio_angular_servo.py +65 -21
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/servos/servo.py +79 -43
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/version.py +3 -3
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat.egg-info/PKG-INFO +44 -8
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat.egg-info/scm_file_list.json +1 -0
- robot_hat-3.3.4/robot_hat.egg-info/scm_version.json +8 -0
- robot_hat-3.3.2/robot_hat.egg-info/scm_version.json +0 -8
- {robot_hat-3.3.2 → robot_hat-3.3.4}/.github/dependabot.yml +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/.gitignore +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/.pre-commit-config.yaml +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/AGENTS.md +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/LICENSE +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/MANIFEST.in +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/Makefile +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/docs/as5048a.md +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/docs/hardware_validation.md +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/docs/lidar_2d.md +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/docs/migration_guide_v2.md +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/docs/migration_guide_v3.md +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/docs/pololu_miniimu9_v5.md +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/hardware-validation/evidence/README.md +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/pyproject.toml +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/pyrightconfig.json +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/common/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/common/event_emitter.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/common/singleton_meta.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/angular_position.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/battery.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/bus.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/battery.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/hts221.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/ina219.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/ina226.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/ina260.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/lidar.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/lis3mdl.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/lps25h.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/lsm6ds33.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/lsm9ds1.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/lsm9ds1_magnetometer.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/motor.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/pwm.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/config/sh3001.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/encoder.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/environment.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/lidar.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/magnetometer.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/motor.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/quadrature.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/data_types/uart.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/adc/INA219.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/adc/INA226.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/adc/INA260.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/adc/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/adc/sunfounder_adc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/angle/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/angle/as5048a.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/angle/as5600l.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/gpio/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/gpio/gpiozero_digital_edge_input.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/pwm/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/pwm/pca9685.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/drivers/pwm/sunfounder_pwm.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/exceptions.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/factories/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/factories/battery_factory.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/factories/motor_factory.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/factories/pwm_factory.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/filedb.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/i2c/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/i2c/i2c_manager.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/i2c/retry_decorator.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/i2c/smbus_protocol.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/angular_position_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/battery_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/digital_edge_input_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/encoder_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/environmental_sensor_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/lidar_2d_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/magnetometer_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/motor_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/pwm_driver_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/quadrature_counter_backend_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/servo_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/smbus_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/spi_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/interfaces/uart_abc.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/angular_position.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/encoder.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/environmental_sensor.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/lidar.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/magnetometer.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/quadrature_counter.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/smbus2.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/spi.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/uart.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/mock/ultrasonic.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/motor/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/motor/i2c_dc_motor.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/motor/mixins/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/motor/mixins/motor_calibration.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/music.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/py.typed +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/angular_position/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/angular_position/as5048a_angular_position.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/angular_position/as5600l_angular_position.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/encoder/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/encoder/as5048a_encoder.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/encoder/as5600l_encoder.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/encoder/gpio_quadrature_counter.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/encoder/quadrature_decoder.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/encoder/quadrature_encoder.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/environmental/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/environmental/hts221.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/environmental/lps25h.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/imu/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/lidar/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/lidar/rplidar_c1.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/magnetometer/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/magnetometer/lis3mdl.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/magnetometer/lsm9ds1.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/ultrasonic/HC_SR04.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sensors/ultrasonic/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/battery/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/battery/ina219_battery.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/battery/ina226_battery.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/battery/ina260_battery.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/battery/sunfounder_battery.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/services/single_motor_service.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/servos/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/spi/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/spi/spidev_device.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/accelerometer.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/address_descriptions.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/grayscale.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/motor.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/pin_descriptions.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/pwm.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/robot.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/sunfounder_servo.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/sunfounder/utils.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/uart/__init__.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/uart/serial_uart.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/uart/usb_uart.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat/utils.py +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat.egg-info/SOURCES.txt +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat.egg-info/dependency_links.txt +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat.egg-info/requires.txt +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/robot_hat.egg-info/top_level.txt +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/setup.cfg +0 -0
- {robot_hat-3.3.2 → robot_hat-3.3.4}/tools/hil_motor_check.py +0 -0
|
@@ -37,7 +37,7 @@ jobs:
|
|
|
37
37
|
persist-credentials: false
|
|
38
38
|
|
|
39
39
|
- name: Set up Python 3.14
|
|
40
|
-
uses: actions/setup-python@
|
|
40
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
41
41
|
with:
|
|
42
42
|
python-version: "3.14"
|
|
43
43
|
cache: pip
|
|
@@ -69,7 +69,7 @@ jobs:
|
|
|
69
69
|
persist-credentials: false
|
|
70
70
|
|
|
71
71
|
- name: Set up Python 3.10
|
|
72
|
-
uses: actions/setup-python@
|
|
72
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
73
73
|
with:
|
|
74
74
|
python-version: "3.10"
|
|
75
75
|
cache: pip
|
|
@@ -132,7 +132,7 @@ jobs:
|
|
|
132
132
|
persist-credentials: false
|
|
133
133
|
|
|
134
134
|
- name: Set up Python ${{ matrix.python-version }}
|
|
135
|
-
uses: actions/setup-python@
|
|
135
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
136
136
|
with:
|
|
137
137
|
python-version: ${{ matrix.python-version }}
|
|
138
138
|
cache: pip
|
|
@@ -159,7 +159,7 @@ jobs:
|
|
|
159
159
|
persist-credentials: false
|
|
160
160
|
|
|
161
161
|
- name: Set up Python 3.12
|
|
162
|
-
uses: actions/setup-python@
|
|
162
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
163
163
|
with:
|
|
164
164
|
python-version: "3.12"
|
|
165
165
|
cache: pip
|
|
@@ -208,7 +208,7 @@ jobs:
|
|
|
208
208
|
persist-credentials: false
|
|
209
209
|
|
|
210
210
|
- name: Set up Python 3.14
|
|
211
|
-
uses: actions/setup-python@
|
|
211
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
212
212
|
with:
|
|
213
213
|
python-version: "3.14"
|
|
214
214
|
cache: pip
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
persist-credentials: false
|
|
34
34
|
|
|
35
35
|
- name: Set up Python 3.14
|
|
36
|
-
uses: actions/setup-python@
|
|
36
|
+
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
|
|
37
37
|
with:
|
|
38
38
|
python-version: "3.14"
|
|
39
39
|
|
|
@@ -160,6 +160,6 @@ jobs:
|
|
|
160
160
|
path: dist/
|
|
161
161
|
|
|
162
162
|
- name: Publish distributions to PyPI
|
|
163
|
-
uses: pypa/gh-action-pypi-publish@
|
|
163
|
+
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
|
|
164
164
|
with:
|
|
165
165
|
attestations: true
|
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.3.4 (2026-11-11)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Normalize `LSM9DS1.read_sample()` to a right-handed sensor-local frame by
|
|
8
|
+
reversing native Y for both acceleration and angular velocity. X, Z, SI
|
|
9
|
+
sensitivities, timestamps, and `read_raw_sample()` native counts are unchanged.
|
|
10
|
+
**Compatibility:** remove any application-side Y inversion that performs this
|
|
11
|
+
same normalization, and express mounting rotations relative to
|
|
12
|
+
`(native X, -native Y, native Z)`. A mounting rotation alone cannot correct the
|
|
13
|
+
previous left-handed output. The separate magnetometer driver is unchanged.
|
|
14
|
+
|
|
15
|
+
### Documentation
|
|
16
|
+
|
|
17
|
+
- Define the shared `IMUSample` and `IMUABC.read_sample()` contract: one
|
|
18
|
+
right-handed local frame, right-hand-rule angular velocity, SI units,
|
|
19
|
+
accelerometer specific force with its stationary gravity response, and host
|
|
20
|
+
monotonic observation timestamps. Document native raw-count semantics and
|
|
21
|
+
keep mounting transforms, bias estimation, and fusion in the application.
|
|
22
|
+
- Identify the native frame references for LSM6DS33 and SH3001 and the
|
|
23
|
+
corresponding sample conventions for the mock IMU.
|
|
24
|
+
|
|
25
|
+
## v3.3.3 (2026-10-16)
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Keep servo travel limits independent of pulse calibration. `Servo` maps
|
|
30
|
+
`real_min_angle`/`real_max_angle` to the configured pulse endpoints; narrower
|
|
31
|
+
`min_angle`/`max_angle` limits reduce travel without stretching the pulse range.
|
|
32
|
+
- Validate servo calibration ranges and reject non-finite commands. Serialize
|
|
33
|
+
servo commands with cleanup and reject writes after close.
|
|
34
|
+
- Initialize GPIO servos without pulses until commanded, and apply the service's
|
|
35
|
+
calibrated center consistently during initialization and calibration updates.
|
|
36
|
+
- Preserve servo calibration state when a hardware write fails and release
|
|
37
|
+
servo resources after failed service initialization.
|
|
38
|
+
- Hold GPIO motor enables low until direction outputs are ready, disable and
|
|
39
|
+
stop motors before releasing GPIO resources. Serialize movement and cleanup.
|
|
40
|
+
- Attempt stops for every managed motor after a command or stop failure, stop
|
|
41
|
+
all motors before service cleanup, and report cleanup failures to callers.
|
|
42
|
+
- Stop phase/enable motors before closing GPIO resources.
|
|
43
|
+
- Serialize shared I²C transactions and cleanup to protect SMBus address
|
|
44
|
+
selection, notify bus managers when context managers close.
|
|
45
|
+
- Keep shared GPIO factories open when deinitializing an individual pin, and
|
|
46
|
+
preserve active bus registrations when a different instance closes.
|
|
47
|
+
|
|
3
48
|
## v3.3.2 (2026-10-11)
|
|
4
49
|
|
|
5
50
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robot_hat
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.4
|
|
4
4
|
Summary: Extensible, typed robotics hardware library for motors, servos, sensors, 2D lidar, I2C, and UART.
|
|
5
5
|
Author-email: Karim Aziiev <karim.aziiev@gmail.com>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -241,7 +241,8 @@ finally:
|
|
|
241
241
|
imu.close()
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
-
The driver reports
|
|
244
|
+
The driver reports a right-handed local frame: native X, reversed native Y,
|
|
245
|
+
and native Z for both acceleration and angular velocity. Configure the transform
|
|
245
246
|
from the HAT to the robot base in the consuming application.
|
|
246
247
|
|
|
247
248
|
The Sense HAT's independently addressed magnetometer, humidity/temperature
|
|
@@ -362,6 +363,22 @@ for examples and custom `MotorABC` requirements.
|
|
|
362
363
|
|
|
363
364
|
GPIO motors are motors that are controlled entirely via direct GPIO calls; no I²C address or external PWM driver is needed. Examples include the Waveshare RPi Motor Driver Board with the MC33886 module.
|
|
364
365
|
|
|
366
|
+
`GPIODCMotor` holds its optional active-high enable pin low during initialization,
|
|
367
|
+
while stopped, and before releasing GPIO resources. It enables the bridge only
|
|
368
|
+
after setting the direction outputs. Each GPIO must belong to one device;
|
|
369
|
+
an indicator LED must not share a motor's enable or direction pin.
|
|
370
|
+
|
|
371
|
+
Motor services stop every motor before releasing resources and attempt every
|
|
372
|
+
stop even if one output fails. Stop and close failures are reported to the caller.
|
|
373
|
+
A failed movement command triggers a stop attempt for all managed motors, and
|
|
374
|
+
closed services reject movement commands.
|
|
375
|
+
|
|
376
|
+
GPIO cleanup releases pin ownership. Software cannot guarantee the electrical
|
|
377
|
+
state during boot, OS halt, power loss, or a crashed process. The motor driver
|
|
378
|
+
must have a hardware-defined disabled state when control inputs are undriven,
|
|
379
|
+
and an independent power cutoff or inhibit appropriate to the mechanism.
|
|
380
|
+
Validate startup, shutdown, and loss of control with wheels clear of the ground.
|
|
381
|
+
|
|
365
382
|
```python
|
|
366
383
|
from robot_hat import GPIODCMotorConfig, MotorFactory, MotorService, setup_env_vars
|
|
367
384
|
|
|
@@ -517,6 +534,29 @@ calibrated_angle = -1 × (input_angle + (-1 × calibration_offset))
|
|
|
517
534
|
|
|
518
535
|
The `ServoService` provides a high-level abstraction for managing servo operations. It allows easy configuration of the calibration mode, movement bounds, and custom calibration logic if needed.
|
|
519
536
|
|
|
537
|
+
`Servo` separates permitted travel (`min_angle`, `max_angle`) from pulse
|
|
538
|
+
calibration (`real_min_angle` at `min_pulse`, `real_max_angle` at `max_pulse`).
|
|
539
|
+
An allowed angle produces the same pulse when travel limits change. For
|
|
540
|
+
example, with measured calibration points of -45° at 1000 µs and +45° at
|
|
541
|
+
2000 µs, limits of -10° to +10° produce approximately 1389–1611 µs.
|
|
542
|
+
The default calibration assumes -90° to +90°; verify it for the particular
|
|
543
|
+
servo. These are two calibration points, not a request to find mechanical
|
|
544
|
+
end stops. Pulse rounding, PWM resolution, backlash, and servo behavior limit
|
|
545
|
+
physical accuracy. Wheel steering angle also depends on the linkage geometry.
|
|
546
|
+
|
|
547
|
+
When using `ServoService`, set its bounds to the desired movement relative
|
|
548
|
+
to the calibrated center. Give its underlying `Servo` the full calibrated
|
|
549
|
+
angle range so that the center offset can be applied without a second travel
|
|
550
|
+
clamp. `GPIOAngularServo` follows gpiozero's convention: its `min_angle` and
|
|
551
|
+
`max_angle` are the measured pulse endpoints; use `ServoService` for narrower
|
|
552
|
+
travel limits. GPIO servos start with pulses disabled until the first angle
|
|
553
|
+
command, including the calibrated center command issued by `ServoService`.
|
|
554
|
+
|
|
555
|
+
Direct `pulse_width_time()` calls are calibration operations and bypass travel
|
|
556
|
+
limits. Use angle commands for normal movement. Non-finite angle, offset, and
|
|
557
|
+
pulse commands are rejected before hardware writes; closed servos reject
|
|
558
|
+
further commands.
|
|
559
|
+
|
|
520
560
|
Here's how to use `ServoCalibrationMode` in your servo configuration:
|
|
521
561
|
|
|
522
562
|
**Example 1**: Steering servo using `ServoCalibrationMode.SUM`
|
|
@@ -548,6 +588,7 @@ driver = PWMFactory.create_pwm_driver(
|
|
|
548
588
|
bus=pwm_config.bus, # either a bus number or an smbus instance.
|
|
549
589
|
config=pwm_config,
|
|
550
590
|
)
|
|
591
|
+
driver.set_pwm_freq(pwm_config.freq)
|
|
551
592
|
|
|
552
593
|
steering_servo = ServoService(
|
|
553
594
|
servo=Servo(
|
|
@@ -560,8 +601,7 @@ steering_servo = ServoService(
|
|
|
560
601
|
# The minimum and maximum pulse widths (in microseconds) corresponding to the servo's physical movement.
|
|
561
602
|
min_pulse=500,
|
|
562
603
|
max_pulse=2500,
|
|
563
|
-
#
|
|
564
|
-
# These values are used to map the logical angle to the physical angle.
|
|
604
|
+
# Measured angles at min_pulse and max_pulse, respectively.
|
|
565
605
|
real_min_angle=-90.0,
|
|
566
606
|
real_max_angle=90.0,
|
|
567
607
|
),
|
|
@@ -571,8 +611,6 @@ steering_servo = ServoService(
|
|
|
571
611
|
calibration_mode=ServoCalibrationMode.SUM,
|
|
572
612
|
calibration_offset=-14.4,
|
|
573
613
|
)
|
|
574
|
-
driver.set_pwm_freq(pwm_config.freq)
|
|
575
|
-
|
|
576
614
|
steering_servo.set_angle(-30) # Turn left.
|
|
577
615
|
steering_servo.set_angle(15) # Turn slightly to the right.
|
|
578
616
|
steering_servo.reset() # Reset to the center position.
|
|
@@ -839,8 +877,6 @@ class MyRobotCar:
|
|
|
839
877
|
else:
|
|
840
878
|
servo = GPIOAngularServo(
|
|
841
879
|
pin=channel,
|
|
842
|
-
min_angle=min_angle,
|
|
843
|
-
max_angle=max_angle,
|
|
844
880
|
)
|
|
845
881
|
return ServoService(
|
|
846
882
|
servo=servo,
|
|
@@ -198,7 +198,8 @@ finally:
|
|
|
198
198
|
imu.close()
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
-
The driver reports
|
|
201
|
+
The driver reports a right-handed local frame: native X, reversed native Y,
|
|
202
|
+
and native Z for both acceleration and angular velocity. Configure the transform
|
|
202
203
|
from the HAT to the robot base in the consuming application.
|
|
203
204
|
|
|
204
205
|
The Sense HAT's independently addressed magnetometer, humidity/temperature
|
|
@@ -319,6 +320,22 @@ for examples and custom `MotorABC` requirements.
|
|
|
319
320
|
|
|
320
321
|
GPIO motors are motors that are controlled entirely via direct GPIO calls; no I²C address or external PWM driver is needed. Examples include the Waveshare RPi Motor Driver Board with the MC33886 module.
|
|
321
322
|
|
|
323
|
+
`GPIODCMotor` holds its optional active-high enable pin low during initialization,
|
|
324
|
+
while stopped, and before releasing GPIO resources. It enables the bridge only
|
|
325
|
+
after setting the direction outputs. Each GPIO must belong to one device;
|
|
326
|
+
an indicator LED must not share a motor's enable or direction pin.
|
|
327
|
+
|
|
328
|
+
Motor services stop every motor before releasing resources and attempt every
|
|
329
|
+
stop even if one output fails. Stop and close failures are reported to the caller.
|
|
330
|
+
A failed movement command triggers a stop attempt for all managed motors, and
|
|
331
|
+
closed services reject movement commands.
|
|
332
|
+
|
|
333
|
+
GPIO cleanup releases pin ownership. Software cannot guarantee the electrical
|
|
334
|
+
state during boot, OS halt, power loss, or a crashed process. The motor driver
|
|
335
|
+
must have a hardware-defined disabled state when control inputs are undriven,
|
|
336
|
+
and an independent power cutoff or inhibit appropriate to the mechanism.
|
|
337
|
+
Validate startup, shutdown, and loss of control with wheels clear of the ground.
|
|
338
|
+
|
|
322
339
|
```python
|
|
323
340
|
from robot_hat import GPIODCMotorConfig, MotorFactory, MotorService, setup_env_vars
|
|
324
341
|
|
|
@@ -474,6 +491,29 @@ calibrated_angle = -1 × (input_angle + (-1 × calibration_offset))
|
|
|
474
491
|
|
|
475
492
|
The `ServoService` provides a high-level abstraction for managing servo operations. It allows easy configuration of the calibration mode, movement bounds, and custom calibration logic if needed.
|
|
476
493
|
|
|
494
|
+
`Servo` separates permitted travel (`min_angle`, `max_angle`) from pulse
|
|
495
|
+
calibration (`real_min_angle` at `min_pulse`, `real_max_angle` at `max_pulse`).
|
|
496
|
+
An allowed angle produces the same pulse when travel limits change. For
|
|
497
|
+
example, with measured calibration points of -45° at 1000 µs and +45° at
|
|
498
|
+
2000 µs, limits of -10° to +10° produce approximately 1389–1611 µs.
|
|
499
|
+
The default calibration assumes -90° to +90°; verify it for the particular
|
|
500
|
+
servo. These are two calibration points, not a request to find mechanical
|
|
501
|
+
end stops. Pulse rounding, PWM resolution, backlash, and servo behavior limit
|
|
502
|
+
physical accuracy. Wheel steering angle also depends on the linkage geometry.
|
|
503
|
+
|
|
504
|
+
When using `ServoService`, set its bounds to the desired movement relative
|
|
505
|
+
to the calibrated center. Give its underlying `Servo` the full calibrated
|
|
506
|
+
angle range so that the center offset can be applied without a second travel
|
|
507
|
+
clamp. `GPIOAngularServo` follows gpiozero's convention: its `min_angle` and
|
|
508
|
+
`max_angle` are the measured pulse endpoints; use `ServoService` for narrower
|
|
509
|
+
travel limits. GPIO servos start with pulses disabled until the first angle
|
|
510
|
+
command, including the calibrated center command issued by `ServoService`.
|
|
511
|
+
|
|
512
|
+
Direct `pulse_width_time()` calls are calibration operations and bypass travel
|
|
513
|
+
limits. Use angle commands for normal movement. Non-finite angle, offset, and
|
|
514
|
+
pulse commands are rejected before hardware writes; closed servos reject
|
|
515
|
+
further commands.
|
|
516
|
+
|
|
477
517
|
Here's how to use `ServoCalibrationMode` in your servo configuration:
|
|
478
518
|
|
|
479
519
|
**Example 1**: Steering servo using `ServoCalibrationMode.SUM`
|
|
@@ -505,6 +545,7 @@ driver = PWMFactory.create_pwm_driver(
|
|
|
505
545
|
bus=pwm_config.bus, # either a bus number or an smbus instance.
|
|
506
546
|
config=pwm_config,
|
|
507
547
|
)
|
|
548
|
+
driver.set_pwm_freq(pwm_config.freq)
|
|
508
549
|
|
|
509
550
|
steering_servo = ServoService(
|
|
510
551
|
servo=Servo(
|
|
@@ -517,8 +558,7 @@ steering_servo = ServoService(
|
|
|
517
558
|
# The minimum and maximum pulse widths (in microseconds) corresponding to the servo's physical movement.
|
|
518
559
|
min_pulse=500,
|
|
519
560
|
max_pulse=2500,
|
|
520
|
-
#
|
|
521
|
-
# These values are used to map the logical angle to the physical angle.
|
|
561
|
+
# Measured angles at min_pulse and max_pulse, respectively.
|
|
522
562
|
real_min_angle=-90.0,
|
|
523
563
|
real_max_angle=90.0,
|
|
524
564
|
),
|
|
@@ -528,8 +568,6 @@ steering_servo = ServoService(
|
|
|
528
568
|
calibration_mode=ServoCalibrationMode.SUM,
|
|
529
569
|
calibration_offset=-14.4,
|
|
530
570
|
)
|
|
531
|
-
driver.set_pwm_freq(pwm_config.freq)
|
|
532
|
-
|
|
533
571
|
steering_servo.set_angle(-30) # Turn left.
|
|
534
572
|
steering_servo.set_angle(15) # Turn slightly to the right.
|
|
535
573
|
steering_servo.reset() # Reset to the center position.
|
|
@@ -796,8 +834,6 @@ class MyRobotCar:
|
|
|
796
834
|
else:
|
|
797
835
|
servo = GPIOAngularServo(
|
|
798
836
|
pin=channel,
|
|
799
|
-
min_angle=min_angle,
|
|
800
|
-
max_angle=max_angle,
|
|
801
837
|
)
|
|
802
838
|
return ServoService(
|
|
803
839
|
servo=servo,
|
|
@@ -8,25 +8,40 @@ mounting transforms, filtering, fusion, wheel geometry, and SLAM state.
|
|
|
8
8
|
|
|
9
9
|
`IMUABC.read_sample()` returns an immutable `IMUSample` with:
|
|
10
10
|
|
|
11
|
-
-
|
|
11
|
+
- accelerometer specific force in metres per second squared, without gravity removal;
|
|
12
12
|
- angular velocity in radians per second;
|
|
13
13
|
- a process-local `time.monotonic_ns()` observation timestamp.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
Both vectors use axis order `(x, y, z)` in the same right-handed local frame.
|
|
16
|
+
Positive angular velocity follows the right-hand rule. A stationary sensor with
|
|
17
|
+
local +Z pointing upward reports approximately `(0, 0, +9.80665)` m/s²; ideal free
|
|
18
|
+
fall reports zero. A concrete driver must document its positive axis directions
|
|
19
|
+
and normalize hardware conventions before returning an `IMUSample`. The
|
|
20
|
+
application applies the mounting rotation into its robot base frame and owns
|
|
21
|
+
bias estimation, gravity compensation, and fusion.
|
|
22
|
+
|
|
23
|
+
`RawIMUSample` contains signed native register counts for diagnostics. Its axis
|
|
24
|
+
signs may differ from the normalized SI sample, as documented by each driver.
|
|
18
25
|
|
|
19
26
|
`SH3001` defaults to ±2 g and ±2000 degrees/s. Its conversion uses the
|
|
20
27
|
manufacturer sensitivity values for those configured ranges and standard gravity
|
|
21
28
|
of 9.80665 m/s². `read_raw_sample()` is available for calibration and diagnostics;
|
|
22
|
-
normal application code should consume `read_sample()`.
|
|
29
|
+
normal application code should consume `read_sample()`. Its local frame follows
|
|
30
|
+
the native right-handed axes in the Senodia SH3001 datasheet, section 7.1,
|
|
31
|
+
Figure 15 (pin-1 marker identifies the package orientation).
|
|
23
32
|
|
|
24
33
|
`LSM9DS1` provides the same six-axis contract for the Raspberry Pi Sense HAT v1
|
|
25
34
|
and v2, and for standalone LSM9DS1 devices. The Sense HAT accelerometer/gyroscope
|
|
26
35
|
function is wired to I²C bus 1 at `0x6a`; its separately addressed magnetometer at
|
|
27
|
-
`0x1c` uses `MagnetometerABC` rather than the six-axis `IMUABC` contract. The IMU
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
`0x1c` uses `MagnetometerABC` rather than the six-axis `IMUABC` contract. The IMU
|
|
37
|
+
driver reports a right-handed local frame for both acceleration and angular
|
|
38
|
+
velocity: `(native X, -native Y, native Z)`. ST's native A/G axes are left-handed
|
|
39
|
+
([datasheet, Figure 1](https://www.st.com/resource/en/datasheet/lsm9ds1.pdf));
|
|
40
|
+
the Y sign normalization lets applications use ordinary rigid mounting rotations.
|
|
41
|
+
With a Sense HAT viewed from above and GPIO at the top, local X points right,
|
|
42
|
+
local Y points toward GPIO, and local Z points out of the board. Robot mounting,
|
|
43
|
+
bias calibration, and fusion belong to the application. `read_raw_sample()`
|
|
44
|
+
returns native signed register counts. The driver's defaults are
|
|
30
45
|
±2 g, ±245 degrees/s, and 119 Hz. Pass a shared `SMBusABC` to combine it safely
|
|
31
46
|
with other drivers on the bus; closing the IMU does not close an injected bus.
|
|
32
47
|
See [Sense HAT environmental and magnetic sensors](sense_hat_sensors.md) for the
|
|
@@ -37,7 +52,9 @@ Pololu's MiniIMU-9 v5 and AltIMU-10 v5, as well as standalone LSM6DS33 carriers.
|
|
|
37
52
|
It defaults to I²C address `0x6b`, ±2 g, ±245 degrees/s, and 104 Hz. The
|
|
38
53
|
independent `LIS3MDL` driver provides magnetic samples in teslas at address
|
|
39
54
|
`0x1e`. Driving the Pololu board's shared `SA0` pin low changes those addresses
|
|
40
|
-
to `0x6a` and `0x1c`, respectively.
|
|
55
|
+
to `0x6a` and `0x1c`, respectively. The IMU's local frame follows the native
|
|
56
|
+
right-handed axes in the [LSM6DS33 datasheet, Figure 1](https://www.pololu.com/file/0J1087/LSM6DS33.pdf).
|
|
57
|
+
Both drivers expose native axes, typed
|
|
41
58
|
configuration, diagnostic raw counts, and caller-owned shared-bus injection.
|
|
42
59
|
In a driver selector, these components should be identified as
|
|
43
60
|
**LSM6DS33 (gyro and accelerometer)** and **LIS3MDL (magnetometer)**.
|
|
@@ -47,7 +64,9 @@ See [Pololu MiniIMU-9 v5 support](pololu_miniimu9_v5.md) for wiring, complete
|
|
|
47
64
|
configuration ranges, and calibration responsibilities.
|
|
48
65
|
|
|
49
66
|
The monotonic timestamp is not Unix time. It is suitable for ordering and fusing
|
|
50
|
-
observations acquired in the same
|
|
67
|
+
observations acquired in the same monotonic clock domain. It records host
|
|
68
|
+
observation time, not a hardware sampling timestamp or a guarantee that the
|
|
69
|
+
accelerometer and gyroscope sampled simultaneously.
|
|
51
70
|
|
|
52
71
|
## Wheel encoders
|
|
53
72
|
|
|
@@ -31,6 +31,13 @@ driver deliberately does not apply hard-iron offsets, soft-iron correction,
|
|
|
31
31
|
declination, board rotation, or heading calculation. Those depend on the
|
|
32
32
|
installation and belong in application calibration or sensor fusion.
|
|
33
33
|
|
|
34
|
+
The six-axis `LSM9DS1.read_sample()` frame is right-handed, with native A/G X,
|
|
35
|
+
reversed native A/G Y, and native A/G Z. Its `read_raw_sample()` frame contains
|
|
36
|
+
native register counts. The independently addressed magnetometer uses the
|
|
37
|
+
magnetic axes shown in ST's datasheet, Figure 1. Applications combining IMU and
|
|
38
|
+
magnetometer samples must align their documented local frames before fusion;
|
|
39
|
+
matching tuple indices alone does not establish a shared frame.
|
|
40
|
+
|
|
34
41
|
The Sense HAT temperature sensors are physically close to the Raspberry Pi and
|
|
35
42
|
LED matrix. Their readings can therefore be warmer than ambient air. The two
|
|
36
43
|
temperature values also come from different physical devices and should remain
|
|
@@ -18,9 +18,23 @@ def _validate_vector(name: str, value: Vector3) -> None:
|
|
|
18
18
|
class IMUSample:
|
|
19
19
|
"""One six-axis inertial observation in SI units.
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
Both vectors use axis order ``(x, y, z)`` in the same right-handed,
|
|
22
|
+
sensor-local frame. Concrete drivers document the positive axis directions
|
|
23
|
+
and normalize hardware axis conventions before constructing this sample.
|
|
24
|
+
Positive angular velocity follows the right-hand rule about each axis.
|
|
25
|
+
|
|
26
|
+
``acceleration_mps2`` is accelerometer specific force in m/s², without
|
|
27
|
+
gravity removal. A stationary sensor with local +Z pointing upward reports
|
|
28
|
+
approximately ``(0, 0, +9.80665)``; ideal free fall reports zero.
|
|
29
|
+
``angular_velocity_radps`` is angular velocity in rad/s.
|
|
30
|
+
|
|
31
|
+
``timestamp_monotonic_ns`` is the host observation time in nanoseconds,
|
|
32
|
+
using ``time.monotonic_ns()`` or an injected clock with the same semantics.
|
|
33
|
+
It is not Unix time or a guarantee of simultaneous hardware acquisition.
|
|
34
|
+
Compare timestamps only within a shared monotonic clock domain.
|
|
35
|
+
|
|
36
|
+
Consumers apply the installation-specific mounting rotation into the robot
|
|
37
|
+
frame and own bias calibration, gravity compensation, and sensor fusion.
|
|
24
38
|
"""
|
|
25
39
|
|
|
26
40
|
acceleration_mps2: Vector3
|
|
@@ -36,7 +50,12 @@ class IMUSample:
|
|
|
36
50
|
|
|
37
51
|
@dataclass(frozen=True)
|
|
38
52
|
class RawIMUSample:
|
|
39
|
-
"""Unscaled signed sensor counts for diagnostics and calibration tools.
|
|
53
|
+
"""Unscaled signed sensor counts for diagnostics and calibration tools.
|
|
54
|
+
|
|
55
|
+
Axis order and signs follow the concrete driver's documented native
|
|
56
|
+
register convention, which may differ from the normalized ``IMUSample``
|
|
57
|
+
frame. The timestamp has the same host monotonic semantics as ``IMUSample``.
|
|
58
|
+
"""
|
|
40
59
|
|
|
41
60
|
accelerometer_counts: RawVector3
|
|
42
61
|
gyroscope_counts: RawVector3
|