Erroneous Accelerometer Readings When Combined w/ Other I2C Sensors

I have an arduino uno doing some statistical functions and logging on readings from the below sensors:

The acceldemo example for the accelerometer works correctly and returns expected values. Without changing the wiring, I will get issues using the same sections of code from the example in my main program, combining the above sensors. I've confirmed no address conflicts between breakout boards, and the program only uses ~40% memory

When reading raw values for XYZ, Y has a flat -32229 offset (see below), with seemingly random dropouts that don't correlate to movement of the sensor.


This really seems to be a scapegoat for a lot of similar bugs that I suspect have the same rootcause. I seem to only be getting 10 samples a second(in the line graph, it's unix time to the second broken down further by an incrementing counter.) I timed how long it's taking to go through loop(), and get weird readings like this:

frame time = 506
frame time = 516
frame time = 516
frame time = 506
frame time = 5032256
frame time = 506
frame time = 50153
frame time = 50-9961
frame time = 516
frame time = 501798
frame time = 511792
frame time = 50-14848

The following works when the acceldemo is uploaded:

  // lis.setDataRate(LIS3DH_DATARATE_50_HZ);
  Serial.print("Data rate set to: ");
  switch (lis.getDataRate()) {
    case LIS3DH_DATARATE_1_HZ: Serial.println("1 Hz"); break;
    case LIS3DH_DATARATE_10_HZ: Serial.println("10 Hz"); break;
    case LIS3DH_DATARATE_25_HZ: Serial.println("25 Hz"); break;
    case LIS3DH_DATARATE_50_HZ: Serial.println("50 Hz"); break;
    case LIS3DH_DATARATE_100_HZ: Serial.println("100 Hz"); break;
    case LIS3DH_DATARATE_200_HZ: Serial.println("200 Hz"); break;
    case LIS3DH_DATARATE_400_HZ: Serial.println("400 Hz"); break;

    case LIS3DH_DATARATE_POWERDOWN: Serial.println("Powered Down"); break;
    case LIS3DH_DATARATE_LOWPOWER_5KHZ: Serial.println("5 Khz Low Power"); break;
    case LIS3DH_DATARATE_LOWPOWER_1K6HZ: Serial.println("16 Khz Low Power"); break;

but in my code, it just returns 15- which means I can't confirm my data rate is even set correctly.

See code below. I know it's a lot of non-specific stuff, but I can't figure out where I am going wrong

Logger
#include <Wire.h>                                   // Include wire library for I2C

#include <SparkFun_GridEYE_Arduino_Library.h>       // AMG8833 Grideye Thermopile

#include <Adafruit_LIS3DH.h>                        // Accelerometer sensor

#include <Adafruit_Sensor.h>                        // Adafruit sensor library used for accelerometer(?)

#include <RTClib.h>                                 // PCF8523 RTC

#include <SparkFun_Qwiic_OpenLog_Arduino_Library.h> // Openlog

#include <movingAvg.h>                              // Library for SMA

#include <Ewma.h>                                   // Library for EMA

//#include <Arduino.h> // was included in filtered ADC library, not sure if needed

/* --- Controls --- */

boolean debugSerial = 0; // Debug to serial console

boolean debugLogger = 0; // Debug to logger file

boolean writeToLog = 0;  // Do/Don't Write to Openlogger

int logRate = 0;       // Sampling rate in ms

float emaAlpha = .05;    // alpha value for EMA

int smaPeriod = 10;      // period for SMA

Ewma emaXF(emaAlpha);               // EMA filter for accelerometer X axis

Ewma emaYF(emaAlpha);               // EMA filter for accelerometer Y axis

Ewma emaZF(emaAlpha);               // EMA filter for accelerometer Z axis

Ewma emaStdDevF(emaAlpha);          // EMA filter for temperature readings

Ewma emaChangeAvgF(emaAlpha);       // EMA filter for temperature readings

movingAvg smaXF(smaPeriod);         // SMA for accelerometer X axis reading

movingAvg smaYF(smaPeriod);         // SMA for accelerometer Y axis reading

movingAvg smaZF(smaPeriod);         // SMA for accelerometer Z axis reading

movingAvg smaStdDevF(smaPeriod);    // SMA for temp readings

movingAvg smaChangeAvgF(smaPeriod); // SMA filter for temperature readings

OpenLog myLog;                           // Create log instance

GridEYE grideye;                         // Init grideye

Adafruit_LIS3DH lis = Adafruit_LIS3DH(); // init accelerometer

RTC_PCF8523 rtc;                         // Init RTC

sensors_event_t event;                   // instantiating event for reading accelerometer in m/s^2

char daysOfTheWeek[7][12] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // Array to hold days of the week

int pixelLast[64];

int unixLast;

int subSecCounter;

void setup(void)

{

  Wire.begin(); // Init I2C

  Serial.begin(9600);

  grideye.begin();

  delay(50); // Allow grid eye time to init

  rtc.begin();

  lis.setRange(LIS3DH_RANGE_4_G);         // 2, 4 ,8, or 16 G

  lis.setDataRate(LIS3DH_DATARATE_400_HZ); // 1, 10, 25, 50, 100, 200, 400 Hz

  myLog.begin(0x1E);                          // Open connection to OpenLog (no pun intended)

  smaXF.begin();                          // begin moving average for X

  smaYF.begin();                          // begin moving average for Y

  smaZF.begin();                          // begin moving average for Z

  smaStdDevF.begin();                     // begin moving average for temp std dev

  smaChangeAvgF.begin();                  // begin moving average for temp chaneg avg

  if (writeToLog == 1) // Control; Write header to log

  {

    DateTime now = rtc.now();

    myLog.println("-- Time --");

    myLog.print("Power-on timestamp = ");

    myLog.print(daysOfTheWeek[now.dayOfTheWeek()]);

    myLog.print(", ");

    myLog.print(now.month(), DEC);

    myLog.print("/");

    myLog.print(now.day(), DEC);

    myLog.print("/");

    myLog.print(now.year(), DEC);

    myLog.print(" ");

    myLog.print(now.hour(), DEC);

    myLog.print(":");

    myLog.print(now.minute(), DEC);

    myLog.print(":");

    myLog.println(now.second(), DEC);

    // myLog.print("Unix Time= ");

    // myLog.println(now.unixtime());

    myLog.println();

    /* Accelerometer */

    // myLog.println("-- Accelerometer--");

    // myLog.print("Data Rate = ");

    /* Cannot get this switch case to work. lis.getDataRate() only ever returns

    15 regardless of what the data rate it is set to */

    /*

    switch (lis.getDataRate()) {

     case LIS3DH_DATARATE_1_HZ: Serial.println("1 Hz"); break;

     case LIS3DH_DATARATE_10_HZ: Serial.println("10 Hz"); break;

     case LIS3DH_DATARATE_25_HZ: Serial.println("25 Hz"); break;

     case LIS3DH_DATARATE_50_HZ: Serial.println("50 Hz"); break;

     case LIS3DH_DATARATE_100_HZ: Serial.println("100 Hz"); break;

     case LIS3DH_DATARATE_200_HZ: Serial.println("200 Hz"); break;

     case LIS3DH_DATARATE_400_HZ: Serial.println("400 Hz"); break;

     case LIS3DH_DATARATE_POWERDOWN: Serial.println("Powered Down"); break;

     case LIS3DH_DATARATE_LOWPOWER_5KHZ: Serial.println("5 Khz Low Power"); break;

     case LIS3DH_DATARATE_LOWPOWER_1K6HZ: Serial.println("16 Khz Low Power"); break;

    }

  */

    // myLog.println("Unix Time | Milli | Frame Avg. Temp | Frame Std. Dev | Frame Change Avg. | X | Y | Z");

    myLog.print("Unix time");

    myLog.print(",");

    myLog.print("Milli");

    myLog.print(",");

    myLog.print("Avg. Temp");

    myLog.print(",");

    myLog.print("Std Dev");

    myLog.print(",");

    myLog.print("Std Dev_SMA");

    myLog.print(",");

    myLog.print("Std Dev_EMA");

    myLog.print(",");

    myLog.print("Change Avg.");

    myLog.print(",");

    myLog.print("Change_SMA");

    myLog.print(",");

    myLog.print("Change_EMA");

    myLog.print(",");

    myLog.print("X_Raw");

    myLog.print(",");

    myLog.print("X_SMA");

    myLog.print(",");

    myLog.print("X_EMA");

    myLog.print(",");

    myLog.print("Y_Raw");

    myLog.print(",");

    myLog.print("Y_SMA");

    myLog.print(",");

    myLog.print("Y_EMA");

    myLog.print(",");

    myLog.print("Z_Raw");

    myLog.print(",");

    myLog.print("Z_SMA");

    myLog.print(",");

    myLog.print("Z_EMA");

    myLog.println();

  }

}

void loop()

{

  int startMillis = millis(); //debug

  float sum = 0.0;  //(Σ xi)^2 Sum of all temps in frame for Std. Dev. calculation

  float sumQ = 0.0; // Σ(xi2)  Sum of square of all temps in frame for Std. Dev. calculation

  float frameAvg;   // avg temp of frame

  float frameStdDev;

  float temps[64];

  float delta[64]; // Array to keep the differenes between current pixel and previous pixel

  float frameChangeAvg;

  float deltaSum = 0;       // variable for average-of-pixel-change function

  DateTime now = rtc.now(); // Variable for storing current time

  /* Giving up on these for now. Not sure why I cant get them to work but I don't think I used them much anyways*/

  // float frameMin;

  // float frameMax;

  for (unsigned char i = 0; i < 64; i++) // Populate temp array with current frame reading

  {

    temps[i] = grideye.getPixelTemperature(i); // Populate temp array with sensor array readings

    if (debugSerial == 1) // Serial debug for displaying frame temp array as 8x8 array

    {

      Serial.print(temps[i]);

      Serial.print(" ");

      if ((i + 1) % 8 == 0) // If current temps[] index is divisible by 8

      {

        Serial.println(); // After 8 temps are printed in a row, start a new line

      }

    }

  }

  /* Code for min/max temp. Unable to get it working

  for (int j = 0; j < 64; j++) // go through temp array and find min/max temps

  {

    if (temps[j] > frameMax)

    {

      frameMax = temps[j];

    }

    if (temps[j] < frameMin)

    {

      frameMin = temps[j];

    }

  }

  */

  for (int q = 0; q < 64; q++) // Process each pixel temps in array and do mathing

  {

    delta[q] = max(temps[q], pixelLast[q]) - min(temps[q], pixelLast[q]); // current and last pixel, subtract whatever is least from whatever is most

    sum += temps[q]; // sum of temps for finding standard deviation, consider combining
    sumQ += sq(temps[q]); // Sum of the square of every temp in frame for finding std. dev


    if (q == 63) // on the last pixel, do this:

    {

      frameAvg = sum / 64; // divide sum by 64 to find average temp for frame
      sum = sq(sum); // Square the sum of all temps, now that we are done using sum for frameAvg

    }
    pixelLast[q] = temps[q]; // Observed reading is now previous reading
  }

  /* After entire frame is processed, do this: */

  for (int i = 0; i < 64; i++)

  {
    deltaSum += delta[i]; // sum of delta between i & i-1
  }

  frameChangeAvg = deltaSum / 64; // Find average amount of change in pixel temp beteen current and last frame

  /* - Moving averages for stats - */

  /* -- Float conversion -- */

  int stdDevInt = frameStdDev * 100;       // cast calculated std dev from float to int for SMA/EMA

  int changeAvgInt = frameChangeAvg * 100; // cast calculated change avg. from float to int for SMA/EMA

  /* -- EMA -- */

  int emaStdDev = emaStdDevF.filter(stdDevInt);          // Store filtered value for std dev

  int emaChangeAvg = emaChangeAvgF.filter(changeAvgInt); // Store filtered value for change avg

  /* -- SMA -- */

  smaStdDevF.reading(stdDevInt);       // store std dev value for sma

  smaChangeAvgF.reading(changeAvgInt); // store change avg value for sma

  int smaStdDev = smaStdDevF.getAvg();

  int smaChangeAvg = smaChangeAvgF.getAvg();

  /* - Moving averages for accelerometer -  */

  // lis.getEvent(&event); // obtaing accelerometer reading for XYZ in m/s^2

  lis.read();                    // read XYZ in raw

  int rawX = lis.x;              // get raw reading for X

  Serial.print(rawX);            // debug

  int rawY = lis.y;              // get raw reading for Y

  int rawZ = lis.z;              // get raw reading for Z

  int emaX = emaXF.filter(rawX); // Store filtered value for X

  int emaY = emaYF.filter(rawY); // Store filtered value for Y

  int emaZ = emaZF.filter(rawZ); // Store filtered value for Z

  smaXF.reading(rawX);           // Add X reading to SMA

  smaYF.reading(rawY);           // Add Y reading to SMA

  smaZF.reading(rawZ);           // Add Z reading to SMA

  int smaX = smaXF.getAvg();     // get current SMA value for X

  int smaY = smaYF.getAvg();     // get current SMA value for Y

  int smaZ = smaZF.getAvg();     // get current SMA value for Z

 

  /* debug: making simple sub-1-second counter until I get something with millis working */

  int unixNow = now.unixtime();

  subSecCounter++;

  if (unixNow != unixLast)

  {

    subSecCounter = 0;

  }

  unixLast = unixNow;

  if (writeToLog == 1) // Control; Whether or not to write data to logs

  {

    myLog.print(now.unixtime());

    myLog.print(",");

    myLog.print(subSecCounter);

    myLog.print(",");

    myLog.print(frameAvg);

    myLog.print(",");

    myLog.print(frameStdDev);

    myLog.print(",");

    myLog.print(smaStdDev);

    myLog.print(",");

    myLog.print(emaStdDev);

    myLog.print(",");

    myLog.print(frameChangeAvg);

    myLog.print(",");

    myLog.print(smaChangeAvg);

    myLog.print(",");

    myLog.print(emaChangeAvg);

    myLog.print(",");

    myLog.print(rawX);

    myLog.print(",");

    myLog.print(smaX);

     myLog.print(",");

    myLog.print(emaX);

    myLog.print(",");

    myLog.print(rawY);

    myLog.print(",");

    myLog.print(smaY);

    myLog.print(",");

    myLog.print(emaY);

    myLog.print(",");

    myLog.print(rawZ);

    myLog.print(",");

    myLog.print(smaZ);

    myLog.print(",");

    myLog.print(emaZ);

    myLog.println();

    //  myLog.print(",");

    // myLog.print(emaX);

    //  myLog.print(",");

    //  myLog.print(emaY);

    //  myLog.print(",");

    //   myLog.print(emaZ);

    //  myLog.print(",");

    // myLog.print(frameMin);

    // myLog.print(",");

    // myLog.print(frameMax);

    // myLog.print(",");

    // myLog.print(event.acceleration.x);

    // myLog.print(",");

    // myLog.print(event.acceleration.y);

    // myLog.print(",");

    // myLog.println(event.acceleration.z);

    myLog.syncFile();

  }

  delay(logRate);

int currentMillis = millis(); //debug

int elapsed = currentMillis - startMillis; //debug

  Serial.println(); //debug

  Serial.print(F("frame time = ")); //debug

  Serial.print(elapsed); //debug

  Serial.flush(); //debug

  delay(1000); //debug

}

Hi,
Can you please post your entire code?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

I did- I wrapped it in a 'hide details' tag at the bottom of the OP :+1:

On a Uno (8bit) you should use unsigned long instead of int here.

And another one:
int unixNow = now.unixtime();

Hi,

Sorry, have not come across this hidden feature for code list

Tom... :smiley: :+1: :australia:

I figured it wouldn't matter since I already knew my loop time would fit in an int. I tried unsigned long for kicks and am still getting the weird serial readings