mirror of
https://github.com/okalachev/flix.git
synced 2026-01-10 21:16:50 +00:00
As it makes the subsystems code easier to understand. Declare the most used variables in main sketch file as forward declarations. Make all control input zero by default (except controlMode). Minor changes.
133 lines
3.6 KiB
C++
133 lines
3.6 KiB
C++
// Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com>
|
|
// Repository: https://github.com/okalachev/flix
|
|
|
|
// Work with the IMU sensor
|
|
|
|
#include <SPI.h>
|
|
#include <FlixPeriph.h>
|
|
#include "vector.h"
|
|
#include "lpf.h"
|
|
#include "util.h"
|
|
|
|
MPU9250 imu(SPI);
|
|
Vector imuRotation(0, 0, -PI / 2); // imu orientation as Euler angles
|
|
|
|
Vector gyro; // gyroscope output, rad/s
|
|
Vector gyroBias;
|
|
|
|
Vector acc; // accelerometer output, m/s/s
|
|
Vector accBias;
|
|
Vector accScale(1, 1, 1);
|
|
|
|
void setupIMU() {
|
|
print("Setup IMU\n");
|
|
imu.begin();
|
|
configureIMU();
|
|
}
|
|
|
|
void configureIMU() {
|
|
imu.setAccelRange(imu.ACCEL_RANGE_4G);
|
|
imu.setGyroRange(imu.GYRO_RANGE_2000DPS);
|
|
imu.setDLPF(imu.DLPF_MAX);
|
|
imu.setRate(imu.RATE_1KHZ_APPROX);
|
|
imu.setupInterrupt();
|
|
}
|
|
|
|
void readIMU() {
|
|
imu.waitForData();
|
|
imu.getGyro(gyro.x, gyro.y, gyro.z);
|
|
imu.getAccel(acc.x, acc.y, acc.z);
|
|
calibrateGyroOnce();
|
|
// apply scale and bias
|
|
acc = (acc - accBias) / accScale;
|
|
gyro = gyro - gyroBias;
|
|
// rotate to body frame
|
|
Quaternion rotation = Quaternion::fromEuler(imuRotation);
|
|
acc = Quaternion::rotateVector(acc, rotation.inversed());
|
|
gyro = Quaternion::rotateVector(gyro, rotation.inversed());
|
|
}
|
|
|
|
void calibrateGyroOnce() {
|
|
static Delay landedDelay(2);
|
|
if (!landedDelay.update(landed)) return; // calibrate only if definitely stationary
|
|
|
|
static LowPassFilter<Vector> gyroBiasFilter(0.001);
|
|
gyroBias = gyroBiasFilter.update(gyro);
|
|
}
|
|
|
|
void calibrateAccel() {
|
|
print("Calibrating accelerometer\n");
|
|
imu.setAccelRange(imu.ACCEL_RANGE_2G); // the most sensitive mode
|
|
|
|
print("1/6 Place level [8 sec]\n");
|
|
pause(8);
|
|
calibrateAccelOnce();
|
|
print("2/6 Place nose up [8 sec]\n");
|
|
pause(8);
|
|
calibrateAccelOnce();
|
|
print("3/6 Place nose down [8 sec]\n");
|
|
pause(8);
|
|
calibrateAccelOnce();
|
|
print("4/6 Place on right side [8 sec]\n");
|
|
pause(8);
|
|
calibrateAccelOnce();
|
|
print("5/6 Place on left side [8 sec]\n");
|
|
pause(8);
|
|
calibrateAccelOnce();
|
|
print("6/6 Place upside down [8 sec]\n");
|
|
pause(8);
|
|
calibrateAccelOnce();
|
|
|
|
printIMUCalibration();
|
|
print("✓ Calibration done!\n");
|
|
configureIMU();
|
|
}
|
|
|
|
void calibrateAccelOnce() {
|
|
const int samples = 1000;
|
|
static Vector accMax(-INFINITY, -INFINITY, -INFINITY);
|
|
static Vector accMin(INFINITY, INFINITY, INFINITY);
|
|
|
|
// Compute the average of the accelerometer readings
|
|
acc = Vector(0, 0, 0);
|
|
for (int i = 0; i < samples; i++) {
|
|
imu.waitForData();
|
|
Vector sample;
|
|
imu.getAccel(sample.x, sample.y, sample.z);
|
|
acc = acc + sample;
|
|
}
|
|
acc = acc / samples;
|
|
|
|
// Update the maximum and minimum values
|
|
if (acc.x > accMax.x) accMax.x = acc.x;
|
|
if (acc.y > accMax.y) accMax.y = acc.y;
|
|
if (acc.z > accMax.z) accMax.z = acc.z;
|
|
if (acc.x < accMin.x) accMin.x = acc.x;
|
|
if (acc.y < accMin.y) accMin.y = acc.y;
|
|
if (acc.z < accMin.z) accMin.z = acc.z;
|
|
// Compute scale and bias
|
|
accScale = (accMax - accMin) / 2 / ONE_G;
|
|
accBias = (accMax + accMin) / 2;
|
|
}
|
|
|
|
void printIMUCalibration() {
|
|
print("gyro bias: %f %f %f\n", gyroBias.x, gyroBias.y, gyroBias.z);
|
|
print("accel bias: %f %f %f\n", accBias.x, accBias.y, accBias.z);
|
|
print("accel scale: %f %f %f\n", accScale.x, accScale.y, accScale.z);
|
|
}
|
|
|
|
void printIMUInfo() {
|
|
imu.status() ? print("status: ERROR %d\n", imu.status()) : print("status: OK\n");
|
|
print("model: %s\n", imu.getModel());
|
|
print("who am I: 0x%02X\n", imu.whoAmI());
|
|
print("rate: %.0f\n", loopRate);
|
|
print("gyro: %f %f %f\n", rates.x, rates.y, rates.z);
|
|
print("acc: %f %f %f\n", acc.x, acc.y, acc.z);
|
|
imu.waitForData();
|
|
Vector rawGyro, rawAcc;
|
|
imu.getGyro(rawGyro.x, rawGyro.y, rawGyro.z);
|
|
imu.getAccel(rawAcc.x, rawAcc.y, rawAcc.z);
|
|
print("raw gyro: %f %f %f\n", rawGyro.x, rawGyro.y, rawGyro.z);
|
|
print("raw acc: %f %f %f\n", rawAcc.x, rawAcc.y, rawAcc.z);
|
|
}
|