Skip to content

Commit 7076199

Browse files
committed
pbio/imu: Set calibrated gyro values.
1 parent 15c84e7 commit 7076199

File tree

4 files changed

+96
-48
lines changed

4 files changed

+96
-48
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
### Added
88

9-
- Added optional `calibrated=True` parameter to `acceleration()` and `up()`
10-
methods of the IMU ([support#943]).
9+
- Added optional `calibrated=True` parameter to `acceleration()` and `up()` and
10+
`angular_velocity()` methods of the IMU ([support#943]).
1111

1212
### Changed
1313

lib/pbio/include/pbio/imu.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ typedef enum {
3333
*/
3434
PBIO_IMU_SETTINGS_FLAGS_ACCEL_STATIONARY_THRESHOLD_SET = (1 << 1),
3535
/**
36-
* The heading correction has been updated.
36+
* The initial values for the gyro bias have been set.
3737
*/
38-
PBIO_IMU_SETTINGS_FLAGS_GYRO_HEADING_CORRECTION_SET = (1 << 2),
38+
PBIO_IMU_SETTINGS_FLAGS_GYRO_BIAS_INITIAL_SET = (1 << 3),
39+
/**
40+
* The per-axis angular velocity scale has been set.
41+
*/
42+
PBIO_IMU_SETTINGS_FLAGS_GYRO_SCALE_SET = (1 << 4),
3943
/**
4044
* The accelerometer offsets and scale has been calibrated.
4145
*/
42-
PBIO_IMU_SETTINGS_FLAGS_ACCEL_CALIBRATED = (1 << 3),
46+
PBIO_IMU_SETTINGS_FLAGS_ACCEL_CALIBRATED = (1 << 5),
4347
} pbio_imu_persistent_settings_flags_t;
4448

4549
/**
@@ -56,17 +60,14 @@ typedef struct {
5660
float gyro_stationary_threshold;
5761
/** Acceleration threshold below which the IMU is considered stationary, in mm/s^2. */
5862
float accel_stationary_threshold;
59-
/**
60-
* Number of degrees measured for one full turn along the user Z axis. This
61-
* is used to correct the heading value. Other rotation methods are not
62-
* affected.
63-
* FIXME: Deprecate and use 3D correction.
64-
*/
65-
float heading_correction;
6663
/** Positive acceleration values */
6764
pbio_geometry_xyz_t gravity_pos;
6865
/** Negative acceleration values */
6966
pbio_geometry_xyz_t gravity_neg;
67+
/** Angular velocity stationary bias initially used on boot */
68+
pbio_geometry_xyz_t angular_velocity_bias_start;
69+
/** Angular velocity scale (unadjusted measured degrees per whole rotation) */
70+
pbio_geometry_xyz_t angular_velocity_scale;
7071
} pbio_imu_persistent_settings_t;
7172

7273
#if PBIO_CONFIG_IMU
@@ -87,7 +88,7 @@ pbio_error_t pbio_imu_get_settings(pbio_imu_persistent_settings_t **settings);
8788

8889
pbio_error_t pbio_imu_set_settings(pbio_imu_persistent_settings_t *new_settings);
8990

90-
void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values);
91+
void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values, bool calibrated);
9192

9293
void pbio_imu_get_acceleration(pbio_geometry_xyz_t *values, bool calibrated);
9394

@@ -128,7 +129,7 @@ static inline pbio_error_t pbio_imu_set_settings(float angular_velocity, float a
128129
return PBIO_ERROR_NOT_SUPPORTED;
129130
}
130131

131-
static inline void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values) {
132+
static inline void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values, bool calibrated) {
132133
}
133134

134135
static inline void pbio_imu_get_acceleration(pbio_geometry_xyz_t *values, bool calibrated) {

lib/pbio/src/imu.c

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
static pbdrv_imu_dev_t *imu_dev;
2626
static pbdrv_imu_config_t *imu_config;
2727

28+
// Cached sensor values that can be read at any time without polling again.
29+
static pbio_geometry_xyz_t angular_velocity_uncalibrated; // deg/s, in hub frame
30+
static pbio_geometry_xyz_t angular_velocity_calibrated; // deg/s, in hub frame, already adjusted for bias and scale.
31+
static pbio_geometry_xyz_t acceleration_uncalibrated; // mm/s^2, in hub frame
32+
static pbio_geometry_xyz_t acceleration_calibrated; // mm/s^2, in hub frame
33+
static pbio_geometry_xyz_t gyro_bias; // Starts at value from settings, then updated when stationary.
34+
static pbio_geometry_xyz_t single_axis_rotation; // deg, in hub frame
35+
2836
// Asynchronously loaded on boot. Cannot be used until loaded.
2937
static pbio_imu_persistent_settings_t *persistent_settings = NULL;
3038

@@ -57,9 +65,10 @@ void pbio_imu_set_default_settings(pbio_imu_persistent_settings_t *settings) {
5765
settings->flags = 0;
5866
settings->gyro_stationary_threshold = 3.0f;
5967
settings->accel_stationary_threshold = 2500.0f;
60-
settings->heading_correction = 360.0f;
6168
settings->gravity_pos.x = settings->gravity_pos.y = settings->gravity_pos.z = standard_gravity;
6269
settings->gravity_neg.x = settings->gravity_neg.y = settings->gravity_neg.z = -standard_gravity;
70+
settings->angular_velocity_bias_start.x = settings->angular_velocity_bias_start.y = settings->angular_velocity_bias_start.z = 0.0f;
71+
settings->angular_velocity_scale.x = settings->angular_velocity_scale.y = settings->angular_velocity_scale.z = 360.0f;
6372
pbio_imu_apply_pbdrv_settings(settings);
6473
}
6574

@@ -71,38 +80,40 @@ void pbio_imu_set_default_settings(pbio_imu_persistent_settings_t *settings) {
7180
void pbio_imu_apply_loaded_settings(pbio_imu_persistent_settings_t *settings) {
7281
// This is called on load, so we can now access the settings directly.
7382
persistent_settings = settings;
83+
84+
// The saved angular velocity bias only sets the initial value. We still
85+
// update the bias continuously from stationary data.
86+
gyro_bias.x = settings->angular_velocity_bias_start.x;
87+
gyro_bias.y = settings->angular_velocity_bias_start.y;
88+
gyro_bias.z = settings->angular_velocity_bias_start.z;
89+
7490
pbio_imu_apply_pbdrv_settings(settings);
7591
}
7692

77-
// Cached sensor values that can be read at any time without polling again.
78-
static pbio_geometry_xyz_t angular_velocity; // deg/s, in hub frame, already adjusted for bias.
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
81-
static pbio_geometry_xyz_t gyro_bias;
82-
static pbio_geometry_xyz_t single_axis_rotation; // deg, in hub frame
83-
8493
// Called by driver to process one frame of unfiltered gyro and accelerometer data.
8594
static void pbio_imu_handle_frame_data_func(int16_t *data) {
86-
for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(angular_velocity.values); i++) {
95+
for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(angular_velocity_calibrated.values); i++) {
8796
// Update angular velocity and acceleration cache so user can read them.
88-
angular_velocity.values[i] = data[i] * imu_config->gyro_scale - gyro_bias.values[i];
97+
angular_velocity_uncalibrated.values[i] = data[i] * imu_config->gyro_scale;
8998
acceleration_uncalibrated.values[i] = data[i + 3] * imu_config->accel_scale;
9099

91100
// Once settings loaded, maintain calibrated cached values.
92101
if (persistent_settings) {
93102
float acceleration_offset = (persistent_settings->gravity_pos.values[i] + persistent_settings->gravity_neg.values[i]) / 2;
94103
float acceleration_scale = (persistent_settings->gravity_pos.values[i] - persistent_settings->gravity_neg.values[i]) / 2;
95104
acceleration_calibrated.values[i] = (acceleration_uncalibrated.values[i] - acceleration_offset) * standard_gravity / acceleration_scale;
105+
angular_velocity_calibrated.values[i] = (angular_velocity_uncalibrated.values[i] - gyro_bias.values[i]) * 360.0f / persistent_settings->angular_velocity_scale.values[i];
96106
} else {
97107
acceleration_calibrated.values[i] = acceleration_uncalibrated.values[i];
108+
angular_velocity_calibrated.values[i] = angular_velocity_uncalibrated.values[i];
98109
}
99110

100111
// Update "heading" on all axes. This is not useful for 3D attitude
101112
// estimation, but it allows the user to get a 1D heading even with
102113
// the hub mounted at an arbitrary orientation. Such a 1D heading
103114
// is numerically more accurate, which is useful in drive base
104115
// applications so long as the vehicle drives on a flat surface.
105-
single_axis_rotation.values[i] += angular_velocity.values[i] * imu_config->sample_time;
116+
single_axis_rotation.values[i] += angular_velocity_calibrated.values[i] * imu_config->sample_time;
106117
}
107118
}
108119

@@ -235,20 +246,23 @@ pbio_error_t pbio_imu_set_settings(pbio_imu_persistent_settings_t *new_settings)
235246

236247
if (new_settings->flags & PBIO_IMU_SETTINGS_FLAGS_ACCEL_STATIONARY_THRESHOLD_SET) {
237248
persistent_settings->accel_stationary_threshold = new_settings->accel_stationary_threshold;
238-
persistent_settings->flags |= PBIO_IMU_SETTINGS_FLAGS_ACCEL_STATIONARY_THRESHOLD_SET;
239249
}
240250

241251
if (new_settings->flags & PBIO_IMU_SETTINGS_FLAGS_GYRO_STATIONARY_THRESHOLD_SET) {
242252
persistent_settings->gyro_stationary_threshold = new_settings->gyro_stationary_threshold;
243-
persistent_settings->flags |= PBIO_IMU_SETTINGS_FLAGS_GYRO_STATIONARY_THRESHOLD_SET;
244253
}
245254

246-
if (new_settings->flags & PBIO_IMU_SETTINGS_FLAGS_GYRO_HEADING_CORRECTION_SET) {
247-
if (new_settings->heading_correction < 350 || new_settings->heading_correction > 370) {
248-
return PBIO_ERROR_INVALID_ARG;
255+
for (uint8_t i = 0; i < 3; i++) {
256+
if (new_settings->flags & PBIO_IMU_SETTINGS_FLAGS_GYRO_BIAS_INITIAL_SET) {
257+
persistent_settings->angular_velocity_bias_start.values[i] = new_settings->angular_velocity_bias_start.values[i];
258+
}
259+
260+
if (new_settings->flags & PBIO_IMU_SETTINGS_FLAGS_GYRO_SCALE_SET) {
261+
if (new_settings->angular_velocity_scale.values[i] < 350 || new_settings->angular_velocity_scale.values[i] > 370) {
262+
return PBIO_ERROR_INVALID_ARG;
263+
}
264+
persistent_settings->angular_velocity_scale.values[i] = new_settings->angular_velocity_scale.values[i];
249265
}
250-
persistent_settings->heading_correction = new_settings->heading_correction;
251-
persistent_settings->flags |= PBIO_IMU_SETTINGS_FLAGS_GYRO_HEADING_CORRECTION_SET;
252266
}
253267

254268
if (new_settings->flags & PBIO_IMU_SETTINGS_FLAGS_ACCEL_CALIBRATED) {
@@ -260,13 +274,13 @@ pbio_error_t pbio_imu_set_settings(pbio_imu_persistent_settings_t *new_settings)
260274
pbio_imu_stationary_acceleration_out_of_range(new_settings->gravity_neg.z, false)) {
261275
return PBIO_ERROR_INVALID_ARG;
262276
}
263-
persistent_settings->flags |= PBIO_IMU_SETTINGS_FLAGS_ACCEL_CALIBRATED;
264277
persistent_settings->gravity_pos = new_settings->gravity_pos;
265278
persistent_settings->gravity_neg = new_settings->gravity_neg;
266279
}
267280

268281
// If any settings were changed, request saving.
269282
if (new_settings->flags) {
283+
persistent_settings->flags |= new_settings->flags;
270284
pbsys_storage_request_write();
271285
}
272286

@@ -297,8 +311,9 @@ pbio_error_t pbio_imu_get_settings(pbio_imu_persistent_settings_t **settings) {
297311
*
298312
* @param [out] values The angular velocity vector.
299313
*/
300-
void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values) {
301-
pbio_geometry_vector_map(&pbio_orientation_base_orientation, &angular_velocity, values);
314+
void pbio_imu_get_angular_velocity(pbio_geometry_xyz_t *values, bool calibrated) {
315+
pbio_geometry_xyz_t *angular_velocity = calibrated ? &angular_velocity_calibrated : &angular_velocity_uncalibrated;
316+
pbio_geometry_vector_map(&pbio_orientation_base_orientation, angular_velocity, values);
302317
}
303318

304319
/**
@@ -359,13 +374,9 @@ static float heading_offset = 0;
359374
* @return Heading angle in the base frame.
360375
*/
361376
float pbio_imu_get_heading(void) {
362-
363377
pbio_geometry_xyz_t heading_mapped;
364378
pbio_geometry_vector_map(&pbio_orientation_base_orientation, &single_axis_rotation, &heading_mapped);
365-
366-
float correction = persistent_settings ? (360.0f / persistent_settings->heading_correction) : 1.0f;
367-
368-
return -heading_mapped.z * correction - heading_offset;
379+
return -heading_mapped.z - heading_offset;
369380
}
370381

371382
/**
@@ -408,7 +419,7 @@ void pbio_imu_get_heading_scaled(pbio_angle_t *heading, int32_t *heading_rate, i
408419

409420
// The heading rate can be obtained by a simple scale because it always fits.
410421
pbio_geometry_xyz_t angular_rate;
411-
pbio_imu_get_angular_velocity(&angular_rate);
422+
pbio_imu_get_angular_velocity(&angular_rate, true);
412423
*heading_rate = (int32_t)(-angular_rate.z * ctl_steps_per_degree);
413424
}
414425

pybricks/common/pb_type_imu.c

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,12 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_imu_acceleration_obj, 1, pb_type_imu_a
120120
static mp_obj_t pb_type_imu_angular_velocity(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
121121
PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
122122
pb_type_imu_obj_t, self,
123-
PB_ARG_DEFAULT_NONE(axis));
123+
PB_ARG_DEFAULT_NONE(axis),
124+
PB_ARG_DEFAULT_TRUE(calibrated));
124125

125126
(void)self;
126127
pbio_geometry_xyz_t angular_velocity;
127-
pbio_imu_get_angular_velocity(&angular_velocity);
128+
pbio_imu_get_angular_velocity(&angular_velocity, mp_obj_is_true(calibrated_in));
128129

129130
// If no axis is specified, return a vector of values.
130131
if (axis_in == mp_const_none) {
@@ -177,7 +178,8 @@ static mp_obj_t pb_type_imu_settings(size_t n_args, const mp_obj_t *pos_args, mp
177178
pb_type_imu_obj_t, self,
178179
PB_ARG_DEFAULT_NONE(angular_velocity_threshold),
179180
PB_ARG_DEFAULT_NONE(acceleration_threshold),
180-
PB_ARG_DEFAULT_NONE(heading_correction),
181+
PB_ARG_DEFAULT_NONE(angular_velocity_bias),
182+
PB_ARG_DEFAULT_NONE(angular_velocity_scale),
181183
PB_ARG_DEFAULT_NONE(acceleration_correction));
182184

183185
(void)self;
@@ -197,10 +199,23 @@ static mp_obj_t pb_type_imu_settings(size_t n_args, const mp_obj_t *pos_args, mp
197199
mp_obj_new_float_from_f(get_settings->gravity_neg.z),
198200
};
199201

202+
mp_obj_t angular_velocity_bias[] = {
203+
mp_obj_new_float_from_f(get_settings->angular_velocity_bias_start.x),
204+
mp_obj_new_float_from_f(get_settings->angular_velocity_bias_start.y),
205+
mp_obj_new_float_from_f(get_settings->angular_velocity_bias_start.z),
206+
};
207+
208+
mp_obj_t angular_velocity_scale[] = {
209+
mp_obj_new_float_from_f(get_settings->angular_velocity_scale.x),
210+
mp_obj_new_float_from_f(get_settings->angular_velocity_scale.y),
211+
mp_obj_new_float_from_f(get_settings->angular_velocity_scale.z),
212+
};
213+
200214
mp_obj_t ret[] = {
201215
mp_obj_new_float_from_f(get_settings->gyro_stationary_threshold),
202216
mp_obj_new_float_from_f(get_settings->accel_stationary_threshold),
203-
mp_obj_new_float_from_f(get_settings->heading_correction),
217+
mp_obj_new_tuple(MP_ARRAY_SIZE(angular_velocity_bias), angular_velocity_bias),
218+
mp_obj_new_tuple(MP_ARRAY_SIZE(angular_velocity_scale), angular_velocity_scale),
204219
mp_obj_new_tuple(MP_ARRAY_SIZE(acceleration_corrections), acceleration_corrections),
205220
};
206221
return mp_obj_new_tuple(MP_ARRAY_SIZE(ret), ret);
@@ -218,9 +233,30 @@ static mp_obj_t pb_type_imu_settings(size_t n_args, const mp_obj_t *pos_args, mp
218233
set_settings.accel_stationary_threshold = mp_obj_get_float(acceleration_threshold_in);
219234
}
220235

221-
if (heading_correction_in != mp_const_none) {
222-
set_settings.flags |= PBIO_IMU_SETTINGS_FLAGS_GYRO_HEADING_CORRECTION_SET;
223-
set_settings.heading_correction = mp_obj_get_float(heading_correction_in);
236+
if (angular_velocity_bias_in != mp_const_none) {
237+
mp_obj_t *bias;
238+
size_t size;
239+
mp_obj_get_array(angular_velocity_bias_in, &size, &bias);
240+
if (size != 3) {
241+
mp_raise_ValueError(MP_ERROR_TEXT("Angular velocity bias must be a 3-element tuple."));
242+
}
243+
set_settings.angular_velocity_bias_start.x = mp_obj_get_float(bias[0]);
244+
set_settings.angular_velocity_bias_start.y = mp_obj_get_float(bias[1]);
245+
set_settings.angular_velocity_bias_start.z = mp_obj_get_float(bias[2]);
246+
set_settings.flags |= PBIO_IMU_SETTINGS_FLAGS_GYRO_BIAS_INITIAL_SET;
247+
}
248+
249+
if (angular_velocity_scale_in != mp_const_none) {
250+
mp_obj_t *scale;
251+
size_t size;
252+
mp_obj_get_array(angular_velocity_scale_in, &size, &scale);
253+
if (size != 3) {
254+
mp_raise_ValueError(MP_ERROR_TEXT("Angular velocity scale must be a 3-element tuple."));
255+
}
256+
set_settings.angular_velocity_scale.x = mp_obj_get_float(scale[0]);
257+
set_settings.angular_velocity_scale.y = mp_obj_get_float(scale[1]);
258+
set_settings.angular_velocity_scale.z = mp_obj_get_float(scale[2]);
259+
set_settings.flags |= PBIO_IMU_SETTINGS_FLAGS_GYRO_SCALE_SET;
224260
}
225261

226262
if (acceleration_correction_in != mp_const_none) {

0 commit comments

Comments
 (0)