Programming Servo control for Model Railroad Turnouts

Hi,
I know this thread is now relatively old now but I am hoping that someone will pick up my question.

I am totally new to the Arduino and have got a Mega 2560 board. I have uploaded the latest sketch onto the board but I am having no success with the hard wiring.

I have a breadboard and separate power supply for the servo's. I am using on/off toggle switches. I have gone through many tutorials but I have not found one that caters for controlling a servo with a toggle switch.
I thought I was there when the servo moved but on switching off the switch, nothing happened.
Can anyone provide a Fritzing diagram or similar to explain just how I should wire up the switches.

Having said all this, am I right in assuming that the sketch supplied here will work on the Mega card and not just the Uno.

I hope you can help and please excuse my ignorance in this matter - it is a steep learning curve for me.

Regards

@bussgarfield

How exactly are you attempting to hardwire everything up? If you can describe in detail how you have tried to wire everything up perhaps we can help.

roboz6

@bussgarfield, I have suggested to the Moderator tp move your question to its own Thread and then we can start afresh. This link will find the old Thread

If you just want a servo to change position when a button is pressed you just need a variable that changeds from 'F' (off) to 'N' (on) when a button is pressed and arrange for something like this

if (buttonState == 'F') {
   myServo.write(20);
}
else {
  myServo.write(107);
}

You can do the same with a toggle switch - when it is in one position set the variable to 'N' etc.

Note that this style of doing things separates the servo action from the switch code which makes things much easier to manage.

if i have misunderstood your problem please explain further.

...R

Hi and thank you for your replies.

@roboz6 I have hopefully attached a jpg so you can see exactly what I have done. The resistor is a 1k as opposed to the 220 as depicted. I have tried to glean as much info from web tutorials as I could but have hit a stumbling block.
The latest and updated sketch has been uploaded from the original thread and I have a seperate power supply for the Mega card and for servo (which is via the breadboard).

All I am trying to do is mirror what the guys have done on the original post and move a servo via a toggle switch to operate numerous sets of points on my railway layout. I have only tried to connect one servo at the moment but ultimately I have around 24 that will need to be moved - hence purchasing the Arduino Mega. If the sketch has been uploaded then all that can be at fault is my hard wiring.
I hope this make a bit more sense.

@Robin2, Thank you for the suggestion of my question being moved to it’s own thread. Makes it a bit simpler now. I thought it was best to have the original thread there so one of the original posters could inform me of their wiring.

Anyway, Hopefully the attachment has worked and I look forward to your replies.
Regards
Gary

Image from Reply #3 so we don’t have to download it. See this Image Guide

df5c4c0d6983ba3e240855c4e62ae89e348050ac.jpg

…R

Please post your program.

If you use pinMode(pin, INPUT_PULLUP); there will be no need for the external resistor.

It is not a good idea to power a servo from the Arduino 5v pin because the servo can overload it and cause the Arduino to misbehave. Give servos a separate power supply with a common GND with the Arduino.

Many of those breadboards don’t have a continuous power rail down the length of them - you need jumpers at the centre.

Apart from those comments I don’t see anything wrong with your diagram. However, for the future a photo of a pencil drawing of wiring connections is easier for us to understand.

…R

Robin2 thank you for the reply.

I have been using a seperate power supply for the Mega and a totally seperate supply for the servo. The breadboard’s power runs down the entire rail so no problems there and I have used a common ground from the breadboard to the Mega.

The programme/sketch I have used was downloaded from the original post from Anders53 and it worked for roboz6. It is as follows,

*/

#include <VarSpeedServo.h>
#include <Bounce2.h>

// Constants to trim switch servo behaviour, mid = midpoint parameters
// Servo button nr             =    { 0,  1,  2,  3,  4,  5,  6,  7,mid}
const byte buttonPins[]        =    {A0, A1, A2, A3, A4, A5,  2,  3, 12};
const byte servoPins[]         =    { 4,  5,  6,  7,  8,  9, 10, 11, 13};
const byte rangeLow[]          =    {85, 85, 85, 85, 85, 85, 85, 85, 90};
const byte rangeHigh[]         =    {95, 95, 95, 95, 95, 95, 95, 95};
const byte travelSpeed[]       =    { 2,  2,  2,  2,  2,  2,  2,  2, 50};
const byte numberServos        =     8;                        // the total number of servos
const long detachTime          =     5000;                     // detach servo after 5 seconds
const long bounceDelay         =     10;                       // Button debouncing delay; increase if the servo sweeps

// Work variables
boolean holdReadVal            =     1;                        // Holds immidiate switch button read value
boolean midPointVal            =     1;                        // Holds immidiate midppoint setting button read value
boolean midState               =     0;                        // To remember if midpoint setting was traversed

// arrays holding work variables
VarSpeedServo             myServos[numberServos];              // Servo objects
Bounce               debouncer[numberServos + 1] = Bounce();   // Bounce objects
unsigned long         detachMillis[numberServos] = {0};        // Detach timer for each servo object
boolean                switchState[numberServos] = {0};        // Holds the status for each switch

void setup()
{
Serial.begin(9600);
for (byte i = 0; i < numberServos + 1; i++)
{
pinMode(servoPins[i], OUTPUT);                             // Define digital pin as output
pinMode(buttonPins[i], INPUT_PULLUP);                      // Define digital input pin with pull up resistor for noise reduction
debouncer[i].attach(buttonPins[i]);                        // Attach input pins to debouncer objects
debouncer[i].interval(bounceDelay);                        // Debouncing delay interval
}
readTrackLayout();                                           // Read the switch status from layout
}

void loop()                                                    // runs forever to detect control buttons and change switches accordingly
{
digitalWrite(servoPins[8], !digitalRead(servoPins[8]));      // Code activity LED, dimmed when code runs, dark or full light if code is trapped
if (!midPointVal) delay(500);                                // Slow down loop activity while midpoint is set, to blink LED at slow pace
bounceReadInput(8);                                          // ### Read the midpoint button input
if (!midPointVal)                                            // ### Is midpoint button active LOW ?
{      
setMidpoint();                                             // ### Yes, midpoint button active, and servos not yet at midpoint, set at midpoint
}
if (midPointVal && midState)                                 // %%% Midpoint button is set inactive high (idle), and servos are at midpoint
{     
readTrackLayout();                                         // %%% - then read the track layout buttons
}

if (midPointVal)                                             // Midpoint button is incative HIGH, control the servos
{
for (byte i = 0; i < numberServos; i++)
{
  bounceReadInput(i);                                      // *** Read the control button inputs
  if ((holdReadVal != switchState[i]))                     // *** Has the button state changed ?
  {
    controlSwitches(i);                                    // *** Yes, then set the switch to new position
  }                                                        // *** No, the button state has not changed, is it time to detach servo then ?
  if (myServos[i].attached() && ((millis() - detachMillis[i]) > detachTime))
  {
    myServos[i].detach();                                  // *** Yes, the time has elapsed, detach the switch servo for a more silent layout
  }
}
}
}

void bounceReadInput(byte i)                                   // Read debounced button inputs
{
debouncer[i].update();                                       // Update the Bounce instance
if (i < 8)
{
holdReadVal = debouncer[i].read();                         // Get the updated debounced button value
}
else
{
midPointVal = debouncer[i].read();                         // Get the updated midpoint button value
}
}

void setMidpoint()                                             // This function is called asynchronous to counter in the main loop
{                                                              // - because the midpoint button is set at random
for (byte i = 0; i < numberServos; i++)                      // A local counter must then be used to set all servos
{
myServos[i].slowmove(rangeLow[8], travelSpeed[8]);         // Set all servos at midpoint, index 8 in array
servoAttach(i);                                         // Only after pre-setting the position control, it's safe to attach the servo    
}
midState = HIGH;                                             // Remember we were here to set midpoint, do not repeat it
}

void readTrackLayout()                                         // This function is called asynchronous to counter in the main loop
{                                                              // - because the midpoint button is set at random
for (byte i = 0; i < numberServos; i++)                      // A local counter must then be used to set all servos
{
switchState[i] = digitalRead(buttonPins[i]);               // Read the current switch state from the track layout
writeBeforeAttach(i);                                      // Write data before attaching servo
}
midState = LOW;                                              // Remember we were here to get layout, enable possibilty to set midpoint again
}

void controlSwitches(byte i)
{
switchState[i] = !switchState[i];                            // Save new switch state
writeBeforeAttach(i);                                        // Write data before attaching servo
}

void writeBeforeAttach(byte i)                                 // Write data before attaching servo
{
if (switchState[i])                                          // Is the new switch state high (greater than 0) ?
{
myServos[i].slowmove(rangeHigh[i], travelSpeed[i]);        // Yes, new switch state is high, move the switch accordingly
}
else
{
myServos[i].slowmove(rangeLow[i], travelSpeed[i]);         // No, new switch state is low, move the switch accordingly
}
servoAttach(i);                                        // Only after pre-setting the position control, it's safe to attach the servo
}

void servoAttach(byte i)                                 // Only after pre-setting the position control, it's safe to attach the servo
{
detachMillis[i] = millis();                                  // Initialise the detach timer
myServos[i].attach(servoPins[i]);                            // Attaches the servo on output pin to its servo object

}
1 Like

The sketch started with the following text but there were too many characters for me to post it all. I am sure there is a way to upload it all together for you to read but I am not sure how to do it.

Anyway, here is the heading text,

/*
Original design idea by PaulDMV
Copyright2015 - SERVO SWITCH CONTROL - SSC - PaulDMV
Modified 02-04-2015 - using arrays - Anders53
Modified 09-04-2015 - V3 code reduced - by Septillion
Modified 13-04-2015 - V4 added override to mid position - by Anders53
Modified 23-04-2015 - V4-2-2 code cleaning & input debounce - by Anders53


Include the VarSpeedServo.h and Bounce2.h libraries in IDE before compiling !


A maximum of 12 servo objects can be created from library.
A maximum of 11 servoes can be controlled by the latest variants
Uno, Nano & Mini having pins A6 & A7 on the board.
Change constants : pin no, speed, range_low, range_high, and
detachTime to trim your layout switches operation. In fact
everything moving the servos and for how long can be trimmed.

Define Arduino pin usage, which are constants :
Arduino pins 0 & 1 are here reserved for any serial communication
i.e. for debugging or future inter comm (TCC) between arduino units.
The pin numbers are those found printed on the arduino board.
They apply to all Arduino Uno, Nano & Mini variants,
but can of course be re-arranged to suit the extra A6 & A7 pins
found on later revisions of Uno derivatives.
This can make for an extra servo channel.
All input pins are set to mode PULL_UP for noise reduction and
the state of input pins are debounced by code.

An override toggle switch can be added to pin 12 as input.
A LOW (GND) level on this pin will set all servo channels to
mid position 90° for physical installation of the servos.
If the input is left open, the internal PULL_UP will set the
input high, which disables the mid position feature.

The internal LED is set to blink every time loop() is
traversed, to indicate activity. If the code is trapped, the
LED will stay dark or at full intensity.
If midpoint input is set active LOW, the blink pace is decreased.
The LED output is availabe at pin13, for a remote LED indication
of the controller status.

NOTES :
Switch = turnout.
Button = input control toggle switch or relay wiper contact.
The reset input pin RST may be remote controlled by an external
pushbutton or a springloaded SPST toggle switch to ground.

The programme/sketch I have used was downloaded from the original post from Anders53 and it worked for roboz6. It is as follows,

I assume that the original dd not have smiley faces and italic characters in it like yours.

Edit the post, select the code and click the </> icon top/left of the editor widow to insert code tags, then save the post. Spot the difference.

With a program that is too long for a single Post you can add the .ino file as an attachment.

...R

Thanks UKHeliBob,

You live and learn. The post has been edited and looks much better - cheers.

Hopefully any issues can be picked up now. I literally copied and pasted the sketch from my library so I do not know where the smileys and italics came from.

The sketch is as per downloaded apparently works with roboz6 so if my wiring is ok and power supplies are as stated, where am I going wrong?

Gary

What is that program supposed to do? It seems to have a lot of stuff in it (compared to what I suggested in Reply #2, for example)?

Sometimes it is easier just to start from scratch. I think this would cover most of it

void loop() {
    for (byte n = 0; n < numTurnouts; n++) {
        switchState[n] = digitalRead(switchPin[n];
        if (switchState[n] == HIGH) {
            turnoutServo[n].write(20);
        }
        else {
            turnoutServo[n].write(123);
        }
    }
    delay(50);
}

…R

I do not know where the smileys and italics came from.

They are there because the forum software interprets some sequences of characters as HTML commands

­8) becomes 8)
An array subscript of i turns subsequent text into italics

The code tags prevent that happening

@UKHeliBob, thank you for explaining that.

@Robin2, I bow to your better judgement. I located the original thread when searching for a way for the Arduino to control numerous points/turnouts for a model railway layout. The idea was to later adapt the sketch from 12 servo's to 24, once I had got it up and running to enable me to use one toggle switch to control one servo to operate/switch one set of points. I need 24 toggle switches to control 24 servo's to operate 24 sets of points when I want them activated.
Being a complete novice within the Arduino community, I am initially totally reliant on other peoples good work to assist me in achieving my aim. At the moment it is beyond my capabilities to write a program/sketch so assumed that the original sketch would suffice.
As stated previously, the sketch has worked with roboz6 so I assumed that all I had to do was to enter it into my library and upload to my Mega board. The issue I had was how I should wire the toggle switches to the Mega board and servos.
Are you saying that the original sketch is not correct or that there is just too much in it for allowing 12 switches to control 12 servo's?

I appreciate your help.

G

bussgarfield:
Are you saying that the original sketch is not correct

All I am saying is that I don't immediately understand it and (for me at least) it would be quicker to write a new program than to try to understand it.

Can you describe for me the features that are supposed to be contained in it - in other words, if it was working, how would the user use it?

...R

Obvious question: are these turnout servos of yours 12v?

Less obvious question: do these servos of yours actually have an internal processor that needs to be spoken to in terms of some model-railway-specific protocol? I was at a model railway exhibition recently, and they were selling stuff that was quite clearly drive-by-wire gearwhich on the box stated that it used some sort of standard to talk to a controller.

I believe they are ordinary hobby servos - that is what the VarSpeedServo library controls.

…R

Hi and thank you for your continued interest,

I shall be using plain old on/off SPDT toggle switches, and standard 9 gram hobbyist minature servos with a separate 5v power feed.

The servo's will be mounted underneath the base board and have a short length of 1.2mm diameter piano wire connected to the servo horn via a 'Z' bend. The piano wire protrudes through a pre-drilled hole in the base board and through the tiny hole in the points actuator. When the toggle switch is turned on, the servo will move the points in one direction and when the switch is turned off, the servo will move the points back in the other direction. The angle of the servo horn (amount of travel in either direction) needs to be adjustable to prevent the servo from stalling when the points above the base board make contact. For example, if the servo is set for a 50 degree travel in either direction but only 35 degrees are required, this needs to be adjustable with in the sketch.

Please let me know if you require any further information.

...G

If individual servos require different values of start angle and stop angle put those in arrays and read them when required.

This is a simple extension to Robin's program in reply #11

I have lost track of where you are stuck.

UKHeliBob:
This is a simple extension to Robin's program in reply #11

Indeed. I thought I would overly complicate things if I mentioned it in that Reply.

...R