我有一个奇怪的情况,使用你的图书馆来读取摩托车的倾角。下面我在道路的同一路段同时进行了相同的实验,红色是我使用 HyperIMU 应用程序的智能手机,蓝色是连接到 GY-521 MPU6050 板的 Arduino Beetle。
正如你所看到的,当我以正常速度转弯时,红色曲线非常水平,这意味着我保持与我所做的相同的倾斜角度。
但奇怪的是,我在 MPU6050 上得到的测量值似乎略微漂移到零。
事实上,当我移到办公桌上的黑板上时,一切都很好。仅当我在摩托车上使用它时才会出现此问题,我猜这可能是由转弯过程中的“高”重力引起的,这可能导致防漂移功能使陀螺仪读数过载。如您所见,问题在转弯期间引起的偏移或多或少会在下一个转弯(h)中找到。
你遇到过这样的问题吗?如果是,您是如何解决的?
我的代码如下:
/**
* From https://github.com/jrowberg/i2cdevlib/issues/441
*/
#include <math.h>
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include <filters.h>
#include <Servo.h>
// ---------------------------------------------------------------------------
#define YAW 0
#define PITCH 1
#define ROLL 2
#define G (double)9.80665
// --------------------- MPU6050 variables ------------------------------------
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// Orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorFloat gravity; // [x, y, z] gravity vector
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
int8_t logPitch[1400];
//int8_t logAZ[700];
int logIdx = 0;
unsigned long logTime;
// ---------------------------------------------------------------------------
#define LED_PIN 13
#define OFFSET (90)
/* The following values depends on the MPU6050 and must be defined for each chip.*/
// MPU moto
#define XACCEL_OFFSET 1921
#define YACCEL_OFFSET 1713
#define ZACCEL_OFFSET 1117
#define XGYRO_OFFSET 102
#define YGYRO_OFFSET -166
#define ZGYRO_OFFSET -200
/*/
// MPU DFRobot
#define XACCEL_OFFSET -1331
#define YACCEL_OFFSET 535
#define ZACCEL_OFFSET 883
#define XGYRO_OFFSET 45
#define YGYRO_OFFSET 29
#define ZGYRO_OFFSET 89
/*/
bool blinkState = false;
Servo servo;
int16_t ms;
int8_t global_fifo_count = 0; //made global so can monitor from outside GetIMUHeadingDeg() fcn
int8_t rollSide = 1, blinkDiv;
float angle, ay, az;
const float cutoff_freq = 7.0; //Cutoff frequency in Hz
const float sampling_time = 0.005; //Sampling time in seconds.
IIR::ORDER order = IIR::ORDER::OD2; // Order (OD1 to OD4)
Filter f_az(cutoff_freq, sampling_time, order);
Filter f_angle(cutoff_freq, sampling_time, order);
/**
Setup configuration
*/
void setup() {
// Serial.begin(115200);
// while (!Serial);
//memset(logPitch, 0, sizeof(logPitch));
logIdx = 0;
Wire.begin();
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
pinMode(LED_PIN, OUTPUT); // LED
mpu.initialize();
// Load and configure the DMP
//Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// Returns 0 if it worked
if (devStatus == 0) {
// Turn on the DMP, now that it's ready
//Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// MPU calibration: set YOUR offsets here.
mpu.setXAccelOffset(XACCEL_OFFSET);
mpu.setYAccelOffset(YACCEL_OFFSET);
mpu.setZAccelOffset(ZACCEL_OFFSET);
mpu.setXGyroOffset(XGYRO_OFFSET);
mpu.setYGyroOffset(YGYRO_OFFSET);
mpu.setZGyroOffset(ZGYRO_OFFSET);
//mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);
mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_8);
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
servo.attach(9);
servo.write(OFFSET);
delay(1000);
digitalWrite(LED_PIN, 1);
delay(10);
digitalWrite(LED_PIN, 0);
delay(50);
digitalWrite(LED_PIN, 1);
delay(10);
digitalWrite(LED_PIN, 0);
delay(50);
digitalWrite(LED_PIN, 1);
delay(10);
digitalWrite(LED_PIN, 0);
delay(2000);
logTime = millis() + 50;
//Serial.println();
}
int n = 10;
/**
Main program loop
*/
void loop() {
int8_t i;
if (Serial.available()) {
int i;
digitalWrite(LED_PIN, 1);
delay(1000);
for (i = 0; i < sizeof(logPitch); i++) {
Serial.println(logPitch[i]);
//Serial.print("\t");
//Serial.println(logAZ[i]);
delay(1);
}
digitalWrite(LED_PIN, 0);
delay(10000);
mpu.resetFIFO();
}
// if programming failed, don't try to do anything
if (!dmpReady) {
Serial.println(F("DMP Initialization failed "));
return;
}
static unsigned long MPUSampletime;
if ((millis() - MPUSampletime) >= 9) { // After FIFO read no new data will be there for at least 9 ms
MPUSampletime = millis();
if (mpu.dmpPacketAvailable())
{
//retreive the most current yaw value from IMU
angle = (f_angle.filterIn(GetIMUHeadingDeg()) * 180.0) / M_PI;
//az = f_az.filterIn((float)mpu.getAccelerationZ() / 4096.0 * G);
/*
Serial.print(-90);
Serial.print("\t");
Serial.print(90);
Serial.print("\t");
//Serial.print(millis());
//Serial.print("\t");
Serial.print(ay);
Serial.print("\t");
Serial.print(az);
Serial.print("\t");
Serial.print((angle * 90.0) / M_PI);
Serial.println();
*/
if ((millis() > logTime ) && (logIdx < (sizeof(logPitch) -1))) {
logPitch[logIdx] = (int8_t)angle;
//logAZ[logIdx] = (int8_t)(az * 10.0);
logIdx++;
logTime = millis() + 50;
// blink LED to indicate activity
if (!((blinkDiv++) % 5)) {
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}
}
//Serial.println(angle + OFFSET);
servo.write(angle + OFFSET);
}
}
}
float GetIMUHeadingDeg()
{
// At least one data packet is available
mpuIntStatus = mpu.getIntStatus();
fifoCount = mpu.getFIFOCount();// get current FIFO count
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024)
{
// reset so we can continue cleanly
mpu.resetFIFO();
//Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
}
else if (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT))
{
// read all available packets from FIFO
while (fifoCount >= packetSize) // Lets catch up to NOW, in case someone is using the dreaded delay()!
{
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
}
global_fifo_count = mpu.getFIFOCount(); //should be zero here
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
}
float pitch = -ypr[PITCH];
return pitch;
}