I am about to program a IMU sensor (MCU9250) to obtain rough estimate of stationary buoy rocking in waves. I don't expect big waves it would be on a lake and wind induced only.
I am looking for advise on sensor initial position. Should it absolutely be leveled? Can I just measure the starting position and work in relative ways vs the start point? The idea is to have maybe 3 conditions. Calm, medium and heavy rocking.
The MPU-9250 is a full 3D sensor, so the starting orientation is irrelevant.
You could use the accelerometer alone to estimate current tilt from vertical in 2D or all three individual sensors with an AHRS program to estimate current absolute orientation angles in 3D.
How big is that buoy ? Will the sensor be in the middle inside or at the top ?
It could be going up and down or rocking left and right. I suggest to calculate the overall g-forces.
Is the buoy made from metal ? That might disturb the magnetometer.
Just curious: are you going to send the data wireless ?
it is a floating platform made of à 3" thick foam and structural wood. The size is about 50 * 50 cm. I have a small air pump on it and some valves. If the weather is bad, I want to put the system to sleep to protect against water going inside the tubbing. This is why I don't need a very precise movement information. I choose this overkill IMU because it came with a BMP280 (a sensor I also use on the system).
No wireless. It is for remote location. Everything is recorded on a SD card.
For simplicity, I plan to mount the sensor in the middle of the platform with the electronics and batteries. I guess the movement/acceleration in Z will be the most relevant for me. This weekend, I plan to test it a bit. I will probably have questions...
You could calculate the overall dynamic g-force (in any direction). I think that just the accelerometer should do.
Start with a millis() timer of 5 to 50 times per second (just a guess, the buoy motion in water is not that fast).
A tiny filter can help to reduce the noise. Some sensors have a filter in the chip.
The offset could be the values with a very strong low-pass filter. That also solves the earth gravity or the position of the sensor.
Give the offset values a good start by filling them with the actual sensor values in setup().
This is a simple low-pass filter (only 0.5% of the new value is put into the filtered value):
xoffset = (0.995 * xoffset) + (0.005 * xnew)
The g-force is the difference with the offset and the total is:
total_g = sqrt( sqr(xdelta) + sqr(ydelta) + sqr(zdelta))
Then you need to find the average or maximum g-force over a certain time.
For example: immediate accept a high g-force, but return to duty after the g-force is below the limit for 5 minutes. The "5 minutes" is by using millis() of course.
That is a lot of steps, but I can't make it shorter
It is very fast to measure tilt and roll angles using just the accelerometer. In this case, the Z axis is assumed to be approximately vertical, but that is not required.
This code works on either the MPU-6050 or MPU-9250:
// minimal MPU-6050 tilt and roll (sjr)
// works perfectly with GY-521, pitch and roll signs agree with arrows on sensor module 7/2019
//
// Tested with 3.3V eBay Pro Mini with no external pullups on I2C bus (worked with internal pullups)
// Add 4.7K pullup resistors to 3.3V if required. A4 = SDA, A5 = SCL
#include<Wire.h>
const int MPU_addr1 = 0x68;
float xa, ya, za, roll, pitch;
void setup() {
Wire.begin(); //begin the wire communication
Wire.beginTransmission(MPU_addr1); //begin, send the slave adress (in this case 68)
Wire.write(0x6B); //make the reset (place a 0 into the 6B register)
Wire.write(0);
Wire.endTransmission(true); //end the transmission
Serial.begin(9600);
}
void loop() {
Wire.beginTransmission(MPU_addr1);
Wire.write(0x3B); //send starting register address, accelerometer high byte
Wire.endTransmission(false); //restart for read
Wire.requestFrom(MPU_addr1, 6); //get six bytes accelerometer data
int t = Wire.read();
xa = (t << 8) | Wire.read();
t = Wire.read();
ya = (t << 8) | Wire.read();
t = Wire.read();
za = (t << 8) | Wire.read();
// formula from https://wiki.dfrobot.com/How_to_Use_a_Three-Axis_Accelerometer_for_Tilt_Sensing
roll = atan2(ya , za) * 180.0 / PI;
pitch = atan2(-xa , sqrt(ya * ya + za * za)) * 180.0 / PI; //account for roll already applied
Serial.print("roll = ");
Serial.print(roll,1);
Serial.print(", pitch = ");
Serial.println(pitch,1);
delay(400);
}