2014-06-29 148 views
0

我是機器人技術和電子產品的一般新手機,所以請不要假設我嘗試了任何您可能認爲明顯的事情。Arduino/MPU6050/AdafruitMotorShieldV2:打開電機時腳本掛起/凍結

我正在嘗試創建一個基本上可以自行運行的購物車(簡單的AI例程以避開障礙物,從點A到點B,圍繞角落,跟隨線條等)。我在Adafruit Arduino Uno R3上安裝Adafruit Motor Shield v2和MPU-6050。我在電機屏蔽上使用電路板上的「麪包板」,焊接所有部件。

我可以通過他們自己的腳本獲得所有獨立工作的部分:電機屏蔽使用Adafruit庫驅動4臺電機,我爲MPU-6050使用了「JRowberg」庫,並從示例MPU6050_DMP6.ino開始,只要手推車電機關閉,它就能正常工作。我在下面的示例腳本中唯一的變化是電機啓動和一些簡單的電機命令。

只要我離開電源關閉的開關,一切似乎都很好:它連續輸出到串行窗口,我假設歐拉數據是正確的。但是,在打開電機的電源(並開始轉動車輪)幾秒鐘之後,它會掛起/凍結:到串行窗口的輸出停止(有時在中線),並且車輪繼續轉向他們最後一次改變的速度。有時我會看到「FIFO溢出」錯誤,但並非總是如此。有時我會在掛起之前看到某些浮點值的「nan」,但並非總是如此。

我嘗試過的一些事情,所有這些都改變了注意: *我已將MPU-6050電路板換成另一個來自同一製造商的電路板。 *我嘗試使用帶狀電纜將MPU-6050從電機上移開。 *我使用JRowber的建議(更改.h文件並更改TWBR變量的值)更改了I2C時鐘,但我認爲我沒有嘗試過所有可能的值。 *我已經在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("euler\t"); 
      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); 
    } 
} 
+0

請減少您的代碼爲一個最小的例子這表明了這個問題,你已經發布了將近400行代碼(其中大部分代碼已經被刪除了,所以我們不需要看到它) - 這是一個很大的挑戰:) –

+0

Andrew:道歉,已經刪除了大部分評論,但我不確定哪些人會覺得有意義,所以我不想切入「精益」。無論如何,這基本上就是JRowberg驅動下載的MPU6050_DMP6.ino腳本,以及在電機屏蔽上運行4個電機的幾行代碼。 –

回答

0

你是否認爲你的煩惱是由流入你的電機的電流乾擾造成的? 如果你的電機是直流電刷,那麼更多的干擾可能會從電刷輻射回你的各種電線。 作爲第一步,也許只讓一臺電機工作,看看hangups是否頻率下降(雖然,可以肯定的是,您需要一個'範圍到幾條載有邏輯信號的電線。