Robofun 機器人論壇

標題: 用ARDUINO計算IDG500 GYRO角度 [打印本頁]

作者: 幸福羔羊    時間: 2011-10-7 23:53
標題: 用ARDUINO計算IDG500 GYRO角度
這位大大好:   我想請問一下 我想用GYRO來計算角度值精準度不用到0.X度,但是我寫完之後發現他都會有誤差可以請大大幫忙看一下嗎??
小弟還是很~~新的新手,寫的很奇怪請見諒。麻煩請指點一下
unsigned char X45input = A0;                  
unsigned char VREFinput= A1;                  
int X45read,VREFread,AN;   
int X45 = 0.00,MAX=0.00;
float VREF = 0.00;
float angle=0;
long timer,timer1;
void setup() {
    Serial.begin(9600);                     
    delay(1000);             //等待GYRO準備好 20ms 但保險我直接用1秒
    timer = millis();        //紀錄時間
}

void loop() {
  X45read  = analogRead(X45input);                   // 將 X45  的輸入電壓存到所設定的變數
  VREFread = analogRead(VREFinput);                  // 將 VREF 的輸入電壓存到所設定的變數
  VREF = 1.35*1024/VREFread;                         //計算參考電位為多少 利用gyro本分的vref反推
  X45 = (X45read*VREF)*100/1024;                      //計算adc轉換後的電壓 只計算到小數第2位因此我*100
if(X45 > MAX && X45 > 135)                           //抓取傳回值的最大值在進行運算
    MAX = X45;
else if(X45 < MAX && X45 < 135)                      //抓取傳回值的最小值在進行運算   擔心auto zero
    MAX = X45;
else
{
    angle += ((X45 - 135)/0.91)*(millis() - timer)/400;      //計算角度 400我用測的...理論因該為1000
    timer = millis();                                       
    MAX = 135;
}
  if(millis() - timer1 > 1000)                                //每一秒判斷角度目前的誤差
  {
      if(abs(angle) < 1)                                       //靜態狀態下 若小於1 清除目前的角度值
         angle = 0;
      else                                             
      {
         AN += angle;                                          //反之則輸出確認角度
         angle = 0;
      }
      timer1 = millis();
  }
  Serial.print(" ");   Serial.print(MAX);   Serial.print(9,BYTE);
  Serial.print(" ");  Serial.print(AN);  Serial.println();  
}
作者: 幸福羔羊    時間: 2011-10-8 13:26
各位大大好,昨天到arduino的網站找到一份gyro的程式,我以他的方式修改成我可以用的之後發現度數轉90度卻只有20度可以請大大幫我看一下嗎...
int X45input = A0;                  
int VREFinput= A1;                  
float gyroV = 5;
float gyroZ = 1.35;
float gyroS =0.0091;
float rotationThreshold = 0.6;
float angle = 0;
void setup() {
    Serial.begin(9600);                     
    delay(20);             //等待GYRO準備好 20ms
}
void loop() {
    float Vref = (1.35*1023)/analogRead(VREFinput);
    float gyroRate = (analogRead(X45input) * Vref) /1023;
    gyroRate -=gyroZ;
    gyroRate /= gyroS;
    if(gyroRate >= rotationThreshold || gyroRate <= -rotationThreshold)
    {
      gyroRate /=50;
      angle += gyroRate;
    }
    Serial.print(" ");  Serial.print(angle);  Serial.println();
    delay(20);
}
作者: vegewell    時間: 2011-10-8 21:05
回復 2# 幸福羔羊
你先試試下面的程式是否可行?

    / -----------------------------------------
// 範例程式:兩軸陀螺儀取值(IDG500),包含 X、X4.5、Y、Y4.5、VREF 共五支腳位的電壓值
// -----------------------------------------
// 使用說明:本程式主要將感測器所讀出之類比電壓轉換為數位資料後顯示於終端機中。
// -----------------------------------------
//腳位接法:IDG500   <----->  Arduino
//     VIN      <----->  5V
//     GND      <----->  GND
//                       AREF  <----->  3V3
//     XOUT     <----->  Analog Pin 0
//     X4.5OUT  <----->  Analog Pin 1
//     YOUT     <----->  Analog Pin 2
//     Y4.5OUT  <----->  Analog Pin 3
//     VREF     <----->  Analog Pin 4
// -----------------------------------------
//
// 變數設定
unsigned char Xinput   = 0;                     // X 軸的類比電壓輸入腳位
unsigned char X45input = 1;                     // Y 軸的類比電壓輸入腳位
unsigned char Yinput   = 2;                     // Z 軸的類比電壓輸入腳位
unsigned char Y45input = 3;                     // X 軸的類比電壓輸入腳位
unsigned char VREF     = 4;                     // Y 軸的類比電壓輸入腳位
int Xread,X45read,Yread,Y45read,VREFread;
void setup() {
    Serial.begin(9600);                         // 串列傳輸的鮑率設定
    analogReference(EXTERNAL);                  // 設定外部參考電壓
}
void loop() {
//
  Xread    = analogRead(Xinput);                // 將 X    的輸入電壓存到所設定的變數
  X45read  = analogRead(X45input);              // 將 X45  的輸入電壓存到所設定的變數
  Yread    = analogRead(Yinput);                // 將 Y    的輸入電壓存到所設定的變數
  Y45read  = analogRead(Y45input);              // 將 Y45  的輸入電壓存到所設定的變數
  VREFread = analogRead(VREF);                  // 將 VREF 的輸入電壓存到所設定的變數
//
// 將計算結果顯示到終端機
  Serial.print("X = ");      Serial.print(Xread);     Serial.print(9,BYTE);
  Serial.print(" X45 = ");   Serial.print(X45read);   Serial.print(9,BYTE);
  Serial.print(" Y = ");     Serial.print(Yread);     Serial.print(9,BYTE);
  Serial.print(" Y45 = ");   Serial.print(Y45read);   Serial.print(9,BYTE);
  Serial.print(" Vref = ");  Serial.print(VREFread);  Serial.println();
  delay(500);                                   // 延遲 0.5 秒
}
作者: vegewell    時間: 2011-10-8 21:06
你腳位接法是否如下圖:

作者: 幸福羔羊    時間: 2011-10-9 14:24
感謝V大的回應
這兩張圖我都嘗試過了讀值也很正確0.0
但是依然沒辦法好好控制
此外我以2.6秒轉90度 用估計計算大約他會輸出1.6V左右
但他卻只有1.4V輸出~
我不知怎麼用了 請大大開導
作者: vegewell    時間: 2011-10-9 19:05
回復 5# 幸福羔羊


    它的角度是以移動的電壓差值去累積計算,
所以你以2.6秒轉90度 輸出歸零值1.35v左右,並不奇怪,
請用以下的程式試看:
使用 At X-OUT and Y-OUT,
先忽略 At X4.5OUT and Y4.5OUT,
所以腳位接線請接正確   ( XOUT     <----->  Analog Pin 0)

int gyroPin = 0;               //Gyro is connected to analog pin 0
float gyroVoltage = 5;         //Gyro is running at 5V
float gyroZeroVoltage = 1.35;   //Gyro is zeroed at 1.35V
float gyroSensitivity = .002;  //Our example gyro is 2mV/deg/sec
float rotationThreshold = 1;   //Minimum deg/sec to keep track of - helps with gyro drifting
float currentAngle = 0;          //Keep track of our current angle
void setup() {
  Serial.begin (9600);
}
void loop() {
  //This line converts the 0-1023 signal to 0-5V
  float gyroRate = (analogRead(gyroPin) * gyroVoltage) / 1023;
  //This line finds the voltage offset from sitting still
  gyroRate -= gyroZeroVoltage;
  //This line divides the voltage we found by the gyro's sensitivity
  gyroRate /= gyroSensitivity;
  //Ignore the gyro if our angular velocity does not meet our threshold
  if (gyroRate >= rotationThreshold || gyroRate <= -rotationThreshold) {
    //This line divides the value by 100 since we are running in a 10ms loop (1000ms/10ms)
    gyroRate /= 100;
    currentAngle += gyroRate;
  }
  //Keep our angle between 0-359 degrees
  if (currentAngle < 0)
    currentAngle += 360;
  else if (currentAngle > 359)
    currentAngle -= 360;
  //DEBUG
  Serial.println(currentAngle);
  delay(10);
}
作者: 幸福羔羊    時間: 2011-10-16 21:25
感謝v大的回覆
   我照v大的方式跑之後,發現他再靜態時會一直加上去.....
目前接線
   A0     <----> XOUT;
   3.3V  <----> VCC;
  GND   <----> GND;
因為ARDUINO的參考電壓為3.3V 因此我參考電壓改成3.3
請問要怎麼用呢??
作者: vegewell    時間: 2011-10-16 22:34
本帖最後由 vegewell 於 2011-10-16 22:36 編輯

回復 7# 幸福羔羊


   如果你只是要問 參考電壓要怎麼使用
就我所知要有以下的code:
void setup() {
    Serial.begin(9600);                       
    analogReference(EXTERNAL);   //參考電壓要加上這行            
}

連線請參考下圖 AREF+3.3v to vcc:


----------------------------------------
至於IDG500要怎麼寫程式才會正確?
我有查到再跟你報告.
作者: vegewell    時間: 2011-10-17 16:02
回復 7# 幸福羔羊

計算IDG500 GYRO動作的角度其實很簡單,
我因為手上沒這顆,
所以用c# 模擬IDG500 GYRO,
注意事項:
一 你要看 ZERO-RATE OUTPUT的值是多少?
如果是1.4 V,就用1.4代替下面code的1.35,
=============================================
int gyroPin = 0;               //Gyro is connected to analog pin 0
   int addd = 0;
  void setup()
    {
        Serial.begin (9600);
    }
  void loop() {
            int angel = 0;
            double cline = 0;
            double dline = 0;
            cline = analogRead(gyroPin);
            if (cline > 1.35)
            {
                dline = cline - 1.35;
                angel = dline / 0.002;
                addd = addd + angel;
            }
                if (cline < 1.35)
                {
                    dline =  1.35 - cline ;
                    angel = dline / 0.002;
                    addd = addd - angel;
                }
            if (cline == 1.35) dline = 0;
   Serial.println(addd);
   delay(7);            

}
=============================================
二 腳位接線請接正確
先試試:
                      ( XOUT     <----->  Analog Pin 0)
                      ( VREF     <----->  Analog Pin 4 )
                      ( VIN      <----->  5V )
                      ( GND     <----->  GND )
不行的話,再試試你的接法,
作者: 幸福羔羊    時間: 2011-10-17 18:09
感謝V大一直幫我!!
V大我用了你的方式後依然沒辦法....以下是RUN之後的一小部分
-29104
-13352
2400
17652
-32632
-16880
-1128
14624
29876
-19908
-4156
11596
27348
-22436
-6684
9068
24820
這是在靜態時測試的,請v大看一下
作者: 幸福羔羊    時間: 2011-10-17 18:16
剛沒看清楚V大少加一行電壓轉換,這是測試之後的結果

1.35        -241
1.35        -241
1.35        -241
1.35        -243
1.35        -245
1.35        -247
1.35        -249
1.34        -253
1.35        -255
1.35        -257
1.35        -259
1.35        -261
1.35        -261
1.35        -263
1.35        -265
1.35        -267
1.35        -267
靜態時的結果 左邊為輸入近來的電壓    右邊為角度0.0
作者: vegewell    時間: 2011-10-17 19:54
本帖最後由 vegewell 於 2011-10-17 19:55 編輯

回復 11# 幸福羔羊


    不客氣,
也謝謝你提供機會,讓我研究與探討,
如果靜態時,
從你讀出角度遞減的結果,
我判斷是ZERO-RATE OUTPUT的電壓值是1.346 左右(被四捨五入成為1.35),
所以你的程式可以稍為改一下:
int gyroPin = 0;               //Gyro is connected to analog pin 0
   int addd = 0;
  void setup()
    {
        Serial.begin (9600);
    }
  void loop() {
            int angel = 0;
            double cline = 0;
            double dline = 0;
            cline = analogRead(gyroPin);
            if (cline > 1.352)
            {
                dline = cline - 1.35;
                angel = dline / 0.002;
                addd = addd + angel;
            }
                if (cline < 1.34)
                {
                    dline =  1.35 - cline ;
                    angel = dline / 0.002;
                    addd = addd - angel;
                }
            if (cline <= 1.352 && cline >= 1.34) dline = 0;
   Serial.println(addd);
   delay(7);            
}
你也可以試試動態,
作者: 幸福羔羊    時間: 2011-10-18 14:33
感謝v大的回應
請問一下
我對於 ZERO-RATE OUTPUT 被四捨五入有些疑問0.0
程式在運算過程中不是先四捨五入後再進行運算嗎??
例如: v = 1.3468     四捨五入 = 1.35
          x = v - 1.35;
          那x不是等於0嗎?
         請大大幫忙解惑~
作者: vegewell    時間: 2011-10-18 17:52
回復 13# 幸福羔羊

被四捨五入是指 Serial.println(); 的時候,
在運算過程中沒有被四捨五入,
你寫 Serial.println(1.236);
執行結果就知道了,

現在做的合不合預期?
作者: 幸福羔羊    時間: 2011-10-19 02:25
本帖最後由 幸福羔羊 於 2011-10-19 02:28 編輯

v大你好,我利用v大前面的程式碼稍微更改了一下,雖然不是很精準在靜態下可以顯示0度
旋轉90度時也大約在那個附近(沒有伺服馬達幫忙旋轉...),一情況還是算理想,但是我有點搞不懂為什麼我
最後累加必須一定得*3倍才會理想請大大幫忙看一下。
此外我想請問...陀螺儀是否可以利用加速儀做補償呢?? 我聽板上的G大說法去查了一下尤拉角 但程度不是我可以理解的程度....
int X45input = A0;                     //X軸腳位
int VREFinput= A1;                     //VREF腳位
float gyroZ = 1.35;                    //AUTOZERO
float gyroS =0.0091;                   //靈敏度
float rotationThreshold = 0.6;         //靜態誤差區間
float angle = 0;                       
long timer;
void setup() {
    Serial.begin(9600);                     
    delay(20);             //等待GYRO準備好 20ms
    timer = millis();
}
void loop() {
    float Vref = (1.35*1023)/analogRead(VREFinput);      //計算ARDUINO的參考電位
    float gyroRate = (analogRead(X45input) * Vref) /1023;      //轉換X軸電壓     
    gyroRate =(gyroRate-gyroZ)/gyroS;                    //轉換角速度
    if(gyroRate >= rotationThreshold || gyroRate <= -rotationThreshold) 靜態誤差比較
    {
      gyroRate = gyroRate*(millis() - timer)/1000 ;            
      angle += gyroRate*3;                      //累加角度
    }
    timer = millis();
    Serial.print(" ");  Serial.print(angle);  Serial.println();
    delay(20);
}
作者: vegewell    時間: 2011-10-19 16:06
回復 15# 幸福羔羊

這應該是你自己摸索出來的程式,
你也是蠻會做的,

至於你的問題--> 最後累加必須一定得*3倍才會理想?
我並不知道analogRead(VREFinput)的值是多少?所以無法評估,
你只要在每一行之間,加上   Serial.print(" 上一行的變數     ");
就可以去推算,

重點是,要準確知道ZERO-RATE OUTPUT 的值,
ZERO-RATE OUTPUT 的值是測出來的,而不是你給它的,
雖然工廠出貨是調為 1.35,
但每一顆有些許差異,

在靜止時,
Serial.print( analogRead(X45input),3);
順便查一下analogRead(VREFinput)的值;  
Serial.print( analogRead(X45input),3);  
要準到小數點以下第三位才行,

更改一些參數,應該可以讓讀出的值更準確,自己慢慢摸索吧,
===============================================
另外--->,陀螺儀是否可以利用加速儀做補償呢??
所謂補償,應該是 採用互補濾波器 complementary filter,
就是 ic內燒一串數學函數,
可以精準一點,
現在都已經到 9 DOF IMU,
你還買 5 DOF嗎?
作者: 幸福羔羊    時間: 2011-10-31 17:33
其實我都是硬著頭皮寫的,都沒有任何的根據0.0
我想請問v大,再接觸一個感測器時,會不會先對他做一些處理呢??
例如 電路,MATLAB 之類的,因為我都直接接上MCU上
另外想請問互補濾波器是否有相關的資料呢??我網路上查很久都沒有詳細的說明..可否請V大幫忙><

我目前還適用 5 DOF 因為我老師買的,所以我只好用了^^||
作者: vegewell    時間: 2011-11-1 21:12
回復 17# 幸福羔羊

不必謙虛,我覺得你蠻會的,

要對感測器先做一些處理的話,可以採用信號放大器,

至於 陀螺儀及加速器的互補濾波器,
[ 互補濾波器就是根據傳感器特性不同,通過不同的濾波器(高通或低通,互補的),然後再相加得到整個頻帶的信號。
例如,加速度計測傾角,其動態響應較慢,在高頻時信號不可用,所以可通過低通抑制高頻;
陀螺響應快,積分後可測傾角,不過由於零漂等,在低頻段信號不好。通過高通濾波可抑制低頻噪聲。
將兩者結合,就將陀螺和加表的優點融合起來,得到在高頻和低頻都較好的信號。
互補濾波需要選擇切換的頻率點,即高通和低通的頻率。]
如下圖:

互補濾波器就是一串數學方程式:
We design a 2nd order complementary filter.



This 2nd order complementary filter compensates for the rate gyro bias with no steady state error.
-------------------------
把數學方程式轉換成自己用程式寫,
成為code, 一連串的函數計算,如下例:
#define LPWM 9          // left motor PWM
#define RPWM 10         // right motor PWM
#define LDIR 11         // left motor direction
#define RDIR 12         // right motor direction
#define A_PIN 0         // accelerometer analog input
#define G_PIN 4         // gyro analog input
#define S_PIN 6         // steering analog input
#define A_ZERO 341      // approx. 1.5[V] * 1024[LSB/V]
#define G_ZERO 253      // approx. 1.23[V] * 1024[LSB/V]
#define S_ZERO 766      // approx. 2.5[V] * 1024[LSB/V]
#define A_GAIN 0.932    // [deg/LSB]
#define G_GAIN 1.466    // [deg/s/LSB]
#define S_GAIN 0.25     // [LSB/LSB] (AAAHHHHHHH WHAT?)
#define DT 0.02         // [s/loop] loop period
#define A 0.962         // complementary filter constant
#define KP 0.5          // proportional controller gain [LSB/deg/loop]
#define KD 0.5          // derivative controller gain [LSB/deg/loop]
float angle = 0.0;      // [deg]
float rate = 0.0;       // [deg/s]
float output = 0.0;     // [LSB] (100% voltage to motor is 255LSB)
void setup()
{
  // Make sure all motor controller pins start low.
  digitalWrite(LPWM, LOW);
  digitalWrite(RPWM, LOW);
  digitalWrite(LDIR, LOW);
  digitalWrite(RDIR, LOW);
  
  // Set all motor control pins to outputs.
  pinMode(LPWM, OUTPUT);
  pinMode(RPWM, OUTPUT);
  pinMode(LDIR, OUTPUT);
  pinMode(RDIR, OUTPUT);
  pinMode(13, OUTPUT);
  
  // switch to 15.625kHz PWM
  TCCR1B &= ~0x07;
  TCCR1B |= 0x01;   // no prescale
  TCCR1A &= ~0x03;  // 9-bit PWM
  TCCR1A |= 0x02;
  
  Serial.begin(9600);
}
void loop()
{
  signed int accel_raw = 0;
  signed int gyro_raw = 0;
  signed int output_left = 0;
  signed int output_right = 0;
  signed int steer_raw = 0;
  
  // Loop speed test.
  digitalWrite(13, HIGH);
  
  // Read in the raw accelerometer, gyro, and steering singals.
  // Offset for zero angle/rate.
  accel_raw = (signed int) analogRead(A_PIN) - A_ZERO;
  gyro_raw = G_ZERO - (signed int) analogRead(G_PIN);
  steer_raw = (signed int) analogRead(S_PIN) - S_ZERO;
  
  // Scale the gyro to [deg/s].
  rate = (float) gyro_raw * G_GAIN;
  
  // Complementarty filter.
  angle = A * (angle + rate * DT) + (1 - A) * (float) accel_raw * A_GAIN;
  
  // PD controller.
  output += angle * KP + rate * KD;
  
  // Clip as float (to prevent wind-up).
  if(output < -255.0) { output = -255.0; }
  if(output > 255.0) { output = 255.0; }
  
  // Add/subtract steering and integerize.
  output_left = (signed int) (output + (float) steer_raw * S_GAIN );
  output_right = (signed int) (output - (float) steer_raw * S_GAIN);
  
  // Clip as integer.
  if(output_left < -255) { output_left = -255; }
  if(output_left > 255) { output_left = 255; }
  if(output_right < -255) { output_right = -255; }
  if(output_right > 255) { output_right = 255; }
  
  // Choose directions and set PWM outputs.
  if(output_left >= 0)
  {
    digitalWrite(LDIR, HIGH);
    analogWrite(LPWM, output_left);
  }
  else
  {
    digitalWrite(LDIR, LOW);
    analogWrite(LPWM, -output_left);
  }
  if(output_right >= 0)
  {
    digitalWrite(RDIR, HIGH);
    analogWrite(RPWM, output_right);
  }
  else
  {
    digitalWrite(RDIR, LOW);
    analogWrite(RPWM, -output_right);
  }
  
  // Loop speed test.
  digitalWrite(13, LOW);

  // Debug.
  Serial.println(output_right);

  // Delay for consistent loop rate.
  delay(20);
你目前只要知道互補濾波器在上述code裡面,就行了.
作者: 幸福羔羊    時間: 2011-11-3 18:30
V大的CODE好複雜....我可能要吸收一陣子才行

請問v在上面的數學方程式是中,是如何轉成code的??

以及數學方程式是怎麼呈現的??

以及程式中的變數是怎麼獲得的呢??

如果可以我想看有關於這方面的書籍,可以請v大推薦一下嗎><
作者: 幸福羔羊    時間: 2011-11-5 14:52
本帖最後由 幸福羔羊 於 2011-11-5 15:08 編輯

v大妳好 我想請問CODE裡面的LSB是什麼呢??網路上查是說最低有效位元,但他是指誰呢?? 請V大幫忙
作者: vegewell    時間: 2011-11-5 18:09
本帖最後由 vegewell 於 2011-11-5 18:10 編輯

回復 20# 幸福羔羊

LSB:
[ADC器件在所有的數值點上對應的模擬值,和真實值之間誤差最大的那一點的誤差值。也就是,輸出數值偏離線性最大的距離。
單位是LSB(即最低位所表示的量)。]
詳細意義請參考:ADC分辨率與精度的區別:
http://bbs.ednchina.com/BLOG_ARTICLE_2058763.HTM
LSB是在註解裡,你大概瞭解就好,
有些知識去信太深,結果它很可能不是很正確,
==========================================
以後使用陀螺儀及加速器,會加入互補濾波器,會變得比較平常,
因為漸漸不是難事,
網路上有很多可以拿來用的例子.
======================
有關於數學方程式的呈現,
例如這個方程式:

轉變成c#的code如下:
p = rho*R*T + (B_0*R*T-A_0-((C_0) / (T*T))+((E_0) / (Math.Pow(T, 4))))*rho*rho +
    (b*R*T-a-((d) / (T)))*Math.Pow(rho, 3) +
    alpha*(a+((d) / (t)))*Math.Pow(rho, 6) +
    ((c*Math.Pow(rho, 3)) / (T*T))*(1+gamma*rho*rho)*Math.Exp(-gamma*rho*rho);

這是對數學有些瞭解,去推算出來,
有關於這方面的書籍,
我是覺得不需要去看書,
網路上有太多這方面的介紹,
你慢慢去瀏覽就行了.
=========================================
有關於GPS過隧道時無法讀取位置,
開車進隧道裡,就只有一條路,跟著路開就行了.
================================
有關於利用陀螺儀及加速器這兩個元件實現虛擬座標有可能實現嗎?
這個問題以前就討論過了,
就我所知是每隔一段時間,需要去做修正的,
所以不是單單這兩個元件,就能實現準確的虛擬座標.
==================
以上幾個一點點意見請參考, 謝謝.
作者: eat1256    時間: 2012-3-6 17:13
會用電腦的你,
是否想過空閒的時間裡,創造出不平凡的收入?
現在我一樣坐在電腦前面上網聊天,
跟你做一樣的事情,我卻有額外的收入。

網路創業的宅經濟網路世代,
唯一的風險就是你沒有參與!!


這班列車正是初升段的時候,
如果您渴望改變生活,希望在家工作並保持財務穩定!
免.費.試.用.90.天>> http://litailhsu.blogspot.com/

(註冊成功後,請每天務必查收信箱重要信息!!)




歡迎光臨 Robofun 機器人論壇 (https://www.robofun.net/forum/) Powered by Discuz! X3.2