I'm trying to run a stepper motor as a second-hand for a chronometer. A single button will start, stop and reset the second hand in that order.
I need it to revolve at 1rpm, obviously!
I find that once the motor is running the sketch will not accept any further input until the motor has completed one full revolution.
I'm guessing that telling it to run for 2048 steps is not the way to do it, but i can't see any other way of guaranteeing it will reolve at the correct speed. helop appreciated:
/*
State change detection (edge detection)
Often, you don't need to know the state of a digital input all the time, but
you just need to know when the input changes from one state to another.
For example, you want to know when a button goes from OFF to ON. This is called
state change detection, or edge detection.
This example shows how to detect when a button or button changes from off to on
and on to off.
The circuit:
- pushbutton attached to pin 2 from +5V
- (10 kilohm resistor attached to pin 2 from ground)
- acutally INPUT_PULLUP used for button
created 27 Sep 2005
modified 30 Aug 2011
by Tom Igoe
Modified badly by Roger October 2023
This example code is in the public domain.
https://www.arduino.cc/en/Tutorial/BuiltInExamples/StateChangeDetection
*/
#include <Stepper.h>
// this constant won't change:
const int buttonPin = 6; // the pin that the pushbutton is attached to
// Variables will change:
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
const int stepsPerRevolution = 2048;
//Use pin 2-5 to IN1-IN4
Stepper CAPT_chrono_needle = Stepper(stepsPerRevolution, 5, 3, 4, 2);
void setup() {
//Set the RPM of the stepper motor
CAPT_chrono_needle.setSpeed(1);
// initialize the button pin as a input:
pinMode(buttonPin, INPUT_PULLUP);
// initialize serial port
Serial.begin(9600);
Serial.println(buttonState);
}
void loop() {
// read the pushbutton input pin:
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
// if the state has changed, increment the counter
if (buttonState == LOW) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter++;
if (buttonPushCounter > 2) { buttonPushCounter = 0; }
switch (buttonPushCounter) {
case 0:
//do something when var equals 0
Serial.println("Chrono home");
break;
case 1:
//do something when var equals 1
Serial.println("Chrono running");
CAPT_chrono_needle.setSpeed(1);
CAPT_chrono_needle.step(stepsPerRevolution);
break;
case 2:
//do something when var equals 2
Serial.println("Chrono stopped");
CAPT_chrono_needle.setSpeed(0);
break;
default:
// if nothing else matches, do the default
// default is optional
break;
}
//Serial.println("on");
Serial.print("number of button pushes: ");
Serial.println(buttonPushCounter);
} else {
// if the current state is LOW then the button went from on to off:
//Serial.println("off");
}
// Delay a little bit to avoid bouncing
delay(50);
}
// save the current state as the last state, for next time through the loop
lastButtonState = buttonState;
}
The stepper-library is the most unsuitable one for such tasks.
accelStepper might work. But I recommend using a different stepper-motor-library
The name is MobaTools.
The MobaTools create the step-pulse "in the backround" this enables to execute code "in parallel" to the step-pulse-creation.
This means you can read in buttons all the time and stop the stepper-monitor at any time.
I do not understand what you mean by "second hand"
I'm pretty sure it is not meant as "buy a used product second hand"
So does this mean
first button-press makes the stepper-motor run
second press stops the stepper-motor
third press moves the stepper-motor and the pin back to zero?
Lots of more elegant approaches will be suggested, but couldn't you run 60 x 2048/60 steps? (yes, I know, non-integer result, read on).
Resolves to 34.1333 steps per second. However, there's going to be some software overhead in there, might actually offset that 0.1333.
I'd try that, anyway.
Here is a MobaTools program to run 1 turn at 1 RPM. Is this accurate enough? Note that you can adjust the speed in 1/10 RPM increments to help to achieve the longer term accuracy that you want.
The MobaTools library is available for installation via the IDE library manager.
I guess maybe 30 seconds inaccuracy would be acceptable. The chronometer is planned to go into my flight simulator cockpit. Even when playing, one can end up in “the hold” for a while. Each "lap" round the hold takes about 4 minutes. If you're in the hold for 30 mins, then thats 7.5 laps. Maybe 3 seconds per lap, so 25 - 30 seconds over 30 mins.
So an accuracy of 1 second/minute would be optimal, i.e. 1,000/1,800,000 milliseconds.
I'm using an Arduino MEGA 2560 with a 28BYJ-48 stepper motor driven by a ULN2003 driver board. I'm not sure this board is compatible with MobaTools though.
Been playing with MobaTools this eve - seems it might just work! Thanks for the guidance. I have a few hours of learning ahead of me so I'll be quiet for a while - but no doubt will have more questions later. Thanks again for the help - so quickly too! I haven't marked any post as the solution yet, since you all contributed. Not sure how to do that - unless i can mark more than one post as the solution?
I played with it till well past midnight last night.
I now have it starting and stopping with the button. I just need to work out how to tell the needle to go back to zero (at a faster speed) when the button is pressed for the third time. In reality, the needle will always take the shortest path back to the zero position, so I'm guessing I'll need to see how many steps it has completed when I do press #3 - and then give it a negative value if less than half, or positive if half or more.
I'll let you know how I get on and post code once working.
If using MobaTools and using the setZero() function in setup() you should be able to call a moveTo(0) function and the motor will go to the starting position. The library keeps track of position so knows where home is.
The move function is relative. If you say move(100) it will move 100 steps. If you say move(100) again it will move another 100 steps.
The moveTo() function is absolute. If you are at 0 and say moveTo(100) the motor will move 100 steps. If you say moveTo(100) again nothing will happen since it is already at 100.