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?
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.
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);
}
}
}
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.
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();
}
}
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?
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.
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.
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