MPU9250 - 9 axis sensor - eratic data.

Hi all,
First post here so I hope I get the posting protocols right.

I am using an Arduino Uno, and an MPU9250 sensor with the idea to use them as a security system for a caravan. If any motion is detected, flash the lights, sound the siren, lock on the electric brakes etc.

I've downloaded the SparkFun MPU9250 library and with a bit of minor editing (addresses mainly) I've got meaningful output from the sensor and it sends it neatly to the serial monitor in the IDE. All good so far.

What I have noticed is that under normal operation (initialising the sensors, self testing, calibrating, and then data points being displayed on the serial monitor) I get what I would consider wildly eratic data. Even to the point where the "roll" data indicates that the sensor is being turned upside down and back again at random.

I should mention that the arduino and sensor are sitting stationary on my desk so there is no way it is flip flopping around as the data would suggest.

Interestingly, if I exclude the Magnetometer calibration from the code by commenting out the call to that library function, the data becomes a lot more stable.

Whilst I've looked at the yaw, pitch and roll numbers, I've also isolated the Quaternion data and had a good look at it. Same deal ... when the magnetometer calibration is used, the data fluctuates wildly ... otherwise it's not too bad.

I've cut and pasted some of the data into a spreadsheet and had a look at using a moving average system to smooth out the variations, but I was quite surprised at how far some of the outliers strayed from the average (again, the UNO and sensor are sitting quietly on my desk). I do plan on introducing a "noise" threshold so that I can eliminate false triggers but you also need to be mindful that the system is not too desensitised.

Has anyone out there experienced the same sort of data fluctations and overcome them?

As you can probably appreciate, for a security system, the sensors need to be fairly sensitive, but hopefully also not experience a wide range of variation ... otherwise the system will be subject to false positives ... that would be very bad!

I've attached a capture of the serial monitor output and ...

I tried to include the code but I've exceeded the 9000 character limit.

I hope someone has already experienced this and has a quick fix.

Thanks

Luke

Just playing with the sensor board and came to realise that the difference between 180° and -180° is NOT 180 degrees! ... Doh! ... but I'm still seeing quite a large variance in the other data points ... is that normal?

The Sparkfun AHRS library for the MPU-9250 doesn't work at all, because it has a fundamental error. The angles it returns are nonsense. Same for the Kris Winer version from which it is derived, for the same reason.

I've corrected the error (rewrote most of the code, actually) and posted it at GitHub - jremington/MPU-9250-AHRS: Arduino Mahony AHRS, includes magnetometer and accelerometer calibration code, along with routines for the absolutely essential sensor calibration.

Mr Remington,
Many thanks for your reply ... especially the link to your code.

Well, you've made me feel better ... I did find it unusual that a library like that need a lot of work just to get it running, let alone now gtting cnfirmation that it is flawed.

I've down loaded your code and will set up a new project using it.

I'll let you know how I go.

Cheers,

Luke.

Hi,

Ok, I'm stuck.

I've used your code to create the two csv files for the calibration of the accelerometer and magnetometer.

The code for magneto is a .c file and I don't seem to be able to get arduino IDE to accept it.

Your thoughts to progress this?

Magneto runs on a PC. I use the free IDE Code::Blocks to compile and run programs on a PC.

Or you can download an executable at the author's web site.

Hi again,

Ok, not much success with magneto ... fed in the data and got some sort of eroneous data ...
So I read a bit more ... seems what we're doing here is trying to get an accurate base point for the magnetometer so it knows exactly where it is pointing ...

I think this is a bit of a rabbit hole for me ... For my project, it really doesn't matter what direction I'm facing, what I'm trying to do is detect changes in the state of the vehicle ... so if someone is attempting to steal it, the sensors will detect a variance.

So to do this, I am using two moving averages for each sensors axis' (one using 20 readings, and the other varying depending on sensitivity ... somewhere between 4 and 6) ... I calculate an absolute abs () of the difference and compare to a threshold ... exceed the threshold, and an event is detected.

Now this seems to work when I am monitoring the accerometer or gyro independently, but when I am monitoring both at the same time, it looks like the gyro goes out of control and the moving average reports "ovf".

Any thoughts about if or how the two sensors (accel and gyro) might be interacting?

Appreciate your input.

Luke.

I use a magnetometer to detect cars moving past a gate, and you are right, you don't have to calibrate it for that purpose.

What works for me is to keep a slow moving average of the magnetic field vector, and if there is a sudden change in its direction or magnitude, report that.

The code is this:

	// read magnetometer, zero out average
	fm.x = 0.;
	fm.y = 0.;
	fm.z = 0.;

	for (i=1; i<nreadings; i++) {

	read_mag_raw(m);

	fm.x += m[0];
	fm.y += m[1];
	fm.z += m[2];
	}

	fm.x *= n_avg; //average the readings
	fm.y *= n_avg;
	fm.z *= n_avg;

	diff.x = fm.x - fm_avg.x; //difference to background
	diff.y = fm.y - fm_avg.y;
	diff.z = fm.z - fm_avg.z;

	//low pass filter, after differencing

	fm_avg.x += (fm.x - fm_avg.x)*0.02;  
	fm_avg.y += (fm.y - fm_avg.y)*0.02;
	fm_avg.z += (fm.z - fm_avg.z)*0.02;

	// distance^2 from this point to average

	d2 = diff.x*diff.x + diff.y*diff.y + diff.z*diff.z + 0.5;

	if (d2 < 999.0) test=d2;
	else test = 999; //big enough!


	if(test > max_test) max_test=test; 
        passcounter++;  //count passes though loop()

// the magic alarm value 14 (below) was determined by experiment

// send a message, either upon alarm or at regular intervals

	if( (test > 14) || passcounter == 0) {  //alarm or keepalive, every ~60 seconds  
        send_message(test, max_test);
...

Yep ... that's pretty much what I've done for the accelerometer and gyro.
I'm using two moving averages though (one slow one faster) so that large outliers are ignored unless there are enough of them to mve the average up.

I think my approach with the magnetometer will be to look or variation to the stationary orientation ... although you detection of a motor vehicle is an interesting possibility. What sort of detection distance is this working over?

Also, have you had any thoughts about how/if the gyro and accerometer might be interaction to cause the "ovf" readings that im getting in the serial monitor?

Cheers

Luke.

The magnetometer I'm using can easily detect a stationary vehicle 3-4 m distant. It is more difficult if they are driving by at any significant speed, (given the background variation) but it reliably detects moving vehicles at about 1 m distance. So, it is mounted on a driveway gatepost.

cause the "ovf" readings

Please post the code, using code tags.

Hi again ...

That presents an interesting possibility for the caravan anti theft system ... detect a vehicle that is perhaps going to attempt to make off with it ... another rabbit hole for now ... lets not go there.

I've cleaned up my code a bit and removed a lot of the (what I consider useless) stuff. This seems to have also eliminated the overflow condition ...

As I mentioned earlier, I'm using moving averages to smooth out the data and avoid false positives ...
Until the moving average array has settled down, the accelerometer is producing approx 20 reports of "events" that are above the threshold. Any suggestions on a clean method of sanitising this startup output?
Serial Monitor output reads:
13:07:16.344 -> MPU9250 I AM 0x71, I should be 0x71 MPU9250 initialized, Ready ...
13:07:17.193 -> Monitoring Accelerometer ...
13:07:17.247 -> AK8963 I AM 0x48, I should be 0x48 AK8963 initialized, Ready ...
13:07:17.347 -> Delta MA_AX = 153.09 Delta MA_AY = 149.78 Delta MA_AZ = 302.80 mg
13:07:17.394 -> Acceleromter has detected an Event.
13:07:17.849 -> Delta MA_AX = 305.74 Delta MA_AY = 299.99 Delta MA_AZ = 605.84 mg
13:07:17.949 -> Acceleromter has detected an Event.
13:07:18.397 -> Delta MA_AX = 458.31 Delta MA_AY = 449.85 Delta MA_AZ = 908.21 mg
13:07:18.498 -> Acceleromter has detected an Event.
13:07:18.953 -> Delta MA_AX = 610.85 Delta MA_AY = 599.85 Delta MA_AZ = 1210.73 mg
13:07:19.021 -> Acceleromter has detected an Event.
13:07:19.496 -> Delta MA_AX = 764.16 Delta MA_AY = 750.04 Delta MA_AZ = 1513.64 mg
13:07:19.563 -> Acceleromter has detected an Event.

...

code follows:

// Serial print at 0.5 s rate independent of data rates
  myIMU.delt_t = millis() - myIMU.count;

  // update serial output once per half-second independent of read rate
  if (myIMU.delt_t > 500)
  {
    if(SeeAccelData)
    {
    // setup moving averages
      ma_sml_ax.push(myIMU.ax);
      ma_lrg_ax.push(myIMU.ax);
      ma_sml_ay.push(myIMU.ay);
      ma_lrg_ay.push(myIMU.ay);
      ma_sml_az.push(myIMU.az);
      ma_lrg_az.push(myIMU.az);
            
      if ( (1000 * abs(ma_lrg_ax.get() - ma_sml_ax.get())) >  acclThreshold 
        || (1000 * abs(ma_lrg_ay.get() - ma_sml_ay.get())) >  acclThreshold 
        || (1000 * abs(ma_lrg_az.get() - ma_sml_az.get())) >  acclThreshold)
      {            
        Serial.print (" Delta MA_AX = "); Serial.print(abs(1000 * (ma_lrg_ax.get() - ma_sml_ax.get())));    
        Serial.print (" Delta MA_AY = "); Serial.print(abs(1000 * (ma_lrg_ay.get() - ma_sml_ay.get())));    
        Serial.print (" Delta MA_AZ = "); Serial.print(abs(1000 * (ma_lrg_az.get() - ma_sml_az.get())));
        Serial.println(" mg");   
        Serial.println("    Acceleromter has detected an Event.");
      }
    }  // SeeAccelData

Also, I think I'm running out of memory ... I've used the above approach for the accelerometer and the gyroscope, but when I try to declare the arrays for the magnetometer the arduino just sits there and does nothing. Interestingly, when I compile the code, to tells me:

"Sketch uses 13592 bytes (42%) of program storage space. Maximum is 32256 bytes.
Global variables use 1105 bytes (53%) of dynamic memory, leaving 943 bytes for local variables. Maximum is 2048 bytes."

One would think that there is enough memory ... your thoughts?

Cheers

Luke

I found another thread here about using the F macro and also the PROGMEM modifier ... looks like they've collectively fixed the problem for now.

Cheers

Luke