Hey all. I have a LISY300AL yaw gyro, and I'm trying to create the most accurate code to return its cardinal position. The code is working, however I'm getting results of as much as 10deg off on a single 1-2 second turn to 90deg and back to 360.
Also, what are typical non-kalman filtered drift errors you can expect? Alright, here's the code...tear it to pieces!
#define GYRO_SENSITIVITY 0.0033;
int loops=0; //configuration stage loops
int centerpoint = 0; // zero rotation value
int high = 0; // motionless calibration error
int low = 1023; // motionless calibration error
int warnled = 2; // warning led pin
int goled = 3; // systems green pin
int sensor = 0; // analog gyro port
int variation = 0; // expected gyro jitter +- value
int change = 0; // ATD conversion change
float position = 0.0; // current cardinal position
unsigned long timetook = 0; //sample time taken
unsigned long lasttook = 0; //last sample time
void setup(){
analogReference(EXTERNAL);
pinMode(warnled,OUTPUT);
pinMode(goled,OUTPUT);
Serial.begin(9600);
}
void loop(){
lasttook = timetook;
int rate = analogRead(0);
timetook = millis();
/* lets quickly run 1000 samples of the gryo
and find out how much jitter we are expecting
throw up an error if its more than 5 */
while(loops < 1000){
digitalWrite(warnled,HIGH);
int sample = analogRead(sensor);
if(sample > high){
high = sample;
}else if(sample < low){
low = sample;
}
loops++;
delay(1);
}
if(loops==1000){
digitalWrite(warnled,LOW);
centerpoint = (high-low)+low;
variation = high-low;
if(variation > 5){
digitalWrite(warnled,HIGH);
}else{
digitalWrite(goled,HIGH);
}
}
// simple statement to keep a little of the natural jitter out
if(abs(centerpoint-rate) > variation){
change = centerpoint-rate;
/* qucik math */
float volts = float(change)*0.00322581;
float rateofchange = volts/GYRO_SENSITIVITY;
float time = (float(timetook)-float(lasttook))/1000.0;
float degchange = rateofchange*time;
position = position+degchange;
position = makecardinal(position);
}
Serial.println(position);
change=0;
delay(10);
}
//simple function to make the poisition make sense
float makecardinal(float position){
if(position > 360.00){
position = position-360.00;
}else if(position < 0){
position = 360+position;
}
return position;
}
Good corrections thanks. The magic constant (which i should have defined) is just 3.3v/1023, voltage per ADC value. How would I reset the high/low each time? wouldn't movement of the gyro throw those values way off?
wouldn't movement of the gyro throw those values way off?
Movement of the gyro when?
Right now, you collect movement information over 1 second, then compute some values.
The loop() function ends, and gets called again. The movement of the gyro is then paid attention to again for 1 second. Only movement outside the range of the first second is observed.
If, during the 1st second, the gyro was moved from 0 to 10, back to 0, then to -10, and held there, high and low would reflect the +10 and -10 values.
If, during the 2nd second, the gyro was moved to +5 and -15, the high and low values would reflect the +10 and -15 limits.
I don't think this is exactly what you want, although I don't have a gyro or a use for one, or much of an understanding of how they work.
The high and the low are set once at the very initialization of the program while the gyro is perfectly still. they are just used to determine the amount of jitter I can expect out of the gyro throughout its use, very very simple error modeling. They gyro is sampled for position information at aprox 100hz, after the initial setup time if I continually reset the high and the low throughout this cycle it would read crazy values that are indicative of the gyro's current movement state, not its own precession, and the error map would be way off.
The high and the low are set once at the very initialization of the program while the gyro is perfectly still.
Is there any assurance that the gyro IS perfectly still?
If this is a one-time operation, it should be done in setup(), not in loop, I would think. I'm not any kind of expert on gyros, so, I'm just thinking out loud, so to speak.
other than being 100% untouched and immoble, there is no assurance. There may be a certain amount of ambient motion, but not enough to significantly effect it. Either way the amount of drift I'm sensing is only about 2-3 ADC.
And yes, you're absolutely right that the drift should be calculated in setup rather than in loop. I was just afraid that I would eventually forget that I called analogReference and move an analogRead before I changed the reference, which apparently can brick the arduino. Silly I know, but sometimes in the "heat" of coding I could see myself forgetting and really regretting it. So I just put it in loop with a simple if statement.
I was just afraid that I would eventually forget that I called analogReference and move an analogRead before I changed the reference, which apparently can brick the arduino.
You can't brick the Arduino by forgetting to change analogReference. You never change it, anyway.
So, doing the calibration is setup is a reasonable thing to do.