Robofun 機器人論壇

 找回密碼
 申請會員
搜索
熱搜: 活動 交友 discuz
查看: 15710|回復: 21
打印 上一主題 下一主題

用ARDUINO計算IDG500 GYRO角度

[複製鏈接]
1#
發表於 2011-10-8 21:05:08 | 顯示全部樓層
回復 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 秒
}
2#
發表於 2011-10-8 21:06:27 | 顯示全部樓層
你腳位接法是否如下圖:
3#
發表於 2011-10-9 19:05: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);
}
4#
發表於 2011-10-16 22:34:18 | 顯示全部樓層
本帖最後由 vegewell 於 2011-10-16 22:36 編輯

回復 7# 幸福羔羊


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

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


----------------------------------------
至於IDG500要怎麼寫程式才會正確?
我有查到再跟你報告.
5#
發表於 2011-10-17 16:02:26 | 顯示全部樓層
回復 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 )
不行的話,再試試你的接法,
6#
發表於 2011-10-17 19:54:07 | 顯示全部樓層
本帖最後由 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);            
}
你也可以試試動態,
7#
發表於 2011-10-18 17:52:24 | 顯示全部樓層
回復 13# 幸福羔羊

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

現在做的合不合預期?
8#
發表於 2011-10-19 16:06:39 | 顯示全部樓層
回復 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嗎?
9#
發表於 2011-11-1 21:12:33 | 顯示全部樓層
回復 17# 幸福羔羊

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

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

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

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

  • The low pass filter is the complementary:

  • As for the 1st order complementary filter, the high pass filter can combine with the integration of the rate gyro. We do not take into account the dynamic of the rate gyro:


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裡面,就行了.
10#
發表於 2011-11-5 18:09:24 | 顯示全部樓層
本帖最後由 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過隧道時無法讀取位置,
開車進隧道裡,就只有一條路,跟著路開就行了.
================================
有關於利用陀螺儀及加速器這兩個元件實現虛擬座標有可能實現嗎?
這個問題以前就討論過了,
就我所知是每隔一段時間,需要去做修正的,
所以不是單單這兩個元件,就能實現準確的虛擬座標.
==================
以上幾個一點點意見請參考, 謝謝.
您需要登錄後才可以回帖 登錄 | 申請會員

本版積分規則

小黑屋|手機版|Archiver|機器人論壇 from 2005.07

GMT+8, 2024-5-12 13:42 , Processed in 0.345384 second(s), 7 queries , Apc On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表