Arduino Mega fails after a while

Hello all,
first time on here - I'm using an Arduino Mega which drives 2 banks of 4 relays in order to tension and release a spring mounted mechanical testing rig operated by linear actuators.

The first linear actuator controls the tilt of this rig, and the second actuator extends to engage with a maglock, then retract until under tension where it can then release the rig, causing rapid shaking movement. The relays drive the actuators

I am looking to record accelerometer data from a GY-521/MPU6050 during the release phase of the rig but currently I am running into certain issues namely:

  1. Sometimes the Mega will skip over the section of code used to extend the vertical actuator; other times it will hang on it indefinitely until the Arduino is reset - manually triggering the switch doesn't break it out of the loop

The vertical actuator movement is controlled by this loop:

 vertRam = digitalRead(M2_end);
    startVertRam();
    while(vertRam != 1){
      startVertRam();
      vertRam = digitalRead(M2_end);
    }

Where vertfFlag is set true by the previous function call; initially I tried but changed it in order to fix the problem, to no success. M2_end is a simple NC switch.

while(digitalRead(M2_end) != HIGH){
    startVertRam();

2.a I am having many issues with consistency of reading the MPU 6050 - I am under the inclination that it is due to incorrect programming flow which causes timing issues in accessing the MPU. I am currently using the implementation used in JeffRowbergs MPU6050raw (originally used DMP but have switched to raw in order to reduce complexity) which has been put into a separate function for calling.

2.b I am not well versed in how I should tackle the problem - I need the actuator phases to complete before reading the GY-521/MPU6050 for an interval of 10 seconds. I am currently using a naive timer implementation using a while loop and millis in order to calculate time passed - however I feel the blocking while loop could be causing issues.

NB: the sketch with MPU6050 access works fine and has pushed to 1900 cycles when ran on an Arduino UNO without being connected to the Linear Actuators & relays - problems only occur with the active rig.

I have tried other versions implementing adafruits watchdog library but have omitted it as it seems to be a bandaid solution

The end goal of this is to create a rig which can be left alone, running the test rig then writing or printing all the MPU6050/GY-521 data to the serial monitor where it can be recorded with a third party program (ie puTTY)

Any advice would be greatly appreciated as I am a bit lost at this stage

Whole project code is below as I am not allowed to attach things yet.


// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
//MPU6050 accelgyro(0x69); // <-- use for AD0 high

int16_t ax, ay, az;
int16_t gx, gy, gz;



#define LED_PIN 13
bool blinkState = false;

//PERSONALIZED SETUP VARS

//Motor and maglock vars
  const int M1_power = 38; // 38 POWERED CONFIRM
  const int M2_power = 51; // 51 POWERED CONFIRM
  // 47,49 MOTOR CTRL

  const int M1_home = 22; //C 23 - LEFT
  const int M1_end = 23; //C 22 - RIGHT

  const int M2_end = 44;

  const int mglk_toggle = 53; //C
  const int mglk_engaged = 6; //C

  //MOTOR DIRECTION CONTROLLED BY POLARITY
  const int M1_ctrl = 49;
  const int M2_ctrl = 47;
  int vertRam;
  bool endFlag = false;
  bool vertFlag = false;

  bool pF0 = false;
  bool pF1 = false;
  bool pF2 = false;
  bool pF3 = false;
  /*
  MOTOR METHOD : M_POWER,M_CTRL
  EXTEND RAM : 0 1
  RETRACT RAM : 0 0
  STOP RAM : 1 0 / 1 1
  */

  //Timing vars
  unsigned long start;
  unsigned long curr;
  unsigned long previousMillis;
  const long interval = 8000; // 20s - units are microseconds
  int cycles = 1;

  // ================================================================
  // ===                TILT RAM MOVEMENT                         ===
  // ================================================================
  void framePhaseOne() {
    //Tilt frame direction check - off M1 home/end sensors
    //checks home/end sensors and sets endflag accordingly - 300ms movement time

  //01 left end touching - RAM RETRACT
   //00 none touching 
   //10 right end touching - RAM EXTEND

    if(digitalRead(M1_home) == HIGH){
      endFlag = true;
    }
    else if(digitalRead(M1_end) == HIGH){
      endFlag = false;
    }
    //endFlag direction check: if endflag is false, motor extends; if true motor retracts - 300ms operation time
    if(endFlag == true){
      //RAM RETRACT
      digitalWrite(M1_power, LOW);
      digitalWrite(M1_ctrl, LOW);
      delay(300);
    }
    else if(endFlag == false){
      //RAM EXTENSION
      digitalWrite(M1_power, LOW);
      digitalWrite(M1_ctrl, HIGH);
      delay(300);
    }

    //Tilt Phase done - stop tilt ram 1 1
    digitalWrite(M1_power, HIGH);
    digitalWrite(M1_ctrl, HIGH);
    vertFlag = true;
    pF0 = false;
    pF1 = true;
  }

  // ================================================================
  // ===              VERTICAL RAM MOVEMENT                       ===
  // ================================================================

  void stopVertRam() {
    digitalWrite(M2_power, HIGH);
    digitalWrite(M2_ctrl, LOW);
  }

  void startVertRam() {
    digitalWrite(M2_power, LOW);
    digitalWrite(M2_ctrl, HIGH );
  }

  void retractVertRam() {
    digitalWrite(M2_power, LOW);
    digitalWrite(M2_ctrl, LOW);
  }

  void framePhaseTwo() {
    //Engage maglock, extend ram til strike plate engaged - sensor triggered
    digitalWrite(mglk_toggle, LOW);

    //Maglok engagement phase 
    //EXTEND RAM till M2_end sensor trips HIGH
    vertRam = digitalRead(M2_end);
    if(vertFlag == true){
      startVertRam();
      while(vertRam != HIGH){
        startVertRam();
        vertRam = digitalRead(M2_end);
      }
    }
    
    //STOP RAM
    stopVertRam();

    //Retract ram for 12s; NB: VERTICAL RAM BOGS WITH SPRING LOAD
    retractVertRam();
    delay(10000);

    //Kill ram power
    stopVertRam();

    //Release maglock
    digitalWrite(mglk_toggle, HIGH);

    vertFlag = false;
    pF1 = false;
    pF2 = true;
  }

  // ================================================================
  // ===                    IMU FUNCTION                          ===
  // ================================================================
  void accessMPU(){
    char buffer[32];
    accelgyro.getAcceleration(&ax, &ay, &az);
    unsigned long raX, raY, raZ;
     
    
    sprintf(buffer, ";%d,%d,%d;", ax , ay, az);
    Serial.write(buffer);
  }


  

void setup() {
    //initialize frame component pinouts
    pinMode(M1_power, OUTPUT);
    pinMode(M1_home, INPUT_PULLUP);
    pinMode(M1_end, INPUT_PULLUP);

    pinMode(M2_power, OUTPUT);
    pinMode(M2_end, INPUT_PULLUP);
  //MAGLOCK POLARITY IS INVERSED
    pinMode(mglk_toggle, OUTPUT);
    pinMode(mglk_engaged, INPUT);

    pinMode(M1_ctrl, OUTPUT);
    pinMode(M2_ctrl, OUTPUT);

    //initialize all motors as LOW

    digitalWrite(M1_power, HIGH);
    digitalWrite(M2_power, HIGH);
    //initialize all motor control as LOW*
    digitalWrite(M1_ctrl, HIGH);
    digitalWrite(M2_ctrl, HIGH);


    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(115200);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
    // configure Arduino LED pin for output
    pinMode(LED_PIN, OUTPUT);
    pF0 = true;
}

void loop() {
    Watchdog.disable();
    //First Phase - TILT FRAME movement
    if (pF0 == true){ framePhaseOne();} 
    
    //Second phase - LOCK FRAME movement
    if (pF1 == true){ framePhaseTwo();}

    //onboard millis() based timer, calculates interval from start and end timepoints
    //Nested code deals with pinging and retrieving data from MPU6050/GY-521
    
    if(pF2 == true){
    	start = millis();
      do{
      	accessMPU();
      	blinkState = !blinkState;
      	digitalWrite(LED_PIN, blinkState);
      
    	curr = millis();
    
  } while(curr - start < interval);
  pF2 = false;
  pF3 = true;
}
    

    Watchdog.disable();

    if(pF3 == true){
      Serial.println(F("EOC"));
      pF3 = false;
      pF0 = true;
    }
}

It sounds like you have power supply problems, or poor power supply decoupling. Noise and voltage instabilities, caused by voltage spikes from relays and large startup currents from linear actuators, can cause the Arduino to misbehave or reboot. A quick check is to power the Arduino completely independently of any equipment, while not forgetting to connect all the grounds.

To help forum members with the analysis, please post a wiring diagram, links to the devices and state the specifications of the power supply.

1 Like

I do hope you are not attempting to power your project using "Vin" or the "barrel jack" of a Mega 2560. :roll_eyes:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.