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

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.

Two axis/Three axis accelerometer, I used an MMA7361L low-g module. It’s 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.5G. A quick look at the product manual gives us the following info: Features • Acceleration along X. Specification • Onboard 3. 3V3: The output of Low drop voltage regulator is connected to this pin.5g and 6g. Y. For logic levels refer to table below.2V to 3.6V to 6V. 206mV/G . 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. 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. YOUT: Analog voltage output proportional to instantaneous acceleration along Y axis.3V Low Drop voltage regulator with input range of 3.6V to 6V. • Supply voltage (Vdd): 2. Z axis. G-Select (logic level) Logic Level G-Range 0 Sensitivity : 1. G.6V @ 400µA (accelerometer supply range) • Sleep mode current: 10 µA • Sensitivity: 1. Z on the board. which is applied at pin no 1 of Accelerometer module. XOUT: Analog voltage output proportional to instantaneous acceleration along X axis.5g : 800 mV/g 6g : 206 mV/ g • Bandwidth: X. These indicate the 3 axes along with their directions. GND: Supply ground pin for accelerometer module. What I mean is that if the position of the accelerometer is changed. ZOUT: Analog voltage output proportional to instantaneous acceleration along Z axis. • High sensitivity of 800mV/g @1. Y. 800mV/G 1 Sensitivity : 6G. then the axes themselves will change directions creating complications that have to be accounted for.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.5g • User selectable acceleration range of ±1.SEL: G-Select pin is used to select g range of the accelerometer between 1.

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

our Y axis acceleration will be negative. If we are to expand to other quadrants. We will have to establish a few corrections to find the length of our vector.G-Direction of gravity The bottom line is parallel to the base plane.pi/2). Now as G is pointing downwards. we need to make suitable corrections as the range of tan in this case will be (0. 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!! . 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.

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

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

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

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

Sign up to vote on this title
UsefulNot useful