Skip to content

Commit f00e345

Browse files
committed
pbio/imu: Calibrate acceleration values.
1 parent 60759b4 commit f00e345

File tree

4 files changed

+74
-67
lines changed

4 files changed

+74
-67
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
## [Unreleased]
66

7+
### Added
8+
9+
- Added optional `calibrated=True` parameter to `acceleration()` and `up()`
10+
methods of the IMU ([support#943]).
11+
712
### Changed
813

914
- The method `DriveBase.angle()` now returns a float ([support#1844]). This
@@ -13,8 +18,9 @@
1318
- Fixed `DriveBase.angle()` getting an incorrectly rounded gyro value, which
1419
could cause `turn(360)` to be off by a degree ([support#1844]).
1520

16-
[support#1844]: https://github.com/pybricks/support/issues/1844
21+
[support#943]: https://github.com/pybricks/support/issues/943
1722
[support#1886]: https://github.com/pybricks/support/issues/1886
23+
[support#1844]: https://github.com/pybricks/support/issues/1844
1824

1925
## [3.6.0b2] - 2024-10-15
2026

lib/pbio/include/pbio/imu.h

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,10 @@ typedef struct {
6363
* FIXME: Deprecate and use 3D correction.
6464
*/
6565
float heading_correction;
66-
/** Positive acceleration value for gravity along the X axis. */
67-
float gravity_x_pos;
68-
/** Negative acceleration value for gravity along the X axis. */
69-
float gravity_x_neg;
70-
/** Positive acceleration value for gravity along the Y axis. */
71-
float gravity_y_pos;
72-
/** Negative acceleration value for gravity along the Y axis. */
73-
float gravity_y_neg;
74-
/** Positive acceleration value for gravity along the Z axis. */
75-
float gravity_z_pos;
76-
/** Negative acceleration value for gravity along the Z axis. */
77-
float gravity_z_neg;
66+
/** Positive acceleration values */
67+
pbio_geometry_xyz_t gravity_pos;
68+
/** Negative acceleration values */
69+
pbio_geometry_xyz_t gravity_neg;
7870
} pbio_imu_persistent_settings_t;
7971

8072
#if PBIO_CONFIG_IMU
@@ -97,11 +89,11 @@ pbio_error_t pbio_imu_set_settings(pbio_imu_persistent_settings_t *new_settings)
9789

9890
void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values);
9991

100-
void pbio_imu_get_acceleration(pbio_geometry_xyz_t *values);
92+
void pbio_imu_get_acceleration(pbio_geometry_xyz_t *values, bool calibrated);
10193

10294
pbio_error_t pbio_imu_get_single_axis_rotation(pbio_geometry_xyz_t *axis, float *angle);
10395

104-
pbio_geometry_side_t pbio_imu_get_up_side(void);
96+
pbio_geometry_side_t pbio_imu_get_up_side(bool calibrated);
10597

10698
float pbio_imu_get_heading(void);
10799

@@ -139,10 +131,10 @@ static inline pbio_error_t pbio_imu_set_settings(float angular_velocity, float a
139131
static inline void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values) {
140132
}
141133

142-
static inline void pbio_imu_get_acceleration(pbio_geometry_xyz_t *values) {
134+
static inline void pbio_imu_get_acceleration(pbio_geometry_xyz_t *values, bool calibrated) {
143135
}
144136

145-
static inline pbio_geometry_side_t pbio_imu_get_up_side(void) {
137+
static inline pbio_geometry_side_t pbio_imu_get_up_side(bool calibrated) {
146138
return PBIO_GEOMETRY_SIDE_TOP;
147139
}
148140

lib/pbio/src/imu.c

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,8 @@ void pbio_imu_set_default_settings(pbio_imu_persistent_settings_t *settings) {
5858
settings->gyro_stationary_threshold = 3.0f;
5959
settings->accel_stationary_threshold = 2500.0f;
6060
settings->heading_correction = 360.0f;
61-
settings->gravity_x_pos = standard_gravity;
62-
settings->gravity_x_neg = -standard_gravity;
63-
settings->gravity_y_pos = standard_gravity;
64-
settings->gravity_y_neg = -standard_gravity;
65-
settings->gravity_z_pos = standard_gravity;
66-
settings->gravity_z_neg = -standard_gravity;
61+
settings->gravity_pos.x = settings->gravity_pos.y = settings->gravity_pos.z = standard_gravity;
62+
settings->gravity_neg.x = settings->gravity_neg.y = settings->gravity_neg.z = -standard_gravity;
6763
pbio_imu_apply_pbdrv_settings(settings);
6864
}
6965

@@ -80,7 +76,8 @@ void pbio_imu_apply_loaded_settings(pbio_imu_persistent_settings_t *settings) {
8076

8177
// Cached sensor values that can be read at any time without polling again.
8278
static pbio_geometry_xyz_t angular_velocity; // deg/s, in hub frame, already adjusted for bias.
83-
static pbio_geometry_xyz_t acceleration; // mm/s^2, in hub frame
79+
static pbio_geometry_xyz_t acceleration_uncalibrated; // mm/s^2, in hub frame
80+
static pbio_geometry_xyz_t acceleration_calibrated; // mm/s^2, in hub frame
8481
static pbio_geometry_xyz_t gyro_bias;
8582
static pbio_geometry_xyz_t single_axis_rotation; // deg, in hub frame
8683

@@ -89,7 +86,16 @@ static void pbio_imu_handle_frame_data_func(int16_t *data) {
8986
for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(angular_velocity.values); i++) {
9087
// Update angular velocity and acceleration cache so user can read them.
9188
angular_velocity.values[i] = data[i] * imu_config->gyro_scale - gyro_bias.values[i];
92-
acceleration.values[i] = data[i + 3] * imu_config->accel_scale;
89+
acceleration_uncalibrated.values[i] = data[i + 3] * imu_config->accel_scale;
90+
91+
// Once settings loaded, maintain calibrated cached values.
92+
if (persistent_settings) {
93+
float acceleration_offset = (persistent_settings->gravity_pos.values[i] + persistent_settings->gravity_neg.values[i]) / 2;
94+
float acceleration_scale = (persistent_settings->gravity_pos.values[i] - persistent_settings->gravity_neg.values[i]) / 2;
95+
acceleration_calibrated.values[i] = (acceleration_uncalibrated.values[i] - acceleration_offset) * standard_gravity / acceleration_scale;
96+
} else {
97+
acceleration_calibrated.values[i] = acceleration_uncalibrated.values[i];
98+
}
9399

94100
// Update "heading" on all axes. This is not useful for 3D attitude
95101
// estimation, but it allows the user to get a 1D heading even with
@@ -246,21 +252,17 @@ pbio_error_t pbio_imu_set_settings(pbio_imu_persistent_settings_t *new_settings)
246252
}
247253

248254
if (new_settings->flags & PBIO_IMU_SETTINGS_FLAGS_ACCEL_CALIBRATED) {
249-
if (pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_x_pos, true) ||
250-
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_x_neg, false) ||
251-
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_y_pos, true) ||
252-
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_y_neg, false) ||
253-
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_z_pos, true) ||
254-
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_z_neg, false)) {
255+
if (pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_pos.x, true) ||
256+
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_neg.x, false) ||
257+
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_pos.y, true) ||
258+
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_neg.y, false) ||
259+
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_pos.z, true) ||
260+
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_neg.z, false)) {
255261
return PBIO_ERROR_INVALID_ARG;
256262
}
257263
persistent_settings->flags |= PBIO_IMU_SETTINGS_FLAGS_ACCEL_CALIBRATED;
258-
persistent_settings->gravity_x_pos = new_settings->gravity_x_pos;
259-
persistent_settings->gravity_x_neg = new_settings->gravity_x_neg;
260-
persistent_settings->gravity_y_pos = new_settings->gravity_y_pos;
261-
persistent_settings->gravity_y_neg = new_settings->gravity_y_neg;
262-
persistent_settings->gravity_z_pos = new_settings->gravity_z_pos;
263-
persistent_settings->gravity_z_neg = new_settings->gravity_z_neg;
264+
persistent_settings->gravity_pos = new_settings->gravity_pos;
265+
persistent_settings->gravity_neg = new_settings->gravity_neg;
264266
}
265267

266268
// If any settings were changed, request saving.
@@ -275,14 +277,6 @@ pbio_error_t pbio_imu_set_settings(pbio_imu_persistent_settings_t *new_settings)
275277
return PBIO_SUCCESS;
276278
}
277279

278-
/**
279-
* Gets the thresholds that define when the hub is stationary.
280-
*
281-
* @param [out] angular_velocity Angular velocity threshold in deg/s.
282-
* @param [out] acceleration Acceleration threshold in mm/s^2
283-
* @param [out] heading_correction Measured degrees per full rotation of the hub.
284-
*/
285-
286280
/**
287281
* Gets the IMU settings
288282
*
@@ -310,10 +304,13 @@ void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values) {
310304
/**
311305
* Gets the cached IMU acceleration in mm/s^2.
312306
*
307+
* @param [in] calibrated Whether to use calibrated or uncalibrated data.
308+
*
313309
* @param [out] values The acceleration vector.
314310
*/
315-
void pbio_imu_get_acceleration(pbio_geometry_xyz_t *values) {
316-
pbio_geometry_vector_map(&pbio_orientation_base_orientation, &acceleration, values);
311+
void pbio_imu_get_acceleration(pbio_geometry_xyz_t *values, bool calibrated) {
312+
pbio_geometry_xyz_t *acceleration = calibrated ? &acceleration_calibrated : &acceleration_uncalibrated;
313+
pbio_geometry_vector_map(&pbio_orientation_base_orientation, acceleration, values);
317314
}
318315

319316
/**
@@ -338,14 +335,17 @@ pbio_error_t pbio_imu_get_single_axis_rotation(pbio_geometry_xyz_t *axis, float
338335
/**
339336
* Gets which side of a hub points upwards.
340337
*
338+
* @param [in] calibrated Whether to use calibrated or uncalibrated data.
339+
*
341340
* @return Which side is up.
342341
*/
343-
pbio_geometry_side_t pbio_imu_get_up_side(void) {
342+
pbio_geometry_side_t pbio_imu_get_up_side(bool calibrated) {
344343
// Up is which side of a unit box intersects the +Z vector first.
345344
// So read +Z vector of the inertial frame, in the body frame.
346345
// For now, this is the gravity vector. In the future, we can make this
347346
// slightly more accurate by using the full IMU orientation.
348-
return pbio_geometry_side_from_vector(&acceleration);
347+
pbio_geometry_xyz_t *acceleration = calibrated ? &acceleration_calibrated : &acceleration_uncalibrated;
348+
return pbio_geometry_side_from_vector(acceleration);
349349
}
350350

351351
static float heading_offset = 0;

pybricks/common/pb_type_imu.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,14 @@ typedef struct _pb_type_imu_obj_t {
3131
} pb_type_imu_obj_t;
3232

3333
// pybricks._common.IMU.up
34-
static mp_obj_t pb_type_imu_up(mp_obj_t self_in) {
35-
switch (pbio_imu_get_up_side()) {
34+
static mp_obj_t pb_type_imu_up(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
35+
PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
36+
pb_type_imu_obj_t, self,
37+
PB_ARG_DEFAULT_TRUE(calibrated));
38+
39+
(void)self;
40+
41+
switch (pbio_imu_get_up_side(mp_obj_is_true(calibrated_in))) {
3642
default:
3743
case PBIO_GEOMETRY_SIDE_FRONT:
3844
return MP_OBJ_FROM_PTR(&pb_Side_FRONT_obj);
@@ -48,14 +54,16 @@ static mp_obj_t pb_type_imu_up(mp_obj_t self_in) {
4854
return MP_OBJ_FROM_PTR(&pb_Side_BOTTOM_obj);
4955
}
5056
}
51-
MP_DEFINE_CONST_FUN_OBJ_1(pb_type_imu_up_obj, pb_type_imu_up);
57+
static MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_imu_up_obj, 1, pb_type_imu_up);
5258

5359
// pybricks._common.IMU.tilt
5460
static mp_obj_t pb_type_imu_tilt(mp_obj_t self_in) {
5561

62+
// Revisit: optionally use not just calibrated but also IMU.
63+
5664
// Read acceleration in the user frame.
5765
pbio_geometry_xyz_t accl;
58-
pbio_imu_get_acceleration(&accl);
66+
pbio_imu_get_acceleration(&accl, false);
5967

6068
mp_obj_t tilt[2];
6169
// Pitch
@@ -86,11 +94,12 @@ static void pb_type_imu_extract_axis(mp_obj_t obj_in, pbio_geometry_xyz_t *vecto
8694
static mp_obj_t pb_type_imu_acceleration(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
8795
PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
8896
pb_type_imu_obj_t, self,
89-
PB_ARG_DEFAULT_NONE(axis));
97+
PB_ARG_DEFAULT_NONE(axis),
98+
PB_ARG_DEFAULT_TRUE(calibrated));
9099

91100
(void)self;
92101
pbio_geometry_xyz_t acceleration;
93-
pbio_imu_get_acceleration(&acceleration);
102+
pbio_imu_get_acceleration(&acceleration, mp_obj_is_true(calibrated_in));
94103

95104
// If no axis is specified, return a vector of values.
96105
if (axis_in == mp_const_none) {
@@ -184,12 +193,12 @@ static mp_obj_t pb_type_imu_settings(size_t n_args, const mp_obj_t *pos_args, mp
184193
pb_assert(pbio_imu_get_settings(&get_settings));
185194

186195
mp_obj_t acceleration_corrections[] = {
187-
mp_obj_new_float_from_f(get_settings->gravity_x_pos),
188-
mp_obj_new_float_from_f(get_settings->gravity_x_neg),
189-
mp_obj_new_float_from_f(get_settings->gravity_y_pos),
190-
mp_obj_new_float_from_f(get_settings->gravity_y_neg),
191-
mp_obj_new_float_from_f(get_settings->gravity_z_pos),
192-
mp_obj_new_float_from_f(get_settings->gravity_z_neg),
196+
mp_obj_new_float_from_f(get_settings->gravity_pos.x),
197+
mp_obj_new_float_from_f(get_settings->gravity_neg.x),
198+
mp_obj_new_float_from_f(get_settings->gravity_pos.y),
199+
mp_obj_new_float_from_f(get_settings->gravity_neg.y),
200+
mp_obj_new_float_from_f(get_settings->gravity_pos.z),
201+
mp_obj_new_float_from_f(get_settings->gravity_neg.z),
193202
};
194203

195204
mp_obj_t ret[] = {
@@ -226,12 +235,12 @@ static mp_obj_t pb_type_imu_settings(size_t n_args, const mp_obj_t *pos_args, mp
226235
mp_raise_ValueError(MP_ERROR_TEXT("Acceleration correction must be a 6-element tuple."));
227236
}
228237
set_settings.flags |= PBIO_IMU_SETTINGS_FLAGS_ACCEL_CALIBRATED;
229-
set_settings.gravity_x_pos = mp_obj_get_float(gravity[0]);
230-
set_settings.gravity_x_neg = mp_obj_get_float(gravity[1]);
231-
set_settings.gravity_y_pos = mp_obj_get_float(gravity[2]);
232-
set_settings.gravity_y_neg = mp_obj_get_float(gravity[3]);
233-
set_settings.gravity_z_pos = mp_obj_get_float(gravity[4]);
234-
set_settings.gravity_z_neg = mp_obj_get_float(gravity[5]);
238+
set_settings.gravity_pos.x = mp_obj_get_float(gravity[0]);
239+
set_settings.gravity_neg.x = mp_obj_get_float(gravity[1]);
240+
set_settings.gravity_pos.y = mp_obj_get_float(gravity[2]);
241+
set_settings.gravity_neg.y = mp_obj_get_float(gravity[3]);
242+
set_settings.gravity_pos.z = mp_obj_get_float(gravity[4]);
243+
set_settings.gravity_neg.z = mp_obj_get_float(gravity[5]);
235244
}
236245

237246
pb_assert(pbio_imu_set_settings(&set_settings));

0 commit comments

Comments
 (0)