Code for accelerometer to activate LED.

Hi Everyone,
I am working on a project where i have an accelerometer and an SD memory card fitted on a RC car. I can drive the car whilst recording the g-force experienced, then view the recoding later from the SD card which is great.
I am looking to change the program code to set g-force limits (example 3g) to active an LED on the car. This function is when the car impacts an objects the LED is activated. I am using an Arduino Uno and MMA8451 accelerometer for this project.

Can anybody help with adapting the below code so the LED will come ON when g-force limit is reached ?

Thanking you in advance of your help.

#include <SD.h>
#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>

Adafruit_MMA8451 mma = Adafruit_MMA8451();

File myFile;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
 Serial.println("Adafruit MMA8451 OK");
   if (! mma.begin()) {
    Serial.println("Couldnt start");
    while (1);
  }
  Serial.println("MMA8451 found!");
  
  mma.setRange(MMA8451_RANGE_2_G);
  
  Serial.print("Range = "); Serial.print(2 << mma.getRange());  
  Serial.println("G");
    
  Serial.print("Initializing SD card...");
  pinMode(10, OUTPUT);
  
  
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  myFile = SD.open("test.txt", FILE_WRITE);
    
    if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("Start Recording");
  
    myFile.close(); 
    Serial.println("done.");
  
  
  } else {
    Serial.println("error opening test.txt");
  }

  myFile = SD.open("test.txt");
  
  if (myFile) {
    Serial.println("test.txt:");
    while (myFile.available()) { 
    Serial.write(myFile.read());
  }
  
 
  myFile.close();
  
  } else {
    Serial.println("error opening test.txt");
  }
}

void loop() {
// Read the 'raw' data in 14-bit counts
  mma.read();
  Serial.print("\tX:\t"); Serial.print(mma.x); 
  Serial.print("\tY:\t"); Serial.print(mma.y); 
  Serial.print("\tZ:\t"); Serial.print(mma.z); 
  Serial.println();
  
    myFile = SD.open("test.txt", FILE_WRITE);
    
    if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("\tX:\t"); myFile.println(mma.x);
    myFile.println("\tY:\t"); myFile.println(mma.y);
    myFile.println("\tZ:\t"); myFile.println(mma.z);
  
    myFile.close(); 
    Serial.println("done.");
  
   } else {
    Serial.println("error opening test.txt");
  }

   myFile = SD.open("test.txt");
  
  if (myFile) {
    Serial.println("test.txt:");
    while (myFile.available()) { 
    Serial.write(myFile.read());
  }
  
   myFile.close();
  
  } else {
    Serial.println("error opening test.txt");
  }
  delay(100);

Set up a pin to drive the LED using pinmode in setup.

Once you have read the accelerometer in loop, use an if statement to see if mma.x is greater than whatever is returned for your g limit. Then use digitalWrite on the LED pin to turn it on. Don't forget a current limiting resistor for the LED.

Then expand for the other directions.

Should the LED stay on forever once the limit has been reached?

Hi Wildbill,

Thank you for the information.
The LED would stay on for 5 seconds then go off. If this LED is activated more than three times a second LED is activated and stays ON until the program or button is reset.

Example, Orange LED is ON for duration of 5 seconds after the RC car impact an object. If this occurs three times a Red LED is ON continuously until reset.

Is this logic possible on the Arduino and what code can achieve it ? Do I need to use an external counter ?

Thanks again for your help.

Is this logic possible on the Arduino

Easily.

what code can achieve it ?

The blink with delay example will show you how to turn the LED off after a suitable duration, without using delay.

A simple counter, to count how many times the LED has been turned on is trivial to implement.

The real question is how do you decide that it is time to turn the LED on?

I made a few changes. You can easily change it to whatever you want. In this draft (compiles, not tested, likely needs debugging...) the idea is:

  • accelerometer samples are taken once per mS

  • samples are averaged over 100mS when the average reading for each axis is logged to file

  • g values are logged, not raw data

  • each mS the instantaneous g readings of each axis are checked to see if they exceed the g-limit. A flag is set that triggers an LED state machine to flash the orange LED and manage the RED

  • the g-checks also include a check of the resultant vector magnitude; this can be disabled by commenting
    out a line near the beginning of the code

  • I arbitrarily assign the orange and red LEDs to pins 13 and 12 respectively; you may need to change to match your wiring

  • the code assumes a "high" on an LED pin turns the LED on

HTH.

#include <SD.h>
#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>

#define TEST_RESULTANT      1               //comment out to exclude resultant vector from g check
#define MAX_G               3.0             //g limit over which an "event" is logged (org LED etc) (individual axes)
#define MAX_G_RESULTANT     3.0             //g limit over which an "event" is logged (org LED etc) (resultant vector only)
#define ORG_LED_ONTIME      5000ul          //mS orange LED flash time when G limit exceeded
#define EVENTS_LIMIT        3               //# of times G limit can be exceeded before RED LED comes on
#define ERROR_BLINK         300ul           //mS blink time for error condition
//
#define SAMPLE_RATE         1000            //uS (microseconds) per sample
#define LOGGING_RATE        100             //mS between logging file writes 

const int SD_CS =           4;              //pin used in SD.begin() call
const int pinORANGE =       13;             //pin driving orange LED. Logic assumes HIGH turns LED on
const int pinRED =          12;             //pin driving red LED. Logic assumes HIGH turns LED on

Adafruit_MMA8451 mma = Adafruit_MMA8451();

File myFile;

char
    szStr[50];

//accumulators for x, y and z axes averaging
//samples are taken once per millisecond
//average is written to SD card at 100mS intervals 
float
    xg_sum,
    yg_sum,
    zg_sum;
unsigned long
    sample_count;
bool
    bGLimitExceeded;
    
void setup() 
{
    // Open serial communications and wait for port to open:
    Serial.begin(9600);

    pinMode( pinORANGE, OUTPUT );
    digitalWrite( pinORANGE, LOW );         //LED off.
    pinMode( pinRED, OUTPUT );
    digitalWrite( pinRED, LOW );            //LED off.
        
    Serial.println("Adafruit MMA8451 OK");
    if (!mma.begin()) 
    {
        Serial.println("###Failed to start MMA8451.");
        ErrorLED();
        
    }//if
    else
        Serial.println("MMA8451 found!");
  
    mma.setRange(MMA8451_RANGE_4_G);        //need +/-4g for checking >3g...
    Serial.print(" Range = "); Serial.print(2 << mma.getRange());  
    Serial.println("G");
    
    Serial.print( "Initializing SD card: ");
    pinMode(10, OUTPUT);    //?
 
    if ( !SD.begin(SD_CS) ) 
        Serial.println("Initialization failed, unable to log.");
    else    
        Serial.println("Initialization complete.");

    myFile = SD.open( "test.txt", FILE_WRITE );
    Serial.print("Writing to test.txt...");
    if (myFile) 
    {
        myFile.println("\nStart Recording\n");
        myFile.close(); 
        Serial.println("done.");
  
    }//if 
    else 
        Serial.println("error opening test.txt");

    myFile = SD.open("test.txt");

    bGLimitExceeded = false;
    xg_sum = 0.0;
    yg_sum = 0.0;
    zg_sum = 0.0;
    sample_count = 0;
    
}//setup

//if an error occurs during init, LEDs alternate blinking rapidly
void ErrorLED( void )
{
    bool
        bLEDState = false;
    unsigned long
        timeBlink = 0;
    unsigned long
        timeNow;

    while( true )
    {
        timeNow = millis();
        //time for a blink?
        if( timeNow - timeBlink >= ERROR_BLINK )
        {
            //yes, save time
            timeBlink = timeNow;
            //toggle flag indicating LED state
            bLEDState ^= true;
            //update orange and red LEDs
            digitalWrite( pinORANGE, (bLEDState)?HIGH:LOW );
            digitalWrite( pinRED, (bLEDState)?LOW:HIGH );
            
        }//if
    
    }//while
    
}//ErrorLED

void TakeSamples()
{
    float
        intermediate,
        resultant,
        xg_sum, yg_sum, zg_sum;
    unsigned long
        sample_count;
        
    static unsigned long
        timeSample = 0;
    unsigned long
        timeNow;

    timeNow = micros();
    if( (timeNow - timeSample ) < SAMPLE_RATE )
        return;
    timeSample = micros();

    mma.read();
    xg_sum += mma.x_g;
    yg_sum += mma.y_g;
    zg_sum += mma.z_g;
    sample_count++;

    //look for excursions over pre-set limits for LED flag
    //include check of resultant vector; can comment this out
    //if not desired
#ifndef TEST_RESULTANT
    resultant = 0.0; 
#else
    resultant = sqrt( pow(mma.x_g,2) + pow(mma.y_g,2) + pow(mma.z_g,2) );
#endif

    if( (abs(mma.x_g) > MAX_G ) ||
            (abs(mma.y_g) > MAX_G ) ||
                (abs(mma.z_g) > MAX_G ) ||
                    resultant > MAX_G_RESULTANT )
    {
        bGLimitExceeded = true;
           
    }//if
    
}//TakeSamples

#define LED_IDLE        0
#define LED_TIME        1
void LED_StateMachine( void )
{
    static int
        nEvents = 0;
    static byte
        stateLED = LED_IDLE;
    static unsigned long
        timeLED;
    unsigned long
        timeNow;

    switch( stateLED )
    {
        case    LED_IDLE:
            if( bGLimitExceeded )
            {
                bGLimitExceeded = false;
                nEvents++;
                if( nEvents >= EVENTS_LIMIT )
                    digitalWrite( pinRED, HIGH );
                    
                digitalWrite( pinORANGE, HIGH );
                timeLED = millis();
                stateLED = LED_TIME;
                
            }//if
        break;

        case    LED_TIME:
            if( (millis() - timeLED) >= ORG_LED_ONTIME )
            {
                digitalWrite( pinORANGE, LOW );
                stateLED = LED_IDLE;
                
            }//if
        break;
    
    }//switch
    
}//LED_StateMachine

void Logging( void )
{
    float
        x, y, z;
        
    static unsigned long
        timeLogging = 0;
    unsigned long
        timeNow;

    timeNow = millis();
    if( (timeNow - timeLogging) < LOGGING_RATE )
        return;
    timeLogging = timeNow;

    x = xg_sum / (float)sample_count;
    y = yg_sum / (float)sample_count;
    z = zg_sum / (float)sample_count;
    xg_sum = 0.0;
    yg_sum = 0.0;
    zg_sum = 0.0;
    sample_count = 0;
    
    myFile = SD.open( "test.txt", FILE_WRITE );
    if( myFile )
    {
        sprintf( szStr, "\tX:\t%6.3f\n", x );
        myFile.print(szStr);    
        sprintf( szStr, "\tY:\t%6.3f\n", y );
        myFile.print(szStr);
        sprintf( szStr, "\tZ:\t%6.3f\n", z );
        myFile.print(szStr);

        myFile.close(); 
        
    }//if
    else
    {
        Serial.println("*** Failed writing to log ***"); 
        
    }//else
    
    Serial.print("\tX:\t"); Serial.print(x); 
    Serial.print("\tY:\t"); Serial.print(y); 
    Serial.print("\tZ:\t"); Serial.println(z); 

#if 0
    //wasn't sure if you still wanted this since you're printing the avg x/y/z already
    //as file grows this will become untenable (printing the entire file to the Serial monitor every 100mS...)
    myFile = SD.open("test.txt", FILE_READ );
    if( myFile ) 
    {
        Serial.println("test.txt:");
        while (myFile.available()) 
        { 
            Serial.write(myFile.read());
        }//while
  
        myFile.close();
  
    }//if
    else 
    {
        Serial.println("error opening test.txt");
    }//else
#endif

}//Logging

void loop() 
{
    //samping, logging and LED control done in their own functions
    TakeSamples();
    Logging();
    LED_StateMachine();
      
}//loop

Hi All, thank ye so far our the advise.

Hi Blackfin, I connected the Yellow LED to pin 12 and Red LED to 13 (see photos). When I run the program both LED's continuously flash as they are receiving data from the accelerometer. Also the values for X,Y and Z shown on the screen is now "nan" and when I read what is saved on the SD card the values for X,Y and Z are "?".

Am in doing something wrong ? Maybe my wiring is no correct ?

Apologise if I am doing something wrong

When you take a picture of your cctry. concentrate on showing the connections so we can trace the wiring.

Who told you to twist resistor wires together and plug them into a breadboard like that?

WE NEED TO SEE A SCHEMATIC

I looked at the Adafruit MMA8451 library on Github and noticed that in the read() method they compute actualy g values from the raw data:

void Adafruit_MMA8451::read(void) {
  // read x y z at once
  Wire.beginTransmission(_i2caddr);
  i2cwrite(MMA8451_REG_OUT_X_MSB);
  Wire.endTransmission(false); // MMA8451 + friends uses repeated start!!

  Wire.requestFrom(_i2caddr, 6);
  x = Wire.read(); x <<= 8; x |= Wire.read(); x >>= 2;
  y = Wire.read(); y <<= 8; y |= Wire.read(); y >>= 2;
  z = Wire.read(); z <<= 8; z |= Wire.read(); z >>= 2;


  uint8_t range = getRange();
  uint16_t divider = 1;
  if (range == MMA8451_RANGE_8_G) divider = 1024;
  if (range == MMA8451_RANGE_4_G) divider = 2048;
  if (range == MMA8451_RANGE_2_G) divider = 4096;

  x_g = (float)x / divider;
  y_g = (float)y / divider;
  z_g = (float)z / divider;

}

so I used x_g, y_g and z_g (which don't error out during compilation so they're public) to save doing that calculation in my code. I wonder if those numbers are actually no good for some reason...?

The red LED flashing is odd as it was just supposed light up after the 3rd event. If it's going off and back on it sounds like the code is resetting. In your serial monitor do you see signs the code is running through setup(), indicating a reset, with lines like "Adafruit MMA8451 OK" recurring over and over?

Sorry it doesn't work for you. I'll try to figure out what's going on.

Any better?

#include <SD.h>
#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>

#define TEST_RESULTANT      1               //comment out to exclude resultant vector from g check
#define MAX_G               3.0             //g limit over which an "event" is logged (org LED etc) (individual axes)
#define MAX_G_RESULTANT     3.0             //g limit over which an "event" is logged (org LED etc) (resultant vector only)
#define ORG_LED_ONTIME      5000ul          //mS orange LED flash time when G limit exceeded
#define EVENTS_LIMIT        3               //# of times G limit can be exceeded before RED LED comes on
#define ERROR_BLINK         300ul           //mS blink time for error condition
//
#define SAMPLE_RATE         5000            //uS (microseconds) per sample
#define LOGGING_RATE        100             //mS between logging file writes 

const int SD_CS =           4;              //pin used in SD.begin() call
const int pinORANGE =       13;             //pin driving orange LED. Logic assumes HIGH turns LED on
const int pinRED =          12;             //pin driving red LED. Logic assumes HIGH turns LED on

Adafruit_MMA8451 mma = Adafruit_MMA8451();

File myFile;

char
    szStr[50];

//accumulators for x, y and z axes averaging
//samples are taken once per millisecond
//average is written to SD card at 100mS intervals 
float
    xg_f,
    yg_f,
    zg_f,    
    xg_sum,
    yg_sum,
    zg_sum;
unsigned long
    sample_count;
bool
    bGLimitExceeded;
    
void setup() 
{
    // Open serial communications and wait for port to open:
    Serial.begin(9600);

    pinMode( pinORANGE, OUTPUT );
    digitalWrite( pinORANGE, LOW );         //LED off.
    pinMode( pinRED, OUTPUT );
    digitalWrite( pinRED, LOW );            //LED off.
        
    Serial.println("Adafruit MMA8451 OK");
    if (!mma.begin()) 
    {
        Serial.println("###Failed to start MMA8451.");
        ErrorLED();
        
    }//if
    else
        Serial.println("MMA8451 found!");
  
    mma.setRange(MMA8451_RANGE_4_G);        //need +/-4g for checking >3g...
    Serial.print(" Range = "); Serial.print(2 << mma.getRange());  
    Serial.println("G");
    
    Serial.print( "Initializing SD card: ");
    pinMode(10, OUTPUT);    //?
 
    if ( !SD.begin(SD_CS) ) 
        Serial.println("Initialization failed, unable to log.");
    else    
        Serial.println("Initialization complete.");

    myFile = SD.open( "test.txt", FILE_WRITE );
    Serial.print("Writing to test.txt...");
    if (myFile) 
    {
        myFile.println("\nStart Recording\n");
        myFile.close(); 
        Serial.println("done.");
  
    }//if 
    else 
        Serial.println("error opening test.txt");

    myFile = SD.open("test.txt");

    bGLimitExceeded = false;
    xg_sum = 0.0;
    yg_sum = 0.0;
    zg_sum = 0.0;
    sample_count = 0;
    
}//setup

//if an error occurs during init, LEDs alternate blinking rapidly
void ErrorLED( void )
{
    bool
        bLEDState = false;
    unsigned long
        timeBlink = 0;
    unsigned long
        timeNow;

    while( true )
    {
        timeNow = millis();
        //time for a blink?
        if( timeNow - timeBlink >= ERROR_BLINK )
        {
            //yes, save time
            timeBlink = timeNow;
            //toggle flag indicating LED state
            bLEDState ^= true;
            //update orange and red LEDs
            digitalWrite( pinORANGE, (bLEDState)?HIGH:LOW );
            digitalWrite( pinRED, (bLEDState)?LOW:HIGH );
            
        }//if
    
    }//while
    
}//ErrorLED

void TakeSamples()
{
    float
        intermediate,
        resultant;
    unsigned long
        sample_count;
        
    static unsigned long
        timeSample = 0;
    unsigned long
        timeNow;

    timeNow = micros();
    if( (timeNow - timeSample ) < SAMPLE_RATE )
        return;
    timeSample = micros();

    mma.read();
    xg_f = (float)mma.x/2048.0;
    yg_f = (float)mma.y/2048.0;
    zg_f = (float)mma.z/2048.0;
    
    xg_sum += xg_f;
    yg_sum += yg_f;
    zg_sum += zg_f;
    sample_count++;

    //look for excursions over pre-set limits for LED flag
    //include check of resultant vector; can comment this out
    //if not desired
#ifndef TEST_RESULTANT
    resultant = 0.0; 
#else
    resultant = sqrt( pow(xg_f,2) + pow(yg_f,2) + pow(zg_f,2) );
#endif

    if( (abs(xg_f) > MAX_G ) ||
            (abs(yg_f) > MAX_G ) ||
                (abs(zg_f) > MAX_G ) ||
                    resultant > MAX_G_RESULTANT )
    {
        bGLimitExceeded = true;
           
    }//if
    
}//TakeSamples

#define LED_IDLE        0
#define LED_TIME        1
void LED_StateMachine( void )
{
    static int
        nEvents = 0;
    static byte
        stateLED = LED_IDLE;
    static unsigned long
        timeLED;
    unsigned long
        timeNow;

    switch( stateLED )
    {
        case    LED_IDLE:
            if( bGLimitExceeded )
            {
                bGLimitExceeded = false;
                nEvents++;
                if( nEvents >= EVENTS_LIMIT )
                    digitalWrite( pinRED, HIGH );
                    
                digitalWrite( pinORANGE, HIGH );
                timeLED = millis();
                stateLED = LED_TIME;
                
            }//if
        break;

        case    LED_TIME:
            if( (millis() - timeLED) >= ORG_LED_ONTIME )
            {
                digitalWrite( pinORANGE, LOW );
                stateLED = LED_IDLE;
                
            }//if
        break;
    
    }//switch
    
}//LED_StateMachine

void Logging( void )
{
    float
        x, y, z;
        
    static unsigned long
        timeLogging = 0;
    unsigned long
        timeNow;

    timeNow = millis();
    if( (timeNow - timeLogging) < LOGGING_RATE )
        return;
    timeLogging = timeNow;

    x = xg_sum / (float)sample_count;
    y = yg_sum / (float)sample_count;
    z = zg_sum / (float)sample_count;
    xg_sum = 0.0;
    yg_sum = 0.0;
    zg_sum = 0.0;
    sample_count = 0;
    
    myFile = SD.open( "test.txt", FILE_WRITE );
    if( myFile )
    {
        sprintf( szStr, "\tX:\t%f\n", x );
        myFile.print(szStr);    
        sprintf( szStr, "\tY:\t%f\n", y );
        myFile.print(szStr);
        sprintf( szStr, "\tZ:\t%f\n", z );
        myFile.print(szStr);

        myFile.close(); 
        
    }//if
    else
    {
        Serial.println("*** Failed writing to log ***"); 
        
    }//else
    
    Serial.print("\tX:\t"); Serial.print(x); 
    Serial.print("\tY:\t"); Serial.print(y); 
    Serial.print("\tZ:\t"); Serial.println(z); 

#if 0
    //wasn't sure if you still wanted this since you're printing the avg x/y/z already
    //as file grows this will become untenable (printing the entire file to the Serial monitor every 100mS...)
    myFile = SD.open("test.txt", FILE_READ );
    if( myFile ) 
    {
        Serial.println("test.txt:");
        while (myFile.available()) 
        { 
            Serial.write(myFile.read());
        }//while
  
        myFile.close();
  
    }//if
    else 
    {
        Serial.println("error opening test.txt");
    }//else
#endif

}//Logging

void loop() 
{
    //samping, logging and LED control done in their own functions
    TakeSamples();
    Logging();
    LED_StateMachine();
      
}//loop

Hi Blackfin,

I will try your new code tomorrow, with some luck it'll work nicely. I've drafted up some schematic of my wiring to eliminate any mistakes I may have created. I'll try the code later and reply with an update. Thanks again for your help. :slight_smile:

Arduino Schematic.pdf (138 KB)

Hi Blackfin,

I tried the code and had to make some small changes (see extract below). Once these were made the program could read the values from the accelerometer PROGRESS !
The LED's are still not working correctly do. When its reading the Orange LED flashes the same as the TX LED on the arduno UNO board. The Red LED stays ON continuously.

Should I simplify my project by removing the SD card reader from the circuit as its more important for me to have the LED active when accelerometer limit is reached. Saving the data to SD card can be conducted at a later stage of this project.

myFile = SD.open( "test.txt", FILE_WRITE );
    if( myFile )
    {
       myFile.println("\tX:\t"); myFile.println(mma.x); 
       myFile.println("\tY:\t"); myFile.println(mma.y); 
       myFile.println("\tZ:\t"); myFile.println(mma.z); 
              
        myFile.close(); 
        
    }//if
    else
    {
        Serial.println("*** Failed writing to log ***"); 
        
    }//else
    
    Serial.print("\tX:\t"); Serial.print(mma.x); 
    Serial.print("\tY:\t"); Serial.print(mma.y); 
    Serial.print("\tZ:\t"); Serial.print(mma.z); 
    Serial.println();

Arduino Schematic - 2.pdf (137 KB)

Give this one a try. I found a divide by zero error due to a local-instance of a variable I intended to be global:

#include <SD.h>
#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>

//#define TEST_RESULTANT      1               //comment out to exclude resultant vector from g check
#define MAX_G               3.0             //g limit over which an "event" is logged (org LED etc) (individual axes)
#define MAX_G_RESULTANT     3.0             //g limit over which an "event" is logged (org LED etc) (resultant vector only)
#define ORG_LED_ONTIME      5000ul          //mS orange LED flash time when G limit exceeded
#define EVENTS_LIMIT        3               //# of times G limit can be exceeded before RED LED comes on
#define ERROR_BLINK         300ul           //mS blink time for error condition
//
#define SAMPLE_RATE         5000            //uS (microseconds) per sample
#define LOGGING_RATE        100             //mS between logging file writes 

const int SD_CS =           4;              //pin used in SD.begin() call
const int pinORANGE =       13;             //pin driving orange LED. Logic assumes HIGH turns LED on
const int pinRED =          12;             //pin driving red LED. Logic assumes HIGH turns LED on

Adafruit_MMA8451 mma = Adafruit_MMA8451();

File myFile;

char
    szStr[50];

//accumulators for x, y and z axes averaging
//samples are taken once per millisecond
//average is written to SD card at 100mS intervals 
float
    xg_f,
    yg_f,
    zg_f,    
    xg_sum,
    yg_sum,
    zg_sum;
unsigned long
    sample_count;
bool
    bGLimitExceeded;
    
void setup() 
{
    // Open serial communications and wait for port to open:
    Serial.begin(9600);
    pinMode( pinORANGE, OUTPUT );
    digitalWrite( pinORANGE, LOW );         //LED off.
    pinMode( pinRED, OUTPUT );
    digitalWrite( pinRED, LOW );            //LED off.
        
    Serial.println("Adafruit MMA8451 OK");
    if (!mma.begin()) 
    {
        Serial.println("###Failed to start MMA8451.");
        ErrorLED();
        
    }//if
    else
        Serial.println("MMA8451 found!");
  
    mma.setRange(MMA8451_RANGE_4_G);        //need +/-4g for checking >3g...
    Serial.print(" Range = "); Serial.print(2 << mma.getRange());  
    Serial.println("G");
    
    Serial.print( "Initializing SD card: ");
    pinMode(10, OUTPUT);    //?
 
    if ( !SD.begin(SD_CS) ) 
        Serial.println("Initialization failed, unable to log.");
    else    
        Serial.println("Initialization complete.");

    myFile = SD.open( "test.txt", FILE_WRITE );
    Serial.print("Writing to test.txt...");
    if (myFile) 
    {
        myFile.println("\nStart Recording\n");
        myFile.close(); 
        Serial.println("done.");
  
    }//if 
    else 
        Serial.println("error opening test.txt");

    myFile = SD.open("test.txt");

    bGLimitExceeded = false;
    xg_sum = 0.0;
    yg_sum = 0.0;
    zg_sum = 0.0;
    sample_count = 0;
    
}//setup

//if an error occurs during init, LEDs alternate blinking rapidly
void ErrorLED( void )
{
    bool
        bLEDState = false;
    unsigned long
        timeBlink = 0;
    unsigned long
        timeNow;

    while( true )
    {
        timeNow = millis();
        //time for a blink?
        if( timeNow - timeBlink >= ERROR_BLINK )
        {
            //yes, save time
            timeBlink = timeNow;
            //toggle flag indicating LED state
            bLEDState ^= true;
            //update orange and red LEDs
            digitalWrite( pinORANGE, (bLEDState)?HIGH:LOW );
            digitalWrite( pinRED, (bLEDState)?LOW:HIGH );
            
        }//if
    
    }//while
    
}//ErrorLED

void TakeSamples()
{
    float
        intermediate,
        resultant;
    static unsigned long
        timeSample = 0;
    unsigned long
        timeNow;

    timeNow = micros();
    if( (timeNow - timeSample ) < SAMPLE_RATE )
        return;
    timeSample = timeNow;

    mma.read();
    xg_f = (float)mma.x/2048.0;
    yg_f = (float)mma.y/2048.0;
    zg_f = (float)mma.z/2048.0;
    
    xg_sum = xg_sum + xg_f;
    yg_sum = yg_sum + yg_f;
    zg_sum = zg_sum + zg_f;
    sample_count = sample_count + 1;

    //look for excursions over pre-set limits for LED flag
    //include check of resultant vector; can comment this out
    //if not desired
#ifndef TEST_RESULTANT
    resultant = 0.0; 
#else
    resultant = sqrt( pow(xg_f,2) + pow(yg_f,2) + pow(zg_f,2) );
#endif

    if( (abs(xg_f) > MAX_G ) ||
            (abs(yg_f) > MAX_G ) ||
                (abs(zg_f) > MAX_G ) ||
                    resultant > MAX_G_RESULTANT )
    {
        bGLimitExceeded = true;
           
    }//if
    
}//TakeSamples

#define LED_IDLE        0
#define LED_TIME        1
void LED_StateMachine( void )
{
    static int
        nEvents = 0;
    static byte
        stateLED = LED_IDLE;
    static unsigned long
        timeLED;
    unsigned long
        timeNow;

    switch( stateLED )
    {
        case    LED_IDLE:
            if( bGLimitExceeded )
            {
                bGLimitExceeded = false;
                nEvents++;
                if( nEvents >= EVENTS_LIMIT )
                    digitalWrite( pinRED, HIGH );
                    
                digitalWrite( pinORANGE, HIGH );
                timeLED = millis();
                stateLED = LED_TIME;
                
            }//if
        break;

        case    LED_TIME:
            if( (millis() - timeLED) >= ORG_LED_ONTIME )
            {
                digitalWrite( pinORANGE, LOW );
                stateLED = LED_IDLE;
                
            }//if
        break;
    
    }//switch
    
}//LED_StateMachine

void Logging( void )
{
    float
        x, y, z;
        
    static unsigned long
        timeLogging = 0;
    unsigned long
        timeNow;

    timeNow = millis();
    if( (timeNow - timeLogging) < LOGGING_RATE )
        return;
    timeLogging = timeNow;

    x = xg_sum / (float)sample_count;
    y = yg_sum / (float)sample_count;
    z = zg_sum / (float)sample_count;
    xg_sum = 0.0;
    yg_sum = 0.0;
    zg_sum = 0.0;
    sample_count = 0;

    myFile = SD.open( "test.txt", FILE_WRITE );
    if( myFile )
    {
        sprintf( szStr, "\tX:\t%f\n", x );
        myFile.print(szStr);    
        sprintf( szStr, "\tY:\t%f\n", y );
        myFile.print(szStr);
        sprintf( szStr, "\tZ:\t%f\n", z );
        myFile.print(szStr);

        myFile.close(); 
        
    }//if
    else
    {
        Serial.println("*** Failed writing to log ***"); 
        
    }//else

    Serial.print("\tX:\t"); Serial.print(x); 
    Serial.print("\tY:\t"); Serial.print(y); 
    Serial.print("\tZ:\t"); Serial.println(z); 

}//Logging

void loop() 
{
    //samping, logging and LED control done in their own functions
    TakeSamples();
    Logging();
    LED_StateMachine();
      
}//loop

Hi Blackfin,

While I'd like to say SUCESS unfortunately its still the same. The Red LED stay ON and the Orange flashes with the TX channel.
Could my wiring schematic (attached) be wrong or need adapting so the Orange LED's only comes ON when 3 G limit is reached and if this occur three times the Red LED stays ON until reset.

Sorry for annoying you guys but it would be great to have this working.

Arduino Schematic.pdf (138 KB)

Your orange and red LEDs are connected to the SPI pins for the SD card.

Can you connect the LEDs to currently-unused GPIOs (say, 8 and 9) and leave the SD connections to 12 and 13?

Hi Blackfin,
Thankfully we're making positive progress with the circuit and LED activation. The important goal for this project is activating the LED's when the RC car impact an object, so for now I've disconnected the SD card reader. With the few changes to the code the resulting outcome is,

1st impact - Orange LED ON for 5 seconds then go's OFF.
2nd impact - Orange LED ON for 10 seconds then go's OFF, After 5 seconds of this the Red LED comes ON and stays ON.
3rd impact - Orange LED ON for 5 seconds then go's OFF.
4th impact - Orange LED ON for 5 seconds then go's OFF.

Have I made a mistake on the code causing the RED LED to be activated on the 2nd impact and staying ON ?

#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>

//#define TEST_RESULTANT      1               //comment out to exclude resultant vector from g check
#define MAX_G               3.0             //g limit over which an "event" is logged (org LED etc) (individual axes)
#define MAX_G_RESULTANT     3.0             //g limit over which an "event" is logged (org LED etc) (resultant vector only)
#define ORG_LED_ONTIME      5000ul          //mS orange LED flash time when G limit exceeded
#define EVENTS_LIMIT        3.0             //# of times G limit can be exceeded before RED LED comes on
#define ERROR_BLINK         300ul           //mS blink time for error condition
//
#define SAMPLE_RATE         5000            //uS (microseconds) per sample
#define LOGGING_RATE        100             //mS between logging file writes 

const int pinORANGE =       13;             //pin driving orange LED. Logic assumes HIGH turns LED on
const int pinRED =          12;             //pin driving red LED. Logic assumes HIGH turns LED on

Adafruit_MMA8451 mma = Adafruit_MMA8451();

char
   szStr[50];

//accumulators for x, y and z axes averaging
//samples are taken once per millisecond
//average is written to SD card at 100mS intervals 
float
   xg_f,
   yg_f,
   zg_f,    
   xg_sum,
   yg_sum,
   zg_sum;
unsigned long
   sample_count;
bool
   bGLimitExceeded;
   
void setup() 
{
   // Open serial communications and wait for port to open:
   Serial.begin(9600);
   pinMode( pinORANGE, OUTPUT );
   digitalWrite( pinORANGE, LOW );         //LED off.
   pinMode( pinRED, OUTPUT );
   digitalWrite( pinRED, LOW );            //LED off.
       
   Serial.println("Adafruit MMA8451 OK");
   if (!mma.begin()) 
   {
       Serial.println("###Failed to start MMA8451.");
       ErrorLED();
       
   }//if
   else
       Serial.println("MMA8451 found!");
 
   mma.setRange(MMA8451_RANGE_4_G);        //need +/-4g for checking >3g...
   Serial.print(" Range = "); Serial.print(2 << mma.getRange());  
   Serial.println("G");
   
   bGLimitExceeded = false;
   xg_sum = 0.0;
   yg_sum = 0.0;
   zg_sum = 0.0;
   sample_count = 0;
   
}//setup

//if an error occurs during init, LEDs alternate blinking rapidly
void ErrorLED( void )
{
   bool
       bLEDState = false;
   unsigned long
       timeBlink = 0;
   unsigned long
       timeNow;

   while( true )
   {
       timeNow = millis();
       //time for a blink?
       if( timeNow - timeBlink >= ERROR_BLINK )
       {
           //yes, save time
           timeBlink = timeNow;
           //toggle flag indicating LED state
           bLEDState ^= true;
           //update orange and red LEDs
           digitalWrite( pinORANGE, (bLEDState)?HIGH:LOW );
           digitalWrite( pinRED, (bLEDState)?LOW:HIGH );
           
       }//if
   
   }//while
   
}//ErrorLED

void TakeSamples()
{
   float
       intermediate,
       resultant;
   static unsigned long
       timeSample = 0;
   unsigned long
       timeNow;

   timeNow = micros();
   if( (timeNow - timeSample ) < SAMPLE_RATE )
       return;
   timeSample = timeNow;

   mma.read();
   xg_f = (float)mma.x/2048.0;
   yg_f = (float)mma.y/2048.0;
   zg_f = (float)mma.z/2048.0;
   
   xg_sum = xg_sum + xg_f;
   yg_sum = yg_sum + yg_f;
   zg_sum = zg_sum + zg_f;
   sample_count = sample_count + 1;

   //look for excursions over pre-set limits for LED flag
   //include check of resultant vector; can comment this out
   //if not desired
#ifndef TEST_RESULTANT
   resultant = 0.0; 
#else
   resultant = sqrt( pow(xg_f,2) + pow(yg_f,2) + pow(zg_f,2) );
#endif

   if( (abs(xg_f) > MAX_G ) ||
           (abs(yg_f) > MAX_G ) ||
               (abs(zg_f) > MAX_G ) ||
                   resultant > MAX_G_RESULTANT )
   {
       bGLimitExceeded = true;
          
   }//if
   
}//TakeSamples

#define LED_IDLE        0
#define LED_TIME        1
void LED_StateMachine( void )
{
   static int
       nEvents = 0;
   static byte
       stateLED = LED_IDLE;
   static unsigned long
       timeLED;
   unsigned long
       timeNow;

   switch( stateLED )
   {
       case    LED_IDLE:
           if( bGLimitExceeded )
           {
               bGLimitExceeded = false;
               nEvents++;
               if( nEvents >= EVENTS_LIMIT )
                   digitalWrite( pinRED, HIGH );
                   
               digitalWrite( pinORANGE, HIGH );
               timeLED = millis();
               stateLED = LED_TIME;
               
           }//if
       break;

       case    LED_TIME:
           if( (millis() - timeLED) >= ORG_LED_ONTIME )
           {
               digitalWrite( pinORANGE, LOW );
               stateLED = LED_IDLE;
               
           }//if
       break;
   
   }//switch
   
}//LED_StateMachine

void Logging( void )
{
   float
       x, y, z;
       
   static unsigned long
       timeLogging = 0;
   unsigned long
       timeNow;

   timeNow = millis();
   if( (timeNow - timeLogging) < LOGGING_RATE )
       return;
   timeLogging = timeNow;

   x = xg_sum / (float)sample_count;
   y = yg_sum / (float)sample_count;
   z = zg_sum / (float)sample_count;
   xg_sum = 0.0;
   yg_sum = 0.0;
   zg_sum = 0.0;
   sample_count = 0;
 
    
   Serial.print("\tX:\t"); Serial.print(x); 
   Serial.print("\tY:\t"); Serial.print(y); 
   Serial.print("\tZ:\t"); Serial.println(z); 

}//Logging

void loop() 
{
   //samping, logging and LED control done in their own functions
   TakeSamples();
   Logging();
   LED_StateMachine();
     
}//loop

Arduino Schematic - 3.pdf (134 KB)

Hi Blackfin,
Just wondering can you assist with my last message for the code. I am almost completed but just need to change the Red LED from been activated on the 2nd to been activated on the 4th instead. I would much appreciate your assistance.

just need to change the Red LED from been activated on the 2nd to been activated on the 4th instead.

It didn't take me long to figure out where, in the code, the red LED is turned on. It didn't take much effort to see that it is turned on when some condition is met. it wouldn't take you much effort to change the condition.

stephenfitz32:
Hi Blackfin,
Just wondering can you assist with my last message for the code. I am almost completed but just need to change the Red LED from been activated on the 2nd to been activated on the 4th instead. I would much appreciate your assistance.

I had a quick look and can't see an obvious reason for what you're seeing but do have a suspicion.

First, FWIW, the EVENTS_LIMIT constant should just be an int (3) rather than a float (3.0) as we're counting integral values, not fractional values.

#define EVENTS_LIMIT        3             //# of times G limit can be exceeded before RED LED comes on

For your actual problem, my suspicion is that the bGLimitExceeded flag is being set true more than once per collision because we're sampling quickly (every 5mS) and collision events are slow, messy things.

In this version I added a dead-time of 500mS after an "event" that sets bGLimitExceeded where the threshold is not checked. This should allow the system/car to settle before allowing for checks again.

I also added a serial print in the LED state machine to print the value of nEvents after each detection as well as a millisecond timestamp. With the dead time I suspect the problem will be fixed but if not, some valuable info can be obtained from this info.

#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>

//#define TEST_RESULTANT      1               //comment out to exclude resultant vector from g check
#define MAX_G               3.0             //g limit over which an "event" is logged (org LED etc) (individual axes)
#define MAX_G_RESULTANT     3.0             //g limit over which an "event" is logged (org LED etc) (resultant vector only)
#define ORG_LED_ONTIME      5000ul          //mS orange LED flash time when G limit exceeded
#define EVENTS_LIMIT        3               //# of times G limit can be exceeded before RED LED comes on
#define ERROR_BLINK         300ul           //mS blink time for error condition
//
#define SAMPLE_RATE         5000            //uS (microseconds) per sample
#define CHK_DEADTIME        100             //uS = CHK_DEADTIME x SAMPLE_RATE
#define LOGGING_RATE        100             //mS between logging file writes 

const int pinORANGE =       13;             //pin driving orange LED. Logic assumes HIGH turns LED on
const int pinRED =          12;             //pin driving red LED. Logic assumes HIGH turns LED on

Adafruit_MMA8451 mma = Adafruit_MMA8451();

char
   szStr[50];

//accumulators for x, y and z axes averaging
//samples are taken once per millisecond
//average is written to SD card at 100mS intervals 
float
   xg_f,
   yg_f,
   zg_f,    
   xg_sum,
   yg_sum,
   zg_sum;
unsigned long
   sample_count;
bool
   bGLimitExceeded;
   
void setup() 
{
   // Open serial communications and wait for port to open:
   Serial.begin(9600);
   pinMode( pinORANGE, OUTPUT );
   digitalWrite( pinORANGE, LOW );         //LED off.
   pinMode( pinRED, OUTPUT );
   digitalWrite( pinRED, LOW );            //LED off.
       
   Serial.println("Adafruit MMA8451 OK");
   if (!mma.begin()) 
   {
       Serial.println("###Failed to start MMA8451.");
       ErrorLED();
       
   }//if
   else
       Serial.println("MMA8451 found!");
 
   mma.setRange(MMA8451_RANGE_4_G);        //need +/-4g for checking >3g...
   Serial.print(" Range = "); Serial.print(2 << mma.getRange());  
   Serial.println("G");
   
   bGLimitExceeded = false;
   xg_sum = 0.0;
   yg_sum = 0.0;
   zg_sum = 0.0;
   sample_count = 0;
   
}//setup

//if an error occurs during init, LEDs alternate blinking rapidly
void ErrorLED( void )
{
   bool
       bLEDState = false;
   unsigned long
       timeBlink = 0;
   unsigned long
       timeNow;

   while( true )
   {
       timeNow = millis();
       //time for a blink?
       if( timeNow - timeBlink >= ERROR_BLINK )
       {
           //yes, save time
           timeBlink = timeNow;
           //toggle flag indicating LED state
           bLEDState ^= true;
           //update orange and red LEDs
           digitalWrite( pinORANGE, (bLEDState)?HIGH:LOW );
           digitalWrite( pinRED, (bLEDState)?LOW:HIGH );
           
       }//if
   
   }//while
   
}//ErrorLED

void TakeSamples()
{
    static byte
        gLimitDeadTime = 0;
   float
       intermediate,
       resultant;
   static unsigned long
       timeSample = 0;
   unsigned long
       timeNow;

   timeNow = micros();
   if( (timeNow - timeSample ) < SAMPLE_RATE )
       return;
   timeSample = timeNow;

   mma.read();
   xg_f = (float)mma.x/2048.0;
   yg_f = (float)mma.y/2048.0;
   zg_f = (float)mma.z/2048.0;
   
   xg_sum = xg_sum + xg_f;
   yg_sum = yg_sum + yg_f;
   zg_sum = zg_sum + zg_f;
   sample_count = sample_count + 1;

   //look for excursions over pre-set limits for LED flag
   //include check of resultant vector; can comment this out
   //if not desired
#ifndef TEST_RESULTANT
   resultant = 0.0; 
#else
   resultant = sqrt( pow(xg_f,2) + pow(yg_f,2) + pow(zg_f,2) );
#endif

    if( gLimitDeadTime )
        gLimitDeadTime--;
        
    if( gLimitDeadTime == 0 )
    {
        if( (abs(xg_f) > MAX_G ) ||
                (abs(yg_f) > MAX_G ) ||
                    (abs(zg_f) > MAX_G ) ||
                        resultant > MAX_G_RESULTANT )
        {
            bGLimitExceeded = true;
            gLimitDeadTime = CHK_DEADTIME;  //N*SAMPLE_RATE microseconds dead time after event (500mS)
            
        }//if
        
    }//if
   
}//TakeSamples

#define LED_IDLE        0
#define LED_TIME        1
void LED_StateMachine( void )
{
   static int
       nEvents = 0;
   static byte
       stateLED = LED_IDLE;
   static unsigned long
       timeLED;
   unsigned long
       timeNow;

    switch( stateLED )
    {
       case    LED_IDLE:
           if( bGLimitExceeded )
           {
                timeNow = millis();
                Serial.print( timeNow );
                Serial.print( "  nEvents = " ); Serial.println( nEvents );       
                
               bGLimitExceeded = false;
               nEvents++;
               if( nEvents >= EVENTS_LIMIT )
                   digitalWrite( pinRED, HIGH );
                   
               digitalWrite( pinORANGE, HIGH );
               timeLED = millis();
               stateLED = LED_TIME;
               
           }//if
       break;

       case    LED_TIME:
           if( (millis() - timeLED) >= ORG_LED_ONTIME )
           {
               digitalWrite( pinORANGE, LOW );
               stateLED = LED_IDLE;
               
           }//if
       break;
   
   }//switch
   
}//LED_StateMachine

void Logging( void )
{
   float
       x, y, z;
       
   static unsigned long
       timeLogging = 0;
   unsigned long
       timeNow;

   timeNow = millis();
   if( (timeNow - timeLogging) < LOGGING_RATE )
       return;
   timeLogging = timeNow;

   x = xg_sum / (float)sample_count;
   y = yg_sum / (float)sample_count;
   z = zg_sum / (float)sample_count;
   xg_sum = 0.0;
   yg_sum = 0.0;
   zg_sum = 0.0;
   sample_count = 0;
 
    
   Serial.print("\tX:\t"); Serial.print(x); 
   Serial.print("\tY:\t"); Serial.print(y); 
   Serial.print("\tZ:\t"); Serial.println(z); 

}//Logging

void loop() 
{
   //samping, logging and LED control done in their own functions
   TakeSamples();
   Logging();
   LED_StateMachine();
     
}//loop

Hi Blackfin,
You are a legend !

It works successfully, i just needed to change the EVENT_LIMIT to 4 and all works perfectly. Thank you so much for your help and patients you have shown towards this project, it is very much appreciated. Thank you.