Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Sensors (http://www.chiefdelphi.com/forums/forumdisplay.php?f=173)
-   -   Building self balancing scooter- troubles with Integrating Gyro (http://www.chiefdelphi.com/forums/showthread.php?t=67982)

gohan22 07-06-2008 11:02

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
}
}

billbo911 07-06-2008 13:37

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.

gohan22 07-06-2008 14:32

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.

EHaskins 07-06-2008 16:04

Re: Building self balancing scooter- troubles with Integrating Gyro
 
Quote:

Originally Posted by gohan22 (Post 751814)
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.

The result from the gyro can change depending one a number of factors, temp, interference, ect. If possible you should calibrate the gyro each time you startup.

Also make sure the wires from the gyro aren't near any motors or other high current wires.

gohan22 09-06-2008 09:25

Re: Building self balancing scooter- troubles with Integrating Gyro
 
If you take a look at my code above, am i calabrating the gyro correctly

jhersh 17-06-2008 00:14

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

Kevin Sevcik 17-06-2008 12:00

Re: Building self balancing scooter- troubles with Integrating Gyro
 
Quote:

Originally Posted by jhersh (Post 753039)
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.

Joe,
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:
  • Dump the 8-bit ADC and continue with the 10-bit.
  • Determine what the likely bandwidth of his signal is.
  • Plan to sample at no less than 2 * that bandwidth
  • Oversample his signal as much as feasible. I'd think +2 bits of resolution is reasonable. Plus a little additional oversampling to average out the noise if it's still necessary.

gohan22 26-06-2008 20:39

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);



}

}

GRS 22-01-2009 23:06

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