Stepper Motor won't work with code to function correctly

Hi,

I want this robot to function so that someone can insert a certain linear velocity (ex. 500) on the keypad, and the motor would move in a certain direction, stop, then wait for the # button to be pressed for it to home using the hall effect sensor. I also have a joystick to control the motor as well.

Right now, the robot starts up, the motor homes (Ex. Direction B) until a magnet is detected by the hall effect sensor, then it stops. It waits for input from either the joystick or keypad. The joystick can move it left and right at three different set speeds. A number can be inserted in the keypad, and when a non-number (A, B, C, D) is pressed, the motor moves a certain distance in one direction (Ex. Direction A) and then moves back in the opposite direction (Ex. Direction B). The * button on the keypad clears the input incase something wrong was inputted into the keypad and the # button homes the motor.

The things that aren't working for me is that I want the motor to move in (Ex. Direction A), and then stop. Then I can press the # button and the motor would home and then the whole process repeats again (Waits for either joystick or keypad input).

Also, it seems like whenever I insert a certain linearv (linear velocity) on the keypad, it doesn't matter and the motor moves in the same speed regardless of the number inputted using the keypad.

Here is the most updated piece of code that I have

#include <LiquidCrystal.h>                                    //LCD
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#include <Keypad.h>                                           //KEYPAD
#include <AccelStepper.h>                                     //STEPPER MOTOR
#define X_pin            A0    // Pin A0 connected to joystick x axis
#define Joy_switch       52  // Pin 4 connected to joystick switch
#define motorInterfaceType 1                                  // Define motor interface type
#define HALL_SENSOR      8
#define DIR              23
#define STEP             25
const int dirPin =       23;                                        // Define pin connections
const int stepPin =      25;
boolean printflag    = true;
boolean setdir       = HIGH;                                 // (HIGH = anti-clockwise / LOW = clockwise)
int step_speed =         10;  // Speed of Stepper motor (higher = slower)
const byte ROWS =         4;                                          // Constants for row and column sizes
const byte COLS =         4;
byte rowPins[ROWS] = {39, 41, 43, 45};                        // Connections to Arduino
byte colPins[COLS] = {47, 49, 51, 53};
int val                 = 0;
unsigned long linearv   = 0;
int flag =                0;
long oldTime            = 0;
int valueOld =            0;
char hexaKeys[ROWS][COLS] =                               // Array to represent keys on keypad
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {':', '0', ';', 'D'}
};

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);// Create keypad object
AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);  // Creates an instance
// Sequence control
//-------------------------------------------------------------------
void Joystick() {
  if (!digitalRead(Joy_switch)) {  //  If Joystick switch is clicked
    printflag = true;
    delay(500);  // delay for deboucing
    switch (step_speed) {  // check current value of step_speed and change it
      case 1:
        step_speed = 10; // slow speed
        break;
      case 3:
        step_speed = 1; // fast speed
        break;
      case 10:
        step_speed = 3; // medium speed
        break;
    }
  }

  if (printflag == true) {
    lcd.clear();                                        // Clear LCD display and print character
    lcd.setCursor(0, 0);
    lcd.print(step_speed);
    printflag = false;
  }
  if (analogRead(X_pin) > 712) {  //  If joystick is moved Left
    digitalWrite(dirPin, LOW);  // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(stepPin, HIGH);
    delay(step_speed);
    digitalWrite(stepPin, LOW);
    delay(step_speed);
  }
  if (analogRead(X_pin) < 312) {  // If joystick is moved right
    digitalWrite(dirPin, HIGH);  // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(stepPin, HIGH);
    delay(step_speed);
    digitalWrite(stepPin, LOW);
    delay(step_speed);
  }
}


int getKeypadIntegerMulti() {
  int value = 0;                                        // the number accumulator
  int keyvalue;                                         // the key pressed at current moment
  int isnum;
  do {
    keyvalue = customKeypad.getKey();                   // input the key
    Joystick();
    if (keyvalue) {
      if (keyvalue == ';') {
        isnum = 0;
        keyvalue = 0;
        value = 0;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print(value);
        homefunction();
      }
    }
    if (keyvalue) {
      if (keyvalue == ':') {
        isnum = 0;
        keyvalue = 0;
        value = 0;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print(value);
      }
      Serial.println(keyvalue);
      isnum = (keyvalue >= '0' && keyvalue <= ';');     // is it a digit?
      if (isnum) {
        value = value * 10 + keyvalue - '0';            // accumulate the input number
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print(value);
      }
    }
  }
  while (isnum || !keyvalue);
  return value;
}



void homefunction() {
  // Set motor speed pulse duration
  int pd = 4000;

  // Move motor until home position reached
  while (digitalRead(HALL_SENSOR) == 1) {

    digitalWrite(DIR, setdir);
    digitalWrite(STEP, HIGH);
    delayMicroseconds(pd);
    digitalWrite(STEP, LOW);
    delayMicroseconds(pd);
    setdir = LOW;
  }

}





//-------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  lcd.begin(16, 2);
  myStepper.setMaxSpeed(100);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(linearv);
  myStepper.moveTo(200);

  // Setup the stepper controller pins as Outputs
  pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);

  // Setup the Hall Effect switch as an Input
  pinMode(HALL_SENSOR, INPUT);
  pinMode(X_pin, INPUT);
  pinMode(Joy_switch, INPUT_PULLUP);

  // Home the motor
  homefunction();
}


//-------------------------------------------------------------------
void loop() {
  while (linearv == 0)                                  // While don´t value
  {
    Serial.println("Running");
    val = getKeypadIntegerMulti();                      // Look keypad
    linearv = (val / 10 / 15.7295 * 60);                // Calc vel. value
  }
  if (flag == 0)                                        // Sequence 0  Shown value on LCD
  {
    lcd.clear();                                        // Clear LCD display and print character
    lcd.setCursor(0, 0);
    lcd.print(linearv);
    flag = 1;                                           // Allow sequence 1
  }
  if (myStepper.distanceToGo() == 0)                    // Change direction once the motor reaches target position
  {
    flag++;                                             // Incremente sequence count
    if (flag == 2)                                      // If sequence 1 complete
    {
      myStepper.moveTo(-myStepper.currentPosition());
    }
    if (flag == 3)                                      // If sequence 2 complete
    {
      flag = 0;                                         // Allow start
      linearv = 0;                                      // Zero vel. value
      lcd.clear();                                      // Clear LCD display and print character
      myStepper.moveTo(-myStepper.currentPosition());   // Return
    }
  }
  myStepper.run();                                      // Move the motor one step
}

Hoping someone can help :slight_smile:

It's a very bad idea to control the step and dir pins by yourself if you use the AccelStepper library. You should not do that. Either you do everything yourself, or you use the AccelStepper. But not mixed. AccelStepper counts the steps, but of course it doesn't know about the steps you create.

You never set the new speed. You only set the speed once in setup(). If you use the myStepper.run() function, only setMaxSpeed(xx) changes your actual speed. setSpeed() is used internally by run();

So then what should I do?

At first decide how you want to control the stepper. No mixing of different methods!

If I understand your description correctly, you want to control the stepper with different inputs ( joystick and keypad). How can it be mixed? Can a number be input while the stepper is moving?
Can you show a picture of your project, so we can better imagine what you really want to do.

If you want to have acceleration and deceleration you should definitely use a library. An alternative may be my MobaTools library, because you don't have to bother with step generation in your sketch. You only tell the stepper what to do, the steps are generated in timer interrupts in the background. With Accelstepper you must not use delay() or blocking code while the stepper is running.

What do you recommend I do?

All of this works already with the code that I have. The only problems I have are
A) I need after the number on the keypad is pressed and the motor runs, I want the motor to go in the A. direction and stop (and not come back in the B direction).
B) The speed of the motor (I have it as linear velocity (linearv)) is always the same no matter what number is inserted on the keypad.

Then why do you explicitly program it to go back?
flag==2 : go on one direction, after that flag==3 go into other direction:

And what do you think what 'currentPosition' is? Because you also move the stepper independent from AccelStepper, AccelStepper don't know about the real current position.

I told you already, that you never changed the speed for AccelStepper. You must do something like
myStepper.setMaxSpeed(linearv);
to change the speed for AccelStepper.

What do you expect from me? Of course I would do all stepper movement with my MobaTools library :rofl:
No seriously: in the end it doesn't matter, but stick to one method. If you don't need any acceleration and it works so far with your blocking design, you can do it all without a library.

Your program is very confusing. At least you should comment on what the individual parts of the program are supposed to do. Commenting on individual instructions does not help very much - at least for me :wink:
And your video doesn't really show useful information either.

I know it is because many hands (specifically from this forum) touched the code when I needed help and it is probably what caused two different libraries as well

Can you help me with this? I'm still a beginner in Arduino compared to you guys and don't know how to do it

Also when I do this it doesn't move the motor at all

Thanks for all your help btw

Probably for this reason:

If you never moved your motor by means of AccelStepper, then currentPosition ist still zero. And -zero is also zero - you never tell the motor to do steps. That's because AccelStepper doesn't now about the other movements.

It is your program. You need to restructure it and control the steppers consistently.

When a program is structured in a confusing way and you mix methods for controlling the same device even a seasoned engineer will have issues trying to help you. The FIRST thing you need to do is remove the code where you are trying to control the servos using the individual pins and replace it with AccelStepper calls. If you move the steppers independently from AccelStepper then the library has NO IDEA the current position of the stepper.

Got it. The problem with that is, for example, is that the hall effect sensor and joystick uses individual pins instead of the library. Is it fine if I use individual pins instead? I don't need the motor to know its position since I don't want it to go back the opposite way.

I will get you started in the cleanup process. These are things from a quick scan of your code:

  1. This is redundant. Either use #defines or const, but not both. const is preferred
#define DIR              23
#define STEP             25
const int dirPin =       23;                                        // Define pin connections
const int stepPin =      25;
  1. The following globals are defined but not used:
long oldTime            = 0;
int valueOld =            0;
  1. Why??? step_speed is initialized to 10 and never changes!
    switch (step_speed) {  // check current value of step_speed and change it
      case 1:
        step_speed = 10; // slow speed
        break;
      case 3:
        step_speed = 1; // fast speed
        break;
      case 10:
        step_speed = 3; // medium speed
        break;
    }
  1. There is no reason to debounce for 500ms! Try 20 or 50.

delay(500); // delay for deboucing

  1. If you only print when the button is pressed then you can eliminate the printflag:
  if (!digitalRead(Joy_switch)) {  //  If Joystick switch is clicked
    printflag = true;
    delay(500);  // delay for deboucing
    switch (step_speed) {  // check current value of step_speed and change it
      case 1:
        step_speed = 10; // slow speed
        break;
      case 3:
        step_speed = 1; // fast speed
        break;
      case 10:
        step_speed = 3; // medium speed
        break;
    }
  }

  if (printflag == true) {
    lcd.clear();                                        // Clear LCD display and print character
    lcd.setCursor(0, 0);
    lcd.print(step_speed);
    printflag = false;
  }
  1. You could get in an infinite loop right here:

while (isnum || !keyvalue);

  1. You should use HIGH and LOW when testing the state of inputs. Also there is no reason to assign LOW to setdir over and over again.
  while (digitalRead(HALL_SENSOR) == 1) {
    digitalWrite(DIR, setdir);
    digitalWrite(STEP, HIGH);
    delayMicroseconds(pd);
    digitalWrite(STEP, LOW);
    delayMicroseconds(pd);
    setdir = LOW;
  }

The hall effect sensor and joystick have nothing to do with the steppers. So, yes, read those inputs as needed.

OK. But you still need to either use the library (preferred) or direct control. Not both.

Of course. And by the way, you helping me with the cleanup is a life-saver, so thanks for that. So if I can still use the joystick and hall effect sensor with independent pins while also using the library for the motor, I'll do that. But from what I can see in the code, I only use individual pins for the joystick and hall effect sensor. The stepper motor itself is using the library if I'm not mistaken.

Yes I have it initialized to 10, and it doesn't change unless if the joystick is clicked then it switches between the three speeds each time its pressed. This doesn't affect the speed when the number is entered on the keypad.

But I use the printflag to clear the screen before printing the new number, or do I not need it for that

I did before but was able to fix it and it doesn't anymore

Sorry but I don't think I understand what you mean here

Thanks a lot for your help by the way I really do appreciate it

??? Every time you do a digitalWrite to dirPin or stepPin you are directly controlling the motor. You should replace all of those with AccelStepper calls or remove AccelStepper calls and do it yourself. NOT BOTH!!!

I see that now. Sorry about that.

That function is the only place you use printflag and you only print if the speed changes. Therefore just put the print in the same conditional where the speed changes. Like this:

if (!digitalRead(Joy_switch)) {  //  If Joystick switch is clicked
    delay(500);  // delay for deboucing
    switch (step_speed) {  // check current value of step_speed and change it
      case 1:
        step_speed = 10; // slow speed
        break;
      case 3:
        step_speed = 1; // fast speed
        break;
      case 10:
        step_speed = 3; // medium speed
        break;
    }
    lcd.clear();                                        // Clear LCD display and print character
    lcd.setCursor(0, 0);
    lcd.print(step_speed);
  }

Like this:

setdir = LOW;
while (digitalRead(HALL_SENSOR) == HIGH) {
    digitalWrite(DIR, setdir);
    digitalWrite(STEP, HIGH);
    delayMicroseconds(pd);
    digitalWrite(STEP, LOW);
    delayMicroseconds(pd);
  }

Ok I understand now. I'll try to do that, but might have problems switching the joystick and hall effect sensor from direct control to the library.

Why do you keep saying that? Joystick and hall effect sensor have nothing to do with the stepper library.

For example this piece of the code

if (analogRead(X_pin) > 712) {  //  If joystick is moved Left
    digitalWrite(dirPin, LOW);  // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(stepPin, HIGH);
    delay(step_speed);
    digitalWrite(stepPin, LOW);
    delay(step_speed);
  }
  if (analogRead(X_pin) < 312) {  // If joystick is moved right
    digitalWrite(dirPin, HIGH);  // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(stepPin, HIGH);
    delay(step_speed);
    digitalWrite(stepPin, LOW);
    delay(step_speed);
  }

and this

void homefunction() {
  // Set motor speed pulse duration
  int pd = 4000;

  // Move motor until home position reached
  while (digitalRead(HALL_SENSOR) == 1) {

    digitalWrite(DIR, setdir);
    digitalWrite(STEP, HIGH);
    delayMicroseconds(pd);
    digitalWrite(STEP, LOW);
    delayMicroseconds(pd);
    setdir = LOW;
  }

They both are coded without using the library but through direct control. So I'd have to switch this to using the library as well no?

 pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);

This too. Correct me if I'm wrong but I don't see any other parts of the program that are coded using direct control rather than the library.

Correct. But you still have to read the hall effect sensor using digitalRead() and read the joystick using analogRead().

Here is a tutorial I found describing how to home the stepper using the AccelStepper library. I think it will answer a lot of questions for you. https://www.youtube.com/watch?v=YsLykxnHApg

Check your PMs.