Stepper with limit switches and push button to start

Hi all

I am wondering if anyone has any ideas to do the following?
I am using a 6 wire stepper motor with the easy driver.
Goal is to have stepper paused at start, then set the speed and direction on a display, then hit the button to start the stepper at said speed and direction and Display values on 7 segment LED display.
I would also like to have limit switches at each end so that when touched by the dolly on the track - the stepper stops.
Hitting the button during motion (after pressing to to start the stepper should also stop it

I am thinking I need the follow functions

1: button detection HIGH or LOW (start or stop)
2: Read pot value and store it as motorSpeed
3 Read Direction switch and store value FWD or REV
4: Display values on 7 segment LED display
5: Run the motor with the values from above

Any thoughts?
When written out it seems very simple
1 button Start or Stop
1 Potentiometer MotorSpeed
1 switch FWD or REV
2 limit switchs that would use the same variables as the button to stop the stepper.

:slight_smile:

This is a basic outline of how I think the code should run based on the above specs

  • I could be TOTALLY wrong though :confused:
//1: button detection HIGH or LOW (start  or stop)
//2: Read pot value and store it as motorSpeed
//3 Read Direction switch and store value FWD or REV
//4: Display values on 7 segment LED display
//5: Run the motor with the values from above

int ledPin = 13;      // select the pin for the LED

// stepper pins
#define DIR_PIN 2
#define STEP_PIN 3
#define switchPin 4

//motorSpeed from POT
int sensorPin = A0;    // select the input pin for the potentiometer

// Start Stop Push Button
int button = 5;     // the number of the pushbutton pin
int buttonState = 0;         // variable for reading the pushbutton status

// Limit switches
int limitLeft = 11;
int limitRight = 12;
// display pot
int displayPin = A1;    // select the input pin for the potentiometer

void setup(){
  Serial.begin(9600);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode (switchPin, INPUT);
  pinMode(button, INPUT);
  // Show me power on LED
  pinMode(ledPin, OUTPUT); 
}

void loop(){
// stop stepper and wait for button push to start routine
// gather speed and dir values
// what function do I call here to gather info?
}


void startStopButton(){
// detact if button is pushed
// Button pushed case one = run stepper based on motorSpeed and Direction
// if pushed while stepper is running - stop the motor and the elapsed time
// if pushed again, start stepper and elapsed time

}
void duration (){
// display elapsed time on LED display that only starts when motor is stepping
// pause when push button is pressed
}

void displayInfo(){
// pot value to display speed and direction and elapsed time on LED display
// map this in thirds - for now 
// 0-335 = show direction
// 336-695 = show motorSpeed
// 696-1023 = show elasped time
}

void motorSpeed(){
// get POT value and make it the stepper speed
}

void getDirection(){
// get the direction from the switch pin
// HIGH = FWD
// LOW = REV
}

void limitLeft(){
// if limit switch is hit - stop stepper and elapsed time
// set direction to FWD?
// restart elapsed time?
}

void limitRight(){
// if limit switch is hit - stop stepper and elapsed time
// set direction to REV?
// restart elapsed time?
}

Having all those different functions is a good idea, but I haven't studied them in detail.

Are you familiar with the concept in the "blink without delay" sketch?

You need to design your loop() function so that it repeatedly runs through other key functions without any delay()s to interfere with things. Perhaps something like this pseudo code

loop() {
  readButtons()
  readPot()
  checkLimits()
  moveMotor()
  updateDisplay()
}

The "moveMotor" function will do its thing depending on the values that have been collected elsewhere.

I suggest you leave the LCD stuff until you have other stuff working simply because it clutters up code if you need to post it here for advice.

...R

Hey Robin.

You are right about the display, I started coding last night and it was really easy to get focused on the display and nothing else.

I am a bit lost as to how to add limit switches and code them, also do you know how to stop a stepper when a limit switch is hit, or on button press.

For example if it hit the push button to stop the stepper - stepper stops
When I hit it again stepper starts

If a limit switch is hit, I should be able to start the stepper in the opposite direction it was going by hitting the push button - right?

Sort of lost on how to code this.
I think its best start with getting the button and limit switches to work and then move on with speed control and display
Any ideas?

You need to study the notion of a "state machine". There is a lot of stuff that makes this appear complex but it can be implemented very easily.

For example, while the left limit switch is pressed the motor should only move to the right.

When the stop button is pressed it should set a variable e.g. "stopBtn = true" and that should not change to false until whatever other appropriate action happens.

Then the code for running the motor (let's call it motorStep) would be a bit like this pseudo code

void motorStep(char dir) {
if (stopBtn == true) {
return; // so there won't be a step
}
if (dir == 'L' && digitalRead(leftLimit) == HIGH) {
return; // because we don't want to go left
}
if (dir == 'R' && digitalRead(rightLimit) == HIGH) {
return; // because we don't want to go right
}

}

This is a very rough example and there are probably lots of reasons to do it differently in practice but I hope it illustrates the idea.

...R

Hi Robin

Yes it totally does clarify things. But it might be a bit beyond me to code
I suppose what confuses me is the simple action of have an off off button to start with.
What im fighting with is having the motor OFF to start, and once the push button is touched the motor goes, press again and the motor stops again.

Lets say I have to functions
checkBTN();
and
startMotor();
Thoughts?

The checkBtn() function reads the button and saves it value in a global variable. Most of the time the button won't be pressed so the variable will hold (say) 0.

The moveMotor() function will check the variable and if it is not 0 it will start or stop the motor as appropriate and also set the btn variable back to 0 so it "knows" it has dealt with the most recent button press.

...R

So do i call checkBTN in void loop then Robin?
global varibale is like this right
const int btnPress = 0;

Does the below make sense? Still unsure as to how to stop the steppers coils

void checkBTN(){
  val = digitalRead(inPin);  // read input value
  Serial.println(val);
  if (val == HIGH) {         // check if the input is HIGH (button released)
    digitalWrite(ledPin, LOW);  // turn LED OFF
stopMotor(); // make a function that stops motor here, or just reverse LOW HIGH here?

  } else {
    digitalWrite(ledPin, HIGH);  // turn LED ON
   rotateMotor(); // start the motor here?
    
  }
}

State machine...

int stage = 1; //initial state

void setup(){
// your setup code here
}

void loop(){
switch (stage){
case 1:  //wait for button press to start
    if(button pressed);
       stage++;
    break;
case 2:
    step motor 1 step  //loop runs very fast so movement will appear continuous
    if (endstop reached);
       stage++;
   break;
case 3: //wait for button press to start
    if(button pressed);
       stage++;
    break;
case 4:  
    step motor -1 step  //reverse direction...loop runs very fast so movement will appear continuous
    if (endstop reached);
       stage++;
   break;
case 5:
   stage = 1;
   break;
}
}
if(button pressed);
       stage++;

Oops.

graphections:
So do i call checkBTN in void loop then Robin?
global varibale is like this right
const int btnPress = 0;

I would have something like this (pseudo code)

void loop() {
checkBtn();
moveMotor();
}

The important thing for clarity is to keep the button code and the motor code separate. That way you can test each part separately in a short sketch. So the checkBtn() code only saves the value of the button and the moveMotor() code reads that value and acts accordingly.

...R

AWOL:

if(button pressed);

stage++;



Oops.

Oops indeed. Try this:

int stage = 1; //initial state

void setup(){
// your setup code here
}

void loop(){
switch (stage){
case 1:  //wait for button press to start
    if(button pressed)  stage++;
    break;
case 2:
    step motor 1 step  //loop runs very fast so movement will appear continuous
    if (endstop reached)  stage++;
   break;
case 3: //wait for button press to start
    if(button pressed)  stage++;
    break;
case 4:  
    step motor -1 step  //reverse direction...loop runs very fast so movement will appear continuous
    if (endstop reached)  stage++;
   break;
case 5:
   stage = 1;
   break;
}
}

So do I just call functions in each stage then?

The issue I am having right now is have the motor stopped at the start.

graphections:
So do I just call functions in each stage then?

Yes, you can do that.

The issue I am having right now is have the motor stopped at the start.[/quote]
Post your revised code.

Ok im lost here.
(code is pointless to show, I have not gotten far with it)

Here is a recap
I need a function for this Push Button to start stop the below function.
But what id like to get this function doing is a set number of steps using the accelStepper lib.
Once steps are done - motor stops - the above button is for stopping the motor and pausing the step count

void rotate(){
  /// LED lights with 9volt power on
  digitalWrite(ledPin, HIGH);
  if (digitalRead(switchPin)){ //if the switch is HIGH, rotate clockwise
    digitalWrite(DIR_PIN,HIGH);
    // Serial.println("Fwd");
  }
  else { // if the swtich is LOW, rotate counter clockiwise
    digitalWrite(DIR_PIN,LOW);
    //  Serial.println("Rev");
  }

  for(int i=0; i < 1600 * .125; i++){
    int usDelay = map(analogRead(A0), 10, 1000, 10, 7000);
    usDelay = constrain(usDelay, 10, 7000);

    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(usDelay);

    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(usDelay);


  }

}

Then I need a function for limit switches to stop the above from running and switching the direction so that when I hit the push button again, the stepper will go in the other direction and start the step count again from 0.

PUlling my hair out here - in my head it seems straight forward but in code im lost

Part of the problem is that you are getting advice about two different ways to achieve the same thing. I suggested an approach in Reply #10 and @Henry_Best has a different approach.

Naturally I think my system is simpler and easier to follow. But you will have to choose which you want to use. Personally I find it difficult to remember what "stage 3" etc. implies.

The code you have in your most recent post doesn't follow either approach and (against both advices) mixes the switch reading code and the motor moving code.

I find it very useful to write out the steps in english (or your own language if different) rather than Arduino code on a piece of paper as a way to get a clear image of a problem and a solution in my mind.

...R

Ok getting close here

This sketch does the following
Two limit switches Left and Right to detect when something hits them var is motorState
Push button to start and stop the stepper - same var motorState

Where I am stuck is where to call the rotate(); function?
Do I need an if statement in the loop to detect the motorState?
If motorState = HIGH;
call the rotate(); function?
else do what????

Here is the Sketch with tons of comments - any help on this would be amazing as it seems so close!
The nest step (no pun) is to incorporate accelStepper into the rotate function and define an exact number of steps - if anyone as an ideas for this - I owe you a beer!!!

SKETCH

#define DIR_PIN 2
#define STEP_PIN 3
#define switchPin 4

// show me steps and delay
int sensorPin = A0;    // select the input pin for the potentiometer
int ledPin = 13;      // select the pin for the LED
int sensorValue = 0;  // variable to store the value coming from the sensor

////////////////////////////////////////////////////////////////////
//////////////////////// BUTTONS AND LIMIT SWITCHES ////////////////

// start stop BTN - BIG RED pin 5
int startStopBTN = 5; 
//////// LEFT limit switch pin 7
int limitLeftBTN = 7; 
//////// RIGHT LIMIT
int limitRightBTN = 6;
//////////// BTN and Limit Switch vars
int motorState = HIGH;
int val;           // the current reading from the BTN and switches pin
int previous = LOW;    // the previous reading from the BTN and switches pin
// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0;         // the last time the output pin was toggled
long debounce = 200;   // the debounce time, increase if the output flickers

///////////////////////////////// SETUP ///////////////////////////////
void setup() {
  Serial.begin(9600);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode (switchPin, INPUT);

  // Show me power on LED
  pinMode(ledPin, OUTPUT); 

  ///////// limit switches
  pinMode (limitLeftBTN, INPUT);  
  pinMode (limitRightBTN, INPUT); 
  
  // start stop BTN
  pinMode (startStopBTN, INPUT); 
}
////////////////////////// END SETUP /////////////////////////

////////////////////////// START LOOP ////////////////////////
void loop(){
  //checkFWDBTN();
  //checkREVBTN();
  //rotate();//will rotate 2 times, with Pot control 
  checkSSBTN();
  //checkLimitLeft();
  //checkLimitRight();
}
/////////////// END LOOP //////////////////////

////////////////// FUNCTIONS ///////////////////

///////////////// LEFT LIMIT BUTTON ////////////

void checkLimitLeft(){
  val = digitalRead(limitLeftBTN);
  // if the input just went from LOW and HIGH and we've waited long enough
  // to ignore any noise on the circuit, toggle the output pin and remember
  // the time
  if (val == HIGH && previous == LOW && millis() - time > debounce) {
    if (motorState == HIGH)
      //stateL = LOW;
      motorState = LOW;
  else
     // stateL = HIGH;
      motorState = HIGH;
    time = millis();    
}
  digitalWrite(ledPin, motorState);
  previous = val;
}
/////////// END LEFT LIMIT

///////////////// RIGH LIMIT BUTTON ////////////
void checkLimitRight(){
  val = digitalRead(limitRightBTN);
  // if the input just went from LOW and HIGH and we've waited long enough
  // to ignore any noise on the circuit, toggle the output pin and remember
  // the time
  if (val == HIGH && previous == LOW && millis() - time > debounce) {
    if (motorState == HIGH)
     // stateR = LOW;
      motorState = LOW;
    else
      //stateR = LOW;
      motorState = HIGH;
    time = millis();    
  }
  digitalWrite(ledPin, motorState);
  previous = val;
}
/////////// END RIGHT LIMIT

///////////////// START STOP BUTTON ////////////
void checkSSBTN(){
  val = digitalRead(startStopBTN);
  // if the input just went from LOW and HIGH and we've waited long enough
  // to ignore any noise on the circuit, toggle the output pin and remember
  // the time
  if (val == HIGH && previous == LOW && millis() - time > debounce) {
    if (motorState == HIGH)
      motorState = LOW;
     // stop motor
    else
      motorState = HIGH;
// start motor
    time = millis();    
  }
  digitalWrite(ledPin, motorState);
  previous = val;
}
///////////////// END START STOP BUTTON ////////////


//////////////////////// STEPPER FUNCTIONS //////////////

///////////////////////// DIRECTION /////////////////////
void getDir(){
  /// LED lights with 9volt power on
  digitalWrite(ledPin, HIGH);
  if (digitalRead(switchPin)){ //if the switch is HIGH, rotate clockwise
    digitalWrite(DIR_PIN,HIGH);
    // Serial.println("Fwd");
  }
  else { // if the swtich is LOW, rotate counter clockiwise
    digitalWrite(DIR_PIN,LOW);
    //  Serial.println("Rev");
  }
}

void rotate(){
  ///////////// DO I check the value of motorState here to run the function if HIGH
  val = digitalRead(startStopBTN);
  if (motorState == HIGH){
  motorState = LOW;
  getDir();
  for(int i=0; i < 1600 * .125; i++){
    int usDelay = map(analogRead(A0), 10, 1000, 10, 7000);
    usDelay = constrain(usDelay, 10, 7000);

    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(usDelay);

    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(usDelay);
    Serial.println ("ROTATE");
  }
}else{
  motorState = HIGH;
  Serial.println ("DONT ROTATE");
// start motor
    time = millis();    
  }
  digitalWrite(ledPin, motorState);
  previous = val;

}

void duration (){
// I need to set total steps here
// accelStepper would be great to use here too
}

Hi Robin, yes I know and its been confusing me - I am going to stick with your way as my previous post shows.

What are your thoughts on it?

Thanks
Mark

It may be easier if you stick to describing the project in english for the moment and leave the code until later.

This sketch does the following
Two limit switches Left and Right to detect when something hits them var is motorState
Push button to start and stop the stepper - same var motorState

How can it possibly make sense to have all these different things recorded in the same variable?

How will you know (say) that the motor has hit the left limit switch and can only move to the right?

Think through this more carefully and come back with the logic that you think covers all possibilities in an easy to understand manner.

When you have that figured out writing the code will be easy.

...R

How can it possibly make sense to have all these different things recorded in the same variable?

Hi Robin, well its on or off. Dolly runs along track all the way to end and hits the limit switch = motor off = variable changed.
Hit start button and motor runs again in other direction = motor on and direction changed.
Dolly moves all the way to other end and hits the second limit switch = motor off
Press the start button again = motor on and reverse direction.

It worked with turning an LED light on and off in testing, and yes I also tried it with using a separate variable for each switch. Which also worked, I was just trying to simplify the code by using on variable.

Im sure you know better than I with programming! I am still learning here bare with me please...

SORRY! :stuck_out_tongue:

Do you grasp the mechanics of what I am attempting here though?
Run a dolly along a track from one end to the other.
IF I want to stop the dolly mid track I can hit the stop button (pause so to speak)
Otherwise let it run all the way to end for a number of steps (how ever many steps it takes, ill figure this number out later).
If the dolly overshoots the end point it hits the limit switch and stops the motor.
When I hit start again the motor does the routine again in the reverse direction.

Make sense?