Skip to content

Commit c2b3b63

Browse files
committed
pbio/imu: Add user adjustable heading correction.
1 parent 368da6b commit c2b3b63

File tree

6 files changed

+78
-27
lines changed

6 files changed

+78
-27
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,19 @@
99
- Allow Bluetooth to be toggled off and on with the Bluetooth button on the
1010
Prime Hub and the Inventor Hub ([support#1615]), and have this state persist
1111
between reboots.
12+
- Added `heading_correction` to `hub.imu.settings` to allow for automatic
13+
correction of the `hub.imu.heading()` value ([support#1678]).
1214

1315
### Changed
1416

1517
- When upgrading the firmware to a new version, the user program will now
1618
be erased. This avoids issues with incompatible program files ([support#1622]).
19+
- The `angular_velocity_threshold`, and `acceleration_threshold` settings
20+
in `hub.imu.settings` are now persistent between reboots.
1721

1822
[support#1615]: https://github.com/pybricks/support/issues/1615
1923
[support#1622]: https://github.com/pybricks/support/issues/1622
24+
[support#1678]: https://github.com/pybricks/support/issues/1678
2025

2126
## [3.5.0] - 2024-04-11
2227

lib/pbio/include/pbio/imu.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ bool pbio_imu_is_stationary(void);
2828

2929
bool pbio_imu_is_ready(void);
3030

31-
void pbio_imu_get_stationary_thresholds(float *angular_velocity, float *acceleration);
31+
void pbio_imu_get_settings(float *angular_velocity, float *acceleration, float *heading_correction);
3232

33-
void pbio_imu_set_stationary_thresholds(float angular_velocity, float acceleration);
33+
pbio_error_t pbio_imu_set_settings(float angular_velocity, float acceleration, float heading_correction);
3434

3535
void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values);
3636

@@ -59,7 +59,11 @@ static inline bool pbio_imu_is_stationary(void) {
5959
return false;
6060
}
6161

62-
static inline void pbio_imu_set_stationary_thresholds(float angular_velocity, float acceleration) {
62+
static inline void pbio_imu_get_settings(float *angular_velocity, float *acceleration, float *heading_correction) {
63+
}
64+
65+
static inline pbio_error_t pbio_imu_set_settings(float angular_velocity, float acceleration, float heading_correction) {
66+
return PBIO_ERROR_NOT_SUPPORTED;
6367
}
6468

6569
static inline void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values) {

lib/pbio/include/pbsys/storage_settings.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ typedef struct _pbsys_storage_settings_t {
4141
float gyro_stationary_threshold;
4242
/** Acceleration threshold below which the IMU is considered stationary, in mm/s^2. */
4343
float accel_stationary_threshold;
44+
/**
45+
* Number of degrees measured for one full turn along the user Z axis. This
46+
* is used to correct the heading value. Other rotation methods are not
47+
* affected.
48+
*/
49+
float heading_correction;
4450
#endif
4551
} pbsys_storage_settings_t;
4652

lib/pbio/src/imu.c

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <stdbool.h>
55
#include <string.h>
6+
#include <math.h>
67

78
#include <pbdrv/clock.h>
89
#include <pbdrv/imu.h>
@@ -133,34 +134,52 @@ bool pbio_imu_is_stationary(void) {
133134
return pbdrv_imu_is_stationary(imu_dev);
134135
}
135136

137+
// Measured rotation of the Z axis in the user frame for exactly one rotation
138+
// of the hub. This will be used to adjust the heading value, which is slightly
139+
// different for each hub.
140+
static float heading_degrees_per_rotation = 360.0f;
141+
136142
/**
137-
* Sets the thresholds that define when the hub is stationary. When the
138-
* measurements are steadily below these levels, the orientation module
139-
* automatically recalibrates.
140-
*
141-
* If a value is negative, it is ignored.
143+
* Sets the IMU settings. This includes the thresholds that define when the hub
144+
* is stationary. When the measurements are steadily below these levels, the
145+
* orientation module automatically recalibrates. Also includes the hub-specific
146+
* correction value to get a more accurate heading value.
147+
*
148+
* If a value is nan, it is ignored.
142149
*
143-
* @param [in] angular_velocity Angular velocity threshold in deg/s.
144-
* @param [in] acceleration Acceleration threshold in mm/s^2
150+
* @param [in] angular_velocity Angular velocity threshold in deg/s.
151+
* @param [in] acceleration Acceleration threshold in mm/s^2
152+
* @param [in] heading_correction Measured degrees per full rotation of the hub.
153+
* @returns ::PBIO_ERROR_INVALID_ARG if the heading correction is out of range,
154+
* otherwise ::PBIO_SUCCESS.
145155
*/
146-
void pbio_imu_set_stationary_thresholds(float angular_velocity, float acceleration) {
147-
if (angular_velocity >= 0) {
156+
pbio_error_t pbio_imu_set_settings(float angular_velocity, float acceleration, float heading_correction) {
157+
if (!isnan(angular_velocity)) {
148158
imu_config->gyro_stationary_threshold = pbio_int_math_bind(angular_velocity / imu_config->gyro_scale, 1, INT16_MAX);
149159
}
150-
if (acceleration >= 0) {
160+
if (!isnan(acceleration)) {
151161
imu_config->accel_stationary_threshold = pbio_int_math_bind(acceleration / imu_config->accel_scale, 1, INT16_MAX);
152162
}
163+
if (!isnan(heading_correction)) {
164+
if (heading_correction < 350 || heading_correction > 370) {
165+
return PBIO_ERROR_INVALID_ARG;
166+
}
167+
heading_degrees_per_rotation = heading_correction;
168+
}
169+
return PBIO_SUCCESS;
153170
}
154171

155172
/**
156173
* Gets the thresholds that define when the hub is stationary.
157174
*
158-
* @param [out] angular_velocity Angular velocity threshold in deg/s.
159-
* @param [out] acceleration Acceleration threshold in mm/s^2
175+
* @param [out] angular_velocity Angular velocity threshold in deg/s.
176+
* @param [out] acceleration Acceleration threshold in mm/s^2
177+
* @param [out] heading_correction Measured degrees per full rotation of the hub.
160178
*/
161-
void pbio_imu_get_stationary_thresholds(float *angular_velocity, float *acceleration) {
179+
void pbio_imu_get_settings(float *angular_velocity, float *acceleration, float *heading_correction) {
162180
*angular_velocity = imu_config->gyro_stationary_threshold * imu_config->gyro_scale;
163181
*acceleration = imu_config->accel_stationary_threshold * imu_config->accel_scale;
182+
*heading_correction = heading_degrees_per_rotation;
164183
}
165184

166185
/**
@@ -216,7 +235,8 @@ pbio_geometry_side_t pbio_imu_get_up_side(void) {
216235
static float heading_offset = 0;
217236

218237
/**
219-
* Reads the estimated IMU heading in degrees, accounting for user offset.
238+
* Reads the estimated IMU heading in degrees, accounting for user offset and
239+
* user-specified heading correction scaling constant.
220240
*
221241
* Heading is defined as clockwise positive.
222242
*
@@ -228,7 +248,7 @@ float pbio_imu_get_heading(void) {
228248

229249
pbio_geometry_vector_map(&pbio_orientation_base_orientation, &single_axis_rotation, &heading_mapped);
230250

231-
return -heading_mapped.z - heading_offset;
251+
return -heading_mapped.z * 360.0f / heading_degrees_per_rotation - heading_offset;
232252
}
233253

234254
/**

lib/pbio/sys/storage_settings.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ void pbsys_storage_settings_set_defaults(pbsys_storage_settings_t *settings) {
3131
#if PBIO_CONFIG_IMU
3232
settings->gyro_stationary_threshold = 5;
3333
settings->accel_stationary_threshold = 2500;
34+
settings->heading_correction = 360.0f;
3435
#endif // PBIO_CONFIG_IMU
3536
}
3637

@@ -41,7 +42,12 @@ void pbsys_storage_settings_set_defaults(pbsys_storage_settings_t *settings) {
4142
*/
4243
void pbsys_storage_settings_apply_loaded_settings(pbsys_storage_settings_t *settings) {
4344
#if PBIO_CONFIG_IMU
44-
pbio_imu_set_stationary_thresholds(settings->gyro_stationary_threshold, settings->accel_stationary_threshold);
45+
// return value not checked, assumed to be set valid previously
46+
pbio_imu_set_settings(
47+
settings->gyro_stationary_threshold,
48+
settings->accel_stationary_threshold,
49+
settings->heading_correction
50+
);
4551
#endif // PBIO_CONFIG_IMU
4652
}
4753

@@ -56,7 +62,11 @@ void pbsys_storage_settings_save_imu_settings(void) {
5662
return;
5763
}
5864
#if PBIO_CONFIG_IMU
59-
pbio_imu_get_stationary_thresholds(&settings->gyro_stationary_threshold, &settings->accel_stationary_threshold);
65+
pbio_imu_get_settings(
66+
&settings->gyro_stationary_threshold,
67+
&settings->accel_stationary_threshold,
68+
&settings->heading_correction
69+
);
6070
pbsys_storage_request_write();
6171
#endif // PBIO_CONFIG_IMU
6272
}

pybricks/common/pb_type_imu.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,27 +164,33 @@ STATIC mp_obj_t pb_type_imu_settings(size_t n_args, const mp_obj_t *pos_args, mp
164164
PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
165165
pb_type_imu_obj_t, self,
166166
PB_ARG_DEFAULT_NONE(angular_velocity_threshold),
167-
PB_ARG_DEFAULT_NONE(acceleration_threshold));
167+
PB_ARG_DEFAULT_NONE(acceleration_threshold),
168+
PB_ARG_DEFAULT_NONE(heading_correction));
168169

169170
(void)self;
170171

171172
// Return current values if no arguments are given.
172-
if (angular_velocity_threshold_in == mp_const_none && acceleration_threshold_in == mp_const_none) {
173+
if (angular_velocity_threshold_in == mp_const_none &&
174+
acceleration_threshold_in == mp_const_none &&
175+
heading_correction_in == mp_const_none) {
173176
float angular_velocity;
174177
float acceleration;
175-
pbio_imu_get_stationary_thresholds(&angular_velocity, &acceleration);
178+
float heading_correction;
179+
pbio_imu_get_settings(&angular_velocity, &acceleration, &heading_correction);
176180
mp_obj_t ret[] = {
177181
mp_obj_new_float_from_f(angular_velocity),
178182
mp_obj_new_float_from_f(acceleration),
183+
mp_obj_new_float_from_f(heading_correction),
179184
};
180185
return mp_obj_new_tuple(MP_ARRAY_SIZE(ret), ret);
181186
}
182187

183188
// Otherwise set new values, only if given.
184-
pbio_imu_set_stationary_thresholds(
185-
angular_velocity_threshold_in == mp_const_none ? -1.0f : mp_obj_get_float(angular_velocity_threshold_in),
186-
acceleration_threshold_in == mp_const_none ? -1.0f : mp_obj_get_float(acceleration_threshold_in)
187-
);
189+
pb_assert(pbio_imu_set_settings(
190+
angular_velocity_threshold_in == mp_const_none ? NAN : mp_obj_get_float(angular_velocity_threshold_in),
191+
acceleration_threshold_in == mp_const_none ? NAN : mp_obj_get_float(acceleration_threshold_in),
192+
heading_correction_in == mp_const_none ? NAN : mp_obj_get_float(heading_correction_in)
193+
));
188194

189195
// Request that changed settings are saved on shutdown.
190196
pbsys_storage_settings_save_imu_settings();

0 commit comments

Comments
 (0)