- C 91.6%
- Python 5.4%
- CMake 3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The power-on defaults are the narrowest ranges the part offers, and the driver hard-coded the matching scale factors, so there was no way to move off them. Both are a poor fit for anything that moves quickly: 250 deg/s is an ordinary aircraft aileron roll, and 2 g is exceeded by any real manoeuvre. A saturated accelerometer is the worse of the two, because it reads low rather than obviously wrong, so code that sanity-checks the vector magnitude against 1 g becomes more likely to accept the bad sample. - lf_mpu6050_init_config() takes gyro range, accel range, DLPF bandwidth and sample-rate divider; scale factors are derived and stored on the context, so read_data() stays correct at any range. - Ranges and filtering can also be changed after init. - Initialization now resets the device before configuring it, which matters across a warm boot, and selects the gyro PLL as the clock source instead of the internal oscillator the part powers up with. - lf_mpu6050_calibrate_gyro() populates the gyro_bias fields that the context has always had and nothing ever set. Bias is kept in raw counts so it survives a range change. - lf_mpu6050_read_si() reports m/s^2 alongside rad/s. read_data() mixes g with rad/s, which is easy to trip over. lf_mpu6050_init() and read_data() keep their signatures and their behaviour, so existing callers are unaffected. Verified by building both simquad Pico firmware targets, which link this driver, against the change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014kuV9nVLjXCNGn8HSsSYNa |
||
| include | ||
| src | ||
| CMakeLists.txt | ||
| conanfile.py | ||
| README.md | ||
lf-mpu6050
Lost + Found MPU6050 6-Axis Accelerometer/Gyroscope driver library for Raspberry Pi Pico C SDK.
🔌 Hardware Setup
Standard Pin Mapping:
- SDA: GP4 (Pico Pin 6)
- SCL: GP5 (Pico Pin 7)
- Bus: I2C0
📦 Usage
Add this package to your conanfile.txt or CMake setup.
CMake Integration
target_link_libraries(your_project PUBLIC lf-mpu6050)
Driver Instantiation
#include "lf_mpu6050.h"
lf_mpu6050_t mpu;
// Initialize with the power-on ranges (+/-2 g, +/-250 deg/s)
if (lf_mpu6050_init(&mpu, i2c0, LF_MPU6050_DEFAULT_I2C_ADDR)) {
// Successfully initialized!
}
// Read telemetry
float accel[3], gyro[3], temp;
if (lf_mpu6050_read_data(&mpu, accel, gyro, &temp)) {
printf("Accel: X=%.2f, Y=%.2f, Z=%.2f g\n", accel[0], accel[1], accel[2]);
printf("Gyro: X=%.2f, Y=%.2f, Z=%.2f rad/s\n", gyro[0], gyro[1], gyro[2]);
printf("Temp: %.2f C\n", temp);
}
⚙️ Choosing ranges
The power-on defaults are the narrowest ranges the part offers, which makes them a poor fit for anything that moves quickly:
- ±250 °/s is exceeded by a hand flick or an ordinary aircraft aileron roll. A clipped gyroscope silently under-reports rotation.
- ±2 g is exceeded by any real manoeuvre or a decent knock. A saturated accelerometer reads low, which is worse than reading obviously wrong: code that sanity-checks the vector magnitude against 1 g becomes more likely to accept the bad sample, not less.
So pick ranges explicitly:
lf_mpu6050_config_t cfg;
lf_mpu6050_config_defaults(&cfg);
cfg.gyro_range = LF_MPU6050_GYRO_1000DPS;
cfg.accel_range = LF_MPU6050_ACCEL_8G;
cfg.dlpf = LF_MPU6050_DLPF_44HZ; // keep motor vibration out
cfg.sample_rate_div = 0; // 1 kHz output with the DLPF on
if (!lf_mpu6050_init_config(&mpu, i2c0, LF_MPU6050_DEFAULT_I2C_ADDR, &cfg)) {
// sensor did not answer
}
lf_mpu6050_read_data() scales according to whichever ranges are configured,
so nothing downstream changes when you widen them. The ranges can also be
changed after init with lf_mpu6050_set_gyro_range(),
lf_mpu6050_set_accel_range() and lf_mpu6050_set_dlpf().
Filtering
cfg.dlpf sets the on-chip low-pass. LF_MPU6050_DLPF_OFF gives the widest
bandwidth and an 8 kHz internal rate; every other setting drops the internal
rate to 1 kHz. Some filtering is usually wanted, especially near motors or
propellers, because vibration that reaches a derivative term is amplified by
it.
SI units
lf_mpu6050_read_data() reports acceleration in g but angular rate in
rad/s, which is easy to trip over. lf_mpu6050_read_si() is identical
except that acceleration comes back in m/s², so both outputs are SI:
float accel[3], gyro[3]; // m/s^2 and rad/s
lf_mpu6050_read_si(&mpu, accel, gyro, NULL);
Gyroscope calibration
// The device must be completely still: any motion during this is measured
// as bias and subtracted from every later reading.
lf_mpu6050_calibrate_gyro(&mpu, 500); // ~500 ms
Bias is stored in raw counts, so it stays correct if you change the full-scale range afterwards. Only the gyroscope is calibrated — separating accelerometer bias from gravity needs a multi-orientation procedure that does not belong behind a single call.
Notes on initialization
lf_mpu6050_init_config() issues a device reset before configuring, then
selects the gyroscope PLL as the clock source rather than the internal
oscillator the part powers up with (the datasheet recommends this; it drifts
less). The reset matters across a warm boot: without it the device keeps
whatever registers the previous firmware left behind.
lf_mpu6050_init() is unchanged and still applies the power-on ranges, so
existing code keeps working and reading identical values.
API
| Function | Purpose |
|---|---|
lf_mpu6050_config_defaults |
Fill a config with the power-on defaults |
lf_mpu6050_init |
Initialize with the power-on ranges |
lf_mpu6050_init_config |
Initialize with explicit ranges, filter and rate |
lf_mpu6050_set_gyro_range |
Change the gyroscope range |
lf_mpu6050_set_accel_range |
Change the accelerometer range |
lf_mpu6050_set_dlpf |
Change the low-pass bandwidth |
lf_mpu6050_ping |
Check the device answers on the bus |
lf_mpu6050_calibrate_gyro |
Average the gyroscope zero offset |
lf_mpu6050_read_raw |
Raw register counts |
lf_mpu6050_read_data |
Scaled: g and rad/s |
lf_mpu6050_read_si |
Scaled: m/s² and rad/s |