# Averaging Acceleration on x,y,z-axis using LIS3DH Breakout Board with Mkr Zero

Hello!
I want to average each axis separately while doing different actions. I need this data for my overall code which will use these different accelerations as switch cases for different actions to happen. I have configured this in the I2C setup not SPI.

The problems I’m having:
I have been trying to read just the X acceleration into an array and then averaging those results. I’ve looked at many examples but all were for analog inputs.
This is how the data is being read.

``````void get_Acceleration( void )
{

lis.getEvent(&event);

accel_X = event.acceleration.x/9.81;
accel_Y = event.acceleration.y/9.81;
accel_Z = event.acceleration.z/9.81;

magnitude = sqrt(sq(accel_X) + sq(accel_Y) + sq(accel_Z));
if (magnitude < 0)
magnitude = 0;
}
``````

My latest attempt to getting average: (definitions are defined globally, not shown)

``````void get_AverageX ( void )
{
get_Acceleration(); //I don't think I need this
array_X[j++] = accel_X;     // populate FIFO array

if( j >= array_size)
j=0;
for (i = 0; i < array_size; i++)
{
sumX = sumX + array_X[i];
}
avgX = sumX / array_size;
}
``````

My main issue is that I can get my code to run but I am getting all zeros for the array and the average. The x acceleration (accel_X) is outputted fine.

I need help figuring out how to get the array to hold about 20 values of X-acceleration and then average it.
(I’ve seen the running average and smoothing examples but all are using analog pins, so I’m confused how I can change that to my type of output)

Thanks!

helpme_impoor:
(I’ve seen the running average and smoothing examples but all are using analog pins, so I’m confused how I can change that to my type of output)

That’s a little bit strange. Such routines are purely mathematical and, if written by other than a monkey, are completely agnostic about how the data is produced or used. Here is an example:

``````// exponential filter (lossy integration)
unsigned int smooth(unsigned int newVal) {
static unsigned int oldVal = 0;
unsigned long sum;
//  sum = (oldVal * 16 + newVal) / 16;
sum = ( (oldVal << 4) - oldVal + newVal) >> 4;
oldVal = sum;
return oldVal;
}
``````

What you’re saying seems like, “I went to buy a drinking cup for my apple juice, but all the cups were for water”.

When I was looking at the smooth examples they were using a potentiometer that was connect to the Arduino through analog pins.
Smoothing Code Below

``````const int numReadings = 10;

int total = 0;                  // the running total
int average = 0;                // the average

int inputPin = A0;

void setup() {
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
}
}

void loop() {
// advance to the next position in the array:

// if we're at the end of the array...
// ...wrap around to the beginning:
}

// calculate the average:
// send it to the computer as ASCII digits
Serial.println(average);
delay(1);        // delay in between reads for stability
}
``````

I am unsure how I could change this to my accel_X readings and plus how I can add the section you commented as well.

Post ALL the code, using code tags, and forum members can help you integrate a sensible moving average into it.

It's easy, you just pass incoming values into smooth(). The return value is the averaged value. So it's like:

average_X = smooth(accel_X);

Except that you are using floating point math, the function I gave you is for unsigned integers. The function can easily be converted to floating point:

``````// exponential filter (lossy integration)
float smooth(float newVal) {
static float oldVal = 0.0;
oldVal = (oldVal * 16 + newVal) / 16;
return oldVal;
}
``````

jremington:
Post ALL the code, using code tags, and forum members can help you integrate a sensible moving average into it.

``````//From the Accel Program
#include <Wire.h>
#include <SPI.h>

// For I2C Wiring Config.

double magnitude, accel_X, accel_Y, accel_Z;
float avg_X, avg_Y, avg_Z, avg_M;
float totalx, totaly, totalz;

float inputX = accel_X, inputY = accel_Y, inputZ= accel_Z;

sensors_event_t event;

void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial)
delay(10);     // will pause Zero, Leonardo, etc until serial console opens

Serial.println("Starting");

if (! lis.begin(0x18))
{   // change this to 0x19 for alternative i2c address
Serial.println("Couldnt start");
while (1) yield();
}
lis.setRange(LIS3DH_RANGE_16_G);   //Choose 16G because of teseting for firing (shock)

//Switch statement from the acceleration demo
switch (lis.getDataRate()) {
case LIS3DH_DATARATE_1_HZ:
break;
case LIS3DH_DATARATE_10_HZ:
break;
case LIS3DH_DATARATE_25_HZ:
break;
case LIS3DH_DATARATE_50_HZ:
break;
case LIS3DH_DATARATE_100_HZ:
break;
case LIS3DH_DATARATE_200_HZ:
break;
case LIS3DH_DATARATE_400_HZ:
break;
case LIS3DH_DATARATE_POWERDOWN:
break;
case LIS3DH_DATARATE_LOWPOWER_5KHZ:
break;
case LIS3DH_DATARATE_LOWPOWER_1K6HZ:
break;
}
}
avg.begin();
}

void loop() {

get_Acceleration();
get_AverageX();
get_AverageY();
get_AverageZ();
averageOutput_test();
delay(100);
totalx = 0;
totaly = 0;
totalz = 0;
}

void get_Acceleration( void )
{

lis.getEvent(&event);

accel_X = event.acceleration.x/9.81;
accel_Y = event.acceleration.y/9.81;
accel_Z = event.acceleration.z/9.81;

magnitude = sqrt(sq(accel_X) + sq(accel_Y) + sq(accel_Z));
if (magnitude < 0)
magnitude = 0;
}

void get_AverageX ( void )
{

{
}
}

void get_AverageY ( void )
{

{
}
}

void get_AverageZ ( void )
{

{
}
}

void averageOutput_test( void )
{
Serial.print("\tX acceleration: ");
Serial.print(accel_X);
Serial.print(" \tX average: ");
Serial.print(avg_X);
Serial.print("\tY acceleration: ");
Serial.print(accel_Y);
Serial.print(" \tY average: ");
Serial.print(avg_Y);
Serial.print("\tZ acceleration: ");
Serial.print(accel_Z);
Serial.print(" \tZ average: ");
Serial.print(avg_Z);
Serial.println();
delay(1000);
}
``````

The accelerations were printing fine, the averages were 0.
I don’t need the values to be in float, they were originally doubles but was having issues with that so I changed to float.

they were originally doubles but was having issues with that so I changed to float.

What sort of issues? "float" and "double" variables should behave the same in an application like this.

``````float inputX = accel_X,
``````

That doesn’t magically bind one variable to the other.

jremington:
What sort of issues? "float" and "double" variables should behave the same in an application like this.

I was able to change to double and didn't get errors. I believe I was getting errors when I was writing the arrays when I was trying to do a different average code. I was confused because I thought they were relatively the same thing.

Thanks!

TheMemberFormerlyKnownAsAWOL:

``````float inputX = accel_X,
``````

That doesn't magically bind one variable to the other.

Thanks! I got rid of the input variable.

My question is do I need to fix the line:

``````readingsX[readIndex] = accel_X;
``````

The example code used:

``````readings[readIndex] = analogRead(inputPin);
``````

Since I'm not reading from a pin but that event created, is that line my problem?

I actually think I found the problem.

I created different readIndex for each axis.

Here is final code:

``````//From the Accel Program
#include <Wire.h>
#include <SPI.h>

// For I2C Wiring Config.

double magnitude, accel_X, accel_Y, accel_Z;
double avg_X, avg_Y, avg_Z, avg_M;
double totalx = 0, totaly = 0, totalz = 0;
sensors_event_t event;

void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial)
delay(10);     // will pause Zero, Leonardo, etc until serial console opens

Serial.println("Starting");

if (! lis.begin(0x18))
{   // change this to 0x19 for alternative i2c address
Serial.println("Couldnt start");
while (1) yield();
}
lis.setRange(LIS3DH_RANGE_16_G);   //Choose 16G because of teseting for firing (shock)
//Switch statement from the acceleration demo
switch (lis.getDataRate()) {
case LIS3DH_DATARATE_1_HZ:
break;
case LIS3DH_DATARATE_10_HZ:
break;
case LIS3DH_DATARATE_25_HZ:
break;
case LIS3DH_DATARATE_50_HZ:
break;
case LIS3DH_DATARATE_100_HZ:
break;
case LIS3DH_DATARATE_200_HZ:
break;
case LIS3DH_DATARATE_400_HZ:
break;
case LIS3DH_DATARATE_POWERDOWN:
break;
case LIS3DH_DATARATE_LOWPOWER_5KHZ:
break;
case LIS3DH_DATARATE_LOWPOWER_1K6HZ:
break;
}
}
}

void loop() {

get_Acceleration();
get_AverageX();
get_AverageY();
get_AverageZ();
averageOutput_test();
delay(100);
}

void get_Acceleration( void )
{

lis.getEvent(&event);

accel_X = event.acceleration.x/9.81;
accel_Y = event.acceleration.y/9.81;
accel_Z = event.acceleration.z/9.81;

magnitude = sqrt(sq(accel_X) + sq(accel_Y) + sq(accel_Z));
if (magnitude < 0)
magnitude = 0;
}

void get_AverageX ( void )
{

{
}
}

void get_AverageY ( void )
{

{
}
}

void get_AverageZ ( void )
{

{
}
}

void averageOutput_test( void )
{
Serial.print("\tX acceleration: ");
Serial.print(accel_X);
Serial.print(" \tX average: ");
Serial.print(avg_X);
Serial.print("\tY acceleration: ");
Serial.print(accel_Y);
Serial.print(" \tY average: ");
Serial.print(avg_Y);
Serial.print("\tZ acceleration: ");
Serial.print(accel_Z);
Serial.print(" \tZ average: ");
Serial.print(avg_Z);
Serial.println();
}
``````

Let me know if you think there is a simpler way.
(Below I attached the monitor from the above code, the circuit was sitting on the table)

Let me know if you think there is a simpler way.

See replies #1 and #4 for a much simpler approach.

Well, there's your problem. At the bottom of loop() you have:

``````  totalx = 0;
totaly = 0;
totalz = 0;
``````

So you are only totaling 1 reading and dividing the total by 100. DON'T clear the totals! The oldest values are being subtracted from the total when you do the averaging.

Thanks!
I found that was one of the problems.

johnwasser:
Well, there's your problem. At the bottom of loop() you have:

``````  totalx = 0;
``````

totaly = 0;
totalz = 0;

``````

So you are only totaling 1 reading and dividing the total by 100. DON'T clear the totals! The oldest values are being subtracted from the total when you do the averaging.``````