Sunteți pe pagina 1din 8

Accelerometer interfacing and using it to control a Servo motor -Pl.

Siddharth
Objective:
To interface an accelerometer to an AVR Microcontroller(Atmega8 in this case) and use it to control a servo motor that traces the movement of the accelerometer.

Components:
Two axis/Three axis accelerometer, I used an MMA7361L low-g module. Its the cheapest available and I found it to be highly accurate during my testing. Atmega8 microcontroller, LCD display(16x2 character display standard ones) and all the other regular stuff like wires,gpb,soldering lead etc. Principles of Operation: Basically there is INPUT CONTROL OUTPUT Lets take the input first. The input is provided by our accelerometer. An accelerometer, as the name suggests, measures the acceleration along each direction. Basically these MEMS accelerometers consist of a tiny test mass and measure acceleration using Force/Mass. The MMA7361L is a three axis accelerometer, meaning it can measure acceleration along each of the X, Y, Z axis in a Cartesian system. Usually the IC is available on a board with a 3.3 Voltage drop regulator.

If you look closely you should be able to make out the capital letters X, Y, Z on the board. These indicate the 3 axes along with their directions. Now while designing any moving system you should be aware that the accereleration measured along a given direction is dependent on the existing position of the accelerometer. What I mean is that if the position of the accelerometer is changed, then the axes themselves will change directions creating complications that have to be accounted for. A quick look at the product manual gives us the following info: Features Acceleration along X, Y, Z axis. High sensitivity of 800mV/g @1.5g User selectable acceleration range of 1.5g or 6g Free fall detection (0g-Detect) Self Test function to test electrical or mechanical integrity of the sensor Sleep mode to reduce power consumption when sensor is not in use. Specification Onboard 3.3V Low Drop voltage regulator with input range of 3.6V to 6V. Supply voltage (Vdd): 2.2V to 3.6V @ 400A (accelerometer supply range) Sleep mode current: 10 A Sensitivity: 1.5g : 800 mV/g 6g : 206 mV/ g Bandwidth: X, Y axis: 400Hz Z axis: 300Hz Output Impedance : 32KO Connections: Pin Description: VIN: The module is working the input supply voltage in the range of 3.6V to 6V, which is applied at pin no 1 of Accelerometer module. GND: Supply ground pin for accelerometer module. 3V3: The output of Low drop voltage regulator is connected to this pin. XOUT: Analog voltage output proportional to instantaneous acceleration along X axis. YOUT: Analog voltage output proportional to instantaneous acceleration along Y axis. ZOUT: Analog voltage output proportional to instantaneous acceleration along Z axis. G.SEL: G-Select pin is used to select g range of the accelerometer between 1.5g and 6g. For logic levels refer to table below. G-Select (logic level) Logic Level G-Range 0 Sensitivity : 1.5G, 800mV/G 1 Sensitivity : 6G, 206mV/G

ST (Self-Test): Self Test allows the verification of the mechanical and electrical integrity of the accelerometer. 0g-Detect: This pin is made logic high when free fall condition (all three axes at 0g) is detected. Connect this pin to the interrupt pin of the microcontroller to take suitable actions in case of free fall. What this information implies is that we would get a voltage output correlation to the magnitude of acceleration in a given direction. Now, the G-select pin controls the sensitivity and range the IC can measure. A lower range implies a higher sensitivity and vice versa. Now setting the G-select to logic low gives a sensitivity of 800mV/G and a range of upto 6G. And G-select=1 gives a range of 1.5G at 800mV/G. (G=9.8m/sec2). My project requires no more than 1.5G, so we will be setting G-select to logic low. Other versions of the IC have more than one G-select pin for more liberal sensitivity choices. It is clear from the features of the IC that we would get a voltage correlation to the acceleration along each direction. But what is important here is how we interpret these voltage values. Now if you observe the specifications more clearly we have Static Acceleration : XOUT,YOUT,ZOUT @ -1g: 0.85V @ 0g: 1.65V @ +1g: 2.45V So our IC is capable of measuring negative voltage as well as positive voltage. The zero bias being 1.65 V. So if there was no acceleration along a given direction we would be reading ~1.65 volts on that pin and similarly for the other values Lets move on to how we allow the servo to trace the accelerometer. Now what we want to determine is the angle the accelerometer is tilting towards gravity. I set my axes as shown in the figure below. Some simple trigonometry yields the angle as atan(Y/X) in the first quadrant.

G-Direction of gravity

The bottom line is parallel to the base plane. Now as G is pointing downwards, our Y axis acceleration will be negative. We will have to establish a few corrections to find the length of our vector. If we are to expand to other quadrants, we need to make suitable corrections as the range of tan in this case will be (0,pi/2). For the second quadrant we can again perform some simple trigonometry to yield the angle as atan(X/Y)+pi/2where we obtain the values of X and Y after correcting both as hereX and Y become negative. After seeing the result you might say atan(X/Y)+pi/2 is the same as atan(Y/X) as some properties of inverse functions reduce it as such but pay more attention to the range of the two functions and then decide!!

Corrections for negative vectors in order to determine their length: Now negative acceleration X,Y,Z 0.85<Acceleration<1.65 for negative 1.65<Acceleration<2.45 for positive From these values our objective is to determine the length of acceleration vector along the requires axis. So we start by subtracting the zero bias voltage(1.65) from the value of voltage we obtain from the acceleration pins. This gives negative value for negative acceleration and positive value for positive acceleration. The next step is to take modulus of our result so that we can apply our atan formula and get the resulting tilt angle. With that our corrections to obtain vector lengths is complete.We will have to implement that in code, of course, to let the micro know what to do. The 3.3 volt output pin is meant to be connected to AREF of the micro so that ADC is as precise as possible. With this we cover the input. Before we move to control, let us see how we control a servo. Now im going to be brief on this part as there as thousands of tutorials for this on the net. Basically what we do is, we set up the time period of the PWM as 20ms(50 hz) or in other words the time taken for the timer to count upto (2^16-1) should be 20ms. Then we impose time varying positive pulses on each cycle. You must check the datasheet of your servo to see the exact angle it turns by for a given length positive pulse. Generally 1.5ms is around 90 degrees. So once we determine our tilt angle, we have to perform some proportion to find the positive pulse period and then impose it on our cycle. Its always useful to have LCD displays connected as they are the best debugging tools. I used an LCD display to print the X, Y, Z accelerations and the resulting tilt angle and a few other things like the square of X,Y,Z accelerations to see if it was constant under static conditions etc. Now we will see the control I used an atmega8 clocked at 8mhz G-select at PC0 Z acc- PC1 Y acc-PC2 X acc-PC3

//Pl.Siddharth #include <avr/io.h>

#include"lcd.h" #include<math.h> #include<inttypes.h> #include <util/delay.h> void initi_ADC() { ADCSRA |= (0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); ADMUX |= (1 << REFS0); ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading ADCSRA|= (1<<ADEN); //enable adc } uint16_t getDigitalValueOf(uint8_t channel) { ADMUX&=0xF0; ADMUX|=channel; // MUX values needed to be changed to use ADC0 ADCSRA|= (1<<ADSC); //start conversion while(!(ADCSRA & 0x10)) { ;//wait to finish convertion till ADIF is set high.will come out of loop } return ADCH; //return digital value } //Simple Wait Function void Wait() { uint8_t i; for(i=0;i<50;i++) { _delay_loop_2(0); _delay_loop_2(0); _delay_loop_2(0); } } int main() { int x,y,z,a,b; DDRC|=0b0110001; DDRC&=~0b0001110; InitLCD(LS_BLINK|LS_ULINE); LCDClear();

initi_ADC(); //Set g-Select=0 PORTC&=~(1<<PC0); //Configure TIMER1 TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11); //NON Inverted PWM TCCR1B|=(1<<WGM13)|(1<<WGM12)|(1<<CS11); //PRESCALER=8 MODE 14(FAST PWM) ICR1=19999; //fPWM=50Hz (Period = 20ms Standard). DDRB|=(1<<PB1)|(1<<PB2); //PWM Pins as Out while(1) { //Read XYZ accelerations x=getDigitalValueOf(PC3)*500/256; LCDWriteIntXY(0,0,x,3); y=getDigitalValueOf(PC2)*500/256; LCDWriteIntXY(4,0,y,3); z=getDigitalValueOf(PC1)*500/256; LCDWriteIntXY(8,0,z,3); a=sqrt((x*x)+(y*y)+(z*z)); LCDWriteIntXY(12,0,a,3); PORTC&=~((1<<PC4)|(1<<PC5)); y=y-165; x=x-165; LCDWriteIntXY(8,1,x,3); LCDWriteIntXY(12,1,y,3); if(x>0) { PORTC|=(1<<PC5);//reference led for fun if(y<0) { y=-y;//modulus } else {; } b=atan(y/x)*100; LCDWriteIntXY(0,1,b,3); OCR1A=(((b*1.5/157)*20000)/20);//Control signal OCR1B=(((b*1.5/157)*20000)/20);//One of the OCR pins is connected to an led

LCDWriteIntXY(4,1,OCR1A/100,3); } else if(x<0) { PORTC|=(1<<PC4);//reference led for fun if(y<0) { y=-y;//modulus } else {; } x=-x; b=(atan(x/y)*100)+157; LCDWriteIntXY(0,1,b,3); OCR1A=(((b*1.5/157)*20000)/20); OCR1B=(((b*1.5/157)*20000)/20); LCDWriteIntXY(4,1,OCR1A/100,3); } } return 0; } You might be wondering why im returning a 16 bit value for the ADC function when Ive set up 8 bit ADC. The reason is that im going to perform an operation on it and then write it over to an integer which is 2 bytes, so I could have type casted it later but I prefer this. And you might also be thinkingg why im multiplying by 100 and dividing by those values. The reason is that the LCDWriteIntXY can only print unsigned integers so I would need to convert my floating points to an interger approximations before I can print them. I had no choice for that but I made suitable corrections in the math. Also in this case I used Aref as 5V. The code works fully and I have tested it. Here is a demo on youtube http://www.youtube.com/watch?v=5LK4s0YIoR8&feature=related

S-ar putea să vă placă și