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:
- 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;
}
}