stepper speed control within functions

Hi all.

I’m creating a station within an automation cell that will produce branded wooden coasters. Basically a robot arm will place a coaster on a carriage controlled by a typical stepper with a timing belt(position RDR), it will move to the branding position(position BRD), move further to be examined by a vision system(position INS), then return to the original position for the robot to pick it again.
Each position within the station has a photosensor. My code involves the usual declarations, setup with pin modes with a “homing to RDR,” instantiation of functions for each of the moves including debounces, then a void loop() that calls the move functions with timed delays in between.
This code functions as it should in terms of movement, but I’d like to control the speed at which the carriage moves from position to position using a potentiometer. I’ve had success with a POT using a clockwise/counterclockwise pushbuttons project, but haven’t had success here. Motor wants to just stay at one very slow speed.
New to C++ and I know I could go the whole Accelstepper or whatever, but the goal is to incorporate the other inputs and outputs that control when the carriage moves into the void loop() so I can keep the code simple.
Also, I haven’t incorporated the LS’s nor steps in any of this yet. Any advice on how to create “e-stops” would be helpful as well.
Actually, any advice would be awesome.

-Karl

/*
 * stepper test
 */

// define physical pins

int driverPUL = 7; //PUL pin
int driverDIR = 6; //DIR pin
int LS_neg = 4; //back limit switches shutoff
int LS_pos = 2; //front limit switch 
int RDR = 8; //position that robot can drop and pick part
int BRD = 12; //position for branding iron
int INS = 13; //position for vision system inspection
int spd = A0; //potentiometer to control speed of motor

// variables

int pd = 500; //pulse delay period

void setup(){

  //setup whether pin is output or input

  pinMode (driverPUL, OUTPUT); //setup kind of pin
  pinMode (driverDIR, OUTPUT);
  pinMode (LS_neg, INPUT);
  pinMode (LS_pos, INPUT);
  pinMode (RDR, INPUT);
  pinMode (BRD, INPUT);
  pinMode (INS, INPUT);
  
  reset_pins(); // reset output pins to low states
  
  //homing procedure of stepper at startup within setup

  while (digitalRead(RDR)) {  //do this until the switch is activated   
    digitalWrite(driverDIR, HIGH);     
    digitalWrite(driverPUL, HIGH);
    delay(5);                       //slow approach to pick drop position
    digitalWrite(driverPUL, LOW);
    delay(5);   
  }

  while (!digitalRead(RDR)) { //do this until the switch is NOT activated
    digitalWrite(driverDIR, LOW); 
    digitalWrite(driverPUL, HIGH);
    delay(10);                       //slow even more while moving away from switch
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

}


//define all functions

void reset_pins() { //writes function to set outputs to low
  
  digitalWrite(driverPUL, LOW);
  digitalWrite(driverDIR, LOW);
 
}

//function to move to BRD sensor

void go_to_BRD() {
  
  while (digitalRead(BRD)) {

    pd = map((analogRead(spd)), 0, 1023, 2000, 50);
    digitalWrite(driverDIR, LOW);
    digitalWrite(driverPUL, HIGH);
    delay(pd);
    digitalWrite(driverPUL, LOW);
    delay(pd);
  }

  while (!digitalRead(BRD)) {

    digitalWrite(driverDIR, HIGH);
    digitalWrite(driverPUL, HIGH);
    delay(10);
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

}

//function to move to INS sensor


void go_to_INS() {
  
  while (digitalRead(INS)) {

    pd = map((analogRead(spd)), 0, 1023, 2000, 50);
    digitalWrite(driverDIR, LOW);
    digitalWrite(driverPUL, HIGH);
    delay(pd);
    digitalWrite(driverPUL, LOW);
    delay(pd);
  }

  while (!digitalRead(INS)) {

    digitalWrite(driverDIR, HIGH);
    digitalWrite(driverPUL, HIGH);
    delay(10);
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

}

//function to move to RDR sensor


void go_to_RDR() {

  while (digitalRead(RDR)) {

    pd = map((analogRead(spd)), 0, 1023, 2000, 50);
    digitalWrite(driverDIR, HIGH);
    digitalWrite(driverPUL, HIGH);
    delay(pd);
    digitalWrite(driverPUL, LOW);
    delay(pd);
  }

  while (!digitalRead(RDR)) {

    digitalWrite(driverDIR, LOW);
    digitalWrite(driverPUL, HIGH);
    delay(10);
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

}

//action sequence

void loop() {

  go_to_BRD();

  delay(2000);

  go_to_INS();

  delay(2000);

  go_to_RDR();

  delay(2000);

}

If you want a responsive program you will need to get rid of all those WHILE loops. WHILE and FOR block the Arduino until they complete so your potentiometer can't be read. You may also find that you need to get rid of the use of delay() for the same reason.

Use IF and allow loop() to do the repetition.

Have a look at how the code is organized in Several Things at a Time

Note how each function runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.

The code also uses millis() for non-blocking timing. And the second example in this Simple Stepper Code may help. See Using millis() for timing. A beginners guide if you need more explanation.

...R

hinbernk:
New to C++ and I know I could go the whole Accelstepper or whatever, but the goal is to incorporate the other inputs and outputs that control when the carriage moves into the void loop() so I can keep the code simple.

The whole point of AccelStepper is to simplify the code.

That's a great place to start when using steppers for the first time, as all the complexity is kept in
the library and it runs in the background. Your code is typically much much simpler without having to
track stepper acceleration everywhere!

loop() is a function, not a void. A void is an empty space! The fact it doesn't return a value means
its return type is declared as "void".

For AccelStepper to do its magic you must called the run() method frequently, meaning no delay()
calls, all time scheduling needs to be done with millis() or micros().

I definitely will look into those options. The original idea of the while()'s was to debounce and get the carriage to absolute positioning without having to actually track steps and all that. Not sure how to do that without them. My focus with this code is to make the whole thing work first, then go back and smooth it out. I still have to roll in the mechanics of the branding iron press and the vision system. The good news is I've made the POT control the speed and have added a function that will wait for the external robot's I/O signal to go ahead. It works perfectly so far. Have look:

/*
 * stepper with homing, debounce, signal to go, and speed control
 */

// define physical pins

int driverPUL = 2; //PUL pin
int driverDIR = 3; //DIR pin
int LS_pos = 4; //back limit switches shutoff
int LS_neg = 5; //front limit switch 
int RDR = 6; //position that robot can drop and pick part
int BRD = 7; //position for branding iron
int INS = 8; //position for vision system inspection
int ARGO = 9; //"Arduino go" signal from robot I/O
int spd = A0; //potentiometer to control speed of motor

// variables

int pd = 500; //pulse delay period
int steps;   //store current number of steps from home after startup

// initial states

int stateCW = 0; //state of pushbuttons and limit switches
int stateCCW = 0;
int LS_neg_state = 0;
int LS_pos_state = 0;
int RDR_state = 0;
int BRD_state = 0;
int INS_state = 0;
int ARGO_state = 0;

void setup(){

  //setup whether pin is output or input

  pinMode (driverPUL, OUTPUT); //setup kind of pin
  pinMode (driverDIR, OUTPUT);
  pinMode (LS_neg, INPUT);
  pinMode (LS_pos, INPUT);
  pinMode (RDR, INPUT);
  pinMode (BRD, INPUT);
  pinMode (INS, INPUT);
  pinMode (ARGO, INPUT);
  
  reset_pins(); // reset output pins to low states
  
  //homing procedure of stepper at startup within setup

  while (digitalRead(RDR)) {  //do this until the switch is activated   
    digitalWrite(driverDIR, HIGH);     
    digitalWrite(driverPUL, HIGH);
    delay(1);                       //slow approach to pick drop position
    digitalWrite(driverPUL, LOW);
    delay(1);   
  }

  while (!digitalRead(RDR)) { //do this until the switch is NOT activated
    digitalWrite(driverDIR, LOW); 
    digitalWrite(driverPUL, HIGH);
    delay(10);                       //slow even more while moving away from switch
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

  reset_pins();

  steps = 0;  //set homed position of carriage as 0

}


//define pin reset function for startup

void reset_pins() { //writes function to set outputs to low
  
  digitalWrite(driverPUL, LOW);
  digitalWrite(driverDIR, LOW);
 
}

//define move to position functions

void go_to_BRD() {
  
  while (digitalRead(BRD)) {

    pd = map((analogRead(spd)), 0, 1023, 2000, 50);
    digitalWrite(driverDIR, LOW);
    digitalWrite(driverPUL, HIGH);
    delayMicroseconds(pd);
    digitalWrite(driverPUL, LOW);
    delayMicroseconds(pd);
  }

  while (!digitalRead(BRD)) {

    digitalWrite(driverDIR, HIGH);
    digitalWrite(driverPUL, HIGH);
    delay(10);
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

}

void go_to_INS() {
  
  while (digitalRead(INS)) {

    pd = map((analogRead(spd)), 0, 1023, 2000, 50);
    digitalWrite(driverDIR, LOW);
    digitalWrite(driverPUL, HIGH);
    delayMicroseconds(pd);
    digitalWrite(driverPUL, LOW);
    delayMicroseconds(pd);
  }

  while (!digitalRead(INS)) {

    digitalWrite(driverDIR, HIGH);
    digitalWrite(driverPUL, HIGH);
    delay(10);
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

}

void go_to_RDR() {

  while (digitalRead(RDR)) {

    pd = map((analogRead(spd)), 0, 1023, 2000, 50);
    digitalWrite(driverDIR, HIGH);
    digitalWrite(driverPUL, HIGH);
    delayMicroseconds(pd);
    digitalWrite(driverPUL, LOW);
    delayMicroseconds(pd);
  }

  while (!digitalRead(RDR)) {

    digitalWrite(driverDIR, LOW);
    digitalWrite(driverPUL, HIGH);
    delay(10);
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

}

//define wait for robot signal to go ahead function

void wait_for_ARGO() {

  while (digitalRead(ARGO));
  
  delay(2000);

}

//action sequences

void loop() {

  wait_for_ARGO();

  go_to_BRD();

  delay(2000);

  go_to_INS();

  wait_for_ARGO();

  go_to_RDR();

}

You can replace this

  while (!digitalRead(RDR)) { //do this until the switch is NOT activated
    digitalWrite(driverDIR, LOW); 
    digitalWrite(driverPUL, HIGH);
    delay(10);                       //slow even more while moving away from switch
    digitalWrite(driverPUL, LOW);
    delay(10);
  }

with something like this

if (step2done == true) {
    if (digitalRead(RDR) == HIGH) { // do this if the RDR is activated (not sure if HIGH is correct)
        digitalWrite(driverDIR, LOW); 
        digitalWrite(driverPUL, HIGH);
        delay(10);                       //slow even more while moving away from switch
        digitalWrite(driverPUL, LOW);
        delay(10);
    }
    else {
        step3Done == true;
    }
}

I'm suggesting the variables step2Done and step3Done as a means to allow the code to progress through the stages. There may be neater way.

...R

To be clear, by the code working I mean that I can adjust the speed of the carriage while the carriage is moving from position to position.

hinbernk:
To be clear, by the code working I mean that I can adjust the speed of the carriage while the carriage is moving from position to position.

That’s what I thought you meant.

…R