3

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;
}
2
  • 2
    Can you monitor the Vin and +5V lines with a scope while the stepper is running? Electric motors can make power supplies noisy and unstable. – Edgar Bonet Nov 23 '20 at 10:00
  • 1
    Your meter may also have a MIN mode that tracks the minimum voltage seen since started. It's not as good as a using a scope as Edgar suggests, but sometimes it can help. – timemage Nov 23 '20 at 12:47
3

Thank you all for your contributions. I managed to find the issue and solve the intermittent reset. I was expecting to find a hardware problem as the root cause, but just in case it was software related I wanted to check as well. It turned out to be hardware

Gil is certainly questioning the correct piece of hardware. It was indeed the wiring of the Prox sensor. I had connected both the data and power common rails to facilitate the prox sensor but on inspection, I decided to keep these separate and voltage divide the prox sensor away from the rails and instead bring a direct 4.8V line into the Arduino. Whatever noise the stepper motor was creating was unable to impact the data lines of the Arduino, and I haven't seen the issue return since.

Really appreciate the help everyone. I didn't scope the power lines to the Arduino, as the issue continued regardless of me powering the arduino through only the COM port of a PC, a combo of both the COM port and 7V to the Vin line (presume the Arduino draws from the 7V line but I am unsure) and just the 7V line. Appears to have been noise disrupting the data common rail of the Arduino.

1

I expect you have a lot going on with your design. Dividing down is never a good voltage (power) supply regardless of what you measure unless you are using a good scope to measure and it is well bypassed. Consider a Buck regulator from one of the China suppliers they are just a few bucks and will stabilize your circuit. If the prox sensor draws just a few mills consider powering it with the Arduino 5 volts. Motors like other inductive devices generate lots of transinents that are both conducted and radiated, something like that may be getting into your system possibly via the prox sensor. This should get you started.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.