Arduino/MPU6050/AdafruitMotorShieldV2:脚本挂起/冻结时,打开电机



一般来说,我是一个机器人和电子产品的新手,所以请不要以为我尝试了任何你认为显而易见的东西。

我正在尝试创建一个手推车,它基本上会自己跑来跑去(简单的AI例程,以避免障碍,从pt. a到pt. B周围的角落,沿着线等)。我把Adafruit Arduino Uno R3与Adafruit Motor Shield v2和MPU-6050放在一起。我在电机屏蔽上使用"面包板"作为电路,焊接那里的所有东西。

我可以得到与自己的脚本独立工作的所有部分:电机屏蔽驱动4电机预期使用Adafruit库;我对MPU-6050使用"JRowberg"库,并从示例MPU6050_DMP6开始。Ino,只要车的马达关闭,它就能正常工作。我在下面的示例脚本中唯一的变化是电机启动和一些简单的电机命令。

只要我离开关闭电机的开关,一切似乎都很好:它用欧拉数据连续输出到串行窗口,我认为这是正确的。然而,在我打开电机电源几秒钟后(轮子开始转动),它只是挂起/冻结:输出到串行窗口停止(有时在中线),轮子继续以他们最后一次改变的速度转动。有时我看到"FIFO溢出"错误,但并非总是如此。有时在挂起之前,我看到一些浮点值为"nan",但并非总是如此。

我尝试了一些事情,都没有改变:*我已经把同一厂家的MPU-6050板换成了另一块。*我试过用带状电缆把MPU-6050从马达上移开。*我已经改变了I2C时钟使用JRowber的建议(改变。h文件和改变TWBR变量的值),但我不认为我已经尝试了所有可能的值。*我在AFMS.begin()命令中改变了MotorShield的速度,虽然,再次,可能还有其他值我没有尝试过,我不确定如何同步这和TWBR值需要。

和其他一些事情,都无济于事。

下面是一个失败的脚本示例:

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif
#include "Adafruit_MotorShield.h"
#include "utility/Adafruit_PWMServoDriver.h"
#define DEBUG 1
MPU6050 mpu;
#define OUTPUT_READABLE_EULER
#define LED_PIN 13
bool blinkState = false;
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
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, 'r', 'n' };
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
#define NUM_MOTORS 4
#define MOTOR_FL 0
#define MOTOR_FR 1
#define MOTOR_RR 2
#define MOTOR_RL 3
Adafruit_DCMotor *myMotors[NUM_MOTORS] =  {
  AFMS.getMotor(1),
  AFMS.getMotor(2),
  AFMS.getMotor(3),
  AFMS.getMotor(4),
};
#define CHANGE_SPEED_TIME 500
long changeSpeedMillis = 0;
int curSpeed = 30;
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}
void setup() {
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif
    Serial.begin(115200);
    while (!Serial); // wait for Leonardo enumeration, others continue immediately
    // start the motor shield.
      AFMS.begin();  // create with the default frequency 1.6KHz
//    AFMS.begin(4000);  // OR with a different frequency, say 4KHz
    // kill all the motors.
    myMotors[MOTOR_FL]->run(BRAKE);
    myMotors[MOTOR_FL]->setSpeed(0);  
    myMotors[MOTOR_FR]->run(BRAKE);
    myMotors[MOTOR_FR]->setSpeed(0);  
    myMotors[MOTOR_RR]->run(BRAKE);
    myMotors[MOTOR_RR]->setSpeed(0);  
    myMotors[MOTOR_RL]->run(BRAKE);
    myMotors[MOTOR_RL]->setSpeed(0);
    Serial.println("Motor Shield ready!");
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    // verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") :     F("MPU6050 connection failed"));
    // wait for ready
    Serial.println(F("nSend any character to begin DMP programming and demo: "));
    while (Serial.available() && Serial.read()); // empty buffer
    while (!Serial.available());                 // wait for data
    while (Serial.available() && Serial.read()); // empty buffer again
    // load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();
    // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
    // make sure it worked (returns 0 if so)
    if (devStatus == 0) {
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);
        // enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();
        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        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(")"));
    }
    // configure LED for output
    pinMode(LED_PIN, OUTPUT);
}
void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;
    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
      // as per Vulpo's post.
      delay(10);
      if (millis() > changeSpeedMillis) {
            curSpeed += 20;
            if (curSpeed > 256) {
              curSpeed = 30;
            }
            Serial.print("changing speed to: ");
            Serial.println(curSpeed);
            myMotors[MOTOR_FL]->run(FORWARD);
            myMotors[MOTOR_FL]->setSpeed(curSpeed);
            myMotors[MOTOR_FR]->run(FORWARD);
            myMotors[MOTOR_FR]->setSpeed(curSpeed);
            myMotors[MOTOR_RR]->run(FORWARD);
            myMotors[MOTOR_RR]->setSpeed(curSpeed);
            myMotors[MOTOR_RL]->run(FORWARD);
            myMotors[MOTOR_RL]->setSpeed(curSpeed);
            changeSpeedMillis = millis() + CHANGE_SPEED_TIME;
      }
    }
    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    // get current FIFO count
    fifoCount = mpu.getFIFOCount();
    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || 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 & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        // read a packet from FIFO
        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;
        #ifdef OUTPUT_READABLE_EULER
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);
            Serial.print("eulert");
            Serial.print(euler[0] * 180/M_PI);
            Serial.print("t");
            Serial.print(euler[1] * 180/M_PI);
            Serial.print("t");
            Serial.println(euler[2] * 180/M_PI);
        #endif
        // blink LED to indicate activity
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
    }
}

你是否考虑过你的故障是由流入电机的电流干扰引起的?如果你的电机是直流电刷,那么更多的干扰可能会从电刷辐射回你的各种电线。作为第一步,也许只让一个电机工作,看看挂起的频率是否减少(尽管,可以肯定的是,你需要一个'scope到几根携带逻辑信号的电线上。

相关内容

  • 没有找到相关文章

最新更新