0

我有一个奇怪的情况,使用你的图书馆来读取摩托车的倾角。下面我在道路的同一路段同时进行了相同的实验,红色是我使用 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;
}
4

0 回答 0