So I know that accelerometer double integration is usually a no-go for measuring position but I have seen quite a few people who have had success with the exact same sensor and the exact same purpose for me. I have attempted to land a model rocket propulsively and have gotten pretty close. However, I used a barometer(ms5607) to measure altitude and during descent, it was no longer accurate because of the high airspeed. To combat this, I thought of integrating the BMI088 twice to get altitude and since each landing test was less than 10 seconds, I thought it would be ok. In the following video, Mark from Project Horizon successfully found position using only the BMI088. In his conditions, the rocket reached 27.4 meters and in the end, was only off by less than 0.5 meters.
Link to video: https://www.youtube.com/watch?v=56R21lG72Ek&t=0s
So anyway, I knew that it is 100% possible to do what I am doing because Mark and a few others I know have successfully implemented this.
Here is my code:
/*
Get position data by globalizing acceleration data and double intergrating it
*/
void global_position(double dt, double body_acc_x, double body_acc_y, double accel_z_cal,
double global_ori_z, double global_ori_y, double global_ori_x) {
double yaw = global_ori_x * DEG_TO_RAD;
double pitch = global_ori_y * DEG_TO_RAD;
double roll = global_ori_z * DEG_TO_RAD;
// Find the Z-axis acceleration in the global reference frame using rotation matrix
//global_acc_z = (body_acc_z * cos(roll));
// Resolve Z-axis acceleration into true vertical acceleration
//global_acc_z = body_acc_z * cos(yaw) - 9.8;
//global_acc_z += global_acc_z_bias;
// During sensor calibration, set the bais so we can later remove the gravity component
if (state == 0) {
global_acc_z_bias = abs(accel_z_cal);
}
// When pad idle, keep first measurements ready but do not intergrate yet!
if (state == 1) {
vel_z = dt * accel_z_cal;
pos_z = (dt * vel_z) + ((0.5 * accel_z_cal) * dt * dt);
}
// Ok, start intergrating, we have liftoff!
if (state > 1) {
vel_z += dt * accel_z_cal;
pos_z += (dt * vel_z) + ((0.5 * accel_z_cal) * dt * dt);
}
// Test output
SerialUSB.print("Global Z-axis acceleration: ");
SerialUSB.println(pos_z);
SerialUSB.println(body_acc_z);
}
Btw, that code is just 1 function in a much larger piece of code. And here are my accelerometer settings:
accel.setOdr(Bmi088Accel::ODR_200HZ_BW_20HZ);
accel.setRange(Bmi088Accel::RANGE_6G);
So I tried a bunch of things. First, I tried to integrate just my body frame acceleration (raw data), subtract gravity (raw data + 9.8), and integrate. This didnt end up too well because although it seemed to kind of get the velocity and position as I moved the flight computer upwards, it the velocity would never decrease. It would either just keep increasing if I was moving the computer upwards in real life or just become a constant when I moved it back down. All of this makes sense except that it never returned to zero. It only returned to like 2 or 3 m/s and so that threw off the entire position estimate. Within 1 or 2 seconds, we were at like 10 or 20 meters. Then I tried a few different methods to try and get global acceleration. I tried using rotation matrices and even tried resolving for the true z-axis acceleration using trigonometry, just the body frame z-axis acceleration, and the global frame orientation (using quaternions from the gyros), but I couldnt get that to work. That method was what Mark used, I asked him. He agreed that in 2 dimensions, Z-acceleration * cos(angle from vertical) - 9.8 m/s = true acceleration but in 3 dimensions you have to do something else. After that, I had no idea what to do because apparently, not many people actually have become successful in this. So yeah, I have reached a dead-end. Some advice would be much appreciated! Thanks in advance!
Edit: Those calculations were not correct...