Still can't stop or home stepper motor. Please help

Hello again.

I'm still stuck on my project. I have a Nema-23 size/format, bi-polar stepper motor being driven by a StepperOnline DM556T driver and controlled with an ESP8266 NodeMCU microcontroller. The motor is attached to a linear rail with a carriage that runs along a screw drive (the motor turns the screw drive). I have a joystick connected for moving the carriage manually after the device "homes" at start-up. The home and endstops that I am using are hall-effect sensors (magnets on the carriage trip the sensors). The code operating the joystick works wonderfully. No problems there.

What I have problems with is trying to home the carriage when the program stops (and then later trying to have the endstops do their function). Right now, I'm concentrating on getting the homing procedure correct. What I want it to do at start up is start moving the carriage in one direction until it reaches the endstop at that end. Once the endstop is tripped, I want the carriage to move away from the endstop about 500 steps at a slower speed, then return to the stop at an even slower speed so that when the sensor trips for the second time I will be more confidant in it's repeatablility. After this, the carriage needs to move back off of the stop 500 steps again (just enough to clear the sensor) at which point I can set that position to zero.

The code I've been working with is below. Right now, when I turn the system on, the carriage will move (motor will turn) until it trips the sensor at which point the motor and carriage stops. Perfect! Here's the delema I'm having... If I put anything else after the "reset home" function, the motor will come to almost a stop, then slowly stutter for another few steps, then trys to take off again. It repeats this until the magnet clears the sensor, then it takes off at full speed again. Any guidance or help will be appreciated. Here's me code:

/* StepperZ_Project_rev38 - includes rev36 baseline plus added lower (homing) stop
    using a hall effect sensor.  Joystick powered by controller, stop powered by 5v.
*/

/* -------------- LIBRARIES USED ------------------------------------------------- */
#include <AccelStepper.h>  //accelstepper library

/* -------------- ASSIGNED PINS -------------------------------------------------- */
const byte xJoyPin = A0;  //x-axis readings
const byte stepPin = D1;
const byte dirPin = D2;
const byte stopUp = D6;
const byte stopDown = D7;

/* -------------- VARIABLES ------------------------------------------------------ */
int xJoy = 0;  //x-axis value
int dirVal = 0;
int xJoy_AVG = 0;  //x-axis value average
long speedVal = 0;
int stopVal = 0;

/* -------------- INITIATE DRIVER ------------------------------------------------ */
AccelStepper xStepper(AccelStepper::DRIVER, stepPin, dirPin);  // direction Digital 2, pulses Digital 1

/*================================ VOID SET-UP FUNCTION ========================== */
void setup() {

  Serial.begin(115200);

  pinMode(xJoyPin, INPUT);
  pinMode(stopUp, INPUT_PULLUP);
  pinMode(stopDown, INPUT_PULLUP);

  digitalWrite(dirPin, HIGH);

  InitialValues();  //averaging the values of the 3 analog pins (values from potmeters)

  xStepper.setMaxSpeed(5000);     //SPEED = Steps / second
  xStepper.setAcceleration(750);  //ACCELERATION = Steps /(second)^2
  delay(1000);

  resetHome();
}

/* ================================ MAIN LOOP FUNCTION ============================ */
void loop() {
  ReadAnalog();

  xStepper.runSpeed(); /* step the motor (this will step the motor by 1 step at each loop indefinitely) */
}


/* ================================ READ ANALOG (JOYSTICK LOOP) ============================ */
/*  This function reads the joystick signal, checks it against
                     *  the average taken in the Set-Up. If the difference is over 25, 
                     *  it uses the value to determine the speed of the motor.  This is 
                     *  "buffer" for when the joystick is supposed to be in the upright
                     *  (non-input) position.
                     */
void ReadAnalog() {
  /* Reading the potentiometer in the joystick: x.  */
  xJoy = analogRead(xJoyPin);
  speedVal = (xJoy - xJoy_AVG);
  if (speedVal < 0) {
    dirVal = (-1);
  }
  if (speedVal > 0) {
    dirVal = 1;
  }

  /* If the value is 25 "value away" from the average (midpoint), we allow the update of the speed
     This is a sort of a filter for the inaccuracy of the reading */
  if (abs(xJoy - xJoy_AVG) > 25) {
    if (abs(speedVal) > 25 && abs(speedVal) < 300) {
      xStepper.setSpeed(speedVal);
    }
    if (abs(speedVal) > 299 && (abs(speedVal) < 460)) {
      xStepper.setSpeed(2.5 * speedVal);
    }
    if (abs(speedVal) > 459) {
      xStepper.setSpeed(5 * speedVal);
    }
  }
  if (abs(xJoy - xJoy_AVG) < 25) {
    speedVal = 0;
    xStepper.setSpeed(speedVal);
  }
}

/* ================================ INITIAL VALUES FUNCTION ======================= */
/*  This function takes 50 readings from joystick
                        prior to operation and records an average to
                        use in caluculating the speed.
                    */
void InitialValues() {
  /* --------- Set the values to zero before averaging ---------------------------- */
  float tempX = 0;

  /* ------------ Read the joystick 50x, then calculate an average. --------------- */
  for (int i = 0; i < 50; i++) {
    tempX += analogRead(xJoyPin);
    delay(10);  //allowing a little time between two readings
  }

  xJoy_AVG = tempX / 50;
}

/* ================================ HOMING FUNCTION =============================== */
/*  After tripping the lower stop, the carriage is
                        to change direction and move out from the stop
                        150 steps @ 200 steps/sec.
*/

void resetHome() {
  xStepper.moveTo(100000);
  xStepper.setSpeed(300);
  while (digitalRead(stopUp) != 0) {
    yield();
    xStepper.run();
    if (digitalRead(stopUp) == 0) {
      break;
    }
  }
  xStepper.stop();
  xStepper.move(0);
  xStepper.setSpeed(0);
  xStepper.runToPosition();

  return;
}

The you really need a more reliable end stop, such as a microswitch. They are either on or off, no ambiguity. You don't care about bounce, so don't bring that up. You only care about the FIRST contact of the switch components.

I think your library has a set position function so that you can call the home position zero (or whatever) once you find it.

Then you can use runtoposition perhaps to step away the required 500 steps. Then home again.

I would put the entire startup/initiation down in setup(), after the reset call.

Hi Paul and thank you for the response.

Okay, even if the microswitch is "more reliable", isn't it possible for the carriage/motor running at full speed to actually travel a few thousandths further than if it was only running 20% of full speed? Even with microswitches, I would still want at least one bouce. The bounce is what I'm struggling with.

Ron.

[quote="jsmwrench, post:5, topic:955977"]
Okay, even if the microswitch is "more reliable", isn't it possible for the carriage/motor running at full speed to actually travel a few thousandths further than if it was only running 20% of full speed?
[/quote] Of course it can move beyond.
That is why no industrial machine ever does what you have designed. They all count the steps so they know exactly where the carriage is at EVERY step.

wildbill,

I appreciate your response. Yes, the library does have that function. The problem I have is if I do what you are saying (after the program is supposed to have escaped the while loop - tripping the stop), then the motor will slow to almost a stop, then stop and start stutter-moving in the original direction several times.... stop again .... then start the stutter-moving again.... and just repeats this until it clears the sensor at which time it just takes off full speed again (like it went BACK into the while loop).

Ron.

Suggest you begin to consider the code you have should be rewritten.

Railroader,

Thank you for your response.

The function is called from the Set-up. It was up there originally. After I got it to actually stop the motor like it was supposed to, I moved it into it's own function. I did this so that I can call on it anytime the carriage trips an endstop (minus setting "zero", like I do when homing).

Regardless, the outcome is the same whether it is entirely in Set-up or in it's own function.

Ron.

Thank you all for your participation in this. Just so we don't get lost in some of the "other" issues I have with my code, I would like to clarify the area I'm having trouble with.

The real issue is that if I add ANYTHING to the code after it homes (even outside of the homing function), the motor/carriage doesn't completely stop like it is supposed to. The program acts like it returns to the While-loop that it was in when it originally tried homing. I don't understand how the code can do this or what is causing it.

Again, any insight or help will be appreciated.
Ron.

Post a version of the code that exhibits those symptoms.

/* StepperZ_Project_rev38 - includes rev36 baseline plus added lower (homing) stop
    using a hall effect sensor.  Joystick powered by controller, stop powered by 5v.
*/

/* -------------- LIBRARIES USED ------------------------------------------------- */
#include <AccelStepper.h>  //accelstepper library

/* -------------- ASSIGNED PINS -------------------------------------------------- */
const byte xJoyPin = A0;  //x-axis readings
const byte stepPin = D1;
const byte dirPin = D2;
const byte stopUp = D6;
const byte stopDown = D7;

/* -------------- VARIABLES ------------------------------------------------------ */
int xJoy = 0;  //x-axis value
int dirVal = 0;
int xJoy_AVG = 0;  //x-axis value average
long speedVal = 0;
int stopVal = 0;

/* -------------- INITIATE DRIVER ------------------------------------------------ */
AccelStepper xStepper(AccelStepper::DRIVER, stepPin, dirPin);  // direction Digital 2, pulses Digital 1

/*================================ VOID SET-UP FUNCTION ========================== */
void setup() {

  Serial.begin(115200);

  pinMode(xJoyPin, INPUT);
  pinMode(stopUp, INPUT_PULLUP);
  pinMode(stopDown, INPUT_PULLUP);

  digitalWrite(dirPin, HIGH);

  InitialValues();  //averaging the values of the 3 analog pins (values from potmeters)

  xStepper.setMaxSpeed(5000);     //SPEED = Steps / second
  xStepper.setAcceleration(750);  //ACCELERATION = Steps /(second)^2
  delay(1000);

  resetHome();
}

/* ================================ MAIN LOOP FUNCTION ============================ */
void loop() {
  ReadAnalog();

  xStepper.runSpeed(); /* step the motor (this will step the motor by 1 step at each loop indefinitely) */
}


/* ================================ READ ANALOG (JOYSTICK LOOP) ============================ */
/*  This function reads the joystick signal, checks it against
                     *  the average taken in the Set-Up. If the difference is over 25, 
                     *  it uses the value to determine the speed of the motor.  This is 
                     *  "buffer" for when the joystick is supposed to be in the upright
                     *  (non-input) position.
                     */
void ReadAnalog() {
  /* Reading the potentiometer in the joystick: x.  */
  xJoy = analogRead(xJoyPin);
  speedVal = (xJoy - xJoy_AVG);
  if (speedVal < 0) {
    dirVal = (-1);
  }
  if (speedVal > 0) {
    dirVal = 1;
  }

  /* If the value is 25 "value away" from the average (midpoint), we allow the update of the speed
     This is a sort of a filter for the inaccuracy of the reading */
  if (abs(xJoy - xJoy_AVG) > 25) {
    if (abs(speedVal) > 25 && abs(speedVal) < 300) {
      xStepper.setSpeed(speedVal);
    }
    if (abs(speedVal) > 299 && (abs(speedVal) < 460)) {
      xStepper.setSpeed(2.5 * speedVal);
    }
    if (abs(speedVal) > 459) {
      xStepper.setSpeed(5 * speedVal);
    }
  }
  if (abs(xJoy - xJoy_AVG) < 25) {
    speedVal = 0;
    xStepper.setSpeed(speedVal);
  }
}

/* ================================ INITIAL VALUES FUNCTION ======================= */
/*  This function takes 50 readings from joystick
                        prior to operation and records an average to
                        use in caluculating the speed.
                    */
void InitialValues() {
  /* --------- Set the values to zero before averaging ---------------------------- */
  float tempX = 0;

  /* ------------ Read the joystick 50x, then calculate an average. --------------- */
  for (int i = 0; i < 50; i++) {
    tempX += analogRead(xJoyPin);
    delay(10);  //allowing a little time between two readings
  }

  xJoy_AVG = tempX / 50;
}

/* ================================ HOMING FUNCTION =============================== */
/*  After tripping the lower stop, the carriage is
                        to change direction and move out from the stop
                        150 steps @ 200 steps/sec.
*/

void resetHome() {
  xStepper.moveTo(100000);
  xStepper.setSpeed(300);
  while (digitalRead(stopUp) != 0) {
    yield();
    xStepper.run();
    if (digitalRead(stopUp) == 0) {
      break;
    }
  }
  xStepper.stop();
  xStepper.move(0);
  xStepper.setSpeed(0);
  xStepper.runToPosition();

  stopVal = digitalRead(stopUp);

  xStepper.move(-500);
  xStepper.setSpeed(175);
  xStepper.runToPosition();

  return;
}

I don't understand Your words. After calling homing, continue with the stepping out, slowly stepping back etc until You reach the zero position. Do all this before setup is left.

This makes no sense. It sounds like You got stuck with Your feet in cement. Get a bit more scientific, a bit more engineer using precise descriptions.

Using serial monitor and debugging Serial.print was my help during many, many, projects facing large, unknown and failing projects.
Use that to find out what's happening in the code.

Railroader,

Okay, I moved the entire function up into the Set-up (code is below). When it starts up, the motor begins moving in one direction. When the magnet on the carriage "trips" the sensor, the motor slows and stops (doesn't come to a dead stop) then immediately changes direction and goes the 500 steps I call for. It then stops for a second or two, and then returns to moving in the original direction until the stop is tripped again, at which time it changes direction and moves the 500 steps I called for. It will continue doing this over and over. During this movement, the joystick has no control (which I didn't expect until the homeing procedure is completed.... it never completes the homing procedure). It never drops out of the Set-up and never enters the void-loop.

I checked the serial monitor and I'm getting a Soft WDT reset error.

I'm not sure what this means but this is what is printed in the serial monitor:

Soft WDT reset

stack>>>

ctx: cont
sp: 3ffffdc0 end: 3fffffc0 offset: 01a0
3fffff60: 40201ce8 3ffe87e9 3ffee5c8 40201637
3fffff70: 3ffe87e9 3ffee5c8 3ffee548 40201911
3fffff80: 3fffdad0 3ffee5c8 3ffee548 40201b33
3fffff90: 3ffe87e9 3ffee5c8 3ffee548 40201284
3fffffa0: 3fffdad0 00000000 3ffee61c 402027cc
3fffffb0: feefeffe feefeffe 3ffe85d8 40100f59
<<<stack<<<

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

ets Jan 8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 3460, room 16
tail 4
chksum 0xcc
load 0x3fff20b8, len 40, room 4
tail 4
chksum 0xc9
csum 0xc9
v00043640
~ld

SDK:2.2.2-dev(38a443e)/Core:3.0.2=30002000/lwIP:STABLE-2_1_2_RELEASE/glue:1.2-48-g7421258/BearSSL:6105635

Runtoposition blocks. But before you call it you set speed to zero. I suspect that is where the problem lies.

wildbill,

Okay. I'll have to read through the library again. Unfortunately, my night is finished (family calls) but I will dive into it again Wednesday night.

Thank you all again for your assistance.
Ron.

As told, post the code.

The main goal of a homing function is to tell the AccelStepper where your reference point is. After you did so, AccelStepper knows from which position to count the steps. This is done by setCurrentPosition, what you never call. So you homing function will never do its job: telling AccelStepper the new reference position.
xStepper.move(0);
will go to this reference position. But because you did not set it to your reference point before, it will still go to the position of the stepper when starting the sketch ( the initial reference point ).
Edit: my mistake - move(0) will do nothing, because it's a relative move. ( moveTo(0) would move the stepper to the zero point). But nevertheless you miss to tell AccelStepper where the reference point is.

All this commands:

  xStepper.stop();
  xStepper.move(0);
  xStepper.setSpeed(0);
  xStepper.runToPosition();

  stopVal = digitalRead(stopUp);

  xStepper.move(-500);
  xStepper.setSpeed(175);
  xStepper.runToPosition();

don't make any sense.

Next to consider:

  xStepper.setSpeed(300);
  while (digitalRead(stopUp) != 0) {
    yield();
    xStepper.run();

The combination of setSpeed and run() doesn't make sense either. run() uses acceleration and deceleration. The target speed is determined by setMaxSpeed in this case. setSpeed is overwritten by run() internally - no matter how you set it before.

You should study the AccelStepper documentation thorougly :wink:

2 Likes