help with coding for a stepper motor

Hello,

I purchased the TB6600 stepper motor driver (here). I am wiring it up to a 3V 1.7A 68oz-in Stepper Motor (here). Ideally I’d like to run a basic test where it turns in one direction stops and then returns to its original position via the opposite direction. I am using the AccelStepepr library.

I tested the resistance and found that the pairings are:
Pair 1: Blue and Yellow
Pair 2: red and Green

Currently when I power it up the stepper motor turns clockwise, and doesn’t stop. I'm too use where im going wrong?

Here is the code:

#include <AccelStepper.h>


AccelStepper stepper (1,3,2); // name of stepper motor (1 = driver, pin 3 = step, pin 2 = direction)


void setup() {
 
    stepper.setMaxSpeed(1000);
    stepper.setAcceleration(1000);
}

void loop()
{
stepper.stop();
stepper.moveTo(stepper.currentPosition()-10);
stepper.run();
stepper.moveTo(stepper.currentPosition()+20);
stepper.run();
}

and here is the set up:

Thanks,

Photo-Tom:
Currently when I power it up the stepper motor turns clockwise, and doesn’t stop. I'm too use where im going wrong?

Every time loop() repeats you are increasing the number of steps you want the motor to move.

A simple fix is to move the line

stepper.moveTo(stepper.currentPosition()-10);

to the setup() function and delete the other similar line.

The longer term solution is only to change the moveTo() value when the stepper has reached its destination - something like

if (stepper.distanceToGo() == 0) {
   stepper.moveTo( nnnnn );
}

...R
Stepper Motor Basics
Simple Stepper Code

Brilliant,

thanks Robin2,

I altered the code to this:

AccelStepper stepper (1,3,2); // name of stepper motor (1 = driver, pin 3 = step, pin 2 = direction)


void setup() {
 
    stepper.setMaxSpeed(1000);
    stepper.setAcceleration(200);
}

void loop()
{
  stepper.moveTo(100);  // 
  while (stepper.distanceToGo() != 0) 
  {  stepper.run(); }

  stepper.moveTo(0);  // 
  while (stepper.distanceToGo() != 0) 
  {  stepper.run(); }
}

As it runs, the stepper doesn't always move back to its original starting position. Would this be because its missing steps? is there any way of limiting this?

Photo-Tom:
As it runs, the stepper doesn't always move back to its original starting position. Would this be because its missing steps? is there any way of limiting this?

Try a lower speed and acceleration. That should deal with missing steps.

The way you have written you code will work - but it is not the style in which AccelStepper is normally used - because the Arduino can do nothing until the WHILE completes.

If you build a more complex program using the same style the blocking will probably become a problem.

...R

Thanks Robin2,

i have removed the while from the code, and attempting to write the code correctly.

I have wired a pir motion sensor up to the arduino, i want the stepper to turn a 100 steps clockwise and then 100 steps counter clockwise when the pir is triggered. Im still new to coding, and have relied upon the arduino sample code for the pir and its not working. can you see the fault in the code?

Heres the code:

#include <AccelStepper.h>

AccelStepper stepper (1,3,2); // name of stepper motor (1 = driver, pin 3 = step, pin 2 = direction)
int pirPin = 4;    //the digital pin connected to the PIR sensor's output

int calibrationTime = 30;    

  //the time when the sensor outputs a low impulse
long unsigned int lowIn;         

//the amount of milliseconds the sensor has to be low 
//before we assume all motion has stopped
long unsigned int pause = 5000;  

boolean lockLow = true;
boolean takeLowTime;  



void setup() {
 
    stepper.setMaxSpeed(1000);
    stepper.setAcceleration(200);

    Serial.begin(9600);
  pinMode(pirPin, INPUT);
  digitalWrite(pirPin, LOW);

  //give the sensor some time to calibrate
  Serial.print("calibrating sensor ");
    for(int i = 0; i < calibrationTime; i++){
      Serial.print(".");
      delay(1000);
      }
    Serial.println(" done");
    Serial.println("SENSOR ACTIVE");
    delay(50);
  }


void loop()
{
  if(digitalRead(pirPin) == HIGH){
       stepper.moveTo(100);
 {  stepper.run(); }

stepper.moveTo(100);
 {  stepper.run(); }

       if(lockLow){  
         //makes sure we wait for a transition to LOW before any further output is made:
         lockLow = false;            
         Serial.println("---");
         Serial.print("motion detected at ");
         Serial.print(millis()/1000);
         Serial.println(" sec"); 
         delay(50);
         }         
         takeLowTime = true;
       }

    if(digitalRead(pirPin) == LOW){      

       if(takeLowTime){
        lowIn = millis();          //save the time of the transition from high to LOW
        takeLowTime = false;       //make sure this is only done at the start of a LOW phase
        }
       //if the sensor is low for more than the given pause, 
       //we assume that no more motion is going to happen
       if(!lockLow && millis() - lowIn > pause){  
           //makes sure this block of code is only executed again after 
           //a new motion sequence has been detected
           lockLow = true;                        
           Serial.print("motion ended at ");      //output
           Serial.print((millis() - pause)/1000);
           Serial.println(" sec");
           delay(50);
           }
       }

}

Photo-Tom:
can you see the fault in the code?

Why do you think there is a fault in the code?

If it won't compile please post the error the compiler produces

If it compiles but does not work as you would like tell us in detail what it actually does and how it needs to be different.

Without those inputs searching for a fault is like looking for a needle without even knowing which haystack to look in.

...R

apologies, I may have worded it wrong.

it does compile and upload to the board.

when the circuit is powered up, the motion sensor will detect movement and be triggered, but the stepper does not rotate. To pin point the problem, when the pirpin turns high, it does not activate the stepper as i would like it to: i would like the stepper to turn a 100 steps clockwise and then 100 steps counter clockwise when the pir is triggered.

If you use the AutoFormat feature to indent your code consistently you will have a much better sense of what parts go together - for example what code is encompassed by an IF or an ELSE.

Don't insert unnecessary braces {} such as here

{  stepper.run(); }

And if you only have one motor you only need stepper.run() in one place - usually the last item in loop() and NOT inside any IF or WHILE.

If that does not help please post the latest version of your program properly formatted.

...R

Thanks for the advice,

i have attempted to tidy up the formatting and code.

Below is the latest version. When i powered it up and triggered the motion sensor the stepper moved cw once. But it did not move ccw afterwards (to essentially return to its starting position). And when i triggered the motion sensor again the stepper didnt move at all.

#include <AccelStepper.h>

AccelStepper stepper (1, 3, 2); // name of stepper motor (1 = driver, pin 3 = step, pin 2 = direction)
int pirPin = 4;

int calibrationTime = 30;
long unsigned int lowIn;
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int PIRValue = 0;

void setup()
{

  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(200);

  Serial.begin(9600);
  pinMode(pirPin, INPUT);
}


void loop()
{
  PIRSensor();
}

void PIRSensor()
{
  if (digitalRead(pirPin) == HIGH)
  {
    if (lockLow)
    {
      stepper.moveTo(100);
      stepper.moveTo(-100);

      PIRValue = 1;
      lockLow = false;
      Serial.println("Motion detected.");
      delay(50);
    }
    takeLowTime = true;
  }

  if (digitalRead(pirPin) == LOW)
  {

    if (takeLowTime) {
      lowIn = millis();
      takeLowTime = false;
    }
    if (!lockLow && millis() - lowIn > pause)
    {
      PIRValue = 0;
      lockLow = true;
      Serial.println("Motion ended.");
      delay(50);
    }

    stepper.run();
  }
}

You still have the line stepper.run() inside an IF statement. Move it to loop() so it is like this

void loop()
{
  PIRSensor();
  stepper.run();
}

And get rid of all the delay()s. If you need intervals use millis() to manage the timing without blocking as illustrated in Several Things at a Time

...R

Thanks Robin2,

i have moved the stepper.run and read through the post you linked to and this tutorial

Below is the altered code, no when i power it up i get no response from the stepper when the pir is triggered.

#include <AccelStepper.h>

AccelStepper stepper (1, 3, 2); // name of stepper motor (1 = driver, pin 3 = step, pin 2 = direction)
int pirPin = 4;

int calibrationTime = 30;
long unsigned int lowIn;
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int PIRValue = 0;
long previousMillis = 0;
long interval = 1000;


void setup()
{

  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(200);

  Serial.begin(9600);
  pinMode(pirPin, INPUT);
}


void loop()
{
  PIRSensor();
  stepper.run();
}

void PIRSensor()
{
  if (digitalRead(pirPin) == HIGH)
  {
    if (lockLow)
    {
      stepper.moveTo(100);
      stepper.moveTo(-100);

      PIRValue = 1;
      lockLow = false;
      Serial.println("Motion detected.");

      unsigned long currentMillis = millis();

      if (currentMillis - previousMillis > interval)
        previousMillis = currentMillis;
    }
    takeLowTime = true;
  }

  if (digitalRead(pirPin) == LOW)
  {

    if (takeLowTime) {
      lowIn = millis();
      takeLowTime = false;
    }
    if (!lockLow && millis() - lowIn > pause)
    {
      PIRValue = 0;
      lockLow = true;
      Serial.println("Motion ended.");

      unsigned long currentMillis = millis();

      if (currentMillis - previousMillis > interval)
        previousMillis = currentMillis;
    }

  }
}

I can't say I can follow the logic of your code but these two things come to mind

These two lines make no sense because the only one that will be recognized is the second one

      stepper.moveTo(100);
      stepper.moveTo(-100);

And this line

  if (digitalRead(pirPin) == LOW)

uses a completely different value from the pirPin to the value in the first IF statement. It is entirely possible that both IF statements could be true.

Try changing the line I have quoted to this

else

so that that part of the code is called if the first reading of pirPin is LOW

Can you explain the purpose of your different boolean variables?

...R

With this:

     stepper.moveTo(100);
      stepper.moveTo(-100);

my thinking was that when the pir is triggered HIGH the stepper will move 100 steps clockwise and then after that 100 steps counter clockwise.

In the second part if the pir does not detect any movement and remains low, then nothing should happen.

i cant explain the different boolean variables as this was a basic code i got from this PIRsense code page.

My thinking for the overall project, and what im trying to get the code to do is;

  • when powered up, the motion sensor should have time to calibrate.
  • when motion is detected the stepper should turn a certain number of steps clockwise, then a certain amount of steps counterclockwise.
  • when the stepper is active there should be a delay with the motion sensor being triggered again until the the stepper has finished.
  • if no motion is detected, the stepper should do nothing.
#include <AccelStepper.h>

AccelStepper stepper (1, 3, 2); // name of stepper motor (1 = driver, pin 3 = step, pin 2 = direction)
int pirPin = 4;

int calibrationTime = 30;
long unsigned int lowIn;
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int PIRValue = 0;
long previousMillis = 0;
long interval = 1000;


void setup()
{

  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(200);

  Serial.begin(9600);
  pinMode(pirPin, INPUT);
}


void loop()
{
  PIRSensor();
  stepper.run();
}

void PIRSensor()
{
  if (digitalRead(pirPin) == HIGH)
  {
    if (lockLow)
    {
      stepper.moveTo(100);
      stepper.moveTo(-100);

      PIRValue = 1;
      lockLow = false;
      Serial.println("Motion detected.");

      unsigned long currentMillis = millis();

      if (currentMillis - previousMillis > interval)
        previousMillis = currentMillis;
    }
    takeLowTime = true;
  }

  else (digitalRead(pirPin) == LOW);
  {

    if (takeLowTime) {
      lowIn = millis();
      takeLowTime = false;
    }
    if (!lockLow && millis() - lowIn > pause)
    {
      PIRValue = 0;
      lockLow = true;
      Serial.println("Motion ended.");

      unsigned long currentMillis = millis();

      if (currentMillis - previousMillis > interval)
        previousMillis = currentMillis;
    }

  }
}

Photo-Tom:
With this:

     stepper.moveTo(100);

stepper.moveTo(-100);





my thinking was that when the pir is triggered HIGH the stepper will move 100 steps clockwise and then after that 100 steps counter clockwise.

This idea is all wrong - sorry. You still seem not to have grasped how the AccelStepper library works.

Those two lines behave as if you said move 100 and then changed your mind and said move -100. When the code gets to the line stepper.run() (which is where the actual movement happens) the only value that will be seen is the -100.

...R

Hi Robin2,

i have been struggling with it, even after reading copious threads and looking at the AccelStepper examples.

I have tried to incorporate the Bounce code, but all im getting is that the stepper turns once on start up and thats it.

Its important that the pir sensor has time to calibrate on start up and that the pir should not try to activate the stepper when the stepper is already moving. If there are any suggestions on how to achieve this is a cleaner way with the coding i'd be happy to give it a go?

#include <AccelStepper.h>

AccelStepper stepper (1, 3, 2); // name of stepper motor (1 = driver, pin 3 = step, pin 2 = direction)
int pirPin = 4;

int calibrationTime = 30;
long unsigned int lowIn;
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int PIRValue = 0;
long previousMillis = 0;
long interval = 1000;


void setup()
{

  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(200);
  stepper.moveTo(100);

  Serial.begin(9600);
  pinMode(pirPin, INPUT);


}


void loop()
{
  PIRSensor();
  stepper.run();
}

void PIRSensor()
{
  if (digitalRead(pirPin) == HIGH)
  {
    if (lockLow)
    {
      if (stepper.distanceToGo() == 0) {
        stepper.moveTo( -stepper.currentPosition() );
      }

      PIRValue = 1;
      lockLow = false;
      Serial.println("Motion detected.");

      unsigned long currentMillis = millis();

      if (currentMillis - previousMillis > interval)
        previousMillis = currentMillis;
    }
    takeLowTime = true;
  }

  else (digitalRead(pirPin) == LOW);
  {

    if (takeLowTime) {
      lowIn = millis();
      takeLowTime = false;
    }
    if (!lockLow && millis() - lowIn > pause)
    {
      PIRValue = 0;
      lockLow = true;
      Serial.println("Motion ended.");

      unsigned long currentMillis = millis();

      if (currentMillis - previousMillis > interval)
        previousMillis = currentMillis;
    }

  }
}

Photo-Tom:
I have tried to incorporate the Bounce code, but all im getting is that the stepper turns once on start up and thats it.

That is just adding another complication.

You did not respond to my question in Reply #11 to explain the purpose of your boolean variables. The names don't mean anything to me.

Maybe a more practical solution is to go back to basics. I suspect what you require is fairly simple but it has got tangled up because you are not familiar with how to use the AccelStepper library.

Write down in English (not code) the sequence of events that you want to happen.

...R

Hi Robin2,

i cant explain the different boolean variables as this was a basic code i got from an Arudino tutorial page.

What i want to happen is:

  • when powered up, the motion sensor calibrates.

  • When the motion sensor detects motion, it triggers the stepper motor to turn clockwise 200 steps.

  • Once the stepper motor has turned 200 steps CW it should turn 200 steps counter clockwise (thus returning to its starting position)

  • While the stepper is actively rotating there should be a delay in making it rotate again for a certain amount of time, (say 5 seconds).

  • If no motion is detected, the stepper should do nothing.

Photo-Tom:

  • While the stepper is actively rotating there should be a delay in making it rotate again for a certain amount of time, (say 5 seconds).

That all seems clear, apart from the piece I have quoted. Do you mean that when it moves 200 steps CW it should wait 5 seconds before the 200 CCW steps?

OR, do you mean that after it has done one out-and-back it should not start another one for at least 5 seconds?

Assuming the latter, I think I would write the program like this pseudo code ...

if PIR is detected 
   PIRdetected = true
   motorDirection = 'F'
    motorMoving = false

if PIRdetected == true
  if motorMovng == false
     if motorDirection == 'F'
         moveTo 200
         motorMoving = true
     else    // meaning motorDirection == 'R'
         moveTo -200
         motorMoving = true
  
  if motorMoving == true and distanceToGo == 0
     motorMoving = false
     if motorDirection = 'F'
           motorDirection = 'R'
     else
          PIRdetected = false
          motorDirection = 'F'
    

   stepper.run()

I have not built the 5 second interval into the above.
I have used 'F' to mean CW and 'R' to mean CCW

...R

Hi Robin2,

i meant the latter;

Robin2:
after it has done one out-and-back it should not start another one for at least 5 seconds

Thanks so much for the code, i am now trying to format it, although coming up with a few errors, on my part,

at the moment i cant seem to figure out the code: if (PIR is detected)

Do i need to declare PIR at the start of the sketch?

#include <AccelStepper.h>

AccelStepper stepper (1, 3, 2); // name of stepper motor (1 = driver, pin 3 = step, pin 2 = direction)
int pirPin = 4;

int calibrationTime = 30;


void setup() {

  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(200);

  Serial.begin(9600);
  pinMode(pirPin, INPUT);

}

void loop() {

  if (PIR is detected) {
    PIRdetected = true;
    motorDirection = 'F';
    motorMoving = false;
  }

  if (PIRdetected == true) {
    if (motorMovng == false) {
      if (motorDirection == 'F') {
        moveTo (200);
        motorMoving = true;
        else {   // meaning motorDirection == 'R'
          moveTo (-200);
          motorMoving = true;
        }
        if (motorMoving == true and distanceToGo() == 0) {
          motorMoving = false;
        }
        if (motorDirection = 'F') {
          motorDirection = 'R';
        }
        else {
          PIRdetected = false;
          motorDirection = 'F';
        }
      }
    }
  }
  stepper.run();


}

Photo-Tom:
at the moment i cant seem to figure out the code: if (PIR is detected)

What I wrote is not code - it is a description of what your code needs to do. AFAIK you already know how to detect a signal from your PIR.

...R