View Single Post
  #2   Spotlight this post!  
Unread 20-06-2008, 12:23
billbo911's Avatar
billbo911 billbo911 is offline
I prefer you give a perfect effort.
AKA: That's "Mr. Bill"
FRC #2073 (EagleForce)
Team Role: Mentor
 
Join Date: Mar 2005
Rookie Year: 2005
Location: Elk Grove, Ca.
Posts: 2,356
billbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond reputebillbo911 has a reputation beyond repute
Re: BEI Gyro Accuracy

Quote:
Originally Posted by John Gutmann View Post
I am hoping for Kevin Watson to chime in on this one. I believe he was around way back when.

I have a BEI gyro I am trying to use for a VEX robot. I wrote a program for it, but it seems to be in accurate. I am using a 10 bit ADC. with a 1khz sampling frequency. I have simply written a (de)accumulator program. This just cuts the ADC reading from 10 to 8 bits, and either adds or subtracts the reading depending on the reading. The problem is that it seems to be very inaccurate. I could be my program, but it doesn't seem to be. I turn the gyro slowly, 90 degrees, and then back 90 degrees. it will return to a range of +/-40.

**Not degrees, these are just raw values from the ADC!**

I have a defined dead band of about .2 volts at the neutral position. When I turn I make sure the voltage output is outside of the dead band. I check this using a DMM. The other weird problem is the dead band is at 2 volts instead of 2.5 volts, which is what it should be.

The analog reference is about 5.1 volts.

If it matters at all I am using at ATMEGA16 microcontroller, and programming it using a STK500 dev board.

Thanks for any help,
John Gutmann
Hey John. Here is my $.02.
To use a gyro with Vex, I just integrated Kevin's Gyro code into the 2007 default FVC code. I run the ADC sample at 1600Hz with a 32 samples per update, giving me 50 averaged samples per second. It really works fairly well.

Now as for your ATMega16, I might be able to help, a little.
I just wrote code for my Arduino that samples a 2005 KOP Gyro at 800Hz, 4 samples per update. It is based on Kevin's gyro code as well but adapted for the Arduino. As you might be aware, the Arduino runs on an ATMega168. I will gladly share this code with you. In fact, I'll just paste it in here now so people can chew on it for a while.

Code:
unsigned int latency;
unsigned char timerLoadValue;
int GyroPin = 5;
volatile int val;
volatile int gyroBias;
int bias_acum;
volatile long gyro_angle;
#define GYRO_READY 13 //Arduino pin to toggle in timer ISR
#define SAMPLES_PER_UPDATE 4 // # of Gyro samples to average before updating accum
#define DEADBAND 6
#define GYRO_GAIN_CAL 1000/1000
volatile unsigned char sample_counter = 0; // Used in Timer ISR
volatile int sample_accum = 0; //hold sample sum until correct # samples aquired
#define TIMER_CLOCK_FREQ 125000.0 //125KHz for /128 prescale from 16MHz



/*Setup Timer2.***********************************************
Configures the ATMega168 8-Bit Timer2 to generate an interrupt
at the specified frequency.
Returns the timer load value which must be loaded into TCNT2
inside your ISR routine.
See the example usage below.
***********************************************************/
unsigned char SetupTimer2(float timeoutFrequency)//Called once from Setup()
{
unsigned char result; //The timer load value.

  //Calculate the timer load value
  result=(int)((257.0-(TIMER_CLOCK_FREQ/timeoutFrequency))+0.5);//The 257 really should be 256 
                                                                //but I get better results with 257.
  //Timer2 Settings: Timer Prescaler /128, mode 0
  //Timer clock = 16MHz/128 = 125Khz or 8us
  //The /128 prescale gives us a good range to work with
  //so we just hard code this for now.
  TCCR2A = 0;
  TCCR2B = 1<<CS22 | 0<<CS21 | 1<<CS20;  

  //Timer2 Overflow Interrupt Enable
  TIMSK2 = 1<<TOIE2;
  //load the timer for its first cycle
  TCNT2=result;
  return(result);
}



/*************************************************
Timer ISR to grag Gyro value at rate 
determined in SetuoTimer2
**************************************************/
ISR(TIMER2_OVF_vect)
{
  //Toggle the IO pin to the other state.
  //digitalWrite(TOGGLE_IO,!digitalRead(TOGGLE_IO));
sample_accum  += analogRead(GyroPin);
sample_counter ++;
  if (sample_counter == SAMPLES_PER_UPDATE)
  {
    val = (sample_accum/SAMPLES_PER_UPDATE)-gyroBias;
    if (val < -DEADBAND || val > DEADBAND)
    {
    gyro_angle += (long)val;
    }
    sample_accum = 0;
    sample_counter = 0;
  }
  //Capture the current timer value. This is how much error we
  //have due to interrupt latency and the work in this function
latency=TCNT2;
  //Reload the timer and correct for latency.
TCNT2=(latency + timerLoadValue);
}



/**************************************
Get_Gyro_Angle converts data from raw measured value to decimal format and 
returns gyro angle in tenths of a degree.
*******************************************/
long Get_Gyro_Angle (void)
{
  long temp_gyro_angle;
     TIMSK2 = 0<<TOIE2;
     temp_gyro_angle = gyro_angle*10L/512L;
     TIMSK2 = 1<<TOIE2;
   temp_gyro_angle = temp_gyro_angle*GYRO_GAIN_CAL;  
 return (temp_gyro_angle);
}



/********************************************************
1)Set the pin mode for LED indication the Gyro is ready.
2)Set up Serial baud rate and initialize communication.
3)Calculate the Gyro Bias value.
4)Preconfigure the timer for Gyro measurement.
*********************************************************/
void setup(void)
{
  //Set the pin we want the ISR to toggle for output.
pinMode(GYRO_READY,OUTPUT);

  //Start up the serial port
Serial.begin(115200);
    
delay (2000); // allow gyro to power up and stabalize

for(int i=0; i<=29;i++) // Collect 30 samples of Gyro output whilw stationary.
                          //The average will become the value for the BIAS.
{
  bias_acum += analogRead(GyroPin);
  delay(100);
}
  
gyroBias = (bias_acum/30); //analogRead(PotPin);
  //Signal the program start
    digitalWrite (GYRO_READY, HIGH);
 
  //Start the timer and get the timer reload value.
  timerLoadValue=SetupTimer2(800); // Gyro Sample rate is 800Hz
}



void loop(void) {

     
    Serial.print("Gyro value is ");
    Serial.println((int)Get_Gyro_Angle());
      
}
__________________
CalGames 2009 Autonomous Champion Award winner
Sacramento 2010 Creativity in Design winner, Sacramento 2010 Quarter finalist
2011 Sacramento Finalist, 2011 Madtown Engineering Inspiration Award.
2012 Sacramento Semi-Finals, 2012 Sacramento Innovation in Control Award, 2012 SVR Judges Award.
2012 CalGames Autonomous Challenge Award winner ($$$).
2014 2X Rockwell Automation: Innovation in Control Award (CVR and SAC). Curie Division Gracious Professionalism Award.
2014 Capital City Classic Winner AND Runner Up. Madtown Throwdown: Runner up.
2015 Innovation in Control Award, Sacramento.
2016 Chezy Champs Finalist, 2016 MTTD Finalist