GithubHelp home page GithubHelp logo

robtillaart / gy521 Goto Github PK

View Code? Open in Web Editor NEW
34.0 3.0 14.0 61 KB

Arduino library for GY521 accelerometer- gyroscope a.k.a. MCU-6050

License: MIT License

C++ 80.25% C 19.75%
arduino acceleration gyro

gy521's Issues

getRegister can return an error which is not handled properly

The getRegister() function can fail and should set an error flag.
This should be handled better in the library.

Although chances are pretty small I2C errors can occur due to noise or whatever.

need to add

  • int16_t _error;
  • int16_t lastError();
  • patch code
  • function signature void -> bool?

Bad results with Teensy 3.2

Using the library with and Arduino NANO works fine. I'm plotting getAccelX, getAccelY, getAccelZ on a serial plotter and values are as expected (+1 / -1 for gradually changing position.

However, using a teensy 3.2 the same code produces very wrong results. The issue is with how the ints are treated on a 32 bit MCU, easy fix, here's how....

replace any int with int16_t and add the uint16_t to the entire value

_ax = ( ( ((int)Wire.read()) << 8) | Wire.read() ); // ACCEL_XOUT_H ACCEL_XOUT_L

final code
_ax = (int16_t)(((int16_t)Wire.read() << 8) | Wire.read()) ; // ACCEL_XOUT_H ACCEL_XOUT_L
_ay = (int16_t)(((int16_t)Wire.read() << 8) | Wire.read()) ; // ACCEL_YOUT_H ACCEL_YOUT_L
_az = (int16_t)(((int16_t)Wire.read() << 8) | Wire.read()) ; // ACCEL_ZOUT_H ACCEL_ZOUT_L
// TEMPERATURE
_temperature = (int16_t)(((int16_t)Wire.read() << 8) | Wire.read()) ; // TEMP_OUT_H TEMP_OUT_L
// GYROSCOPE
_gx = (int16_t)(((int16_t)Wire.read() << 8) | Wire.read()) ; // GYRO_XOUT_H GYRO_XOUT_L
_gy = (int16_t)(((int16_t)Wire.read() << 8) | Wire.read()) ; // GYRO_YOUT_H GYRO_YOUT_L
_gz = (int16_t)(((int16_t)Wire.read() << 8) | Wire.read()) ; // GYRO_ZOUT_H GYRO_ZOUT_L

This code works on Arduino NANO and Teensy 3.2

Shifted pitch and yaw measurement

It's difficult to describe the issue in words, so I made an illustration of it.

image

The following output is from the GY521_pitch_roll_yaw example after calibration. The actual pitch and roll movement was gradual and slow. From line 34 to 35, the measured pitch shifts by around -17. A similar shift occurs in the roll from line 36 to 37.

CNT	PITCH	ROLL	YAW
30	0.772	345.005	358.791
31	0.669	344.142	358.607
32	0.797	342.071	358.438
33	0.244	338.645	358.423
34	0.171	335.321	358.668
35	343.608	341.118	357.288
36	341.322	342.920	355.539
37	342.271	2.811	354.572
38	342.297	1.450	354.143
39	342.342	2.843	353.974

I'm not sure why this behavior happens, but I assume that the problem is caused by this library, since it does the computation of pitch/roll/yaw from the raw sensor output. I'm using version 0.3.9.


added the image for future reference

refactor GY521_readCalibration_2 (generate calibration code snippet) into a proper calibrate() function, as part of GY521 init

Right now:

GY521_readCalibration_2 generate calibration code snippet.

User need to manually copy & paste the data numbers, e.g. into application code, e.g. GY521_pitch_roll_yaw.

It's better to move GY521_readCalibration_2 (generate calibration code snippet) into a proper calibrate() function, as part of GY521 init, so the user can just call:

void setup()
  ...
  sensor.calibrate(optional_n_times_counter=100);  // easy init
}

why when I run the GY521_pitch_roll_yaw example code, all the numbers slowly increase 0 -> 359 -> 0?

I didn't move my chip, but:

...
CNT	PITCH	ROLL	YAW
97940	68.228	70.984	113.046
97941	68.247	71.046	113.051
97942	68.247	71.046	113.051
97943	68.247	71.046	113.051
97944	68.247	71.046	113.051
97945	68.263	71.107	113.057
97946	68.263	71.107	113.057
97947	68.263	71.107	113.057
97948	68.263	71.107	113.057
97949	68.279	71.166	113.061

CNT	PITCH	ROLL	YAW
97950	68.279	71.166	113.061

CNT	PITCH	ROLL	YAW
130150	215.906	233.981	152.385
130151	215.906	233.981	152.385
130152	215.924	234.042	152.390
130153	215.924	234.042	152.390
130154	215.924	234.042	152.390
130155	215.924	234.042	152.390
130156	215.942	234.107	152.395
130157	215.942	234.107	152.395
130158	215.942	234.107	152.395
130159	215.955	234.159	152.399

it goes on and on.

use float variables in example GY521_test_1.ino

  int ax = sensor.getAccelX();
  int ay = sensor.getAccelY();
  int az = sensor.getAccelZ();
  int gx = sensor.getGyroX();
  int gy = sensor.getGyroY();
  int gz = sensor.getGyroZ();
  int t = sensor.getTemperature();

change to float would give more info about the noise.
print it with 3 decimals.

improve precision

issue split of from #22

use micros() for the duration to correct pitch yaw etc.
NB with a throttle of 10 millis the accuracy of millis is typically in 2 decimals.
By using micros() one would expect one or two additional digits accuracy.

The gain will be that the duration of a force will become accurate in 0.1 or 0.01 of a millisecond.

Need to investigate how this affects the math.

  • all math is done in seconds ==> conversion factors from 1.000 => 1.000.000 (or 1e-3 to 1e-6 )
  • function lastTime() will be in micros() ==> interface break;
  • throttle time, should it be in micros() too?
  • initial values may be affected more as initial duration might be large?
  • need extra memory ?

Elaborate unit tests

  • wakeup()
  • read()
    • throttle / not
    • all xyz accel gyro angle pitch roll yaw
      • lastTime?

Raw data

hi,
I thought my board was broken, but if you read out the data manually, I get values back.
Unfortunately, with the test1 example, I only get zeros and short deflections when I move it strongly. only the temperature value works properly.
until I found out that you don't get the raw data but a calculated value.
I then built myself functions that give me the raw value, I think it would be good to add that.
the variables also have the name raw but do not contain the raw data.
I think that would help many and also mention it in the explanation.

otherwise a very good library and i hope this is a good suggestion.
Greetings orichienal

improve performance + precision

There are 3 hypot() calls in read(). These can be replaced by the equivalent

    float a2 = a * a;
    float b2 = b * b;
    float c2 = c * c;
    x = sqrt(a2 + b2);
    y = sqrt(b2 + c2);
    z = sqrt(c2 + a2);

advantage is a slightly 26 us faster read() on an UNO (163 us -> 137 us) as squares are only calculated once, and smaller size ~258 bytes ~ (number based upon test sketch).


use micros() for the duration to correct pitch yaw etc.
NB with a throttle of 10 millis the accuracy of millis is typically in 2 decimals.
By using micros() one would expect one or two additional digits accuracy.


Enabling the interruptions

The datasheet explained that we can write into the Interrupt Configuration Register to enable interrupts. And then read into the Interrupt Status Register.
Is that possible to make that from your library ?

Feature request: API for low-pass filter

Nice library! I just woul like to have a dedicated function to set/get the digital low pass filter mode. Something like setDLPFmode and getDLPFmode.

In the mean time, I will directly get/set the register, but a new function looks nicer.

Thanks!

getYaw, getPitch and getRoll go past 360 degrees

Hello!

Great work on the library, very useful for getting prototypes done, however, I would like to know if there is any way to make the return of the functions getYaw, getPitch and getRoll to clamp to 360 degrees? I have a device that continuously rotates in one direction (quickly), I don't know if waiting for a float overflow to reset the counter is a good idea.

Calibration never zeros out

13:04:18.394 -> 	ACCELEROMETER		GYROSCOPE		TEMPERATURE
13:04:18.394 -> 	-8.040	2.777	-500.143	0.568	-2.084	1.113
13:04:18.394 -> 	axe	aye	aze	gxe	gye	gze	T
13:04:18.394 -> 480	-0.018	0.005	-1.042	0.019	0.041	0.013	39.77
13:04:18.584 -> 481	-0.016	0.006	-1.042	-0.029	-0.003	-0.050	39.84
13:04:18.725 -> 482	-0.017	0.006	-1.042	0.005	0.020	0.072	39.79
13:04:18.863 -> 483	-0.017	0.006	-1.042	0.042	-0.053	-0.061	39.83
13:04:19.049 -> 484	-0.017	0.006	-1.043	-0.041	0.048	0.060	39.77
13:04:19.187 -> 485	-0.017	0.007	-1.042	0.013	0.001	-0.018	39.82
13:04:19.378 -> 486	-0.017	0.006	-1.042	0.034	-0.045	-0.005	39.82
13:04:19.556 -> 487	-0.017	0.007	-1.042	-0.049	0.002	0.036	39.80
13:04:19.704 -> 488	-0.016	0.006	-1.043	0.017	0.013	-0.014	39.82
13:04:19.844 -> 489	-0.016	0.006	-1.044	0.035	-0.029	-0.034	39.77

...

13:11:07.122 -> 	ACCELEROMETER		GYROSCOPE		TEMPERATURE
13:11:07.122 -> 	-53.020	16.354	-3115.312	0.550	-2.084	1.194
13:11:07.122 -> 	axe	aye	aze	gxe	gye	gze	T
13:11:07.122 -> 2990	-0.022	0.004	-1.042	0.023	0.038	-0.060	39.82
13:11:07.259 -> 2991	-0.020	0.004	-1.043	0.005	0.027	-0.027	39.84
13:11:07.446 -> 2992	-0.021	0.003	-1.043	-0.006	-0.040	0.068	39.80
13:11:07.586 -> 2993	-0.020	0.004	-1.042	0.021	-0.018	-0.088	39.81
13:11:07.773 -> 2994	-0.021	0.005	-1.042	0.008	-0.003	0.047	39.85
13:11:07.915 -> 2995	-0.020	0.005	-1.043	-0.038	0.004	-0.016	39.82
13:11:08.102 -> 2996	-0.021	0.004	-1.043	0.026	0.019	0.023	39.78
13:11:08.242 -> 2997	-0.020	0.003	-1.043	0.000	-0.017	-0.040	39.82
13:11:08.430 -> 2998	-0.021	0.004	-1.042	-0.025	0.039	0.042	39.80
13:11:08.572 -> 2999	-0.021	0.003	-1.041	0.037	-0.021	-0.018	39.83

In my case, the values for the accel and gyro switched.

Invalid data without Reset while initializing the begin

whith out the code bellow i am getting invalid data when starting up the sensor
Wire.write(0x6B); //make the reset (place a 0 into the 6B register)
Wire.write(0x00);
Wire.endTransmission(true); //end the transmission

we need to reset the MPU6050 before we set any other register

this is coded in your function bool GY521::wakeup()
we need to call this after begin() before we read() any data.

Please verify and include this Readme if needed !!

void GY521 :: setAccelSensitivity (uint8_t as) _afs problem in function.

void GY521::setAccelSensitivity(uint8_t as)
{
  if (as > 3) as = 3;
  uint8_t val = getRegister(GY521_ACCEL_CONFIG);
  val &= 0xE7;
  val |= (as << 3);
  setRegister(GY521_ACCEL_CONFIG, val);
  // calculate conversion factor.
  _raw2g = 16384.0;
  for (uint8_t i = 0; i < _afs; i++) _raw2g *= 0.5;
  _raw2g = 1.0 / _raw2g;
}

_afs is zero-defined.
the corrected version should be like this.

void GY521::setAccelSensitivity(uint8_t as)
{
  _afs = as;
  if (_afs > 3) _afs = 3;
  uint8_t val = getRegister(GY521_ACCEL_CONFIG);
  val &= 0xE7;
  val |= (_afs << 3);
  setRegister(GY521_ACCEL_CONFIG, val);
  // calculate conversion factor.
  _raw2g = 16384.0;
  for (uint8_t i = 0; i < _afs; i++) _raw2g *= 0.5;
  _raw2g = 1.0 / _raw2g;
}

am I right?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.