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.


 

118 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 have read that using the Arduino to control servos directly is not a good idea. I have a PCA9865 to do it with a separate 5V PS. I’m still learning this a piece at a time. I’m going to use MERG mounts for the motors. What’s your thoughts on a separate servo control board? I have 16 turn-outs.

    • 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;
    }

      • For PCA9685 PWM drivers I recommend the Adafruit Library. While you are at their site, take the time to look over their products … they have quite a few items of interest to Model Railroaders, and if we are going to use their software, the least we can do is see what they have!

        Once you have the library installed, here’s the missing line:

        #include <Adafruit_PWMServoDriver.h>

    • Where is the void loop() in this code?
      Where do you set previousMillisSwitch?
      Where do you set currentMillis?
      Where do you compare both?

  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

  20. Hi Robin
    I am very new in the Arduino universe 🙂 and are not ready yet for programming Arduino.
    I have used your turnout project and modified a little for railway crossing. It is working well with one button, but Is it possible to change to two buttons. One button for opening gate and number two button for closing the gate
    Best Peter

    • Hi Peter,

      The short answer is yes, you can do it with two buttons.

      The second button would be assigned to its own pin, with a pull-dwon resistor to ground as with the first button.

      Secondly, you will have to modify the code to read both buttons and decide which button has been pressed–and you will need to reject situations where both buttons are pressed at the same time. So the code structure would have be be modified along these lines (this is outline code, not final working code):

      b1 = digitalread(button1);
      b2 = digitalread(button2);
      if(b1 == b2){
      // do nothing
      // act only when one is high and other is low; never act when they are the same
      } else {
      if(b1==HIGH){
      //set target position to open
      pos = OPEN;
      } else if (b2 == HIGH) {
      //set target position to close
      pos = CLOSED;
      }
      }

      Continue from here with original code

      Hope this helps.

      Best, Rob

  21. thank you for the n scaler, without it I would be totally lost. I mastered your servo/momentary buttton sketch but this is the limit of my abilities. I want to control my turnouts with an arduino uno and servos, is there a sketch that maximizes the number of servos controlled by one button each (no leds). Adjusting each servo individually is a must. If you can steer my in the right direction, I would appreciate it. Thanks Bob

    • This particular post is the most basic one I did on this subject. To handle multiple turnouts, here are some posts you’ll want to look at: Multiple Turnouts and Other Multitasking, Running Lots of Turnouts, and C++ Objects for Layout Control, Part 2 — Turnouts. These posts will bring you up to speed on how I do things.

      In general, the Servo library limits you to 10 servos. If you want to handle more than that, you will need one or more PWM Driver Boards, like the Adafruit 16-Channel 12-bit PWM/Servo Driver (see Running Lots of Turnouts).

      Your other limitation is the number of pins you have available for buttons. It you use the Servo Library, the practical limit on servos & buttons will be 8 of each, leaving 4 pins for other uses on an UNO. With a PWM Driver, your practical limit is 16 servos & buttons on most Arduino boards. With a MEGA and two chained PWM Drivers you could handle 32 servo/button combos.

      Hope this helps. Feel free to ask questions after you check out the other posts.

      Best, Rob

  22. GOOD MORNING, I HAVE MUCH LIKED YOUR WORK Complete servo installation. THERE WOULD BE A POSSIBILITY TO MAKE THE CODE EASIER FOR ME TO DO IT WITH TWO TWO-COLORED LEDS (RED AND GREEN).
    GREETINGS AND MANY THANKS

  23. hello my name is joël
    can you also make a code where you can control two servos thanks in advance

  24. Good morning, could you use the PCA9685 controller with this push button and led systems ?. You could send me schema and code.
    Thank you.

  25. Hi,
    i’m new to the JMRI world, i’m running a Arduino connected to JMIR via CMRI protocol, i can’t find any sketch that works with Arduino using 5 servos, I’m using an external 5v psu for the servos, but i can only make 1 servo move from JMRI with the sketch, i’ve tried adding turnout2 to the sketch, but it doesn’t work, surely it shouldn’t be that hard? looking aat york previous posts, it looks like i need to define my extra turnouts?.

    Any help would be greatly appreciated

    Here is the sketch i’m currently working on below:
    #include
    #include
    #include

    #define CMRI_ADDR 1

    #define DE_PIN 2
    int turnout1 = 0;

    Auto485 bus(DE_PIN); // Arduino pin 2 -> MAX485 DE and RE pins
    CMRI cmri(CMRI_ADDR, 24, 48, bus); // defaults to a SMINI with address 0. SMINI = 24 inputs, 48 outputs
    Servo turnOut1;

    void setup() {
    turnOut1.attach(9);
    turnOut1.write(2);
    bus.begin(9600);
    }

    void loop() {

    cmri.process();
    turnout1 = (cmri.get_bit(47));
    if (turnout1 == 1){
    turnOut1.write(10);
    turnOut1.write(9);
    }
    else{
    turnOut1.write(2);
    }
    }

    • Hi Mark,

      I have not worked with JMRI much, so I can’t be a lot of help. I did take a moment to look over the ArduinoCMRI Library.

      Your code is too incomplete for me to be helpful, but I would observe that since you only read bit 47 in the code as given which would only support one turnout object.

      May I suggest that you go back to the documentation and create a simple example that reads and writes only one bit; then add a second bit and so one until you get the hang of the library.

      Best, R.

  26. Hi there. Thank you for all the wonderful useful information. I have one quick question and that is, what size screws did you use to Mount Your servos initially?

      • Thank you, got them at my LHS. I saw the mounts but at $12 a pop, that’s a bit out of my league, even for the convenience. 🙂

        • This gets to the problem we all face in one form or another: money vs. time.

          If you are going to fabricate your own mounts, make them one-piece or they will be prone to breakage under stress. The way I originally did it with multiple pieces and hot glue is not reliable.

          Agree that $12 seems like a lot for one mount — but if you compare it to other servo mounting options on the market, it’s actually one of the lowest cost options. At $15 with the servo ready to install, the cost is a little less than tortoise switch machines (the de facto standard in this area). They also offer additional discounts for multiple units. With even the cheapest, old fashioned switch machines running around $10 ea, there aren’t any cheaper options other than roll-your-own.

  27. Hi, I have searched long and hard to find an Arduino project to turn servo’s on a Model Railway layout using either a push button or a toggle switch without success and using the PCA9685, yours is the only one I have found that I think I can modify, as being an old git my program skills are just about zero, I did build one that I found on Dronebot Workshop using Analog inputs using a Mega which I modified for 9 inputs including controlling a scissor crossing and that does work but I have to use a voltage divider to get 60deg but as of yet not found a way of adding LED’s, and also giving me a digital output to feed to a second Mega which controls the polarity on a 4 Line crossing on 10 diamond crossings, nightmare, so I will try your setup and try and incorporate the PCA9685 and add 5 single servo’s and 2 x 2 servo’s for scissor crossing. Wish me luck ….

  28. Hi Robin,
    I’ve been reading a great deal about using an Arduino Uno and servos to change my points and along the way, discovered the limitation of 1 Uno – I need to change 18 points. Then I discovered the PCA9685 and, with the help of a professional coder on another board, ended up with a sketch the turns the servos slowly. All good. In my testing, I’m using a breadboard and jumper wires for connection, nothing is permanently soldered yet. Occasionally, when testing, one or more of the servos in test would jerk violently when power was applied. More recently, after fitting 5 servos to the underside of a section of my layout, when power was applied, one servo reacted so strongly that it pulled itself out of my mounting. The next thing I know is one of the servos is spinning 360 degrees. These are SG90 servos, supposed to be 0 to 180 degrees and each controlled via a toggle switch. The plan is flick the switch and the servo will move left or right and a led will display the position on a panel.
    Last night, I went out to a friend’s place to operate on his layout and inadvertently, left power on in my train room. Although there was no action on the toggle switches, when I returned, the servos, which I had disconnected from the layout but still connected to the PCA9685, were all spinning madly 360 degrees!

    I’m sure I read somewhere in your posts that you touched on the subject of servos spinning? Can you repeat it here or point me in the right direction?

    • Hi David — I apologize for the long wait. Thanks for stopping by and taking the time to comment.

      Wow. I don’t have a solution for you off the top of my head. A standard SG90 has stops that prevent movement past 180 degrees — and attempting to do so would usually burn out the motor. However, some servos are the free spinning type that do not have stops … is that what you have?

      That tendency of the servos to jerk when power comes up is common and usually harmless. If it is causing a problem, use the OE pin of the PC9685 to control the PWM driver. When the OE is pulled HIGH, output is disabled. So with OE high you can set PWM levels where they are supposed to be, then pull OE LOW to enable output. Any out of position servos will move, but the jerking thing should be better.

      Best, Rob

  29. Using your diagram above to activate a servo using only one push button, I would like to know how best to to connect around 10-15 servos to an Arduino Mega (using 2 digital pins per servo) where the servos would have their own power supply as the Arduino wouldn’t be able to support that load. Near the bottom on this webpage http://www.sumidacrossing.org/ModelTrains/Servos/ shows a diagram for such wiring, but doesn’t use push buttons. To incorporate push buttons, would the positive feed going to the pushbutton come from Arduino Mega or from the servos power supply?

    • The wiring approach you reference is still a little primitive. To run many servos with many buttons you’ll need to split the servos and the buttons into two separate problems, binding them together in your sketch.

      First, To control LOTS of servos [literally, up to just under 1000 servos] with just 2 pins on ANY Arduino board, use one or more PCA9685 PWM driver boards. Each board can handle power and data for up to 16 servos; multiple boards can be chained to the limits of I2C addressing. See this post: L&NC Update; Running Lots of Turnouts. The post refers to the Adafruit product (which is excellent quality), but lower cost generics are available on the open market. You will need an independent 5 volt power supply for the servo power terminals on the boards; make sure the ground of that power supply is tied to Arduino ground [In a properly wired layout for Arduino control, all DC grounds must be tied together even where there are different DC voltages in use — 5v plus 12v would be a common combination]. For logic power on the boards you can use either the Arduino +5v or the independent power supply 5 volt.

      That takes care of wiring the servos themselves. You can wire individual buttons to individual pins as shown in the post. The power supply for the buttons comes the Arduino, as shown on the post.

      I have a better solution for managing multiple buttons (from 1 to 255 buttons) with just 3 pins that will be generally available soon. I can correspond with you separately on that if you are interested.

      In your code, associate specific pins with specific servo ports on the driver board. It should be pretty straight forward.

      Also see posts on OOP objects for layouts generally, and turnouts specifically.

      Rob

  30. Hello
    Re turn out control.
    I would be most grateful if you could help with the following. I have used your excellent wiring diagram and code for operating one servo with push button from the Arduino Uno rev 3. and have it working perfectly. I have been trying to wire and code a second servo with push button but really have no idea what I am doing and have not been able to achieve this.
    Could you show how it can be done.
    Thank you.

    • Hi Peter,

      Actually, its straightforward to add more buttons and servos.

      To add ONE more button + servo, you essentially duplicate the code for the second set. Create additional variables: buttonpin2, servopin2, myservo2, pos2 and old_pos2. Then in setup() add a pinmode and servo attach with the new variables [you are duplicating code and change variable names in the duplicate]. In loop(), read the second button the way you read the first, then duplicate the if() statement to handle that button and servo.

      That is brute force and inelegant coding, but it will work.

      The elegant way — and the way to handle more than 2 — is to use arrays to hold your data and step through them using for() loops to read buttons and act. If you are unfamiliar with arrays and looping through them, find a c++ tutorial to learn about that. I generally recommend w3schools.com for basic computer language tutorials and reference.

      There are later posts you might want to look at about using C++ objects for turnouts. In general, the semantics of C++ objects make it easier to implement something like turnout motor control : C++ Objects for Layout Control, Part 1 and C++ Objects for Layout Control, Part 2 — Turnouts. Also see L&NC Update; Running Lots of Turnouts.

      Best, Rob

  31. Hello
    Firstly thank you so much for replying to my request. You will think I am absolutely hopeless.
    I have attempted to follow your guidance but I honestly do not know what I am doing. Perhaps the only way I could begin to get how this works is to see the code for two servos and buttons and work backwards from there. Just to say I have wired the Arduino exactly the same as the diagram you have given except the second servo is wired button to 10 and servo to 11 and I have powered the servos from external 5v supply.
    I completely understand if what I ask is not possible but I would love to be able to begin to see how this all works. Arrays I think are quite far distant!!
    With many thanks again for taking the time to respond.

  32. Hi Robin,

    Was wondering if you have a web site that shows all the examples you have spoken on. I have followed your advice since 2017 and am now starting my own SR model (HO),
    Like others before me am planning on using an Arduino to control turnouts (15) all controlled from a mimic board by button switches. Home and distant lights, just red and green – sensor switch, and more as I continue this journey.
    I reside in Western Canada – BC

    • Hi Michael,

      I don’t have a separate site with everything. I’m happy to guide you to specific material you are interested in, if that would help.

      Best, R

  33. Fantastic Article and comments. Now onto my newbie questions.

    What size resistors are you using?
    Also, is there any way you have a Sketch that shows an array for 2+ servos? I am sure it will be easy to add more servos and LED’s. Just trying to find a foundation for the array. Drawing a complete blank there and hope you may be able to provide something.

  34. Hello Rob,
    I am getting back to an old problem I had some time ago. Have used your code
    to setup a PCA9685 with four servos SG90; I believe it was your “demo for four servos” or something like that. I got it working for PCA9685, but one error remains.
    I have set quite small movement limits, works fine with buttons, but upon applying power
    servos quickly move close to 90 degrees, and then slowly go to the correct position.
    I did ask about this, the explanation you gave was that servos need to go to “main” to establish a starting position. But, this movement is far from that and would most likely destroy turnouts or servos. It is not like the little jerk you would expect upon startup; more like a controlled movement.
    I would appreciate a hint on a possible solution. Here is the code I suspect is the problem:
    Can not find a definition for “Align main” ?

    void setup()
    {
    //Serial.begin(9600);

    pwm.begin();
    pwm.setPWMFreq(50);

    for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){
    pinMode(turnouts[i].data.button_pin, INPUT);
    setTurnout(i, ALIGN_MAIN);
    }
    } // end of setup

    Please give me some advice
    Peter Unger

    • Hi Peter,
      I’ll have to go through past posts to find the source you used. But I’ve learned some new tricks so lets start over.

      First, ALIGN_MAIN, ALIGN_DIVERGENT and ALIGN_NONE are the three possible states of a turnout. The values are arbitrary; what I use is ALIGN_NONE = 0; ALIGN_MAIN = 1 and ALIGN_DIVERGENT = 2. Those values work out well for making decisions in a sketch. But you can use any set of values you choose. Your SetTurnout() function should act on those alignment values by starting off a process to slowly move the turnout from one side to the other.

      ALSO, on a PCA9685 used to run servos, set the PWM Frequency to 60, not 50 ———– pwm.setPWMFreq(60);

      re: movement: ” but upon applying power servos quickly move close to 90 degrees, and then slowly go to the correct position . . . .this movement is far from that and would most likely destroy turnouts or servos.”

      Unpacking this a bit, it sounds like the servo does a quick movement after power up, followed by a reversal where the movement is at normal slow speed. Is that correct? Also, does the servo stay between the main and divergent positions, or does it stray out of range? A full speed movement by a servo won’t hurt either the servo or the turnout UNLESS the movement pushes the servo past your defined positions.

      For each servo/turnout combo, you will need to establish the servo positions for the main and divergent positions (closed and thrown, for those who prefer that terminology). With the PCA9685 at 60 hz, the positions will be between 150 ticks (0 degree position) and 650 ticks (180 degree position). The center is 400 ticks and the typical throw (very much installation dependent) will be between 75 and 150 ticks. So, assuming you mounted the servo so that the center position puts the points in the middle between positions, your two position settings might be 350 and 450 ticks.

      There are two circumstances under which the PCA9685 will “jerk” uncontrollably: 1) upon application of servo power to the board before setting the PWM level of each port; this is a “soft” jerk, usu about 20 degrees; then 2) when you set the initial position of the servo. The first problem can be fixed the a relay; the second problem is partially avoidable, by requires making choices.

      To avoid the power-on jerk, put a single or double channel relay between the PCA9685 Servo Power terminals and the +5v power source. You will turn the servo power on in the sketch.

      That leaves problem #2 for when the power is turned on. The movement happens because you have to set a starting position but the sketch has no way of knowing the position of the servo on startup, and can only do controlled movement after it knows the starting position … UNLESS you save position information between sessions. The info would have to be stored on an SD Drive or in EEPROM. Every time you move the servo, save its position. Then when you power up again, you have a record of the servo’s last set position. EEPROM is easy to use for this, but there is a limit to how many times to you write to it. To avoid those limits, use an SD card for non-volatile data storage.

      WIth the relay and stored position info, your startup works like this:
      1. at POWER ON – Feed power to PCA9685 logic power terminals, but not the servo power terminals. Use a relay to control servo power.
      2. When the sketch starts, fetch the saved position information to know the current position of each turnout. In your code, record that data and call setPWM() for each servo using that position information; that step will sync the pwm output with the actual position of each servo. NOW activate your relay to feed power to the servo power terminals. The turnouts should go “hard” (unmoveable) without noticeable motion.
      3. Now use your setTurnout() function to set the desired starting alignment and start the normal movement process if the turnout is out of position..

      If you are not using my object oriented version of turnout control – C++ Objects for Layout Control, Part 2 — Turnouts – I’d suggest you go that route. It makes things easier in the long run.

      Best, Rob

  35. I saw that you responded to someone asking how they would control about 40 turnouts. You said they could use a Arduino Mego or multiple Unos.
    The Rev3 mega has 54 digital inputs at $47
    the Rev3 uno has 14 at $27
    You recomended the option to use multiple Unos. Why this over a single mega.
    How many Digital ports are used when making a turnout with a button and 2 turnout indication lights
    I’m trying to figure out how to make a setup for around 30 switches.

    For adding additional power to this system would you recommend using a separate dedicated power supply and using a breadboard to route power and ground to all of these servos?

    • Hi Stephen,

      Your core question is why use multiple UNOs when a single MEGA would seem to have enough ports?

      The basic answer is that the MEGA’s current handling capability is the same as an UNO, 200 mA, and putting all the ports to use can cause current draw to exceed the limits of the board. Input ports usually don’t present a problem, but outputs do. A typical LED draws between 20 and 30 mA.

      Let’s catalog all the resources you need to control 30 turnouts:

      1. A means to run turnout motors. You are using servos so you’ll need 2 or more PCA9685 PWM driver boards to get 32 PWM ports … or more, because of wiring distances depending on the size and configuration of your layout. On the bright side, a PWM driver board only uses 2 controller ports and gives you 16 or more (if chained) PWM ports in return.

      2. For every turnout you’ll need a button port and two indicator ports — 30 input ports plus 60 indicator ports. Even if only half of the indicator ports are on at any one time, 30 LEDS can overdraw a MEGA.

      As you can see, you need 90 ports for the control panel, plus the ports used to control motors. A MEGA alone can’t handle it; the numbers just don’t work.

      Port extenders, and there are all kinds out there, solve the basic problem. PCA9685 boards are readily available for servos and other PWM applications. For digital ports there are I2C and SPI boards available; but be picky and make sure any board you buy has the current handling capacity you need, and make sure you understand how multiple boards are chained to create uniform arrays of ports.

      I built my own input and output port extenders on dev pcbs by hand originally (trust me, that’s the hard way to do it), and now have them manufactured. I call the line duinoNodes under the brand name Lew’s Duino Gear, and you can find out about them here: https://beaglebay.com/duinogear/ldg-duinonodes/ They are available in both assembled and kit form. These are easier to use and and extend than other solutions, which is why I created them.

      My primary solution to the practical problems of electronic layout control is to divide the layout into functional zones, assign a less expensive MCU — such as an UNO or NANO — to each zone, then use port extenders to run layout objects. I link the controllers together with an nRF24L01 radio network. You’ll find blog entries on that subject on the site. You can also use WiFi for controller-to-controller communication.

      I’m also bringing up a commercial plug and play layout control solution, designed along the lines I’ve described, which you can see on the Lew’s Duino Gear site. A DCC interface board is coming soon. Please note that documentation is being rebuilt. The new documentation under construction, including current duinoNode documentation, is here: https://beaglebay.com/duinogear/docs/.

      “For adding additional power to this system would you recommend using a separate dedicated power supply and using a breadboard to route power and ground to all of these servos?”

      Good question. With 30 servos, a second power supply might be a good idea. OR you can use a 300+ watt computer power supply, with a breakout board to gather current from the main connector. See this article for more info. Depending on the size and configuration of your layout, you may need multiple power supplies to overcome power loss over distance. Use a bus system to convey power, using a wire guage adequate for the distances. IMPORTANT: When using multiple power supplies, all grounds must be connected together in a single master ground.

      Best, Rob

  36. Hi Rob, I have been trying to set up a puss button servo with 2 leds and have downloaded the sketch from your website.
    The code works to a point however when the button is pressed the servo moves to position 110 but does not stop it goes back to original position 90.
    Furthermore the second led goes to green when press Botton is pressed but goes off as soon as button is released.Also can I run 2 servos from 1 uno or 1 nano with a second push button and additional leds ?
    Can you advise how to fix this problem.

    • Hi Malcolm,

      It’s hard to know what the problem is without seeing the code. If you could post your sketch, I’ll take a look and see if I can help.

      Your second question, can you run 2 servos on 1 Uno or Nano, the answer is yes. You should have enough pins for the additional button and LEDS. You can run more than 2 Servos directly attached to your controller, with the caveat that the Servos will need an independent power source; powering more than 2 from the +5v terminal will overdraw the controller board. The next step is a PCA9685 Servo driver board to provide PWM ports and control. Also, with indicators and buttons/switches, you’ll need a digital port expansion system because you’ll run out of pins quickly. With the right supporting systems, an Uno or Nano could manage 16 turnouts together with buttons and indicators.

      Best, Rob

  37. Hi Rob, Here is the sketch I am using.
    #include

    // 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 led0 = 6;
    const int led1 = 7;
    const int buttonpin0 = 8;
    const int servopin0 = 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(buttonpin0, INPUT);
    pinMode(led0, OUTPUT);
    pinMode(led1, OUTPUT);

    // setup the servo
    myservo.attach(servopin0); // attach to the servo on pin 9
    myservo.write(pos); // set the initial servo position

    // set initial led states
    digitalWrite(led0, HIGH);
    digitalWrite(led1, 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(buttonpin0);
    if(button_state == HIGH){
    // turn off the lit led
    if(pos == straight){
    digitalWrite(led0, LOW);
    } else {
    digitalWrite(led1, 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
    }
    }
    // turn on the appropriate LED.
    if(pos == straight){
    digitalWrite(led0, HIGH);
    } else {
    digitalWrite(led1, HIGH);
    }
    }
    }// end of loop

  38. Hi Again. The sketch did include this line at the start although it was not included when I copied into “Comment” just now.
    #include

  39. Hi, Rob, Here is the code as downloaded above

    #include

    // 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 led0 = 6;
    const int led1 = 7;
    const int buttonpin0 = 8;
    const int servopin0 = 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(buttonpin0, INPUT);
    pinMode(led0, OUTPUT);
    pinMode(led1, OUTPUT);

    // setup the servo
    myservo.attach(servopin0); // attach to the servo on pin 9
    myservo.write(pos); // set the initial servo position

    // set initial led states
    digitalWrite(led0, HIGH);
    digitalWrite(led1, 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(buttonpin0);
    if(button_state == HIGH){
    // turn off the lit led
    if(pos == straight){
    digitalWrite(led0, LOW);
    } else {
    digitalWrite(led1, 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
    }
    }
    // turn on the appropriate LED.
    if(pos == straight){
    digitalWrite(led0, HIGH);
    } else {
    digitalWrite(led1, HIGH);
    }
    }
    }// end of loop

    Servo still keeps returning to original position after button press
    Regards
    Malcolm

    • Hi Malcolm,
      I see some issues.
      1. Just to be sure, do you have a 10k pull-down resistor attached to the button pin?
      2. The movement algorithm isn’t quite right. You have this:
      if(old_pos < pos){ // if the new angle is higher but no way to handle the case where old_pos > pos. So you need an “else” and additional code to handle that case.
      3. Experimentally, what you are doing is fine. For something that is practical for a layout and allows the controller to do multiple things, you’ll want to change your turnout code so that you don’t use delay() at any point in the process. I have a new post coming soon that may be helpful, but here are older posts you can refer to: Multiple Turnouts and Other Multitasking, C++ Objects for Layout Control, Part 2 — Turnouts.

      The best approach is to create turnout “objects” that contain all the data and methods needed to run a turnout, then in loop() call that turnout’s “update” method to manage motion. Here is an example of an update() method that gets called, with the current millis() time as an argument, on every loop() iteration. Notice that the method exits update() immediately if the turnout isn’t moving; if it is moving, one movement increment is executed then the method exits. The motion algorithm contained inside update() is what you are trying to do:

      void update(unsigned long curMillis) {
      if(is_moving){
      if((curMillis – last_move) >= move_delay){
      last_move = curMillis;
      if (pos_now < target_pos) { // if the new position is higher pos_now = min(pos_now + 1, target_pos); setServo(pos_now); } else { // otherwise the new position is equal or lower if (pos_now != target_pos) { // not already at destination pos_now = max(pos_now - 1, target_pos); setServo(pos_now); } } if (pos_now == target_pos) { is_moving = false; last_move = 0; alignment = target_alignment; } } } } SetServo() is a different method of the turnout object. Replace those calls with myservo.write(pos_now). Best, Rob

  40. Hi Rob, Yes I do have 10K resistor on the press button.
    I am very new to Arduino and are not familiar with programming. That is why I downloaded the sketch from this page below the diagram above showing the wiring. If this is the sketch used in the video then why does it need to be amended to include “void update” followed by new code.
    I have no idea where to insert this code. Are you able to amend the original sketch to include the amendments needed to make it work just like in your video ?
    I do appreciate the time you have taken in the above responses.

    • Hi Malcolm,
      I’m going to try to explain the problem in a way that will help you fix it, because you will need to adapt what you learn in this context to your future needs. I could write the sketch but then you won’t understand the why of it. The example you are working from is simplified and lacks some things I would do in a real world application.

      The reason your sketch isn’t working is you didn’t copy the loop() code in its entirety, so the algorithm will not work right. The main problem is you missed half the movement code, where “new_pos > pos” — it should be:


      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
            }
          }
        }

      Put the above code in loop(), removing the movement code you have now.

      Rob

  41. Hi Rob,Thanks again for your prompt response.
    I did what you suggested but still not working. I checked your text in the sketch against the sketch I downloaded and your is exactly the same. If you look at my messages to you on 9th & 11th May 2023 you will see that I did copy the loop code so that is not the problem.
    In the downloaded code and your sketch there is no code “new_position>pos” as it is not defined anywhere including Global Variables.
    It appears there is some code missing to get servo to move and stay in the new position instead of moving back and forth which is still happening.
    I would be very grateful for some new code to fix the problem.
    Regards
    Malcolm
    PS. Is the code above the video on this page correct ? i.e.(1 button 2 leds)

    • Hi Malcolm,

      For some reason, WordPress is mangling code is comments. Do this: go back to the post and near the top find the code that comes just after the illustration of connecting a button to an UNO. That block is complete — copy it exactly with no changes, connect a button and servo using the same pins and give it a try. Don’t do anything with the LEDs yet — lets just get the button and servo working properly. What should happen is when you push the button, the servo moves to the opposite position then stops.

      Rob

  42. Thanks Rob, It turns out I had a damaged UNO and press button switch. All working now.
    Regards
    Malcolm

  43. Hi Robin. Thank you so much for your the information you have posted. I have been reviewing it for sometime now. I am interested in using servos and an Arduino to control my turnouts. Do you have any concerns with the turnout’s points drifting after servo operation? Thank you. Dave

    • Hi Dave,

      So long as the servo is powered, it will stay put and you won’t have any issue with point drift. If using more than one servo, use a PCA9685 board attached to your Arduino to run your servos. It helps manage the power consumption issue and supplies a PWM signal with a little finer resolution than achievable on a regular Arduino board.

      One thing about servos is they tend to make a little jerk when powered up. You can control that by starting the PWM signal (which will set the servo position) before applying power to the servo itself. You can use EEPROM to “remember” which position the turnout was in when the power last went off…keep it to remembering the turnout state as “closed or thrown” and don’t try to record the actual position of the servo on each movement or you’ll burnout EEPROM in no time at all.

      Best, Rob

      • Thank you so much Robin. I appreciate your help. This may be off topic, but I was hoping you might be able to comment on how to incorporate reversing frog polarity with a servo? Or, please point me in the right direction in the comment archives. Thanks again.

        • Hi Dave,

          I should do a post on that subject, because it turns I’ve never covered that! I do recommend as a starting point, the turnout object described here: https://thenscaler.com/?p=1266; there is a link to code on github at the end of the post.

          You will need to add a pointer or other reference to a relay — an off-the-shelf 5v DPDT relay is the best choice. The relay has to be attached to a port, so just add the port number to the object. Relays have a jumper that sets whether activation is HIGH or LOW. For the example below, set it for LOW — this is the best setting for attaching a relay to an Arduino pin. Ideally, the relay default (no power to coil) should be wired to produce the correct polarity for your turnout default. If the default position for the turnout is closed, then when you throw the turnout, you also energize the relay to change the track polarity.

          Accordingly, your turnout object properties might now look like this (changes in bold — these are code fragments — see the github files for the complete code set):

          class turnout
          {
          private:
          // object properties
          int servo_pin;
          int relay_pin;
          int pos_main; // servo position for CLOSED
          int pos_div; // servo position for THROWN
          int align_default; // default alignment when the system starts
          int alignment; // actual current alignment

          // motion data
          bool is_moving;
          int move_delay;
          int increment;
          int pos_now;
          int target_pos;
          int target_alignment;
          unsigned long last_move;
          }

          The turnout::set() function might now look like this:

          void set(int align){
          if(align != alignment){
          is_moving = true;
          last_move = 0;
          target_alignment = align;
          alignment = ALIGN_NONE;
          switch(align){
          case ALIGN_MAIN: // CLOSED
          target_pos = pos_main;
          break;
          case ALIGN_DIVERGENT: // THROWN
          target_pos = pos_div;
          break;
          }
          }
          if(align != align_default){
          // activate relay coils
          digitalWrite(relay_pin, LOW);
          } else {
          // de-activate relay coils
          digitalWrite(relay_pin, HIGH);
          }

          }

          That is probably the most basic way to do it. For large numbers of relays (3 or more), I recommend a switching board that will allow you to control as many relays as you need using just 3 pins on the Arduino.

          Best, Rob

          • Thank you so much Rob. I appreciate your help and generosity. Dave.

Leave a Reply to Rene m Cancel reply

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