Histogram of stationary GY-521 accelerometer readings over 10 minutes.

I was using an GY-521 accelerometer/gyroscope module in order to provide inertial tracking. The GY-521 interfaces with an Arduino which sends data over a serial connection. I convert these values into physical values (simply multiplying by a calibration constant) in a python script and then append all values to an array which I have plot into a histogram shown.

I left the sensor stationary on a table top for approximately 10 minutes to try and work out the nature of the noise.

As you can see from the histogram certain values of acceleration never had a single observation and these values appear at regular intervals. Some values also seem to be much more common than the rest of the noise.

(Main question) Is there a physical explanation for this?

(Sub-Question) What type of filtering/smoothing would you suggest to improve this? We first implemented box smoothing which worked well at preventing drift when stationary but made the system less responsive to sudden changes in rotation. I explored heavily the use of kalman filters but without a magnetometer to give measurements for attitude I could not work out how to use accelerator data for both correction of orientation and displacement tracking (since moving around with acceleration in the order of g makes the gravity vector ambiguous). Without proper smoothing of the angular velocity data the reference frame is rotated with sensor noise making drift significant after only a few seconds of running.

[EDIT]: The code running on the Arduino is from this github repository. The python script is shown below. To my knowledge the histogram is plotting raw data (multiplied by a constant).

import serial
import time
import matplotlib.pyplot as plt

#establish serial connection to Arduino/GY521
ser = serial.Serial('COM3', 38400) #Baud rate 38400 Hz, COM port must match.
for i in range(0,3):

res = 2**16;
# sensitivity setting
a_sen = 2* 9.81; #m/s^2
g_sen = 250 ; #deg/s

ax = []
ay = []
az = []
gx = []
gy = []
gz = []
t  = []

#main loop
    print("Capturing data, press ctrl+C to finish")

    #obtain data
    while 1:
        s = ser.readline(100)
        ss = s.decode("utf-8","ignore").replace('\r\n','').split('\t')
        ss = ss[1:]

except KeyboardInterrupt:

    #convert the read values into physical values
    ax = [int(i)*a_sen*2 / res for i in ax] 
    ay = [int(i)*a_sen*2 / res for i in ay] 
    az = [int(i)*a_sen*2 / res for i in az] 
    gx = [int(i)*g_sen*2 / res for i in gx]
    gy = [int(i)*g_sen*2 / res for i in gy]
    gz = [int(i)*g_sen*2 / res for i in gz]
    t = [int(tm)/1000 for tm in t]

    plt.xlabel('Accel (m/s^2)')
    plt.legend(loc = 'center left',bbox_to_anchor=(0.975, 0.5))

  • 1
    \$\begingroup\$ What if you do the same for raw values? If you multiply with a value greater than unity and round off the result could explain this, so post your code to find out bugs in it. \$\endgroup\$ – Justme Mar 8 '20 at 18:11
  • \$\begingroup\$ @Justme I've posted the code \$\endgroup\$ – Space Otter Mar 8 '20 at 18:26
  • \$\begingroup\$ Try and collect the raw data and recreate the plot with a spreadsheet to rule out errors in the plotting routines. \$\endgroup\$ – KalleMP Mar 8 '20 at 20:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.