2014/08/22


為了測速球計畫, 萊恩大兵得找個方法讓 Arduino 能將 MPU6050 測得的數據暫存起來. Arduno Uno 只有 1KB 的 EEPROM 空間, 萊恩大兵本來是不考慮的. 後來想說做個實驗也好, 換個不同思考角度, 也許 1KB 夠用也說不定.


本來以為這實驗小蛋糕一片, 結果.. 很可怕. 寫入和讀出兩邊的數值比較起來, 都是前數十筆資料不對, 而後面百多筆資料是正確的. 
第17筆資料之後, 才兩邊一致.


第33筆資料之後, 才兩邊一致.


不懂這是怎麼回事.. 難道寫入 EEPROM 之前要先 warm up 嗎? 萊恩大兵需要有經驗的朋友指點一下. 謝謝.

(2014/8/25 更新-1) 感謝各位路過朋友的指點, 這題目在臉書的討論串1討論串2.
(2014/8/25 更新-2) 萊恩大兵改寫程式, 解決了寫入與讀取不一致的問題. 


  • 宣告一個 array 來暫存 MPU6050 ax/ay/az 的輸出值.
  • 找個適當時機做一次寫入. 
  • 寫入 EEPROM 時, 還要 delay 夠長一段時間, 才能去中斷程式執行. 如果等不夠久的話, 這次反而會造成讀出與寫入數值相比, 變成是前半段一致, 後半段不一致的情況.
新版本程式碼如下:


// Based on I2Cdevlib, MPU6050_raw
// Experiments to verify if any data loss when writing MPU6050 outputs to EEPROM 

#include "I2Cdev.h"
#include "MPU6050.h"
#include <EEPROM.h>
#include "eeprom_anything.h"

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;

// [eeprom] 
struct accelData{
  int16_t ax;
  int16_t ay;
  int16_t az;
};
accelData acc;
int accIdx = 0;
int accMem = 0;
int writeOnce = 0;

#define NUM 170
//int max = 1024 / sizeof(acc);
accelData accArray[NUM];

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(38400);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}

void loop() {
    /*int n = writeEEPROM();
    if (n >= NUM 200 && !writeOnce)
    {
        EEPROM_writeAnything(0, accArray);
        writeOnce = 1;
        delay(5000); // give enough time to write EEPROM
        Serial.println("Now you can stop this program...");
    }
    */
        
    dumpEEPROM();
}

int writeEEPROM()
{
    // read raw accel/gyro measurements from device
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    // waive the first 200 sensor data
    if (accIdx >= 200 && accIdx < NUM+200)
    {
        int n = accIdx - 200;
        Serial.print("Idx: "); Serial.print(n); 
        Serial.print(", ax: "); Serial.print(ax); accArray[n].ax = ax;
        Serial.print(", ay: "); Serial.print(ay); accArray[n].ay = ay;
        Serial.print(", az: "); Serial.println(az); accArray[n].az = az;
        //accMem  = EEPROM_writeAnything(accMem, acc);
    }
    return accIdx  ;
}

void dumpEEPROM()
{
  accelData accTmp;
  int tmpMem = 0;
  for (int i=0; i<NUM; i  )
  {
    tmpMem  = EEPROM_readAnything(tmpMem, accTmp);
    Serial.print("Idx: "); Serial.print(i);
    Serial.print(", ax: "); Serial.print(accTmp.ax);
    Serial.print(", ay: "); Serial.print(accTmp.ay);
    Serial.print(", az: "); Serial.println(accTmp.az);    
  }
}

-=-=-=-=-=-=-= 分隔線 =-=-=-=-=-=-=-=-=-
萊恩大兵這個實驗的規劃如下:

(1) 怎麼讀寫 EEPROM?



(2) 寫入 EEPROM vs MPU6050 數據產出, 速度對決

  • 講起來這是個假議題. 如果寫 EEPROM 跟不上, 那就把 MPU6050 量測輸出調慢一點啊. 是這樣沒錯, 錯的就在萊恩大兵不懂怎麼去調慢 MPU6050 的時脈. XD.
  • 只好拿現成的東西來改. i2cdevlib 的示範程式 MPU6050_raw 讓 MPU6050 的數據輸出間隔為 10ms. 就用這標準來做實驗.

(3) 改寫 MPU6050_raw, 包括:

  • 將 ax, ay, az 的值寫入 EEPROM, 共 170 筆 [1024/(2+2+2)]. 同時也將 ax, ay, az 的值倒在 serial port monitor 上.
  • 再從 EEPROM 去讀出值來, 兩邊做比對.


程式碼如下:

// Based on I2Cdevlib, MPU6050_raw
// Experiments to verify if any data loss when writing MPU6050 outputs to EEPROM 

#include "I2Cdev.h"
#include "MPU6050.h"
#include <EEPROM.h>
#include "eeprom_anything.h"

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;

// [eeprom] 
struct accelData{
  int16_t ax;
  int16_t ay;
  int16_t az;
};
accelData acc;
int accIdx = 0;
int accMem = 0;
int max = 1024 / sizeof(acc);

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(38400);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}

void loop() {
    //writeEEPROM();
    dumpEEPROM();
}

void writeEEPROM()
{
    // read raw accel/gyro measurements from device
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    // waive the first 100 sensor data
    if (accIdx >= 200 && accIdx < max + 200)
    {
        Serial.print("Idx: "); Serial.print(accIdx-200); 
        Serial.print(", ax: "); Serial.print(ax); acc.ax = ax;
        Serial.print(", ay: "); Serial.print(ay); acc.ay = ay;
        Serial.print(", az: "); Serial.println(az); acc.az = az;
        accMem  = EEPROM_writeAnything(accMem, acc);
    }
    accIdx  ;
}

void dumpEEPROM()
{
  accelData accTmp;
  int tmpMem = 0;
  for (int i=0; i<max; i  )
  {
    tmpMem  = EEPROM_readAnything(tmpMem, accTmp);
    Serial.print("Idx: "); Serial.print(i);
    Serial.print(", ax: "); Serial.print(accTmp.ax);
    Serial.print(", ay: "); Serial.print(accTmp.ay);
    Serial.print(", az: "); Serial.println(accTmp.az);    
  }
}

-=-=-=-=-=-=-= 分隔線 =-=-=-=-=-=-=-=-=-
未來, 這技術應該可以用在測速球計畫上面.


(1) 寫 EEPROM 的作法, 本質上也是將資料暫存起來, 等以後再找時機將資料倒出來. 這樣來看, 應該可以是測速球的實作選項之一.

(2) 1KB 空間, 可以存多少資料? 
根據先前手推車實驗得到的 accel 圖表, 施力的作用時間約為 300ms. (y軸的peak) 而一筆資料佔空間 6bytes (ax, ay, az: int type, 16bit value), 1KB 可記錄 170筆, 170*10ms = 1700ms. 應該是足夠的..




[萊恩大兵的其它文章]

自製大四軸

自製大四軸, 實作分享@華山文創園區
自製大四軸, (1) 零組件篇, 遙控器 (Drone, Quadcopter, Futaba, Maker, Arduino, Animatronic Eye)
自製大四軸, (2) 零組件篇, 飛控板 (Drone, Quadcopter, MultiWii, Arduino, Futaba, Maker)
自製大四軸, (3) 零組件篇, 自行雷切木質機架 (Drone, Quadcopter, Maker, Laser Cut)
自製大四軸, (4) 零組件篇, 馬達與電變調整 (Drone, Quadcopter, Maker, Electric Speed Control, Motor)
自製大四軸, (5) 組裝篇, 四軸飛行器成形 (Drone, Quadcopter, MultiWii, Arduino, Maker, Electric Speed Control, Motor)
自製大四軸, (6) 調整篇, 飛行前兩三事 (Drone, Quadcopter, Maker, Futaba, Arduino, MultiWii)
自製大四軸, (7) 充電篇, iMax B6 充電器操作記要 (Charger, Battery)
自製大四軸, (8) 問題篇, 機架損壞維修 (Drone, Quadcopter, Laser Cut)
自製大四軸, (9) 改良篇, 方便拆卸的木質機架 (Drone, Quadcopter, Maker, Laser Cut)

自動報球速的棒球


CC2540 Bluetooth Low Energy
筆記, CC2540 Bluetooth Low Energy, (1) 開發環境 架設 (Bluetooth, CC2540)
筆記, CC2540 Bluetooth Low Energy, (2) 跑第一個範例程式 (Bluetooth, CC2540)
筆記, CC2540 Bluetooth Low Energy, (3) SimpleBLEPeripheral 簡單介紹 (Bluetooth, CC2540)
筆記, CC2540 Bluetooth Low Energy, (4) 在智慧手機上執行範例程式 (Bluetooth, CC2540)
筆記, CC2540 Bluetooth Low Energy, (5) 偵測與發送 iBeacon 訊號 (Bluetooth, CC2540, iBeacon)
實作, iBeacon 發訊器 x 防丟器 (Bluetooth, CC2540, iBeacon)
實作, iBeacon 尋寶遊戲 (Bluetooth, CC2540, iBeacon, iOS app)
實作, BLE + iOS app, 遙控燈泡君 (Bluetooth, CC2540, iOS app)
做實驗, 用 iBeacon 做自動控制的可行性 (Bluetooth, iBeacon, CC2540, Automation, URL Scheme, iOS app)

藍色小鋪一起來做

藍色小鋪一起來做, (1) 用 beacon 控制開關的枱燈
藍色小鋪一起來做, (2) 講解 BLE CC2540 UART 通訊範例程式 (Bluetooth, CC2540, UART)
藍色小鋪一起來做, (3) 藍牙枱燈專案實作 (上) (Bluetooth, CC2540)
藍色小鋪一起來做, (4) 藍牙枱燈專案實作 (下) (Bluetooth, CC2540)
藍色小鋪一起來做, (5) iBeacon scanner 專案示範與解說 (Bluetooth, CC2540, iBeacon)
藍色小鋪一起來做, (6) 完成, 用 iBeacon 控制開關的枱燈 (Bluetooth, CC2540, iBeacon)
藍色小鋪, 初嚐樹莓派 (Raspberry Pi)
藍色小鋪, iBeacon 應用, 自動記錄到訪時間 (iBeacon, Geohopper, Zapier)

小惡魔 無線溫度感測器

108 大眼仔
Plot Clock

體驗, 原住民互動故事書@宜蘭大同鄉泰雅生活館
體驗, 蛋生音互動裝置@兒童美術館 (Arduino, 3D Printing, HC-SR04, Interactive)


實作, 電容感應音樂樹

0 意見:

張貼留言