C++ Objects for Layout Control, Part 2 — Turnouts

In C++ Objects for Layout Control, Part 1 I did an introduction to C++ objects, and demonstrated the basics of OOP with a simple “fire” object that I use to run an LED to simulate a fire in the turntable operator’s hut on the L&NC. In the demo sketch I did two instances of the fire object with two LED’s to demonstrate object independence and scalability.

In this post, we’ll take the basics of C++ objects for animation and extend them to the most common animated object on our layouts: turnouts.

L&NC Progress

Before I go hardcore programmer on you, I thought’ I’d share a few progress notes & pictures. Last weekend we rejoined the three lower level modules together for the first time in over a year.

All Three lower level sections reassembled.

Crossing from module 1 to module 2 for the first time.

Red Bluffs Yard

Another view of Modules ! & 2

I was especially pleased that the three sections came back together perfectly, even though they have been apart for over a year. I attribute the stability of the structures and the accuracy of the alignment to the style of framing, use of hardwoods and the McMaster-Carr alignment pins I use to assure the sections align correctly when put back to together. It all looked good on paper; but until proven you can’t be completely sure. Now I’m confident I can take the layout apart and put it back together again reliably.

I’m getting the basic wiring and interconnections with modules 2 & 3 completed, following the same basic methods as on module 1 (the main difference from where I began is I’ve moved to current transformers for occupancy detection). Once the basic wiring is in and the turnouts are mated with servos, I’ll start in with scenicking. I’ll cover and further shape the mountain with plaster cloth and sculptamold. Since I am doing more roads (using the Woodland Scenics road system which I think works pretty well; more about that at the end of this previous post) on both modules 2 & 3, I’ll pour those first. I find it best to get the roads in before applying any paint or other material. All that should keep me busy for a while.

Turnout Issues & Requirements

Like the fire object, the turnout object requires certain basic parameters to run, and has to be able to keep track of its own state. The turnout object has to respond to positioning commands and manage the turnouts’ motion to achieve a slow, scale appropriate movement from one alignment to the other.

The added complication is that the turnout class will need to deal with different hardware configurations and interfaces in different situations. For example, on the L&NC module I’ve been working on there are 9 turnouts and I’m using the Adafruit PWM Driver to run the servos and additional PWM devices, which I discussed in L&NC Update: Running Lots of Turnouts. The adjacent module has only two turnouts, so I’ll use the standard servo library and a couple of pins there. But regardless of the hardware interface, I want to use the same software objects in both places so they perform the same way.


The turnout class is a little more complicated than the fire class. Its basic properties include the pin (in the case of the Adafruit driver, the channel) the servo is attached to, the current alignment of the turnout, the default alignment and the servo settings for the main and divergent positions (pos_main and pos_divergent). Then, to facilitate motion, there are a variety of properties that work together: delay between moves, the increment (1 or more units) of each move, the current position, the target position and the target alignment.

class turnout
 // object properties
 int pin;
 int pos_main;
 int pos_div;
 int align_default;
 int alignment;
 // motion data
 bool is_moving;
 int move_delay;
 int increment;
 int pos_now;
 int target_pos;
 int target_alignment;
 unsigned long last_move;

I mentioned that I am using the turnout class in different situations where the hardware that runs the servos could be a standard pin, or an external driver board such as the Adafruit PWM Driver. To complicate matters, while the standard Servo Library positions by degrees, the Adafruit PWM Driver positions by the “tick” value of the desired PWM setting.  These are different units and different scales; but it doesn’t matter. So long the turnout class is initialized with a correct set of values (in the same units) for the hardware interface in question, it works consistently.


For the turnout class I have created an interface of public methods for interacting with the class. Additionally, the class has a private hardware interface for interacting with the hardware environment.

The Constructor

The constructor is straight forward with one twist. Because a lot of arguments are required to set up the object, I’m using a data structure to pass most of the arguments.

typedef struct TURNOUT_PARAMS {
 int pin;
 int pos_main;
 int pos_div;
 int align_default;
 int move_delay;

On the L&NC Module1, Lower Level the array of turnout parameters looks like this (STANDARD_DELAY is 20):

 {2, 330, 370, ALIGN_MAIN, 30},

The constructor takes a pointer to a TURNOUT_PARAMS variable, plus an optional movement_increment argument. I added the movement increment parameter (and the corresponding class property) as an additional factor in turnout motion after encountering problems integrating multiple processes on the Uno on Module 1. Manipulating both delay and increment values improves control over the movement of servos in different situations. On the L&NC Module 1, Lower Level there are both a lot of turnouts and a lot of block detectors. I’ll discuss the issues more in an upcoming post, but the resources required for block detection make it difficult to move the servos fast enough without adjusting the movement increment.

// Constructor
 turnout(TURNOUT_PARAMS *parameters, int movement_increment = 1){
   pin = parameters->pin;
   pos_main = parameters->pos_main;
   pos_div = parameters->pos_div;
   align_default = parameters->align_default;
   move_delay = parameters->move_delay;
   is_moving = false;
   increment = movement_increment;

After capturing the parameter values, the constructor invokes the private init_servo() method which I will talk about below in the hardware interface section.

Using the array of parameters above, the turnout objects are instantiated with this bit of code in setup, taking the default value for movement_increment (turnouts is global, declared before setup):

 turnout *turnouts[NUM_TURNOUTS];
 for(int i = 0; i < NUM_TURNOUTS; i++){
   turnouts[i] = new turnout(&tdef[i]);

What’s all this Pointer Stuff?

If you’ve been working with Arduino for a while you’ve likely dealt with pointers before. For those who are unfamiliar with the term (and it is a complex subject, worth learning), pointers are the memory address of a variable. Pointers are another way to access variables unique to the C/C++ languages. In the case of the Constructor, passing a pointer to the parameters array grants access to a complex data structure without having to copy it first. The Reference (&) operator returns a pointer to an variable (&tdef[i]); the dereference (*) operator declares a pointer variable used to access a pointer’s value — such as TURNOUT_PARAMS *parameters in the Constructor. With pointers to data structures or objects, use “->” to access members instead of “.”; eg: params->data instead of params.data or object->method() instead of object.method().

The Public Interface

The public interface is comprised for four methods. The getAlignment() method is a good example of the correct way to share the value of an internal property with an external process. Its correct because it outputs the value of the alignment property without breaking its protection as a private property (and thus exposing it to being changed externally).

 int getAlignment(){
   return alignment;

Another simple method provides a way to toggle the position of the turnout back and forth.

void toggle(){
   if(alignment == ALIGN_MAIN){
   } else {

The alignment can be one of three values at any given time.

#define ALIGN_NONE 0
#define ALIGN_MAIN 1

As you’ll see, ALIGN_NONE indicates that the turnout is in motion.

The heart of the logic for moving the turnout is in the set() and update() methods.

void set(int align){
 if(align != alignment){
   is_moving = true;
   last_move = 0;
   target_alignment = align;
   alignment = ALIGN_NONE;
     case ALIGN_MAIN:
       target_pos = pos_main;
       target_pos = pos_div;

 void update(unsigned long curMillis) {
     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 + increment, target_pos);
       } else { // otherwise the new position is equal or lower
         if (pos_now != target_pos) { // not already at destination
           pos_now = max(pos_now - increment, target_pos);
       if (pos_now == target_pos) {
          is_moving = false;
          last_move = 0;
          alignment = target_alignment;

Motion works by setting motion variables in the set() method then calling update() repeatedly to execute the motion. Update() is intended to be called continually as part of the main loop() while the sketch is running—my multitasking model is to get the current time (millis()) at the start of every iteration of the main loop(), then pass that value to every object that uses time to manage its own state. It is very important that the very first logic test within the update() method is whether or not the turnout is in motion; if not in motion the method exits immediately. With nine turnouts on the lower lever of module 1, efficiency is necessary or the sketch bogs down.

Hardware Interface

Up to this point there has been no direct interaction with hardware. Instead there have been calls to two private methods: init_servo() and setServo(). These two private methods interact directly with the servo hardware.

I should emphasize that any motor type can be used with appropriate connections, even 12 volt stall motors. I like servos because they are cheap and easily supported in the Arduino world. But don’t feel that just because you have a different motor type you can’t run them with an Arduino. The point of creating a private, protected hardware interface is to isolate all the hardware specific stuff in one place while presenting a more general public interface. That makes it much easier to drive a wide variety of hardware while behaving consistently.

 void init_servo(){
   int data;
     case ALIGN_MAIN:
     data = pos_main;
     data = pos_div;
   is_moving = false;
   pos_now = data;
   alignment = align_default;
 // hardware interface 
 void setServo(int data){
   // use compiler directives to determine which
   // method is used to drive the actual hardware
   #ifdef ADAF_DRIVER
   extern Adafruit_PWMServoDriver pwm;
   pwm.setPWM(pin, 0, data);
   #ifdef SERVO_LIB
   extern servo servos;

Init_servo() is for doing whatever your motor needs to set up. Here the method sets the default alignment and commands the servo to move to that position immediately. This is private so that it can never be called from outside a turnout object.

setServo() moves the servo to a specific position. I use a compiler directive — by defining either ADAF_DRIVER or SERVO_LIB (but not both)— to determine which hardware system is in use. In some cases I’ll be using the Adafruit 16 Channel PWM Driver and its library; in other cases regular pins with the native servo library.

The Whole Enchilada

I’m posting the turnout class on the github site.

This time I’m posting it in the form of a header — *.h — file. To use it, copy it into your sketch directory. The Arduino IDE will recognize and allow you to edit the “h” file, but it won’t automatically include it in your build.  To in include it in the build you must explicitly include it near the top of your main sketch this way:

#include "turnout.h"

Why do it this way? Because the class definition has to be seen by the compiler before it can be used to create run-time objects. Therefore, in a single file sketch you’d have to put the class definition at the top of the sketch. If you have a lot of header material of that sort (class definitions, typdefs, etc.), the top of your sketch can get long and the whole thing harder to maintain.  By putting the class definition in a header file you can segregate different elements of your sketch, control exactly when the compiler sees it during the build process, ensure all dependencies are satisfied and keep your main sketch file clean and uncluttered. The bigger your sketch gets the more important this becomes.

Coming Soon

Back to block occupancy detection with 24 blocks and one Arduino to rule them all! To say scale started to be a problem would be an understatement. More about that in the next post.

Until then, Happy Railroading!



One thought on “C++ Objects for Layout Control, Part 2 — Turnouts

Leave a Reply

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