Quote:
Originally Posted by John Gutmann
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());
}