Turnout Control with Arduino & Servos

Complete servo installation.

Complete servo installation.

[Since this was originally posted I’ve come up with a low-noise, low-profile side mounting method. The mounting method does not change the programming required to control one, or more, servos.]

This is a basic method for using an off-the-shelf micro servo as a turnout motor, in this case the

Tower Pro SG90

Tower Pro SG90

Tower Pro SG90 which can be purchased for $2 to $3 each.

The first thing I do is prepare the servo by setting the position of the shaft to 90 degrees, the midpoint of its 180 degree total travel. I do this by attaching the servo to an Arduino Uno and uploading this little sketch once to set the servo (for those who don’t know, “//” signifies the start of a comment ):

#include <Servo.h> // compiler directive to get the servo library
 
Servo myservo;  // create a servo object
// from here on use the variable "myservo" to 
// access and control the servo object
void setup() // the setup function is run once at boot
{ 
  myservo.attach(9);  // attaches to the servo on pin 9
  myservo.write(90);  // set the servo shaft at 90 degrees
} 
 
// the loop function runs after setup until the board is powered off 
void loop() 
{ 
  // do nothing
}

Here is the basic circuit for controlling a servo with an Arduino Uno, where the servo draws power from the Arduino. Servos can be independently powered, in which case only the signal wire and ground are connected to the Arduino.

Basic Arduino/servo circuit.

Basic Arduino/servo circuit (from www.arduino.cc).

The Arduino can Source a maximum of 200 mA current, and can Sink a maximum of 400 mA current. As you connect and try to run more devices, you’ll get to those limits quickly. In Model Railroad applications, given that we’re already routing track power, routing a few amps of +5 volt power to supply actuators like servos is a no-brainer for performance and system integrity.  Whenever you use a separate power supply, the servo ground has to connect to both the power supply ground and the Arduino ground.

I fabricate a simple mounting bracket with a small plywood plate and a couple of blocks. Now I mount the servo in the bracket, place the horn onto the shaft in the position shown and then screw it down to the shaft.

Micro Servo with shaft/horn set to 90 degrees

Micro Servo with shaft/horn set to 90 degrees

Using a 1/16″ bit, I drill out a hole in the horn (usually the second hole from the end of the horn) and a hole in the turnout actuator bar.  Don’t over ream the holes; the soft, slightly flexible plastic will provide a snug fit so you don’t have to use adhesives. Then, I slide a piece of 1/16″ brass rod through the horn to establish the location for a hole in the mounting plate.

Establishing the location for the rod hole.

Establishing the location for the rod hole.

I mark and drill the hole in the base plate. I rock the bit along the axis the rod will move (left to right in the view below) to slightly elongate it, and give it a more hour-glass profile. This hole functions as a fulcrum for the rod.

Servo mounting bracket ready for use.

Servo mounting bracket ready for use.

I mount the servo below the turnout. For this demonstration, I used hot glue to mount the bracket to the underside of the demonstration layout segment; screws are a better idea for most situations, allowing you to build in some adjustability. With the turnout set in the straight-through position, I carefully thread the rod through the turnout actuator bar, down through a prepared hole in the layout to the hole in the mounting plate and then the servo horn. The brass rod is perpendicular to the horn at the 90 degree setting.  Moving the servo horn tilts the rod, moving the turnout above to its divergent position.

Threading the rod down from the turnout to the servo.

Threading the rod down from the turnout to the servo.

At this point I test the servo and make any adjustments necessary for smooth operation. When I’m satisfied everything is right, I trim the rod to its final size.

I’m planning to try music wire instead brass rod in the near future. The problem with brass rod is that it is stiff, and the servo can get fussy at the end of movement ranges because there is no give. Music wire is like spring wire and should allow me to apply pressure at the ends of movement ranges without overtaxing the servo.  I’ll update this page with the results of those tests.

Servo mounted and ready

Servo mounted and ready

Servo Control by Button

Servo Control by Button

The button takes power from the +5v board supply and, when the button is pushed, routes the power to a designated pin, putting the pin in a HIGH state. On the output side of the button a pull-down resistor routes stray power to ground to guarantee that the pin is in a LOW state whenever the button is not pushed.

Here is a simple sketch to control a servo and have it move over about 2 seconds every time a button is pressed. The straight position is always 90 degrees because of the way I install the servo.  The divergent angle depends on how the servo was installed in relation to the turnout– it will either be a larger angle in the 110 – 120 degree range, or a smaller angle in the 60-70 degree range.  With practice and consistent placement of servos, they can all be the same; but if not, storing unique settings for each servo is not difficult.

#include <Servo.h>

// constant variables used to set servo angles, in degrees
const int straight = 90; 
const int divergent = 110;

// constant variables holding the ids of the pins we are using
const int buttonpin = 8;
const int servopin = 9;

// servo movement step delay, in milliseconds
const int step_delay = 70;

// create a servo object
Servo myservo;  
 
// global variables to store servo position
int pos = straight; // current
int old_pos = pos; // previous

void setup() 
{ 
  // set the mode for the digital pins in use
  pinMode(buttonpin, INPUT);
   
  // setup the servo
  myservo.attach(servopin);  // attach to the servo on pin 9
  myservo.write(pos); // set the initial servo position
}

void loop() 
{ 
 // start each iteration of the loop by reading the button
 // if the button is pressed (reads HIGH), move the servo
  int button_state = digitalRead(buttonpin);
  if(button_state == HIGH){
    
    old_pos = pos;   // save the current position
    
    // Toggle the position to the opposite value
    pos = pos == straight ? divergent: straight;
       
    // Move the servo to its new position
    if(old_pos < pos){   // if the new angle is higher
      // increment the servo position from oldpos to pos
      for(int i = old_pos + 1; i <= pos; i++){  
        myservo.write(i); // write the next position to the servo
        delay(step_delay); // wait
      }
    } else {  // otherwise the new angle is equal or lower
      // decrement the servo position from oldpos to pos
      for(int i = old_pos - 1; i >= pos; i--){ 
        myservo.write(i); // write the next position to the servo
        delay(step_delay); // wait
      }
    }
    
  } 
}// end of loop

Finally, we can add one more refinement and have the Arduino feedback position status via two pins that we can use to power leds at the control panel. The circuit looks like this:

Servo Control with LED Feedback

Servo Control with LED Feedback

To update the sketch, we’ll add variables for the led pins and add commands to turn the leds on and off.

#include <Servo.h>

// constant variables used to set servo angles, in degrees
const int straight = 90; 
const int divergent = 110;

// constant variables holding the ids of the pins we are using
const int divergent_led = 6;
const int straight_led = 7;
const int buttonpin = 8;
const int servopin = 9;

// servo movement step delay, in milliseconds
const int step_delay = 70;

// create a servo object
Servo myservo;  
 
// global variables to store servo position
int pos = straight; // current
int old_pos = pos; // previous

void setup() 
{ 
  // set the mode for the digital pins in use
  pinMode(buttonpin, INPUT);
  pinMode(straight_led, OUTPUT);
  pinMode(divergent_led, OUTPUT);
  
  // setup the servo
  myservo.attach(servopin);  // attach to the servo on pin 9
  myservo.write(pos); // set the initial servo position
  
  // set initial led states
   digitalWrite(straight_led, HIGH);
    digitalWrite(divergent_led, LOW);
}

void loop() 
{ 
 // start each iteration of the loop by reading the button
 // if the button is pressed (reads HIGH), move the servo
  int button_state = digitalRead(buttonpin);
  if(button_state == HIGH){
    // turn off the lit led
    if(pos == straight){
              digitalWrite(straight_led, LOW);
          } else {
              digitalWrite(divergent_led, LOW);
          }
    old_pos = pos;   // save the current position
    
    // Toggle the position to the opposite value
    pos = pos == straight ? divergent: straight;
       
    // Move the servo to its new position
    if(old_pos < pos){   // if the new angle is higher
      // increment the servo position from oldpos to pos
      for(int i = old_pos + 1; i <= pos; i++){  
        myservo.write(i); // write the next position to the servo
        delay(step_delay); // wait
      }
    } else {  // otherwise the new angle is equal or lower
      // decrement the servo position from oldpos to pos
      for(int i = old_pos - 1; i >= pos; i--){ 
        myservo.write(i); // write the next position to the servo
        delay(step_delay); // wait
      }
    }
    // turn on the appropriate LED.
    if(pos == straight){
            digitalWrite(straight_led, HIGH);
        } else {
            digitalWrite(divergent_led, HIGH);
       }
  } 
}// end of loop

To control multiple servos with one Arduino, your sketch would need variables for each servo to hold its pin id and unique divergent angle. More advanced programmers will want to create something like an array of data structures to organize pertinent data about the servos.

Now lets put it all together:

NOTE: The delay() function is used a lot in small demonstration sketches to control timing.  The problem with delay is that it throws the board into a do-nothing state that prevents anything else from happening. In more complex sketches it is often advisable to avoid delay() and use other methods to meter actions across multiple controller cycles. In this case, be aware that the board is tied up while the servo is in motion.


 

For more on avoiding delay() and controlling multiple turnouts, see Multiple Turnouts and Other Multitasking.


 

65 thoughts on “Turnout Control with Arduino & Servos

    • I haven’t tried it myself yet (I will in due course as this project proceeds), but there are two ways that I know of. The simplest would be to attach the output of a stationary decoder to a digital input pin on an Arduino, and use the signal on that pin to trigger action. The decoder signal will likely be at full track voltage so you’ll need to protect the pin from excess current with a resistor and/or voltage limiter (unless the decoder supports or allows voltage/current limits on its signal line). Alternatively, using minimal additional circuitry and readily available code, you can turn the Arduino into a stand alone, smart decoder. Check out this project – http://model-railroad-hobbyist.com/node/19446 – where that has been done, turning an Arduino into a 17 function smart decoder.

      Rob

    • I hear you can expand it out to 4 servo and a relay control up to change tracks,

  1. Hello friend:
    I am fond of N Scale model railroading. And I loved your video related to Arduino and control of turnout motors.
    My question is this, that’s for moving one, but as it is in my case my model has 40 turnout motors and what I want is to change by servos, as could do. I would love that to your knowledge would help me to establish this system in my N Scale Model Railroading

    If you want to stay in touch via email, here I leave my email to comment with more breadth of your knowledge.
    many Thanks
    regards

    frantabarca@gmail.com

    • Francisco – Thanks for visiting!

      You can control as many servos with an Arduino as there are available digital pins. On an UNO like I used here, you have up to 12 digital pins available for servo control. On a Mega 2560, which as many more I/O pins than the UNO, you can control up to 48 servos. If you need digital pins for other uses, that would reduce pins available for servos.

      On a large layout, the distance from your Arduino to your servos could become a problem. So on a large layout, or any layout where there are a lot of servos and other things to control, its probably easer to use multiple Arduino boards networked together (using usb, wifi, Ethernet, Xbee or something else). With 40 turnouts to control, I suspect you’d do best taking this approach.

      Given the modular design of the L&NC, and the need to limit wiring between modules, I’m going to use the networked board approach. There will probably have to be a main controller board — a Mega in all likelihood — to tie all the pieces together.

      Rob

  2. Dear Sir
    You have sent me off on a quest to find out how to program more than one servo, Without any real success my inability to take the programming examples and apply it to the the case in point. Have you got any clues or starting points that you could help with. Keep up the good work and thank you in advance
    Kind Regards
    Ron

    • Ron, Thanks for visiting! If I’m understanding correctly, is sounds like you have been able to control one servo but are having trouble extending that to multiple servos. What I’ll do is assume you have the sketch at the end of post above working, and explain how I would adapt the sketch to multiple servos.

      Problem #1: All the variables in use are good for only one servo: “myservo”, “servo_pin” and so on can only refer to one device. We need a way to handle multiple sets of similar data that can be easily manipulated in the sketch.

      The optimal solution is to gather all the data elements you need for a servo into a data structure (keyword struct – see playground.arduino.cc/Code/Struct) that can be referenced through a single variable.

      I use a structure to hold the three key bits of mechanical data about a turnout and its servo: its pin, its main position in degrees and its divergent position in degrees:

      typedef struct TURNOUT_DEF {
      int pin;
      int pos_main; //main servo position in degrees
      int pos_div; //divergent servo position in degrees
      };

      To declare a variable and initialize its values for one turnout:

      TURNOUT_DEF turnouts = {2, 94, 121};

      To reference the values:

      turnouts.pin ( == 2)
      turnouts.pos_main ( == 94)
      turnouts.pos_div (==121)

      I made the variable name plural deliberately to illustrate the ease of shifting to multiple turnouts and servos. To do that, variable “turnouts” is changed from being a single structure, to an array (www.arduino.cc/en/Reference/Array) of structures. Secondly the “myservo” servo object variable needs to become an array of servo objects.

      Declare and initialize the variables this way:

      #define NUMBER_OF_TURNOUTS 2
      Servo servos[NUMBER_OF_TURNOUTS];
      TURNOUT_DEF turnouts[NUMBER_OF_TURNOUTS] = { {2, 94, 121}, {3, 96, 119} };

      To reference the values, add the array subscript:

      turnouts[0].pin ( == 2)
      turnouts[1].pin ( == 3)

      So, the initialization loop in setup() looks like this:

      for(i = 0; i < NUM_TURNOUTS; i++){ // for each turnout servos[i].attach(turnouts[i].pin); } Ok this gets you to the point where you have an array of active servos you can move. Problem #2: How do you keep track of positions and movement of multiple servos? One way is to modify the TURNOUT_DEF struct this way, so that you have unique pos and old_pos elements for each turnout: typedef struct TURNOUT_DEF { int pin; int pos_main; //main servo position in degrees int pos_div; //divergent servo position in degrees int pos; int old_pos; }; Now, you can modify the main loop in the example sketch like this: for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){ //place button or other command source check here // assume we've got a buttons array buttons[NUMBER_OF_TURNOUTS] int button_state = digitalRead(buttons[i]); if(button_state == HIGH){ turnouts[i].old_pos = pos; // save the current position // Toggle the position to the opposite value turnouts[i].pos = turnouts[i].pos == straight ? divergent: straight; // Move the servo to its new position if(turnouts[i].old_pos < turnouts[i].pos){ and so on as in the example, adding 'turnouts[i].' to variable references as shown. This should get you started and enable you to control more than one servo in a basic way. Let me know how you do with this or if you need help. Be sure to note the limits of the servo library: arduino.cc/en/Reference/Servo There is one major flaw in the demonstration sketch --- if you want multiple servos to move at the same time, this sketch will move them sequentially instead of simultaneously (actually, the button reading algorithm in the demo sketch essentially guarantees you cannot move more than one servo at a time). The solution that requires getting into time slicing your sketch to manage multiple simultaneous activities. Its doable and a worthy subject for a new post here in the near future.

    • WordPress is mangling the last bit — lets try that again:

      So, the initialization loop in setup() looks like this:

      for(i = 0; i < NUM_TURNOUTS; i++){ // for each turnout servos[i].attach(turnouts[i].pin); }

      Ok this gets you to the point where you have an array of active servos you can move.

      Problem #2: How do you keep track of positions and movement of multiple servos?

      One way is to modify the TURNOUT_DEF struct this way, so that you have unique pos and old_pos elements for each turnout:

      typedef struct TURNOUT_DEF {
      int pin;
      int pos_main; //main servo position in degrees
      int pos_div; //divergent servo position in degrees
      int pos;
      int old_pos; };

      Now, you can modify the main loop in the example sketch like this:


      for(int i = 0; i < NUMBER_OF_TURNOUTS; i++) { //place button or other command source check here // assume we’ve got a buttons array buttons[NUMBER_OF_TURNOUTS] int button_state = digitalRead(buttons[i]); if(button_state == HIGH){ turnouts[i].old_pos = pos; // save the current position // Toggle the position to the opposite value turnouts[i].pos = turnouts[i].pos == straight ? divergent: straight; // Move the servo to its new position if(turnouts[i].old_pos < turnouts[i].pos){

      and so on as in the example, adding ‘turnouts[i].’ to variable references as shown.

      This should get you started and enable you to control more than one servo in a basic way. Let me know how you do with this or if you need help.

      Be sure to note the limits of the servo library: arduino.cc/en/Reference/Servo

      There is one major flaw in the demonstration sketch — if you want multiple servos to move at the same time, this sketch will move them sequentially instead of simultaneously (actually, the button reading algorithm in the demo sketch essentially guarantees you cannot move more than one servo at a time).

      The solution requires getting into time slicing to enable the sketch to manage multiple simultaneous activities. Its doable and a worthy subject for a new post here in the near future.”

      • Hi Rob
        I’m not a programmer at all just a dedicated Dad trying to please a son and his train set. I’ve looked through all the posts and references but am still clueless as to how to design the code for multiple turnouts, just haven’t got the logical brain.
        Is there any chance you can post the full sketch of the above explanation you gave to Ron above. You certainly would make our day if you could.
        many thanks

        • Hi Colin

          The example(s) are excerpts from much bigger sketches; all the extra stuff would confuse the issue.

          So maybe I can craft a full example, based on your specific needs, that would be useful to others with similar needs.

          How many turnouts are you trying to control, how do you want to control your turnouts (button(s), toggle switches, or something else?) and what Arduino board will you be using? Rob.

          • Hi Rob
            In essence we have 5 turnouts to control, using push buttons (push once from straight to divergence, push again it moves back to straight) and giving feedback using LED’s (yes he also wants a control board, the things we do for kids)
            I am using an Arduino Uno
            Thanks so much
            Colin

          • Hi Colin,
            Seems reasonable. One caveat: depending on the number of LEDS that need to be controlled on the control panel, you may run out of connections on your UNO. You can solve that problem using chained logic shifters (which require only three connections) to run all the LED indicators. Heck, if you do that you can even think about adding a signal or two (I’ll bet that touch would be a surprise!).

            I think your son’s requirements would make a good concrete example for people trying to set up a small layout. So I think I’d like to do a post on the main blog, which will include a working sketch. I’ll put something together this week. Best, Rob

  3. Hello
    thanks for your useful and beautiful blog
    and your willingness to share information

    I’m working on a project for diverters with Arduino

    could you kindly post a skeg

    to drive most servo with buttons (1 for switch button)

    thank you

  4. I would like to thank you for this information! Although I haven’t started my layout yet, your ideas are pure gold to get your imagination flowing! I have so many ideas that I have to write them down!

  5. I developed this, it may be an option, it uses a 16 servo board and a Arduino UNO R3

    /*This sketch is designed to operate Model Railway Points that are driven by Servo Motors
    *A SPDT switch connected to + and – 5vDC with the centre tap going to an Input Pin.
    *
    *This will scan a predefined set if Pins and allocate as INPUT then set them LOW.
    *Dependant on the PIN STATE and whether or not it has changed it will rotate a SERVO on the active pin
    *to a pre-determined location as set out in the SERVOMIN/SERVOMAX arrays.
    *Millis() function has been used to streamline the operation.
    *Serial.print can be removed, they are just for checking.
    *
    *Machine:- UNO R3 and 16 Servo Controller
    *
    *Created by Doug Reed 10/05/2016
    *
    *My thanks to the Forum Members who pointed me in the right direction.
    */

    #include
    #include

    unsigned long previousMillisSWITCH=0; //Button Millis() setup
    int intervalSWITCH = 20; //intervals for millis()

    Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); // called this way, it uses the default address 0x40

    unsigned int SERVOMIN[11] = {172,172,172,246,246,172,246,200,200,150}; //servo lower setting to suit individual servo
    unsigned int SERVOMAX[11] = {565,530,500,492,492,565,492,550,550,525}; //servo upper setting to suit individual servo
    int InPin[11] = {2,3,4,5,6,7,8,9,10,11,12}; //array of input pins
    int PinCount = 11; //the number of pins used, lenght of array
    int Dir = 0;
    int OldDir[11];
    int NewDir[11];
    int thisPin;
    int degrees;

    void setup() {
    Serial.begin(9600);
    pwm.begin();
    pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates

    for (int thisPin = 0 ; thisPin < PinCount ; thisPin++) { //"thisPin" is array position
    pinMode(InPin[thisPin],INPUT); //sets all pins 2 -12 as INPUT
    }
    for (int thisPin = 0 ; thisPin = intervalSWITCH) { // time between button presses

    for (int thisPin = 0 ; thisPin < PinCount ; thisPin++) { //assess the direction settings
    Dir = digitalRead(thisPin+2);
    OldDir[thisPin] = NewDir[thisPin];
    Serial.print(InPin[thisPin]);
    Serial.print(" Dir ");
    Serial.println(Dir);

    if ((Dir == 1) && (OldDir[thisPin] == 0)){
    for (uint16_t pulselen = SERVOMIN[thisPin]; pulselen SERVOMIN[thisPin]; pulselen–) {
    pwm.setPWM(thisPin, 0, pulselen);
    Serial.print(InPin[thisPin]);
    Serial.print(” LOW “);
    Serial.println(pulselen);
    }
    NewDir[thisPin] = 0;
    }
    }
    }
    previousMillisSWITCH = currentMillis;
    }

  6. I do know if you can help me with this but here goes.
    I have typed the code as far as I can see correctly, but when I try to download it, it gets as far as

    // create a servo object
    Servo myservo;

    then gives me an error message

    ‘Servo’ does not name a type
    being a little old and never having tried this before I am a little baffled as to what this means. Can anyone explain please?
    Thanks in anticipation,
    Mike

    • Hi Mike,

      Resolving compiler errors can be a pain. In your case, the most likely cause is a missing header declaration. Place this line at the top of the sketch (exactly as shown with no other punctuation):

      #include <Servo.h>

      so that the compiler knows was a “servo” object is and what to do with it. An idiosyncratic requirement of the C++ language is that “.h” or header files are used to formally define function types and parameters before they can be used. So any time you are invoking a library function (one that is not part of the language core), you must direct the compiler to the appropriate header file for that library function.

      If you already have that line, then check your sketch line by line looking for punctuation or structural errors such as missing or inappropriate semicolons (compiler directives, such as the #include line, are an exception to the general rule and do not get a semicolon to mark the end of a line), or unbalanced curly braces (eg, an opening brace without a matching closing brace; a very common error).

      General debugging tip: The IDE only shows the last error emitted, so the first thing you should do when the compiler fails is scroll through the output window and look at all the errors generated. In general, the first error emitted is the critical one, and following errors are usually just side effects. The most efficient way to debug a sketch is to track down and resolve them in the order they are emitted by the compiler.

      Best, Robin

      • Good morning Robert,
        Thanks for the quick response. You were correct, I had missed out the #include even though I had spent ages going through the code before asking for help. I found a couple of other bits that were wrong and then low and behold the code downloaded.
        There is one other question I would like to ask, and that is, should this code keep repeating each time I press the button. At present it only works the once IE, moves and stops, then returns to start when the button is pressed again. To make it work a second time I have to press the reset button on the Arduino.
        Do I have to enter the second part of the code to get this action?
        I will as usual be trying to sort the problem myself, but as this is my first time of dipping my toes in the Arduino pond I may finish up drowning myself.
        Any help would be appreciated
        Cheers,
        Mike

  7. Good afternoon Robert,
    Panic over as I have found the problem. I had missed a > on the >= pos; .
    Many many thanks for this code. I have been looking for this type of thing for ages but was getting seriously fed up as many people show you what is happening, but nobody gives you the code.
    All I have to do now is look at the rest of the code to see how to get more than one servo to work, but having worked through your code I now have a far better idea of what should happen and a bit of an idea of where to look when it does not work (see how confidant i have become)
    Once more thanks for your help.
    Cheers
    Mike.

    • I figured something like that from your description of the problem. Glad you worked it out.

      You are welcome. I’m thinking about setting up a Github repository for helpful code bits. Perhaps this Spring I’ll get around to it …..

      If you are interested in a multitasking technique that allows you to handle multiple servos and do other things too, see Multiple Turnouts and other Multitasking.

      Cheers! Robin

  8. Hello Robin, I’m trying to use the servos on my turnouts, but I’m have a trouble. When I turn on the arduino the servo moves (about 5-10° to each side) before stopping at the 90° position. This movement can damage the N-scale turnouts, which are very sensitive. Do you have any solutions to this problem? Thanks from Brazil

    • Hi Maurico,

      The tendency to move when powered up seems to be an issue with the standard servo library. I’ve seen it before, though it usually is not as bad as moving each way 5 – 10 deg before stopping in the middle. In fact, that seems extreme. I assume the servo works correct after startup — right?

      My first thought is to suggest you recheck your grounds and make sure they are all tied together. #1 cause of weird servo behavior is grounds not being tied together. My second thought is to use a different pin on your arduino for the servo signal and see if that makes any difference.

      If that does not solve your problem, I can think of two solutions:

      1) Use a relay or a switching IC like a Darlington Array to control ground to the servo. You want to keep the servo powered off until after you have initialized the servo library and the servo object(s). After initialization, set the position then use the relay/IC to turn the servos on. You want to control the ground side because the servo has two “hot” inputs that share that ground.

      2) Instead of attaching directly to your Arduino, use a servo shield (you should be able to find lots of options) or an external PWM Driver like the Adafruit 16 channel, 12 bit board. Either one should do the trick. I’m working on a new blog entry about working with the Adafruit board and should have that out soon.

      Best,

      Robin

      • Hi Robin, thanks for your quick reply! I’ll try these possibilities. At this moment I’m trying to use your code with “Typedef struct” but I’m not an expert and I’m having some difficulties. In your blog post of “Multiple Turnouts” the code is partitioned and I must be making a mistake when I put all the commands together. Could you send me a copy of the complete code? (I’m using 8 servos) Tks!

        • Take a look at the test loop code and see if that helps you — you can download it here: https://github.com/rpsimonds/thenscaler/tree/Testloop.

          The test loop had only one turnout, but it used all the techniques described in the Multiple Turnouts post. Extending it to multiple turnouts is just a matter of supplying the turnout data. Hopefully it will help you see how the pieces fit together.

          I’ll be writing more about multiple turnouts soon.

          Robin

  9. This looks like what I need to tie my CMRI Arduino nodes to turnout control. Now I just need to figure out how to fill in the blanks on the code to control my 4 turnouts. I guess I would need one shift register to control 4 turnouts, 4 push buttons, and 8 led’s? Thank You

    • If you haven’t seen it you might want to look at Running a Small Layout with An Uno.

      One 8 bit shift register can control 8 LEDS. You cannot use a shift register to read buttons. If you had more than 4 buttons I’d suggest an I/O multiplexer chip, but for four that strategy wouldn’t save you any pins. Attach them to your analog pins (but still use digitalRead()) if those are available.

      Shift Registers aren’t useful where you need PWM, such as with servos for turnouts. If need a pin-saving solution for PWM, try Adafruit’s 16 Channel PWM driver. For stall motor turnouts, you could use a shift register plus a darlington driver array so long as the motor draw is less than 500 mA per channel; that solution allows you to run 12 volt motors with 5 volt Arduino logic.

  10. Hallo, mijn naam is Cvetko Grujic, ik woon in Maastricht,
    Servobesturing met LED-feedback die ik heb gemaakt en het werkt geweldig
    Ik ben geïnteresseerd in dit servoprogramma, dat twee servo’s of meer kan hebben
    Ik ben al begonnen met het maken van een model voor treinen in HO schal,
    Ik zou heel blij zijn als je me kunt helpen . Bij voorbaat dank

      • Hi rob i like you c++ turnout control. But am a littlee fuzzy on one aspect. I have servis going onto my turnouts and an adafruit 16 bit to run the turnouts. I can make them do a serco dance on the adfruit. But am stuck when it comes to putting 16 swithches in the loop somewhere.

        Now i have a toggle switch for each servo. How would i use your c++ code to move servo 1 on adfruit pin 0 when the toggle switch is thrown?

        I know i need some io extender ic2 board to do the 48 controls i need to get to. But for now if you could show me how to put tje toggle switch directly into the ardunio then call the adfruit to switch using your c++ code be so helpful

        • Hi Mike:

          Try these posts and see if they have the answers you seek:

          C++ Objects for Layout Control, Part 2 — Turnouts
          L&NC Update; Running Lots of Turnouts

          Make sure you understand my multi-tasking method: Multiple Turnouts and Other Multitasking

          None of my recent examples use toggle switches because i use network control methods, but that’s not a big deal — you’ll just need to read your toggle switch connections on every loop, and trigger a turnout whenever it’s switch is changed. So at the start of your main loop (see the post on multitasking mentioned above) you do three things: 1) capture the time; 2) check the switches and call the triggers for any turnout switch that has changed; and 3) run the turnout.update() method to continue the movement sequence.

          Don’t forget to download the example code. If you still have questions, let me know and I’ll try to help.

          Best, Rob

          • Hi
            I am a backend LAMP dev on some huge projects, but i think i am over thinking what i need to do and hence stuck as you get.

            What I need to see is a simple sample to talk back to the adfruit when a toggle or push button switch is pressed.

            – what do I need to call xxxx.h as well as turnout.h
            – if a switch into digital pin 6 (uno) and I toggle high move turnout into yard
            – if a switch is in digital pin 6 (uno) and I toggle low to set the mainline straight threw

            Parts i have uno R3, adafruit 16bit.

            Can make my servos dance, but now need to switch them and am a little stuck as where to start I looked at your Organizing Turnout Data but as i mentioned before have a mind blank with how to use the switch to trigger things.

          • Hi Mike,

            You probably are overthinking it a bit. I’ve been there; I’m buried in PHP and Javascript right now and sometimes the transition back to Arduino C++ can be head-snapping.

            If I’m understanding correctly 1) you are ok using the adafruit board and setting a servo position with it; 2) you have my turnout class (turnout.h) and understand how it works and how to use it to move turnouts; but 3) you are uncertain how to use a button or switch to trigger movement.

            OK. First all all, whether you use a button or a switch, you’ll need a pull-down resistor as shown on this page; that prevents false readings. A switch is wired the same way as a button except only one of its outputs connects to your Uno pin (leaving other outputs unconnected). The difference between the two is the button pulls the pin high momentarily, while the switch pulls it high continuously until toggled off. The code is similar, with a few differences due to the differences in the way buttons and switches work.

            Button:
            // turnout object created with the parameters that a correct for your installation
            turnout = new turnout(TURNOUT_PARAMS *parameters);
            loop(){
            unsigned long currentMillis = millis(); // get elapsed time as required for the turnout object

            // check the button
            if(digitalRead(6) == HIGH){
            turnout.toggle(); // With buttons, use the toggle function to change position and trigger movement; toggle() will reverse a switch in motion
            }

            // update turnout objects for movement
            turnout.update(currentMillis);

            // do other stuff
            ....
            }

            Switch:
            // turnout object created with the parameters that a correct for your installation
            turnout = turnout(TURNOUT_PARAMS *parameters, int movement_increment = 1);
            loop(){
            unsigned long currentMillis = millis(); // get time as required for the turnout object

            // check your switch
            if(digitalRead(6) == HIGH){
            // if the switch reads HIGH, turnout should diverge into the yard
            // check turnout state first
            // call set() only if turnout is currently in wrong position and is NOT in motion
            // in the turnout class, alignment is set to ALIGN_NONE while the turnout is in motion
            if(turnout.getAlignment() == ALIGN_MAIN) { // if TURNOUT is aligned for main track
            turnout.set(ALIGN_DIVERGENT);
            }
            } else {
            // switch is currently LOW; turnout should be aligned for the mainline
            if(turnout.getAlignment() == ALIGN_DIVERGENT { // if TURNOUT is aligned for yard track
            turnout.set(ALIGN_MAIN);
            }
            }

            // update turnout objects for movement
            turnout.update(currentMillis);

            // do other stuff
            ....
            }

            Other than turnout.h for the turnout CLASS (and the adafruit header) you don’t need any other .h files.

            I hope this helps.

            Best, Robin

  11. Thanks Robin,

    I will this a go a see where I get to but last night I had my head in the right place and things were working. I think I am over thinking the electronic sides of things as the understanding of some of the concepts/language used is making me over think.

    I have another i2c board that is addressable along the lines of the adafruit where it can read and writes to put my switches (it only turned up yesterday) into I think this will solve the problem of running out of pins on the Arduino, and I think this board will handle the diodes as well well we will see.

    My thinking around this is to make things easy for people is this single pin addressable board for switches on i2c (I think the lull up resistor is on the board) linked to Arduino — then i2c to adafruit. A class called switching and your turnout class, we have a nice pluggable solution that a few of my model club members could work out as the heavy lifting portions of the code are will be done.

  12. Robin thanks for the code that you put above it is great and will be testing it out later today.

    And ill post up a link to the new component I discovered, it is chainable as well

  13. Hi Robin: in the past month I have been trying your code and diagram to control the turnout with a single button and 2 LEDs. I have gotten a single servo working on my Arduino Uno and I am trying to get 2 servos working at the same time. I am wondering if you can give me some code to do so. I have been trying to “copy & paste” (not literally) the code. So in the end I have a single servo controlled with a single button and 2 LEDs and in the same code have another running the same thing, of course on the Arduino Uno.

  14. Your work has inspired me to jump in on a large project in HO scale. I have been reading and learning some from your posts but most of those Aha moments come from the answers to questions others have posted to you.

    I can control 23 turnouts with 2 Adafruit 16ch pwm boards. I am also using 2 Adafruit 12 key capacitive touch sensor board to pick up the “NX” style controls and have that working to select the routes. I was trying to figure out how to add the address/variable of each pwm board to the array and call it to perform the action without the need to start each line with “pwmX”. Probably so easy I am just overlooking it. Here is a sample of the routines I have to align everything.

    void east1(){
    pwm1.setPWM(1, 0, turnout[1].pos_norm);
    pwm1.setPWM(2, 0, turnout[2].pos_norm);
    pwm1.setPWM(3, 0, turnout[3].pos_norm);
    void west0(){
    pwm2.setPWM(0, 0, turnout2[0].pos_norm);
    pwm2.setPWM(1, 0, turnout2[1].pos_norm);
    pwm2.setPWM(2, 0, turnout2[2].pos_norm);
    pwm2.setPWM(3, 0, turnout2[3].pos_norm);
    pwm2.setPWM(4, 0, turnout2[4].pos_norm);
    pwm2.setPWM(5, 0, turnout2[5].pos_norm);

    • Hi Scott,

      Its been a busy month and I’m way behind on almost everything. Sorry to take so long to respond.

      This is a route setting problem at its heart. Each each pwmX represents a unique instance of the Adafruit pwm object that matches one board, right? It looks like you have an array of turnout objects/structs for your data. So far, so good.

      To simplify your code, you want to encapsulate more of your functionality inside an object. I did that in my turnout class so that it can be used with either the Adafruit board or the standard servo library. Since my class does not yet support multiple Adafruit boards, you will want to add a parameter (and use it in the object) to reference the board associated with a turnout. Taking that post as a starting point (read that first), the new class member of the turnout class might look like:

      Adafruit_PWMServoDriver *board;

      the parameters array might look like:

      typedef struct TURNOUT_PARAMS {
      int pin;
      int pos_main;
      int pos_div;
      int align_default;
      int move_delay;
      Adafruit_PWMServoDriver *board;
      };

      then the actual parameters might look like:

      TURNOUT_PARAMS tdef[NUM_TURNOUTS] = {
      {0, 375, 310, ALIGN_MAIN, DEF_DELAY, board1},
      {1, 335, 408, ALIGN_MAIN, DEF_DELAY, board2} ..... etc}

      Modify the setServo() method along these lines:

      void setServo(int data){
      // compiler directives determine which
      // method is used to drive the actual hardware
      #ifdef ADAF_DRIVER
      board.setPWM(pin, 0, data); // uses *board pointer
      #endif
      #ifdef SERVO_LIB
      extern servo servos;
      servos[pin]->write(data);
      #endif
      #ifdef PWM_PIN
      analogWrite(pin, data);
      #endif
      }

      Create two member functions, east() and west(). Each turnout object will need some data to know how to align for each state.

      Assuming you hold all your turnout objects in an array call “turnouts”, a master function can set your route:

      void setTurnouts(int route){
      switch(route){
      case EAST:
      for(int i =0; i < NUM_TURNOUTS; i++){ turnouts[i]->east();
      }
      break;
      case WEST:
      for(int i =0; i < NUM_TURNOUTS; i++){ turnouts[i]->west();
      }
      }
      }

      This is not a complete solution …. rather I’m suggesting a different approach to the problem that would improve code simplicity and readability. The main point is to 1) create an object that wraps around and hides the nitty-gritty of moving servos, and knows what alignment is required for each route; and 2) to hold all references to your turnout objects in a single array that your can step through with a “for loop.” You could extend this to support multiple routes by loading each object with a data array so it has alignments for each route. Just call all turnouts with a given route # and they should set themselves accordingly.

      RS

  15. Hi Robin:
    Thank you for posting your article regarding turnout control using Arduinos. Your turnouts control is exactly what I am looking for. Your article was easy to follow. Iing 1 pushbutton to control the 2 way point movement. As I would like to control all my turnouts using something like this I have some questions:
    1. Can more than one turnout be installed on an Arduino uno?
    2. Would it be best to order a Mega rather than an uno for multiple turnouts?
    3. Could a command control and/or signalling system be attached at a later date?
    Again, thank you for posting your tutorial…it is appreciated.
    Regards
    Geoff Danish

    • Hi Geoff,

      Let me suggest that you look at my more recent posts on C++ objects. Also, if you haven’t already, take a look at this page on multitasking techniques.

      To answer your questions:
      1. Yes. Its a matter of pins and available memory. Using the standard servo library, documentation says:

      The Servo library supports up to 12 motors on most Arduino boards and 48 on the Arduino Mega.

      You can overcome those limitations using Adafruit PWM Driver boards.

      2. If you need more than 12 servos; alternatively, use Adafruit boards.

      3. Absolutely. The incremental approach is often the best.

      Cheers!

      RS

  16. Thanks for the response. I know all about busy too. I will try adding the “elegance” of your suggestion as soon as I figure out either the 12 channel cap touch issue or change the input method to something reliable like momentary push buttons. I can’t get the cap touch to read consistently even after changing some of the suggested parameters. Then I have enough sensors I added a second cap board (different address) but when I test the second board it screws up the primary and the code doesn’t seem to run just hangs during Setup. Oh well I know you aren’t using cap touch and to keep the rest of my hair on my head I don’t think I will either so I can get this project moving forward. I may revisit the cap touch later for a sleek control panel.

    • Always good to limit your variables in the beginning and get one piece working at a time. I’d definitely get the turnouts themselves functional before creating an advanced control system.

      You might consider touch screen control. Adafruit has compatible touchscreens. 800 x 600 is your max resolution for Arduino based projects; higher resolutions require a different solution such as Raspberry PI, but you could use a large commercial HDMI touchscreen which would be nice. Come to think of it, using using “Processing” for Raspberry PI, or Javascript, it should be straight forward to getting a Pi to talk to your Arduino via serial or network protocols. That gains you powerful graphics capabilities using HDMI displays plus access to any device a PI can access — including printers. I’ve always thought that it would be fun to have a system create and spit out waybills and dispatch orders for operating sessions… but I digress.

      I’ve worked with an UNO driving a 4″ touch screen successfully. Adafruit has a 7″ one that, with a TFT Graphics interface board, works with Arduino.

      My long term plan is to create a master control center with 2 or 4 7″ touchscreens (a 14 x 14 display), using graphics drivers plus a MEGA to do the processing. Additionally, I’ll create 2 or 3 convenience panels with 4″ screens and Unos in places where you would do a lot of switching ops. Everything talks via the network so it shouldn’t be too hard pull it all together.

      • Sometime in the future is a CTC system for the club and I had planned on the Pi to run the whole show so we could talk to our guests while trains operated in the background or we could actually have an op session.
        As an update I did tweak the registers on the MPR121 to reliably read each board reliably but I still get the freeze when both boards are on the I2C bus. The illuminated momentary PBs are here so I will get this working and continue to tinker with bigger better things.

        • The freeze sounds like an I2C addressing problem. Each board should have a unique address within the I2C range. Your boards should have a way to set the address, with maybe 4 or 5 address choices. RS

          • When I get a few hours to tinker with all I2C stuff I will try all the address combinations (0x5A-0x5D) available for the cap touch. The lighted momentary PBs work with the servo boards and for now that is phase 1 (a working system).

  17. Hi,

    I am helping my son setup his layout and I am interested in setting up his turnouts to use this control method that you have come up with. I was talking to some other model RR friends and the one concern they had was about the servos and if they could withstand the wear and tear to the gears. They were wondering how has this system worked for you and have you had to replace any servos due to stripped gears? Their concern was about dirt/ gravel getting stuck in the switches which would prevent the turnouts from being completely thrown. If this occurs would the servo keep trying to complete the position change and possibly strip the gears over time?

    Thanks,

    Dave

    • Hi Dave,

      I’ve never had a servo strip its gears. The only mishaps I’ve had so far are a couple of broken servo->throw rod linkages, probably because I didn’t have the alignment quite right.

      Servos stopped before the intended destination will exert pressure, and if the remaining travel is significant they will get buzzy and hot. Eventually something ought to break, but I haven’t seen that yet. I’ve blown out parts on the layout, so I’d say the servos are proving resilient.

      I use fairly stiff music wire to actuate my turnouts, and I intentionally set the servos to put a little pressure on the turnout at both ends of travel — my Peco electrofrog turnouts seem to like that — so I can say that servos can take some mild resistance without breaking. If you want to make a servo more forgiving of obstructions, increase the flex of the actuating wire and let the wire take the stress of the interrupted travel.

      I recommend music wire for this application. I use .062 (1.57mm) dia wire; in 4 – 6 ” lengths it will bend about 1/4″ or so (the longer the wire the more bend you get). Try different diameters to get the flexibility you need.

      Best,
      Robin

  18. Robin, Thank You so much for this information. I recently retired and decided that the time had finally come to get back into Model Railroading. I was introduced into it by my father about 60 years ago. Most of my equipment is 40 to 60 years old. Anyway, in planning I had decided the regular switch machine were not to my liking and stumbled onto an article talking about Ardino. Since I had a past that included programming in BASIC, sounded like I was set. Little did I know. So for the last month I have been pouring over every tutorial I could find to re-educate myself. The common thread was none teach you how to take arrays and operate from them. That’s been where I was stuck. So with your examples and explanations I hope to move forward.

      • Robin, I took a look at the 2 parts and with just coming to grips with C++ don’t feel I am ready. Still working on getting totally working code using arrays. But as I mentioned before, the info you have in your write ups really expands on the on line tutorials out there.
        Do you have a direct email address I could use to ask a question about using your code?

  19. Hi Robin,
    Have found your page helpful. Would appreciate some help. I have a hidden storage yard 3 roads either side of single main. The roads can be entered from either end off the main. I have tortoise motors rather than servos. My concept is using Arduino Mega processor to select a route for any of the roads by pressing a button. Once button is pressed and released the motors would be set to the selected route. This would stay until another button is selected and another route is chosen. At present 7 buttons are required. One for each road.

    Stage 1 is to use a mimic board with buttons positioned on each road and bi polar LEDs indicating route selection. LEDs to be driven by tortoise motors. Switching via Mega

    Stage 2. Replace mimic board with a 7” touch screen. Colour code routes as selected by button pressed.

    Stage 3 Have a touch screen wireless, wifi etc connected. Ultimately an old iPad.

    The power for tortoise motors is via two power paks in series and connected to a group of relays. The purpose of relays is just to change polarity. These in turn are controlled by Arduino Mega board.

    My immediate problem is how to code for pressed button.

    Appreciate any help or suggestions

    • Hi John,

      Your concept seems sound. I assume you are at stage 1 at this point.

      The classic way to deal with buttons is to poll them in your main loop and act when they go HIGH (when pressed). So, your main loop looks something like this:

      loop(){
      if(digitalRead(pin_for_button1)==HIGH){
      //set route 1
      } else if(digitalRead(pin_for_button2)==HIGH){
      //set route 2
      } else if(digitalRead(pin_for_button3)==HIGH){
      //set route 3
      } else if
      etc…. for all buttons
      }

      This approach should get you started.

      Some random thoughts and suggestions:
      1. don’t forget the pull-down resistor on each button pin. Use 10k ohms; prevents false HIGHS;
      2. be aware that some relays will draw more power for the coil than the Mega can handle; I usually have to use a transistor or darlington array as an intermediary to prevent over draw. Use a relay shield if you can find one rated for the power you’ll be supplying the tortoises (the coils will be within the MEGAs power limits).
      3. if you don’t use a shield, use bi-stable relays: they hold position without constantly energizing the coil — just 50-100 ms trigger power on one side of the coil or the other is all they require.

      Let me know how it goes.

      Rob

      • Rob,
        Thanks will start coding.
        FYI Tortoise motors on own circuit and supply.
        Relays have own power supply. Using two Songle 8ch5v relays to isolate from Mega board. Mega board has own power supply.

        Will get back when working or if get stumped.

        Thanks again
        John

        Propose that all tortoise motors to be set to straight as default. Relays to support this ie pins will be set to low thus going high will reverse polarity. This will give me a consistent reference at start up of layout.

        • So far so good. I don’t know what you mean by “switch bounce”; you shouldn’t have to do anything more than set the correct polarity to control the Tortoise machines.

          • From my research when using a momentary switch they recommend coding for “debounce”. I believe it’s to make sure that mega has read the signal correctly.

            I now have another problem. Couldn’t up load code to board. The board is a “ funduino mega “ from a reputable Australian company and says is fully compatible with the Arduino, plus I now have a virus on the PC.
            Have you had any experience with this type of issue?

          • I’ve never had an issue requiring “debounce” handling. My advice is to keep it simple until you work through the basics. A bounce problem would be a good sign that you are making progress.

            A brute force method of preventing the problem would be to add a delay (say 100ms, so delay(100)) after each button read cycle. That gives the pin a chance to go low before you try to read it again. Obviously, you wouldn’t want to hold a button down under these circumstances or your program will go nuts — press and release is easiest to deal with.

            How did you get a virus? I’ve used “compatibles” without problems. Maybe you picked it up from a website? I’m always wary of downloadable zip files.

  20. Robin,
    Sorry the virus is on my machine. I visited my son and it was on his computer that I was unable to down load to the Funduino mega. Two seperate situations at different locations.
    Cheers
    John

Leave a Reply

Your email address will not be published. Required fields are marked *