Arduino Mega freezing when asked to move stepper motors

Hi!

I'm pretty new to arduino, and programming in general, and I'm currently working on my first large Arduino-based project and I've run into an issue I just cant seem to solve or even understand why its not working as intended.

The project is a motorized platform for moving in the X and Y directions, controllable by a joystick for random movement, and with direction buttons for pre-set distance movements. I also want it to be able to remember locations with a button press, and be able to move back to them at a later time with another button press. I'm using Accelstepper for the movement.

The issue: When i press the button to memorise the coordinates of a location (mem1), it saves the coordinates (confirmed through serial monitor) and when i press the recall button for those coordinates(Rec1) , it moves back to them, as intended. However, if i move away from those coordinates, and press the recall button again, the arduino freezes, and has to be reset. I dont understand why it always works the first time, but always freezes on the second.

The same thing happens with the Home button, which is able to move to the intended position ONCE, then freezes the arduino when the button is pushed again after its moved away from that position.
Here is the code:

#include <AccelStepper.h>
#include <ezButton.h>

//Stepper motors step & direction 
const int stepXPin = 2;  
const int dirXPin = 5;   
const int stepYPin = 3;  
const int dirYPin = 6;   

//Recall LEDs
const int Rec1LED = 50;
const int Rec2LED = 46;
const int Rec3LED = 42;
const int Rec4LED = 38;

//Memory LEDs
const int Mem1LED = 48;
const int Mem2LED = 44;
const int Mem3LED = 40;
const int Mem4LED = 36;

//Home LED
const int HomeLED = 34;

//Memory Buttons
ezButton Mem1(49);
ezButton Mem2(45);
ezButton Mem3(41);
ezButton Mem4(37);

//Recall Buttons
ezButton Rec1(51);
ezButton Rec2(47);
ezButton Rec3(43);
ezButton Rec4(39);

//Home button
ezButton Home(35);

//Mode select buttons
ezButton ModeUp(32);
ezButton ModeDn(33);

//Field movement direction buttons
ezButton Up(30);
ezButton Down(31);
ezButton Left(28);
ezButton Right(29);

//Limit switches
const int Ymax = 24;
const int Ymin = 25;
const int Xmax = 26;
const int Xmin = 27;

int YmaxState = 0;
int YminState = 0;
int XminState = 0;
int XmaxState = 0;

//Saved positions
int HomePosY = 1;
int HomePosX = 1;
int XPos1 = 1;
int YPos1 = 1;

// Joystick 
#define JOYSTICK_X A14
#define JOYSTICK_Y A12





// Create instances of AccelStepper for each motor
AccelStepper stepper1(AccelStepper::DRIVER, stepXPin, dirXPin);
AccelStepper stepper2(AccelStepper::DRIVER, stepYPin, dirYPin);

// Variables to store joystick readings and motor speed 
int joystickX;
int joystickY;
int motor1Speed;
int motor2Speed;

void setup() {


  pinMode(Ymin, INPUT);
  pinMode(Ymax, INPUT);
  pinMode(Xmin, INPUT);
  pinMode(Xmax, INPUT);

  pinMode(Rec1LED, OUTPUT);
  pinMode(Rec2LED, OUTPUT);
  pinMode(Rec3LED, OUTPUT);
  pinMode(Rec4LED, OUTPUT);
  pinMode(Mem1LED, OUTPUT);
  pinMode(Mem2LED, OUTPUT);
  pinMode(Mem3LED, OUTPUT);
  pinMode(Mem4LED, OUTPUT);
  pinMode(HomeLED, OUTPUT);

  YminState = digitalRead(Ymin);
  YmaxState = digitalRead(Ymax);
  XminState = digitalRead(Xmin);
  XmaxState = digitalRead(Xmax);

  stepper1.setMaxSpeed(4000.0);      // Adjust this value to set the maximum speed
  stepper1.setAcceleration(1000.0);  // Adjust this value to set the acceleration
  stepper2.setMaxSpeed(4000.0);      // Adjust this value to set the maximum speed
  stepper2.setAcceleration(1000.0);  // Adjust this value to set the acceleration

  Mem1.setDebounceTime(50);
  Mem2.setDebounceTime(50);
  Mem3.setDebounceTime(50);
  Mem4.setDebounceTime(50);

  Rec1.setDebounceTime(50);
  Rec2.setDebounceTime(50);
  Rec3.setDebounceTime(50);
  Rec4.setDebounceTime(50);

  Home.setDebounceTime(50);

  ModeUp.setDebounceTime(50);
  ModeDn.setDebounceTime(50);

  Up.setDebounceTime(50);
  Down.setDebounceTime(50);
  Left.setDebounceTime(50);
  Right.setDebounceTime(50);

  //Initial Homing sequence 
  digitalWrite(HomeLED, HIGH);
  while (YminState == 1) {

    YminState = digitalRead(Ymin);
    stepper2.setSpeed(-1500);
    stepper2.run();
  }

  while (XminState == 1) {
    XminState = digitalRead(Xmin);
    stepper1.setSpeed(-1500);
    stepper1.run();
  }
  digitalWrite(HomeLED, LOW);
  stepper1.setCurrentPosition(0);
  stepper2.setCurrentPosition(0);
}


void loop() {



  Rec1.loop();
  Rec2.loop();
  Rec3.loop();
  Rec4.loop();

  Mem1.loop();
  Mem2.loop();
  Mem3.loop();
  Mem4.loop();

  Home.loop();

  ModeUp.loop();
  ModeDn.loop();

  Up.loop();
  Down.loop();
  Left.loop();
  Right.loop();

  //State of limit swithes
  YminState = digitalRead(Ymin);
  YmaxState = digitalRead(Ymax);
  XminState = digitalRead(Xmin);
  XmaxState = digitalRead(Xmax);


  // Read the analog values from the joystick
  joystickX = analogRead(JOYSTICK_X);
  joystickY = analogRead(JOYSTICK_Y);

  //Map joystick values to motor speed for each axis
  if (joystickX > 550 && XminState == 1) {
    motor1Speed = map(joystickX, 550, 1023, -100, -4000);
  } else if (joystickX < 450 && XmaxState == 1) {
    motor1Speed = map(joystickX, 450, 0, 100, 4000);
  } else {
    motor1Speed = 0;
  }

  if (joystickY > 550 && YmaxState == 1) {
    motor2Speed = map(joystickY, 550, 1023, 100, 4000);
  } else if (joystickY < 450 && YminState == 1) {
    motor2Speed = map(joystickY, 450, 0, -100, -4000);
  } else {
    motor2Speed = 0;
  }

  stepper1.setSpeed(motor1Speed);
  stepper2.setSpeed(motor2Speed);
  stepper1.runSpeed();
  stepper2.runSpeed();

  //Field step 
  if (Up.isReleased() && YmaxState == 1) {
    stepper2.move(200);
    stepper2.runToPosition();
  }

  if (Down.isReleased() && YminState == 1) {
    stepper2.move(-200);
    stepper2.runToPosition();
  }

  if (Left.isReleased() && XmaxState == 1) {
    stepper1.move(200);
    stepper1.runToPosition();
  }

  if (Right.isReleased() && XminState == 1) {
    stepper1.move(-200);
    stepper1.runToPosition();
  }

  //Return to home position
  if (Home.isReleased()) {
    stepper1.runToNewPosition(HomePosX);
    stepper2.runToNewPosition(HomePosY);
  }

  //save current position to memory 1
  if (Mem1.isReleased()) {
    digitalWrite(Mem1LED, HIGH);
    XPos1 = stepper1.currentPosition();
    YPos1 = stepper2.currentPosition();
  }


  //Recall previously saved position from memory 1
  if (Rec1.isReleased()) {
    if (XPos1 != stepper1.currentPosition()) {
      digitalWrite(Rec1LED, HIGH);
      stepper1.runToNewPosition(XPos1);
    }

    if (YPos1 != stepper2.currentPosition()) {
      stepper2.runToNewPosition(YPos1);
      digitalWrite(Rec1LED, LOW);
    }
  }
}

I think ive managed to track the problem to the block of code that controls the joystick movement:

  //Map joystick values to motor speed for each axis
  if (joystickX > 550 && XminState == 1) {
    motor1Speed = map(joystickX, 550, 1023, -100, -4000);
  } else if (joystickX < 450 && XmaxState == 1) {
    motor1Speed = map(joystickX, 450, 0, 100, 4000);
  } else {
    motor1Speed = 0;
  }

  if (joystickY > 550 && YmaxState == 1) {
    motor2Speed = map(joystickY, 550, 1023, 100, 4000);
  } else if (joystickY < 450 && YminState == 1) {
    motor2Speed = map(joystickY, 450, 0, -100, -4000);
  } else {
    motor2Speed = 0;
  }

  stepper1.setSpeed(motor1Speed);
  stepper2.setSpeed(motor2Speed);
  stepper1.runSpeed();
  stepper2.runSpeed();

because if i remove this, the recall and home buttons work as many times as i press them, after moving using the field step buttons.

Like i said, I'm quite new to Arduino and programming so I'm very stumped why this as causing me issues and any help would be greatly appreciated.

Many thanks

what happens if the speed is set to zero and runSpeed() is executed?

The joystick stops working, but the recall and home buttons work without freezing after the first press

Isn't a speed of 4000 a little to high, maybe causing an instability?

Jim, I tried a lower speed of 500, but the issue is still the same

I don't see any serial monitoring going on.

Add more serial monitor printing of the values of key variables and confirm they are plausible and properly informing the flow through your code.

Can you disconnect to motors and still see if the motor control signals are what you expect?

A heartbeat LED in your loop,would show if you are truly frozen, a print statement in setup() woukd show if you were be getting unexpected resets.

Two lines, put it in the loop function:

    pinMode(13, OUTPUT);
    digitalWrite(13, millis() & 0x200 ? LOW : HIGH);

a7

Nothing. ( This is exactly how run() works if the target position is reached ).

@dimi815

Your usage of Accelstepper is a little bit weird. You should never use setSpeed() and run() together, because run() uses setSpeed() internally. It is pure coincidence that this works, but not as intended by the Library.

does it hang if the speed is zero and the target is not reached?

No. runSpeed() simply does nothing (returns immediately) if speed is set to 0.
runSpeed() also doesn't care about the target if speed != 0. It simply does one step if it's time to do so ( according to speed ) and increments/decrements the current position.
Only run() does care about the target ( and uses runSpeed() internally to do a step and setSpeed() to accelerate, decelerate and stop ). That's why it is always a bad idea to mix up run(), with runSpeed() and setSpeed().

thanks for explaining

I'm not really understanding what you mean by this, could you please elaborate?

I've added a serial print for the saveable coordinates at XPos1 and YPos1, these change when prompted by the Memory button as intended, and do not change after the first Recall. after the second Recall, arduino freezes, the added heartbeat freezes on whatever state the LED it was on when the button was pressed.

When the Home coordinates are set to X = 0, Y=0, the home button causes it to instantly freeze on the first button press.

I've also tried to add into the recall command a change in the coordinate after each time it is recalled.

//Recall previously saved position from memory 1
  if (Rec1.isReleased()) {
    if (XPos1 != stepper1.currentPosition()) {
      digitalWrite(Rec1LED, HIGH);
      stepper1.runToNewPosition(XPos1);
      XPos1 = XPos1 + 1;
    }

    if (YPos1 != stepper2.currentPosition()) {
      stepper2.runToNewPosition(YPos1);
      YPos1 = YPos1 + 1;
      digitalWrite(Rec1LED, LOW);
    }
  }

This returns it to pretty much the correct location, offset by 1 step in each direction. If each recall is to a different coordinate each time, even if only different by 1 step, it does not freeze. If it tries to recall to the same coordinates more than once, it freezes

Should i be using runSpeed() instead?

That would definitely make more sense. And you can move setSpeed before the while loop.

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