I am currently struggling with an intermittent problem with an Arduino project.
Background
I am using a LabVIEW program to control a few pieces of hardware. One of them is a NEMA 17 stepper motor that drives a rack and pinion actuator. I am using a genuine Arduino Nano with an (official) EasyDriver motor driver to drive the NEMA 17. The Arduino listens for the state of a DI pin, and if it is pulled high it moves out the rack until a U-shaped sensor sends a high input signal at the outermost position, it then listens for that DI pin to be pulled low and retracts the rack until a proximity sensor sends a high input signal.
The Problem
I noticed that my actuator was either becoming unresponsive to the input signals from the LabVIEW DAQ, or that it was getting stuck mid actuation (motor has plenty of torque for this application). After changing up the code to print updates to the serial port, I realized that after a few cycles the Arduino resets and re-enters the Setup() function.
I changed out the Nano and it made no difference. I am using a timeout feature for the first time and I was wondering if the memory usage of this feature could be causing problems - however I commented out this part of the code and the Arduino still reset. The code is below - would really love to hear any thoughts on whether this is likely to be a hardware or software issue. I am powering the Arduino with a 7V line from a Power Supply into the Vin port. The prox sensor operates at 24V but I divide the output signal's voltage so that the input voltage is ~4.8V (I have measured this). I am using the same U-shaped sensor with a few other Arduinos and I am not seeing this issue. I have powered Arduinos with the same 7V line in the past and have also never seen them reset like this.
Let me know what you think, thank you!
const int uSensor = 12;
const int proxSensor = 10;
const int labViewHomePin = 9;
const int labViewInputPin = 8;
const int labViewOutFeedback = 7;
const int labViewInFeedback = 6;
const int StepperStepPin = 2;
const int StepperDirectionPin = 3;
const int ENPin = 13;
enum {IdleState, ForwardState, BackwardState} State; // this switch case is used to call the correct function that turns the motor in the desired direction
boolean rampDone = false;
boolean pusherIn = false;
boolean pusherOut = false;
boolean homingDone = false;
boolean updateGiven = false;
int motorSpeed = 300;
int rampStartSpeed = 500;
int rampStepCountNo = 800;
boolean boolInitialMove = true;
unsigned long timeInitialMove = 6000;
unsigned long startTime;
unsigned long endTime;
void setup() {
Serial.begin(9600);
pinMode(uSensor, INPUT);
pinMode(proxSensor, INPUT);
pinMode(labViewHomePin, INPUT); // initialising input pins
pinMode(labViewInputPin, INPUT); // initialising input pins
pinMode(StepperDirectionPin, OUTPUT); //Direction
pinMode(StepperStepPin, OUTPUT); // Step
pinMode(ENPin, OUTPUT); // Enable
Serial.println();
Serial.println("Setup phase called");
Serial.println();
pinMode(labViewInFeedback, OUTPUT);
pinMode(labViewOutFeedback, OUTPUT);
State = IdleState;
digitalWrite(ENPin,HIGH); // Disable the drive by default
homingDone = false;
}
void loop() {
if ((digitalRead(labViewHomePin) == HIGH) && (homingDone == false)) {
Serial.println("Homing Pin High Detected");
homingRoutine();
homingDone = true;
Serial.print("Homing Done = ");
Serial.println(homingDone);
State = IdleState;
if(digitalRead(proxSensor) == HIGH) {
digitalWrite(labViewInFeedback,HIGH);
digitalWrite(labViewOutFeedback,LOW);
}
else if(digitalRead(uSensor) == HIGH) {
digitalWrite(labViewInFeedback,LOW);
digitalWrite(labViewOutFeedback,HIGH);
}
else {
digitalWrite(labViewInFeedback,LOW);
digitalWrite(labViewOutFeedback,LOW);
}
}
switch (State) {
case IdleState:
boolInitialMove = true;
digitalWrite(ENPin,HIGH);
if(updateGiven == false) {
Serial.println("I am in IdleState");
Serial.print("Pusher Out Boolean = ");
Serial.println(pusherOut);
Serial.print("Pusher In Boolean = ");
Serial.println(pusherIn);
Serial.print("Prox Sensor status: ");
Serial.println(digitalRead(proxSensor));
Serial.print("U-Sensor status: ");
Serial.println(digitalRead(uSensor));
updateGiven = true;
}
if ((digitalRead(labViewInputPin) == HIGH) && (pusherOut == false) && (homingDone == true)) {
digitalWrite(ENPin,LOW); // Enable drive
State = ForwardState;
Serial.println("LabVIEW High detected. Case switched to ForwardState");
Serial.println("");
updateGiven = false;
}
else if ((digitalRead(labViewInputPin) == LOW) && (pusherIn == false) && (homingDone == true)) {
digitalWrite(ENPin,LOW); // Enable drive
State = BackwardState;
Serial.println("LabVIEW Low detected. Case switched to BackwardState");
Serial.println("");
updateGiven = false;
}
else {
//do nothing
}
if(digitalRead(uSensor) == HIGH) {
pusherOut = true;
pusherIn = false;
}
else if(digitalRead(proxSensor) == HIGH) {
pusherOut = false;
pusherIn = true;
}
else {
//do nothing
}
break;
case ForwardState:
if(updateGiven == false) {
Serial.println("I am in ForwardState");
Serial.print("LabVIEW Actuate Pin = ");
Serial.println(digitalRead(labViewHomePin));
updateGiven = true;
}
if(boolInitialMove == true) {
digitalWrite(StepperDirectionPin, LOW);
rampUpCosineWave(rampStartSpeed, rampStepCountNo, motorSpeed);
startTime = millis();
endTime = startTime;
boolInitialMove = false;
}
endTime = millis();
rotateForward(motorSpeed); // this calls the function ForwardState which starts pushing out the pusher
if (digitalRead(uSensor) == HIGH) {
digitalWrite(labViewInFeedback,LOW);
digitalWrite(labViewOutFeedback,HIGH);
Serial.println("U-Sensor High detected. Case switched to Idlestate");
Serial.println("");
updateGiven = false;
pusherOut = true;
pusherIn = false;
State = IdleState;
}
else if((endTime-startTime) > timeInitialMove) {
digitalWrite(ENPin,HIGH);
digitalWrite(StepperStepPin, LOW);
digitalWrite(StepperDirectionPin, LOW);
digitalWrite(labViewOutFeedback,HIGH);
digitalWrite(labViewInFeedback,HIGH);
Serial.println("");
Serial.println("**TIMEOUT DETECTED**");
Serial.println("");
State = IdleState;
}
break;
case BackwardState:
if(updateGiven == false) {
Serial.println("I am in BackwardState");
Serial.print("LabVIEW Actuate Pin = ");
Serial.println(digitalRead(labViewHomePin));
updateGiven = true;
}
if(boolInitialMove == true) {
digitalWrite(StepperDirectionPin, HIGH);
rampUpCosineWave(rampStartSpeed, rampStepCountNo, motorSpeed);
startTime = millis();
endTime = startTime;
boolInitialMove = false;
}
endTime = millis();
rotateBackward(motorSpeed);
if (digitalRead(proxSensor) == HIGH) {
digitalWrite(labViewInFeedback,HIGH);
digitalWrite(labViewOutFeedback,LOW); // Disable drive
Serial.println("Prox Sensor High detected. Case switched to Idlestate");
Serial.println("");
updateGiven = false;
pusherOut = false;
pusherIn = true;
State = IdleState;
}
else if((endTime-startTime) > timeInitialMove) {
digitalWrite(ENPin,HIGH);
digitalWrite(StepperStepPin, LOW);
digitalWrite(StepperDirectionPin, LOW);
digitalWrite(labViewOutFeedback,HIGH);
digitalWrite(labViewInFeedback,HIGH);
Serial.println("");
Serial.println("**TIMEOUT DETECTED**");
Serial.println("");
State = IdleState;
}
break;
} // end switch
}
void rotateForward(int mtrSpeed) {
digitalWrite(StepperDirectionPin, LOW);
digitalWrite(StepperStepPin, HIGH);
delayMicroseconds(mtrSpeed);
digitalWrite(StepperStepPin, LOW);
}
void rotateBackward(int mtrSpeed) {
digitalWrite(StepperDirectionPin, HIGH);
digitalWrite(StepperStepPin, LOW);
delayMicroseconds(mtrSpeed);
digitalWrite(StepperStepPin, HIGH);
}
void homingRoutine() {
digitalWrite(ENPin,LOW);
Serial.println("Homing Routine called");
bool firstCycle = false;
bool secondCycle = false;
bool thirdCycle = false;
bool fourthCycle = false;
while(digitalRead(uSensor) != HIGH) {
rotateForward(rampStartSpeed);
}
delay(500);
Serial.println("First home movement completed");
while(digitalRead(proxSensor) != HIGH) {
rotateBackward(rampStartSpeed);
}
delay(500);
Serial.println("Second home movement completed");
while(digitalRead(uSensor) != HIGH) {
rotateForward(rampStartSpeed);
}
delay(500);
Serial.println("Third home movement completed");
while(digitalRead(proxSensor) != HIGH) {
rotateBackward(rampStartSpeed);
}
delay(500);
homingDone = true;
pusherIn = true;
pusherOut = false;
}
int rampUpCosineWave(int startSpeed, int rampUpSteps, int maximumSpeed) {
int countedSteps = 0;
float amp = ((startSpeed-maximumSpeed)/2);
for(int currentSpeed = startSpeed; currentSpeed > maximumSpeed; currentSpeed = (int)((amp + maximumSpeed)+(amp*(cos((PI/rampUpSteps)*countedSteps))))) {
digitalWrite(StepperStepPin, LOW);
delayMicroseconds(currentSpeed);
digitalWrite(StepperStepPin, HIGH);
countedSteps++;
}
return countedSteps;
}