Maybe a little out of my league since the TxNamib Railroad does not reach far enough south to connect to Luderitz, where the last, unconnected turntable is.
But a good friend Chip Romig had turntable trouble and we decided implement two manual controls for the "get it closer quicker" and then "align it perfectly, going slower, smoothly" Arduino.
Of course, people who has the turntable as the main focus point, want to have better control, including sensors to align the table, but certainly has spent the time setting it up and calibrating it. And quite a number of times doing it again, which is where Chip decided to let the operator do all the alignment work himself.
So here it is, the crude two center-off-toggle switch solution to move a stepper motor faster with the first toggle and then slower with the second, so you can align them by eye-sight, like I've seen them do in Durango.
The Stepper motor for the code above, has 5 or 6 wires, which can be controlled with the 5th or the 5th and 6th wire connected to Vcc and then turning any of the 4 coils on by connecting the other wires to ground. Of course, not all at the same time, but by following the sequence diagram as shown in the motor's datasheet. This is called the Unipolar motor configuration.
In the Bipolar motor configuration you only get 4 wires (see BLK,GRN,RED and BLU below).
To turn the coils on with current flowing in all four steps, you need to be able to control the direction the current through the 2 coils as well. This requires an H-bridge circuit ($0.15 on Ebay), and shown below:
For controlling more than one Stepper, or need acceleration and deceleration, then AccelStepper would be a better choice.
Moving a Stepper back and forth with AccelStepper’s bounce example:
But a good friend Chip Romig had turntable trouble and we decided implement two manual controls for the "get it closer quicker" and then "align it perfectly, going slower, smoothly" Arduino.
Of course, people who has the turntable as the main focus point, want to have better control, including sensors to align the table, but certainly has spent the time setting it up and calibrating it. And quite a number of times doing it again, which is where Chip decided to let the operator do all the alignment work himself.
So here it is, the crude two center-off-toggle switch solution to move a stepper motor faster with the first toggle and then slower with the second, so you can align them by eye-sight, like I've seen them do in Durango.
/*
4 inputs, pulled high internally. Clockwise, counterclock-
wise and another set for going even slower.
Cycle through the states to turn the stepper clockwise or
in reverse for ccw, using the 4 output pins to drive the
FETs turning the coils on with the correct polarity.
LED flash every 2.5 seconds or faster depending on
which mode it is in.
Author: Gert 'Speed' Muller
2016.03.28
*/
#define VERSION "Stepper r004"
#define LED 13
// 4 Stepper motor pins:
#define P1 4
#define P2 5
#define P3 6
#define P4 7
#define DELAYBETWEEN 3
#define DELAYBETWEENMAX 20
#define DELAYPIN 5
#define TIMETOCHANGE 2000
unsigned long before = 0;
unsigned long now = 0;
int timestep = DELAYBETWEEN;
int readByte = 0;
// which pin is being toggled
int state = 0;
// bigger than zero to avoid divide by
zero, see LED toggle later
int mode = 1;
// The setup function runs once when
// you press reset or power the board
void setup( ) {
pinMode( LED, OUTPUT );
digitalWrite( LED, LOW );
pinMode( P1, OUTPUT );
pinMode( P2, OUTPUT );
pinMode( P3, OUTPUT );
pinMode( P4, OUTPUT );
digitalWrite( P1, LOW ); // turn pin off
digitalWrite( P2, LOW ); // turn pin off
digitalWrite( P3, LOW ); // turn pin off
digitalWrite( P4, LOW ); // turn pin off
Serial.begin( 115200 );
Serial.println( VERSION );
// need a GND pin on the same side as the A1-4 inputs
pinMode( A0, OUTPUT );
digitalWrite( A0, LOW ); // so drive it low.
pinMode( A1, INPUT_PULLUP ); // CW slow
pinMode( A2, INPUT_PULLUP ); // CCW slow
pinMode( A3, INPUT_PULLUP ); // CW slower
pinMode( A4, INPUT_PULLUP ); // CCW slower
// check inputs on startup, no real
// other use, just debug!
if ( digitalRead( A1 ) != HIGH ) {
Serial.println( "A1 LOW" );
} // if
if ( digitalRead( A2 ) != HIGH ) {
Serial.println( "A2 LOW" );
} // if
if ( digitalRead( A3 ) != HIGH ) {
Serial.println( "A3 LOW" );
} // if
if ( digitalRead( A4 ) != HIGH ) {
Serial.println( "A4 LOW" );
} // if
now = millis( );
before = now;
state = 0;
mode = 1;
} // setup
void stepPin( char pin, char multiply ) {
digitalWrite( pin, HIGH ); // coil on
delay( DELAYPIN ); // wait
digitalWrite( pin, LOW ); // coil off
delay( DELAYPIN ); // wait
delay( timestep * multiply );
} // stepPin
void counterOrClockWise( bool COUNTER, char multiply ) {
if ( COUNTER ) {
state -= 1; // states decreases going counter clockwise
if ( state < 0 ) state = 3; // roll under goes to 3
} else {
state += 1; // states increases going clockwise
if ( state > 3 ) state = 0; // roll over goes to 0
} // else
switch ( state ) {
case 0:
stepPin( P1, multiply );
break;
case 1:
stepPin( P3, multiply );
break;
case 2:
stepPin( P2, multiply );
break;
case 3:
stepPin( P4, multiply );
break;
default:
state = 0;
break;
} // switch
} // clockwise
// the loop function runs over and over again, forever
void loop( ) {
// sometimes you missed the VERSION,
// so sending a '?' repeats it
if ( Serial.available( ) > 0 ) {
readByte = Serial.read( );
if ( readByte == '?' ) {
Serial.println( VERSION );
} // if help
} // if available
// time tells if we need to toggle the LED
now = millis( );
// toggling the LED with a rate based on the mode
if ( ( now - before ) > ( TIMETOCHANGE / mode ) ) {
before = now;
digitalWrite( LED, !digitalRead( LED ) ); // toggle LED
} // if
// look which pin is connected to ground and do the highest
// priority one, clockwise slow, ccw slow, cw slower,
// ccw slower, else do nothing
if ( digitalRead( A1 ) != HIGH ) {
counterOrClockWise( false, 0 ); // false:CW, 0:slow
mode = 2;
} else {
if ( digitalRead( A2 ) != HIGH ) {
counterOrClockWise( true, 0 ); // true:Counter, 0:slow
mode = 3;
} else {
if ( digitalRead( A3 ) != HIGH ) {
counterOrClockWise( false, 1 ); // false:CW, 1:slower
mode = 4;
} else {
if ( digitalRead( A4 ) != HIGH ) {
counterOrClockWise( true, 1 ); // true:Counter,
// 1:slower
mode = 5;
} else {
mode = 1; // no button, flash LED slowest!
} // else, not cw0
} // else, not ccw0
} // else, not cw1
} // else, not ccw1
} // loop
// Sketch uses 3042 bytes (9%) of program
// storage space. Maximum is 30720 bytes.
// Global variables use 240 bytes (11%) of dynamic
// memory, leaving 1808 bytes for local variables.
// Maximum is 2048 bytes.
The Stepper motor for the code above, has 5 or 6 wires, which can be controlled with the 5th or the 5th and 6th wire connected to Vcc and then turning any of the 4 coils on by connecting the other wires to ground. Of course, not all at the same time, but by following the sequence diagram as shown in the motor's datasheet. This is called the Unipolar motor configuration.
In the Bipolar motor configuration you only get 4 wires (see BLK,GRN,RED and BLU below).
The polarity of BLK/GRN and RED/BLU is switched when needed.
To turn the coils on with current flowing in all four steps, you need to be able to control the direction the current through the 2 coils as well. This requires an H-bridge circuit ($0.15 on Ebay), and shown below:
One coil shown, blue and green for opposite current flows
And here is a short sketch to control the Stepper motor in your floppy disk or CDROM drive in one direction:
/*
2 inputs, pulled high internally. Clockwise/Counterclock-
wise and On/Off.
Cycle through the states to turn the stepper clockwise or
in reverse for ccw, using the 4 output pins to drive the
H-bridge turning the bi-polar coils on with the correct polarity.
LED is on in the first phase (well for DELAY milliseconds)
Author: Gert 'Speed' Muller
2017.10.31
*/
#define Coil1A 4
#define Coil1B 5
#define Coil2A 6
#define Coil2B 7
#define InputPin A0
#define LEDPin 13
#define DELAY 50
unsigned int myPhase;
void setup() {
pinMode( Coil1A, OUTPUT );
pinMode( Coil1B, OUTPUT );
pinMode( Coil2A, OUTPUT );
pinMode( Coil2B, OUTPUT );
pinMode( LEDPin, OUTPUT );
pinMode( InputPin, INPUT_PULLUP );
myPhase = 0;
myStep( myPhase );
digitalWrite( LEDPin, HIGH ); // flash with boot message
Serial.begin( 115200 );
delay( 100 );
Serial.write( "StepperFan 0.1..\n" );
digitalWrite( LEDPin, LOW );
} // setup
void myStep( unsigned int phase ) {
digitalWrite( LEDPin, LOW ); // turn the LED off
switch( phase ) {
case 1: digitalWrite( LEDPin, HIGH ); // turn the LED on
digitalWrite( Coil1A, LOW );
digitalWrite( Coil1B, HIGH );
digitalWrite( Coil2A, LOW );
digitalWrite( Coil2B, HIGH );
break;
case 2: digitalWrite( Coil1A, HIGH );
digitalWrite( Coil1B, LOW );
digitalWrite( Coil2A, LOW );
digitalWrite( Coil2B, HIGH );
break;
case 3: digitalWrite( Coil1A, HIGH );
digitalWrite( Coil1B, LOW );
digitalWrite( Coil2A, HIGH );
digitalWrite( Coil2B, LOW );
break;
case 4: digitalWrite( Coil1A, LOW );
digitalWrite( Coil1B, HIGH );
digitalWrite( Coil2A, HIGH );
digitalWrite( Coil2B, LOW );
break;
default:
digitalWrite( Coil1A, LOW );
digitalWrite( Coil1B, LOW );
digitalWrite( Coil2A, LOW );
digitalWrite( Coil2B, LOW );
break;
} // switch
} // myStep
void loop() {
delay( DELAY );
if ( digitalRead( InputPin ) == LOW ) {
myPhase++;
if ( myPhase > 4 ) myPhase = 1;
} else {
myPhase--;
if ( myPhase < 1 ) myPhase = 4;
} // if LOW
myStep( myPhase );
} // loop
// Sketch uses 2400 bytes (7%) of program
// storage space. Maximum is 30720 bytes.
// Global variables use 202 bytes (9%) of dynamic
// memory, leaving 1846 bytes for local variables.
// Maximum is 2048 bytes.
Who does not have an unused CDROM drive?
There are also three or four example Stepper motor sketches in the Arduino IDE’s Example folder if you only need to control a single Stepper motor. Please try them all out. They use the local Stepper library, defined in Stepper.h to create a Stepper object with the number of steps you complete a rotation and the 4 pins connected to the Stepper, or the switches controlling the Stepper windings, example:
#define STEPS 100
Stepper stepper( STEPS, 8, 9, 10, 11 );
And in the setup( ) function they typically set the speed in RPMs:
stepper.setSpeed( 30 );
And what follows in some form or fashion in loop( ):
stepper.step( numberOfSteps );
You can now add a potentiometer and either increase the position by stepping forward, or decrease it be step backwards with negative numbers, or keep stepping and change the speed with setSpeed according to the rotation of the knob on the potentiometer.
For controlling more than one Stepper, or need acceleration and deceleration, then AccelStepper would be a better choice.
Moving a Stepper back and forth with AccelStepper’s bounce example:
#include <accelstepper.h>
AccelStepper stepper; // Defaults to the 4 pins on 2,3,4 and 5
void setup( ) {
stepper.setMaxSpeed( 100 ); // set the speed
stepper.setAcceleration( 20 ); // set the acceleration
stepper.moveTo( 500 ); // set the target position
} // setup
void loop( ) {
if ( stepper.distanceToGo( ) == 0 ) // when it gets there
stepper.moveTo( -stepper.currentPosition( ) );
// change the target
stepper.run( ); // make at most one step, call this often
} // loop
Something you need to keep in mind, a call to the Stepper.step( ) function is “blocking”, meaning that you will need to wait for that command to finish before you can do the next thing. Not important if you are simply commanding something scripted play by play, but if you also need to read an input like an Infrared TV remote control or an LCC command coming from JMRI, you might miss that completely while the Stepper code is “blocking”. On the other hand, a call to AccelStepper.run( ); will only check if a step is needed, make a step and return, or if not needed, just return. In this “non-blocking” way, you can quickly check if a command was sent over the Serial, Infrared or CAN bus and process that command as well.
When the coils in the motor have a DC resistance of 9 or 25 Ohms, you can calculate that a 5 Vdc supply would need to deliver 0.55 A or 0.2 A (from I = V/R) and the Arduino board or chip by itself cannot provide that current. So the Vs pin on the H-bridge circuit need to go straight to a good power supply and not the 5 Vdc on the Uno or Nano board.