GY-63_MS5611/libraries/GY521/GY521.cpp

556 lines
12 KiB
C++
Raw Normal View History

2021-01-29 06:31:58 -05:00
//
// FILE: GY521.cpp
// AUTHOR: Rob Tillaart
2024-05-10 10:22:06 -04:00
// VERSION: 0.5.3
2021-01-29 06:31:58 -05:00
// PURPOSE: Arduino library for I2C GY521 accelerometer-gyroscope sensor
// URL: https://github.com/RobTillaart/GY521
#include "GY521.h"
2022-10-08 09:41:16 -04:00
// keep register names in sync with BIG MPU6050 lib
2021-01-29 06:31:58 -05:00
#include "GY521_registers.h"
2022-10-08 09:41:16 -04:00
// COMMANDS
2021-01-29 06:31:58 -05:00
#define GY521_WAKEUP 0x00
/////////////////////////////////////////////////////
//
// PUBLIC
//
2021-07-05 13:35:46 -04:00
GY521::GY521(uint8_t address, TwoWire *wire)
2021-01-29 06:31:58 -05:00
{
_address = address;
2021-07-05 13:35:46 -04:00
_wire = wire;
2023-12-11 09:36:02 -05:00
_ax = _ay = _az = 0;
_aax = _aay = _aaz = 0;
_gx = _gy = _gz = 0;
_pitch = 0;
_roll = 0;
_yaw = 0;
2021-01-29 06:31:58 -05:00
}
2021-06-13 10:00:27 -04:00
2021-01-29 06:31:58 -05:00
bool GY521::begin()
{
2021-10-20 12:48:35 -04:00
if (isConnected())
{
return wakeup();
}
2023-12-11 09:36:02 -05:00
reset();
2021-10-20 12:48:35 -04:00
return false;
2021-01-29 06:31:58 -05:00
}
2021-06-13 10:00:27 -04:00
2021-01-29 06:31:58 -05:00
bool GY521::isConnected()
{
2021-07-05 13:35:46 -04:00
_wire->beginTransmission(_address);
return (_wire->endTransmission() == 0);
2021-01-29 06:31:58 -05:00
}
2022-10-08 09:41:16 -04:00
2024-05-10 10:22:06 -04:00
uint8_t GY521::getAddress()
{
return _address;
}
2021-06-13 10:00:27 -04:00
void GY521::reset()
{
setThrottleTime(GY521_THROTTLE_TIME);
_ax = _ay = _az = 0;
_aax = _aay = _aaz = 0;
_gx = _gy = _gz = 0;
_pitch = 0;
_roll = 0;
_yaw = 0;
}
2024-01-18 12:45:28 -05:00
void GY521::calibrate(uint16_t times)
{
// disable throttling / caching of read values.
bool oldThrottle = _throttle;
_throttle = false;
2024-05-10 10:22:06 -04:00
2024-01-18 12:45:28 -05:00
// set errors to zero
axe = aye = aze = 0;
gxe = gye = gze = 0;
for (uint16_t i = 0; i < times; i++)
{
read();
axe -= getAccelX();
aye -= getAccelY();
aze -= getAccelZ();
gxe -= getGyroX();
gye -= getGyroY();
gze -= getGyroZ();
}
// adjust calibration errors so table should get all zero's.
float factor = 1.0 / times;
axe *= factor;
aye *= factor;
aze *= factor;
gxe *= factor;
gye *= factor;
gze *= factor;
// restore throttle state
_throttle = oldThrottle;
}
2021-01-29 06:31:58 -05:00
bool GY521::wakeup()
{
2021-07-05 13:35:46 -04:00
_wire->beginTransmission(_address);
_wire->write(GY521_PWR_MGMT_1);
_wire->write(GY521_WAKEUP);
return (_wire->endTransmission() == 0);
2021-01-29 06:31:58 -05:00
}
2021-06-13 10:00:27 -04:00
2021-01-29 06:31:58 -05:00
int16_t GY521::read()
{
2021-07-12 14:19:59 -04:00
uint32_t now = millis();
2021-01-29 06:31:58 -05:00
if (_throttle)
{
2021-07-12 14:19:59 -04:00
if ((now - _lastTime) < _throttleTime)
2021-01-29 06:31:58 -05:00
{
2022-10-08 09:41:16 -04:00
// not an error.
2021-01-29 06:31:58 -05:00
return GY521_THROTTLED;
}
}
2021-07-12 14:19:59 -04:00
_lastTime = now;
2021-01-29 06:31:58 -05:00
2022-10-08 09:41:16 -04:00
// Connected ?
2021-07-05 13:35:46 -04:00
_wire->beginTransmission(_address);
_wire->write(GY521_ACCEL_XOUT_H);
if (_wire->endTransmission() != 0)
{
_error = GY521_ERROR_WRITE;
return _error;
}
2021-01-29 06:31:58 -05:00
2022-10-08 09:41:16 -04:00
// Get the data
2021-07-05 13:35:46 -04:00
int8_t n = _wire->requestFrom(_address, (uint8_t)14);
if (n != 14)
{
_error = GY521_ERROR_READ;
return _error;
}
2022-10-08 09:41:16 -04:00
// ACCELEROMETER
_ax = _WireRead2(); // ACCEL_XOUT_H ACCEL_XOUT_L
_ay = _WireRead2(); // ACCEL_YOUT_H ACCEL_YOUT_L
_az = _WireRead2(); // ACCEL_ZOUT_H ACCEL_ZOUT_L
// TEMPERATURE
_temperature = _WireRead2(); // TEMP_OUT_H TEMP_OUT_L
// GYROSCOPE
_gx = _WireRead2(); // GYRO_XOUT_H GYRO_XOUT_L
_gy = _WireRead2(); // GYRO_YOUT_H GYRO_YOUT_L
_gz = _WireRead2(); // GYRO_ZOUT_H GYRO_ZOUT_L
// duration interval
2021-07-12 14:19:59 -04:00
now = micros();
2023-11-02 10:58:05 -04:00
float duration = (now - _lastMicros) * 1e-6; // duration in seconds.
2021-07-12 14:19:59 -04:00
_lastMicros = now;
2021-01-29 06:31:58 -05:00
2023-06-12 11:34:31 -04:00
// next lines might be merged per axis. (performance)
2021-07-05 13:35:46 -04:00
2022-10-08 09:41:16 -04:00
// Convert raw acceleration to g's
2021-01-29 06:31:58 -05:00
_ax *= _raw2g;
_ay *= _raw2g;
_az *= _raw2g;
2022-10-08 09:41:16 -04:00
// Error correct raw acceleration (in g) measurements // #18 kudos to Merkxic
2021-04-25 13:56:44 -04:00
_ax += axe;
_ay += aye;
_az += aze;
2022-10-08 09:41:16 -04:00
// prepare for Pitch Roll Yaw
2021-07-05 13:35:46 -04:00
float _ax2 = _ax * _ax;
float _ay2 = _ay * _ay;
float _az2 = _az * _az;
2024-01-18 12:45:28 -05:00
// calculate angle
2022-10-08 09:41:16 -04:00
_aax = atan( _ay / sqrt(_ax2 + _az2)) * GY521_RAD2DEGREES;
_aay = atan(-1.0 * _ax / sqrt(_ay2 + _az2)) * GY521_RAD2DEGREES;
_aaz = atan( _az / sqrt(_ax2 + _ay2)) * GY521_RAD2DEGREES;
// optimize #22
// _aax = atan(_ay / hypot(_ax, _az)) * GY521_RAD2DEGREES;
// _aay = atan(-1.0 * _ax / hypot(_ay, _az)) * GY521_RAD2DEGREES;
// _aaz = atan(_az / hypot(_ax, _ay)) * GY521_RAD2DEGREES;
2021-01-29 06:31:58 -05:00
2022-10-08 09:41:16 -04:00
// Convert to Celsius
2021-01-29 06:31:58 -05:00
_temperature = _temperature * 0.00294117647 + 36.53; // == /340.0 + 36.53;
2022-10-08 09:41:16 -04:00
// Convert raw Gyro to degrees/seconds
2021-01-29 06:31:58 -05:00
_gx *= _raw2dps;
_gy *= _raw2dps;
_gz *= _raw2dps;
2021-07-05 13:35:46 -04:00
2022-10-08 09:41:16 -04:00
// Error correct raw gyro measurements.
2021-01-29 06:31:58 -05:00
_gx += gxe;
_gy += gye;
_gz += gze;
2021-07-05 13:35:46 -04:00
2024-01-18 12:45:28 -05:00
// integrate gyroscope data
2021-01-29 06:31:58 -05:00
_gax += _gx * duration;
_gay += _gy * duration;
_gaz += _gz * duration;
2024-01-18 12:45:28 -05:00
// experimental below this line.
// Pitch Roll Yaw are work in progress
2023-06-12 11:34:31 -04:00
// normalize
// _gax etc might loose precision after many iterations #36
if (_normalize)
{
// correction at 375 due to the factor 0.96 in roll
if (_gax >= 375) _gax -= 375;
else if (_gax < 0) _gax += 375;
// correction at 375 due to the factor 0.96 in pitch
if (_gay >= 375) _gay -= 375;
else if (_gay < 0) _gay += 375;
2023-11-02 10:58:05 -04:00
// correction at 360
2023-06-12 11:34:31 -04:00
if (_gaz >= 360) _gaz -= 360;
else if (_gaz < 0) _gaz += 360;
}
2022-10-08 09:41:16 -04:00
2023-06-12 11:34:31 -04:00
// Calculate Pitch Roll Yaw
2021-07-05 13:35:46 -04:00
_yaw = _gaz;
_roll = 0.96 * _gax + 0.04 * _aax;
2023-06-12 11:34:31 -04:00
_pitch = 0.96 * _gay + 0.04 * _aay;
2021-01-29 06:31:58 -05:00
2023-06-12 11:34:31 -04:00
if (_normalize)
{
if (_pitch >= 360) _pitch -= 360;
else if (_pitch < 0) _pitch += 360;
if (_roll >= 360) _roll -= 360;
else if (_roll < 0) _roll += 360;
if (_yaw >= 360) _yaw -= 360;
else if (_yaw < 0) _yaw += 360;
}
2022-10-08 09:41:16 -04:00
2021-01-29 06:31:58 -05:00
return GY521_OK;
}
2021-06-13 10:00:27 -04:00
2022-07-27 06:42:05 -04:00
int16_t GY521::readAccel()
{
uint32_t now = millis();
if (_throttle)
{
if ((now - _lastTime) < _throttleTime)
{
// not an error.
return GY521_THROTTLED;
}
}
_lastTime = now;
2022-10-08 09:41:16 -04:00
// Connected ?
2022-07-27 06:42:05 -04:00
_wire->beginTransmission(_address);
_wire->write(GY521_ACCEL_XOUT_H);
if (_wire->endTransmission() != 0)
{
_error = GY521_ERROR_WRITE;
return _error;
}
// Get the data
int8_t n = _wire->requestFrom(_address, (uint8_t)6);
if (n != 6)
{
_error = GY521_ERROR_READ;
return _error;
}
2022-10-08 09:41:16 -04:00
// ACCELEROMETER
_ax = _WireRead2(); // ACCEL_XOUT_H ACCEL_XOUT_L
_ay = _WireRead2(); // ACCEL_YOUT_H ACCEL_YOUT_L
_az = _WireRead2(); // ACCEL_ZOUT_H ACCEL_ZOUT_L
2022-07-27 06:42:05 -04:00
2022-10-08 09:41:16 -04:00
// next lines might be merged per axis.
2022-07-27 06:42:05 -04:00
2022-10-08 09:41:16 -04:00
// Convert raw acceleration to g's
2022-07-27 06:42:05 -04:00
_ax *= _raw2g;
_ay *= _raw2g;
_az *= _raw2g;
2022-10-08 09:41:16 -04:00
// Error correct raw acceleration (in g) measurements // #18 kudos to Merkxic
2022-07-27 06:42:05 -04:00
_ax += axe;
_ay += aye;
_az += aze;
2022-10-08 09:41:16 -04:00
// prepare for Pitch Roll Yaw
2022-07-27 06:42:05 -04:00
float _ax2 = _ax * _ax;
float _ay2 = _ay * _ay;
float _az2 = _az * _az;
2024-01-18 12:45:28 -05:00
// calculate angles.
2022-10-08 09:41:16 -04:00
_aax = atan( _ay / sqrt(_ax2 + _az2)) * GY521_RAD2DEGREES;
_aay = atan(-1.0 * _ax / sqrt(_ay2 + _az2)) * GY521_RAD2DEGREES;
_aaz = atan( _az / sqrt(_ax2 + _ay2)) * GY521_RAD2DEGREES;
// optimize #22
// _aax = atan(_ay / hypot(_ax, _az)) * GY521_RAD2DEGREES;
// _aay = atan(-1.0 * _ax / hypot(_ay, _az)) * GY521_RAD2DEGREES;
// _aaz = atan(_az / hypot(_ax, _ay)) * GY521_RAD2DEGREES;
2022-07-27 06:42:05 -04:00
return GY521_OK;
}
int16_t GY521::readGyro()
{
uint32_t now = millis();
if (_throttle)
{
if ((now - _lastTime) < _throttleTime)
{
// not an error.
return GY521_THROTTLED;
}
}
_lastTime = now;
2022-10-08 09:41:16 -04:00
// Connected ?
2022-07-27 06:42:05 -04:00
_wire->beginTransmission(_address);
_wire->write(GY521_GYRO_XOUT_H);
if (_wire->endTransmission() != 0)
{
_error = GY521_ERROR_WRITE;
return _error;
}
2022-10-08 09:41:16 -04:00
// Get the data
2022-07-27 06:42:05 -04:00
int8_t n = _wire->requestFrom(_address, (uint8_t)6);
if (n != 6)
{
_error = GY521_ERROR_READ;
return _error;
}
2022-10-08 09:41:16 -04:00
// GYROSCOPE
_gx = _WireRead2(); // GYRO_XOUT_H GYRO_XOUT_L
_gy = _WireRead2(); // GYRO_YOUT_H GYRO_YOUT_L
_gz = _WireRead2(); // GYRO_ZOUT_H GYRO_ZOUT_L
2022-07-27 06:42:05 -04:00
2022-10-08 09:41:16 -04:00
// duration interval
2022-07-27 06:42:05 -04:00
now = micros();
2022-10-08 09:41:16 -04:00
float duration = (now - _lastMicros) * 1e-6; // duration in seconds.
2022-07-27 06:42:05 -04:00
_lastMicros = now;
2022-10-08 09:41:16 -04:00
// next lines might be merged per axis.
2022-07-27 06:42:05 -04:00
2022-10-08 09:41:16 -04:00
// Convert raw Gyro to degrees/seconds
2022-07-27 06:42:05 -04:00
_gx *= _raw2dps;
_gy *= _raw2dps;
_gz *= _raw2dps;
2022-10-08 09:41:16 -04:00
// Error correct raw gyro measurements.
2022-07-27 06:42:05 -04:00
_gx += gxe;
_gy += gye;
_gz += gze;
_gax += _gx * duration;
_gay += _gy * duration;
_gaz += _gz * duration;
2022-10-08 09:41:16 -04:00
2024-01-18 12:45:28 -05:00
// experimental below this line.
2023-06-12 11:34:31 -04:00
// normalize
// _gax etc might loose precision after many iterations #36
if (_normalize)
{
// correction at 375 due to the factor 0.96 in roll
if (_gax >= 375) _gax -= 375;
else if (_gax < 0) _gax += 375;
// correction at 375 due to the factor 0.96 in pitch
if (_gay >= 375) _gay -= 375;
else if (_gay < 0) _gay += 375;
2023-11-02 10:58:05 -04:00
// correction at 360
2023-06-12 11:34:31 -04:00
if (_gaz >= 360) _gaz -= 360;
else if (_gaz < 0) _gaz += 360;
}
2022-07-27 06:42:05 -04:00
return GY521_OK;
}
int16_t GY521::readTemperature()
{
// DO NOT THROTTLE
_wire->beginTransmission(_address);
_wire->write(GY521_TEMP_OUT_H);
if (_wire->endTransmission() != 0)
{
_error = GY521_ERROR_WRITE;
return _error;
}
2022-10-08 09:41:16 -04:00
// Get the data
2022-07-27 06:42:05 -04:00
int8_t n = _wire->requestFrom(_address, (uint8_t)2);
if (n != 2)
{
_error = GY521_ERROR_READ;
return _error;
}
2022-10-08 09:41:16 -04:00
// TEMPERATURE
_temperature = _WireRead2(); // TEMP_OUT_H TEMP_OUT_L
2022-07-27 06:42:05 -04:00
return GY521_OK;
}
2021-01-29 06:31:58 -05:00
bool GY521::setAccelSensitivity(uint8_t as)
{
_afs = as;
if (_afs > 3) _afs = 3;
uint8_t val = getRegister(GY521_ACCEL_CONFIG);
if (_error != 0)
{
return false;
}
2023-11-02 10:58:05 -04:00
// no need to write same value
2021-01-29 06:31:58 -05:00
if (((val >> 3) & 3) != _afs)
{
val &= 0xE7;
val |= (_afs << 3);
if (setRegister(GY521_ACCEL_CONFIG, val) != GY521_OK)
{
return false;
}
}
2023-11-02 10:58:05 -04:00
// calculate conversion factor. // 4 possible values => lookup table?
2022-10-08 09:41:16 -04:00
_raw2g = (1 << _afs) * GY521_RAW2G;
2021-01-29 06:31:58 -05:00
return true;
}
2021-06-13 10:00:27 -04:00
2021-01-29 06:31:58 -05:00
uint8_t GY521::getAccelSensitivity()
{
uint8_t val = getRegister(GY521_ACCEL_CONFIG);
if (_error != GY521_OK)
{
2023-11-02 10:58:05 -04:00
return _error; // return and propagate error (best thing to do)
2021-01-29 06:31:58 -05:00
}
_afs = (val >> 3) & 3;
return _afs;
}
2021-06-13 10:00:27 -04:00
2021-01-29 06:31:58 -05:00
bool GY521::setGyroSensitivity(uint8_t gs)
{
_gfs = gs;
if (_gfs > 3) _gfs = 3;
uint8_t val = getRegister(GY521_GYRO_CONFIG);
if (_error != 0)
{
return false;
}
2022-10-08 09:41:16 -04:00
// no need to write same value
2021-01-29 06:31:58 -05:00
if (((val >> 3) & 3) != _gfs)
{
val &= 0xE7;
val |= (_gfs << 3);
if (setRegister(GY521_GYRO_CONFIG, val) != GY521_OK)
{
return false;
}
}
2023-11-02 10:58:05 -04:00
// calculate conversion factor..
2022-10-08 09:41:16 -04:00
// 4 possible values => lookup table?
_raw2dps = (1 << _gfs) * GY521_RAW2DPS;
2021-01-29 06:31:58 -05:00
return true;
}
2021-06-13 10:00:27 -04:00
2021-01-29 06:31:58 -05:00
uint8_t GY521::getGyroSensitivity()
{
uint8_t val = getRegister(GY521_GYRO_CONFIG);
if (_error != GY521_OK)
{
2022-10-08 09:41:16 -04:00
return _error; // return and propagate error (best thing to do)
2021-01-29 06:31:58 -05:00
}
_gfs = (val >> 3) & 3;
return _gfs;
}
2021-06-13 10:00:27 -04:00
2024-05-10 10:22:06 -04:00
// CONFIGURATION
// Digital Low Pass Filter datasheet P13-reg26
bool GY521::setDLPFMode(uint8_t mode)
{
if (mode > 6)
{
_error = GY521_ERROR_PARAMETER;
return false;
}
uint8_t value = getRegister(GY521_CONFIG);
value &= 0xF8;
value |= mode;
return (setRegister(GY521_CONFIG, value) == GY521_OK);
}
uint8_t GY521::getDLPFMode()
{
uint8_t val = getRegister(GY521_CONFIG);
return val & 0x07;
}
// GENERIC
2021-01-29 06:31:58 -05:00
uint8_t GY521::setRegister(uint8_t reg, uint8_t value)
{
2021-07-05 13:35:46 -04:00
_wire->beginTransmission(_address);
_wire->write(reg);
_wire->write(value);
2022-10-08 09:41:16 -04:00
// no need to do anything if not connected.
2021-07-05 13:35:46 -04:00
if (_wire->endTransmission() != 0)
2021-01-29 06:31:58 -05:00
{
_error = GY521_ERROR_WRITE;
return _error;
}
return GY521_OK;
}
2021-06-13 10:00:27 -04:00
2021-01-29 06:31:58 -05:00
uint8_t GY521::getRegister(uint8_t reg)
{
2021-07-05 13:35:46 -04:00
_wire->beginTransmission(_address);
_wire->write(reg);
if (_wire->endTransmission() != 0)
2021-01-29 06:31:58 -05:00
{
_error = GY521_ERROR_WRITE;
return _error;
}
2021-07-05 13:35:46 -04:00
uint8_t n = _wire->requestFrom(_address, (uint8_t) 1);
if (n != 1)
2021-01-29 06:31:58 -05:00
{
_error = GY521_ERROR_READ;
return _error;
}
2021-07-05 13:35:46 -04:00
uint8_t val = _wire->read();
2021-01-29 06:31:58 -05:00
return val;
}
2021-06-13 10:00:27 -04:00
2022-10-08 09:41:16 -04:00
// to read register of 2 bytes.
2021-01-29 06:31:58 -05:00
int16_t GY521::_WireRead2()
{
2021-07-05 13:35:46 -04:00
int16_t tmp = _wire->read();
2021-01-29 06:31:58 -05:00
tmp <<= 8;
2021-07-05 13:35:46 -04:00
tmp |= _wire->read();
2021-01-29 06:31:58 -05:00
return tmp;
}
2021-07-05 13:35:46 -04:00
2023-11-02 10:58:05 -04:00
// -- END OF FILE --
2021-12-18 12:14:36 -05:00