![]() |
Building self balancing scooter- troubles with Integrating Gyro
Hi there, i am building a self balancing scooter and i am trying to integrate the gyro (ADIS16100) in order to use it as a tilt sensor but the value of the integration keeps drifting away weather the Gyro is moving or not. Currently every 10 seconds the value increases by a small amount. Does anyone know of a better way to integrate or a way to determine the offset than just assuming its constant which clearly its not?
#include<16f877A.h> #DEVICE ADC=8 #fuses hs,nowdt,noprotect,noput,nobrownout #use delay(clock=20000000) #include<lcd420.c>//set up for LCD #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,bits=8,pari ty=N) //#use spi(MASTER,DI=pin_A0,DO=pin_A1,CLK=pin_A2,BAUD=100 0000,IDLE=1,SAMPLE_RISE,ENABLE_ACTIVE=1,MODE=1,BIT S=16,MSB_FIRST,STREAM=SPI_STREAM,ENABLE=PIN_D2) #define GYRO_OFFSET 123 //offset for 8 bits is 123 and for 10 bit it is 507 #int_timer0 void main () { float dt,angle; double gz_adc,last_angle; /* Analog values */ int gz_deg,gyro_deg; /* Unit values */ double newgyrovalue = 0; double oldgyrovalue = 0; double gyrointegral = 0; lcd_init (); delay_us(10); //Setup the Timer setup_timer_0(RTCC_INTERNAL | RTCC_8_BIT| RTCC_DIV_256); // sets up timer set_timer0(0); // intitializes timer to 0 //Setup the ADC setup_adc(ADC_CLOCK_INTERNAL );//setup clock before setup setup_adc_ports( ALL_ANALOG ); set_adc_channel( 0 );//check to see why not A0 while(1) { newgyrovalue = read_adc(); set_timer0(0);//start the timer gyro_deg=((newgyrovalue-gyro_offset)*41); dt=get_Timer0();//get the timer value gyrointegral = (oldgyrovalue + (gyro_deg*0.000051*dt)); oldgyrovalue = gyrointegral; angle=gyrointegral; printf (lcd_putc,"\f Angle is :%f", angle); // d for int and f for float and double delay_ms(40); //set_timer0(0);//reset the timer } } |
Re: Building self balancing scooter- troubles with Integrating Gyro
Let me start first off by stating that I am not a Gyro expert. There are two people on this site that have way more experience than I do, they are: Kevin Watson and Dr. Eugene Brooks.
I would suggest starting by searching for posts with "gyro" in the title. Dr. Brooks and Kevin each take different approaches to integrating the Gyro. In a nutshell, Kevin uses a dead band to eliminate the drift and noise. Dr. Brooks integrates the noise which actually gives a higher resolution. Both approaches are correct the trick is to determine which is most appropriate for your application. The next question I would like to ask you is which microcontroller you are using to create this project? And are you using an 8-bit or 10 bit ADC? In either case make certain that the offset is not randomly chosen as the center of the ADC range. Make certain you are actually measuring the output with zero motion from the Gyro, using that value for your offset. |
Re: Building self balancing scooter- troubles with Integrating Gyro
Im using the 16F877a Pic controller and using 8 bit adc. i hooked the gyro to an lcd screen for it to display the reading when its not moving and that reading was 123 so thats the offset i subtract. I found when i used 10 bit for adc the value that i was reading when the gyro wasn't moving was jumping around quite a bit...+/- 2 numbers and when i used 8 bits it was pretty solid.
|
Re: Building self balancing scooter- troubles with Integrating Gyro
Quote:
Also make sure the wires from the gyro aren't near any motors or other high current wires. |
Re: Building self balancing scooter- troubles with Integrating Gyro
If you take a look at my code above, am i calabrating the gyro correctly
|
Re: Building self balancing scooter- troubles with Integrating Gyro
Another thing you might try that has been very effective for me is oversampling the value before accumulating. Oversampling is much like averaging, except that you don't divide. It's easiest (just like averaging) if you work with powers of 2. Let say you choose to add 4 bits to your measurements by oversampling. That means that for each sample you want to accumulate, you need to actually aquire 2^4 or 16 samples. By doing this, your center value that you subtract off of each value before accumulating can be more accurate.
The way to get the best center value for your accumulator is to average the samples for a long period. Probably at least 1 second. Remember that since your center value is now based on oversampled readings, you need to be averaging oversampled readings to calibrate your center value. You also noted that you have a 10-bit ADC but are only using 8 bits because at 8 bits, the values don't change. Truncating your values is worse than averaging them. It has the exact opposite effect that oversampling does. You should definitly use all 10 bits plus oversampling and simply average enough points to find the stable value. It is that very noise in the system that makes oversampling possible. One caveat to oversampling is that you must sample faster to maintain the same bandwidth. Probably the best thing to do is run the ADC as fast as it will go and then oversample as much as you can while still keeping the bandwidth that you need from the gyro. That is, of course, if your processor can keep up. Another thing you might try to augment the integrated sensor (which will always have some amount of drift) is to use a sensor that can tell you angle statically to help zero the measurements. You could then use even low bandwidth readings from that sensor to correct the integrated value. Cheers! -Joe |
Re: Building self balancing scooter- troubles with Integrating Gyro
Quote:
I agree that oversampling to increase the resolution could be a good way to reduce the drift in Gohan22's integration. Integrating a 1-bit error in an 8-bit signal is much much worse than a 1 bit error in a 12-bit signal. That said, your math is a little off, Joe. Acquiring more resolution from a given signal is a process of oversampling and decimation. The decimation part is important, as half the extra information you acquire is still just noise. Using your method, accumulating 16 samples does increase the accumulated total by 4 bits over the original value. But the last 2 bits of the value are still just so much noise. To actually oversample a signal to increase resolution, you need to sample at 4^n times your original rate, accumulating the values you're sampling, then right shift the result by n bits. To get 4 more bits of resolution, you need to sample 256 times faster. There's some real important caveats here, though. First, your signal HAS to be noisy for oversampling to work. If Gohan22's signal from an 8-bit ADC is nice and stable, then oversampling won't get him anything. If your signal is stable at 127 when the real value is 127.4, then adding 127 a bunch of time isn't going to get you any more information. So oddly enough, I'd prefer Gohan's slightly noisy 10-bit ADC result, as there's more information to be extracted there. The other caveats are a little more subtle. The noise has to be random in nature, or at least appear so to you ADC. If some of the noise is from a timer that increases your reading every 3rd sample, you'll get skewed results. Also, the signal should be be relatively stable in your oversampling window. Similar to the last, if the signal is meaningfully fluctuating during the oversampling window, those meaningful fluctuations are going to disturb your average. Plus, if it's a meaningful fluctuation, you're not sampling at the Nyquist frequency and you'll be ending up with an aliased signal anyways. Finally, if your oversampled and decimated signal is still noisy, you can always further decimate it until it stops being so. You can also sample even faster to make up for these extra decimations and maintain your target sampling rate. So! In conclusion to a long winded post, I think Gohan22 should:
|
Re: Building self balancing scooter- troubles with vibrations and balanacing
Ok so my code has changed quite a bit. Currently i am having problems with vibrations which is causing my sensors to go crazy and not allowing me to balance. I have coded my PWM to increase smoothly and decrease smoothly.
Any suggestions on how to solve this? My code is below. If you require any more infomation please let me know. Should i code a deadzone between -2 to 2 degrees? #include<16f877A.h> #DEVICE ADC=10 #fuses hs,nowdt,noprotect,noput,nobrownout #use delay(clock=20000000) #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,bits=8,pari ty=N) //#define kp 0.4 //#define kd 0.5 void main () { float motor=0,angle,last_motor=0; long lmotor=0,rmotor=0,value; long gz_adc,ax_adc, ax_offset=512,gz_offset=494; /* Analog values */ signed long gz_deg,ax_deg; long dt=0, i; /*Setup PWM timers*/ setup_ccp1(CCP_PWM); setup_ccp2(CCP_PWM); setup_timer_2(T2_DIV_BY_16, 255, 1); output_bit(pin_b6,0);//Disable pin enable=0 and disable=1 goes to pin 4 of cable output_bit(pin_b5,1); //AHI and BHI always pulled high goes to pin7 and pin 5 /*Timer0, 8 bit, prescaler of 256, 20Mhz/4=5,000. Inverse 5,000 times the prescaler value, this will be the increment by which your timer counts 'one tic'in our case it's 56.2 ms */ //setup_timer_0(RTCC_INTERNAL | RTCC_8_BIT| RTCC_DIV_256); //sets up timer setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //Setup the ADC setup_adc(ADC_CLOCK_INTERNAL );//setup clock before setup setup_adc_ports( ALL_ANALOG ); set_adc_channel( 0 ); delay_ms(10); while(1) { dt=get_timer1(); set_timer1(0x0000); //setup ADC for accel set_adc_channel(0); delay_us(10); ax_adc=read_adc(); //Setup read for gyro set_adc_channel(1); delay_us(10); gz_adc = read_adc(); if (ax_adc>=ax_offset){ax_deg=(((ax_adc-ax_offset)*14)>>5); } else { ax_deg=((((ax_adc-ax_offset)*14)*-1)>>5)*-1;} if (gz_adc>=gz_offset) {gz_deg=(((gz_adc-gz_offset)*41)>>6); angle = 0.97* (angle + (float)(gz_deg*0.00000016*dt)); angle += 0.03*(ax_deg); } else { gz_deg=((((gz_adc-gz_offset)*41)*-1)>>6)*-1; angle = 0.97* (angle + (((float)gz_deg)*0.0000016*(float)dt)); angle += 0.03*((float)ax_deg); } //Calculate motor value for PD controller if (angle>3 && angle<50) {motor=(((angle)/30)*345)+(0.2*(float)(gz_deg)); last_motor=motor; } else if (angle<-2 && angle>=-45) { motor=(((angle)/(-25))*285)+(0.6*(float)(gz_deg)); last_motor=motor; } else { motor=(long)(motor); last_motor=motor;} if(motor>255) {motor=255;} else {motor=(long)(motor);} if(motor>(last_motor+4) && motor<(last_motor-4)) {motor=last_motor;} else {motor=motor;} lmotor= rmotor=(long)(motor); delay_us(10); //lmotor=((56523+lmotor)>>8); //rmotor=((56523+rmotor)>>8); //Control the motors if (angle>=2 && angle<70) { output_b(0b00100001); output_d(0b00100010); set_pwm1_duty(rmotor); set_pwm2_duty(lmotor); delay_us(100); } //Reverse else if (angle<-2 && angle>=-45) { output_b(0b00100010); output_d(0b00100001); set_pwm1_duty(rmotor); set_pwm2_duty(lmotor); delay_us(100); } //Turn off motors else { output_b(0b00100001); output_d(0b00100010); rmotor=lmotor=0; set_pwm1_duty(rmotor); set_pwm2_duty(lmotor); delay_us(100); } //dt=get_timer0(); //gz_adc=gz_adc+5; //ax_adc=ax_adc+3; //printf ("\rAX_ANGLE=%ld \n\rANGLE=%f \n\rdt=%ld \n\rMOTOR=%f \n",ax_deg,angle,dt,motor ); // d for int and f for //printf (lcd_putc,"\f%ld %ld \n %ld",gz_deg,ax_deg,gyrointegral); // d for int and f for //delay_ms(10); } } |
Re: Building self balancing scooter- troubles with Integrating Gyro
Try placing the sensor on a block of vibration isolation foam.
|
| All times are GMT -5. The time now is 02:37. |
Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi