In the case that the accuracy is not high, the displacement can be obtained by integrating the three axis acceleration. Freescale gives the official method

Cache.freescale.com/files/senso…

Abstract

This document describes and implements the algorithm to solve the position using the MMA7260QT three-axis accelerometer and the low-power 9S08QG8 eight-bit microcontroller.

In today’s advanced electronics market, there are many multifunctional products that add many features and intelligence. Location and gaming are only part of the market that benefit from location information. One alternative to obtaining this information is through the use of inertial sensors. The signals obtained from these sensors require some processing because there is no direct conversion between acceleration and position.

To get the position, we need to integrate the acceleration twice. This paper introduces a simple algorithm to realize double integration of acceleration. To get the double integral of acceleration, a simple integral is done twice, because you can also get the velocity incidentally.

The algorithm to be shown next can be applied to any sensor axis, so the one, two, and three dimensional positions can be calculated. When obtaining three-dimensional position information, the influence of gravity acceleration should be especially removed. The following algorithm implementation also includes an example of a two-dimensional system (such as a mouse).

 

Potential applications

The potential applications of this algorithm are personal navigation, car navigation and back-up GPS, anti-theft devices, map tracking, 3D games, computer mice and more. All of these products require algorithms to solve location information.

The algorithm presented in this paper is useful when the displacement accuracy is not strictly required. Other situations and effects, especially in applications, need to be considered when adopting the algorithm in this paper. With minor modifications and adjustments to the final program, this algorithm can achieve higher accuracy.

 

Theoretical knowledge and algorithms

The best way to understand this algorithm is to review the mathematics of integration.

Acceleration is the rate at which an object’s velocity changes. Meanwhile, velocity is the rate at which the position of the same object changes. In other words, velocity is the derivative of position and acceleration is the derivative of velocity, hence the following formula:

         

An integral is the opposite of a derivative. If the acceleration of an object is known, then we can use a double integral to get the position of the object. Assuming that the initial condition is 0, the following formula can be obtained:

One way to understand this formula is to define the integral as the region under the curve, and the result of the integral is the sum of very small regions whose width tends to zero. In other words, the sum of the integral represents the magnitude (velocity) of a physical variable.

 

Using the previous concept of the region under the curve, we can come to the conclusion that sampling a signal gives an instantaneous value of the size of the signal, so that a small region can be obtained between two samples. Sampling times must be the same in order to obtain consistent values. The sampling time represents the width of the region and the sampled value represents the height of the region. To eliminate multiplications with fractions (microseconds or milliseconds), we assume that time is a unit.

Now, we know that the sampling time for each representative region width is equal to 1. The next conclusion:

The value of the integral can be approximately equal to the sum of the areas.

If the sampling time approaches 0, the conclusion will be correct. However, in practice, the following errors will be generated, which will accumulate during the processing process.

           

These errors are called sampling losses. To reduce these errors, let’s make a further assumption. The resulting region can be viewed as a combination of two smaller regions:

Region 1 is the value of the previous sample (square), and region 2 is a triangle that is half the difference between the previous sample and the current sample.

In this way, we now have a first-order approximation (interpolation) of the signal.

The current error is much lower than the previous approximation.

Although the acceleration can be positive or negative, the sampled value is always positive (based on the output characteristics of MMA7260QT), so an offset judgment needs to be made, in other words, a reference is required. This procedure is the calibration procedure.

Calibration procedures are used for acceleration values without movement. In this case, the obtained acceleration value can be regarded as zero reference point. Values below zero reference point represent negative values (deceleration) and values above zero reference point represent positive values (acceleration).

The accelerometer output ranges from 0V to Vdd, and it is usually obtained by an AD converter. The value of 0 is close to Vdd/2. The calibration values obtained previously are affected by the orientation of the chip and the static acceleration (gravitational acceleration) of the decomposition at each axis. If the device is parallel to the earth’s surface, the calibration value will be close to Vdd/2.

The following diagram shows the results of the calibration procedure.

    

    

Subtracting the zero reference value from the sampled signal, we obtain the true sampled acceleration.

 

A1 is positive acceleration, A2 is negative acceleration.

If we consider this data as sampled data, the signal value will look very similar to the following figure.

 

By using the above integral Formula, Formula 1, we will obtain a proportional approximation of the velocity. Again, to get the position, you have to integrate again. Applying the same formula and steps to the obtained velocity values, we now obtain a proportional approximation for an instantaneous position. (See Figure 6)

    

Notes on software design

The following steps and recommendations should be considered when applying this algorithm to real-world implementations.

  • There is some noise in the signal, so the signal must be filtered digitally. The filtering in this algorithm is a moving average algorithm, and the value to be processed is the average result of a certain number of sample values.
  • Even though some of the previously filtered data may be faulty due to mechanical noise, another filter must be implemented. Depending on the number of filtered samples, a window of true acceleration can be selected (typically 16±2 sampling times).
  • Inactivity is critical to getting the right data. The calibration routine needs to be at the beginning of the application. The calibration must be as accurate as possible.
  • The true value of acceleration is equal to the sampling value minus the calibration value; It can be positive or negative. This should never be ignored when you’re defining variables, you need to define them as signed numbers.
  • Faster sampling frequency means more accurate results, because faster sampling frequency means less error. But it requires more memory, time, and hardware considerations.
  • The time between samples must be the same. If The Times are different, an error will be generated.
  • Linear approximation (interpolation) between two sample results is recommended for more accurate results.

Code comments


1. Calibration procedure

This calibration procedure removes the offset component of the acceleration sensor’s output because of the presence of gravitational acceleration (static acceleration).

The calibration program averages the acceleration when the accelerometer is in a state of no motion. The more the number of samples, the more accurate the calibration results of the acceleration.

1 voidCalibrate(void) 2 { 3 unsignedint count1; 4 count1 =0; 5 do{ 6 ADC_GetAllAxis(); 7 sstatex = sstatex +Sample_X; // Accumulate Samples 8 sstatey = sstatey +Sample_Y; 9 count1++; 10 }while(count1! =0x0400); // 1024 times 11 sstatex=sstatex>>10; // division between 1024 12 sstatey=sstatey>>10; 13}Copy the code

2. The filter

Low pass filtering is a good method to eliminate signal noise (both mechanical and electronic) in accelerometers. Noise reduction is essential for positioning applications in order to reduce most errors when integrating the signal.

A simple way of filtering the sampled signal is to perform a rolling average. Filtering simply averages a set of samples, and it is important to get a stable average of the total number of samples. Too many samples may result in data loss, while too few may result in inaccurate results.

1 do{ 2 accelerationx[1]=accelerationx[1]+Sample_X; //filtering routine for noise attenuation 3 accelerationy[1]=accelerationy[1]+Sample_Y; //64 samples are averaged. The resulting 4 count2++; // average represents the acceleration of 5 // an instant. 6 }while(count2! =0x40); // 64 sums of the acceleration sample 7 accelerationx[1]= accelerationx[1]>>6; // division by 64 8 accelerationy[1]= accelerationy[1]>>6;Copy the code

3. Mechanical filtering window

When in the inactive state, a small error in acceleration may be treated as a constant velocity because it does not equal zero after the sample values are added up. In the ideal case where there is no movement, all the samples are zero. This constant velocity represents a continuous moving and unstable position.

Even though some of the previously filtered data may be incorrect, a window must be implemented to distinguish between “valid data” and “invalid data” in inactive states.

1 if ((accelerationx[1] <=3)&&(accelerationx[1] >= -3)) //Discrimination window applied to
2 {
3     accelerationx[1] = 0;
4 } // the X axis acceleration variable
Copy the code

 

    

 

4. Locate

Double integration is the step required to obtain position from acceleration data. The first integral gives you speed, and the second one gives you position.

1 //first integration
2 velocityx[1]= velocityx[0]+ accelerationx[0]+((accelerationx[1]- accelerationx[0])>>1)
3 //second integration
4 positionX[1]= positionX[0]+ velocityx[0]+((velocityx[1]- velocityx[0])>>1);
Copy the code

 

5. Data transmission

The main purpose of this section is for debugging and display; The 32-bit result in this function is split into four 8-bit data pieces.

1 if (positionX[1]>=0) 2 { //This line compares the sign of the X direction data 3 direction= (direction | 0x10); // if its positive the most significant byte 4 posx_seg[0]= positionX[1] & 0x000000FF; // is set to 1 else it is set to 8 5 posx_seg[1]= (positionX[1]>>8) & 0x000000FF; // the data is also managed in the 6 // subsequent lines in order to be sent. 7 posx_seg[2]= (positionX[1]>>16) & 0x000000FF; // The 32 bit variable must be split into 8 posx_seg[3]= (positionX[1]>>24) & 0x000000FF; // 4 different 8 bit variables in order to 9 // be sent via the 8 bit SCI frame 10 } 11 else 12 { 13 direction=(direction | 0x80); 14 positionXbkp=positionX[1]-1; 15 positionXbkp=positionXbkp^0xFFFFFFFF; 16 posx_seg[0]= positionXbkp & 0x000000FF; 17 posx_seg[1]= (positionXbkp>>8) & 0x000000FF; 18 posx_seg[2]= (positionXbkp>>16) & 0x000000FF; 19 posx_seg[3]= (positionXbkp>>24) & 0x000000FF; 20}Copy the code

 

6. “End of movement” check

Based on the concept that the integral represents the region below the curve, velocity is the result of accelerating the region below the curve.

If we look at A typical motion: an object moving along an axis from point A to point B, A typical acceleration results in the following figure:

Looking at the graph above, the acceleration increases and then decreases until the velocity reaches its maximum (acceleration is always positive, which means accelerating in the same direction). And then accelerate in the opposite way until it reaches zero again. At this point a stable displacement and a new position are achieved.

In the real world, where the area under the positive side of the curve is not equal to the area above the negative side, the integral result will never reach zero velocity and will therefore be an oblique position (never stable).

Because of this, forcing the speed down to zero is critical. This is done by constantly reading the acceleration value and comparing it to zero. If this is the case in a certain number of samples (sample==0), the speed will simply return to 0.

1 if (accelerationx[1]==0) // we count the number of acceleration samples that equals zero 2 { 3 countx++; 4 } 5 else 6 { 7 countx =0; 8 } 9 if (countx>=25) // if this number exceeds 25, we can assume that velocity is zero 10 { 11 velocityx[1]=0; 12 velocityx[0]=0; 13}Copy the code

 

 

 

 

 

 

7. The source code

 

  1 #include <hidef.h>
  2 #include "derivative.h"
  3 #include "adc.h"
  4 #include "buzzer.h"
  5 #include "SCItx.h"
  6 #pragma DATA_SEG MY_ZEROPAGE
  7 unsigned char near Sample_X;
  8 unsigned char near Sample_Y;
  9 unsigned char near Sample_Z;
 10 unsigned char near Sensor_Data[8];
 11 unsigned char near countx,county ;
 12 signed int near accelerationx[2], accelerationy[2];
 13 signed long near velocityx[2], velocityy[2];
 14 signed long near positionX[2];
 15 signed long near positionY[2];
 16 signed long near positionZ[2];
 17 unsigned char near direction;
 18 unsigned long near sstatex,sstatey;
 19 #pragma DATA_SEG DEFAULT
 20 void init(void);
 21 void Calibrate(void);
 22 void data_transfer(void);
 23 void concatenate_data(void);
 24 void movement_end_check(void);
 25 void position(void);
 26 void main (void)
 27 {
 28  init();
 29  get_threshold();
 30  do
 31  {
 32  position();
 33  }while(1);
 34 }
 35 /*******************************************************************************
 36  The purpose of the calibration routine is to obtain the value of the reference threshold.
 37  It consists on a 1024 samples average in no-movement condition.
 38 ********************************************************************************/
 39 void Calibrate(void)
 40 {
 41  unsigned int count1;
 42  count1 = 0;
 43  do{
 44  ADC_GetAllAxis();
 45  sstatex = sstatex + Sample_X; // Accumulate Samples
 46  sstatey = sstatey + Sample_Y;
 47  count1++;
 48  }while(count1!=0x0400); // 1024 times
 49  sstatex=sstatex>>10; // division between 1024
 50  sstatey=sstatey>>10;
 51 }
 52 /*****************************************************************************************/
 53 /******************************************************************************************
 54 This function obtains magnitude and direction
 55 In this particular protocol direction and magnitude are sent in separate variables.
 56 Management can be done in many other different ways.
 57 *****************************************************************************************/
 58 void data_transfer(void)
 59 {
 60  signed long positionXbkp;
 61  signed long positionYbkp;
 62  unsigned int delay;
 63  unsigned char posx_seg[4], posy_seg[4];
 64  if (positionX[1]>=0) { //This line compares the sign of the X direction data
 65  direction= (direction | 0x10); //if its positive the most significant byte
 66  posx_seg[0]= positionX[1] & 0x000000FF; // is set to 1 else it is set to 8
 67  posx_seg[1]= (positionX[1]>>8) & 0x000000FF; // the data is also managed in the
 68  // subsequent lines in order to
 69  posx_seg[2]= (positionX[1]>>16) & 0x000000FF; // be sent. The 32 bit variable must be
 70  posx_seg[3]= (positionX[1]>>24) & 0x000000FF; // split into 4 different 8 bit
 71  // variables in order to be sent via
 72  // the 8 bit SCI frame
 73 }
 74  else {direction=(direction | 0x80);
 75  positionXbkp=positionX[1]-1;
 76  positionXbkp=positionXbkp^0xFFFFFFFF;
 77  posx_seg[0]= positionXbkp & 0x000000FF;
 78  posx_seg[1]= (positionXbkp>>8) & 0x000000FF;
 79  posx_seg[2]= (positionXbkp>>16) & 0x000000FF;
 80  posx_seg[3]= (positionXbkp>>24) & 0x000000FF;
 81  }
 82  if (positionY[1]>=0) { // Same management than in the previous case
 83  direction= (direction | 0x08); // but with the Y data.
 84  posy_seg[0]= positionY[1] & 0x000000FF;
 85  posy_seg[1]= (positionY[1]>>8) & 0x000000FF;
 86  posy_seg[2]= (positionY[1]>>16) & 0x000000FF;
 87  posy_seg[3]= (positionY[1]>>24) & 0x000000FF;
 88  }
 89  else {direction= (direction | 0x01);
 90  positionYbkp=positionY[1]-1;
 91  positionYbkp=positionYbkp^0xFFFFFFFF;
 92  posy_seg[0]= positionYbkp & 0x000000FF;
 93  posy_seg[1]= (positionYbkp>>8) & 0x000000FF;
 94  posy_seg[2]= (positionYbkp>>16) & 0x000000FF;
 95  posy_seg[3]= (positionYbkp>>24) & 0x000000FF;
 96  }
 97  delay = 0x0100;
 98  Sensor_Data[0] = 0x03;
 99  Sensor_Data[1] = direction;
100  Sensor_Data[2] = posx_seg[3];
101  Sensor_Data[3] = posy_seg[3];
102  Sensor_Data[4] = 0x01;
103  Sensor_Data[5] = 0x01;
104  Sensor_Data[6] = END_OF_FRAME;
105  while (--delay);
106  SCITxMsg(Sensor_Data); // Data transferring function
107  while (SCIC2 & 0x08);
108 }
109 /*****************************************************************************************/
110 /******************************************************************************************
111 This function returns data format to its original state. When obtaining the magnitude and
112 direction of the position, an inverse two's complement is made. This function makes the two's
113 complement in order to return the data to it original state.
114 It is important to notice that the sensibility adjustment is greatly impacted here, the amount
115 of "ones" inserted in the mask must be equivalent to the "ones" lost in the shifting made in
116 the previous function upon the sensibility modification.
117  ******************************************************************************************/
118 void data_reintegration(void)
119 {
120  if (direction >=10)
121 {positionX[1]= positionX[1]|0xFFFFC000;} // 18 "ones" inserted. Same size as the
122  //amount of shifts
123  direction = direction & 0x01;
124  if (direction ==1)
125  {positionY[1]= positionY[1]|0xFFFFC000;}
126 }
127 /******************************************************************************************
128 This function allows movement end detection. If a certain number of acceleration samples are
129 equal to zero we can assume movement has stopped. Accumulated Error generated in the velocity
130 calculations is eliminated by resetting the velocity variables. This stops position increment
131 and greatly eliminates position error.
132 ******************************************************************************************/
133 void movement_end_check(void)
134 {
135  if (accelerationx[1]==0) //we count the number of acceleration samples that equals cero
136  { countx++;}
137  else { countx =0;}
138  if (countx>=25) //if this number exceeds 25, we can assume that velocity is cero
139  {
140  velocityx[1]=0;
141  velocityx[0]=0;
142  }
143  if (accelerationy[1]==0) //we do the same for the Y axis
144  { county++;}
145  else { county =0;}
146  if (county>=25)
147  {
148  velocityy[1]=0;
149  velocityy[0]=0;
150  }
151 }
152 /*****************************************************************************************/
153 /******************************************************************************************
154 This function transforms acceleration to a proportional position by integrating the
155 acceleration data twice. It also adjusts sensibility by multiplying the "positionX" and
156 "positionY" variables.
157 This integration algorithm carries error, which is compensated in the "movenemt_end_check"
158 subroutine. Faster sampling frequency implies less error but requires more memory. Keep in
159 mind that the same process is applied to the X and Y axis.
160 *****************************************************************************************/
161 void position(void)
162 {
163 unsigned char count2 ;
164 count2=0;
165  do{
166  ADC_GetAllAxis();
167  accelerationx[1]=accelerationx[1] + Sample_X; //filtering routine for noise attenuation
168  accelerationy[1]=accelerationy[1] + Sample_Y; //64 samples are averaged. The resulting
169 //average represents the acceleration of
170  //an instant
171  count2++;
172  }while (count2!=0x40); // 64 sums of the acceleration sample
173  accelerationx[1]= accelerationx[1]>>6; // division by 64
174  accelerationy[1]= accelerationy[1]>>6;
175  accelerationx[1] = accelerationx[1] - (int)sstatex; //eliminating zero reference
176  //offset of the acceleration data
177  accelerationy[1] = accelerationy[1] - (int)sstatey; // to obtain positive and negative
178  //acceleration
179  if ((accelerationx[1] <=3)&&(accelerationx[1] >= -3)) //Discrimination window applied
180  {accelerationx[1] = 0;} // to the X axis acceleration
181  //variable
182  if ((accelerationy[1] <=3)&&(accelerationy[1] >= -3))
183  {accelerationy[1] = 0;}
184  //first X integration:
185 velocityx[1]= velocityx[0]+ accelerationx[0]+ ((accelerationx[1] -accelerationx[0])>>1);
186  //second X integration:
187 positionX[1]= positionX[0] + velocityx[0] + ((velocityx[1] - velocityx[0])>>1);
188  //first Y integration:
189 velocityy[1] = velocityy[0] + accelerationy[0] + ((accelerationy[1] -accelerationy[0])>>1);
190  //second Y integration:
191 positionY[1] = positionY[0] + velocityy[0] + ((velocityy[1] - velocityy[0])>>1);
192  accelerationx[0] = accelerationx[1]; //The current acceleration value must be sent
193 //to the previous acceleration
194  accelerationy[0] = accelerationy[1]; //variable in order to introduce the new
195 //acceleration value.
196  velocityx[0] = velocityx[1]; //Same done for the velocity variable
197  velocityy[0] = velocityy[1];
198  positionX[1] = positionX[1]<<18; //The idea behind this shifting (multiplication)
199  //is a sensibility adjustment.
200  positionY[1] = positionY[1]<<18; //Some applications require adjustments to a
201  //particular situation
202  //i.e. mouse application
203  data_transfer();
204  positionX[1] = positionX[1]>>18; //once the variables are sent them must return to
205  positionY[1] = positionY[1]>>18; //their original state
206  movement_end_check();
207  positionX[0] = positionX[1]; //actual position data must be sent to the
208  positionY[0] = positionY[1]; //previous position
209  direction = 0; // data variable to direction variable reset
210 }
211 /*****************************************************************************************/
Copy the code

 

Schematic diagram

conclusion

This document provides some basic concepts for implementing localization algorithms using accelerometers.

This particular algorithm is very useful when the accuracy of displacement is not very strict. Other considerations and application-specific implications should be considered when implementing this example.

This integration algorithm is suitable for low-end embedded applications because of its simplicity and small number of instructions. Nor does it involve any floating point operations.