Running a Small Layout with an Uno

Arduino Uno R3

Arduino Uno R3

A reader on another thread had questions about running multiple turnouts on a small layout with an Uno. Primarily he wants to control turnouts with a control panel and feedback indicators.  I thought that his needs are pretty typical for small layouts, and would be a good example for others planning and building on a similar scale.

So this post is bottom-up exercise in planning and implementing single UNO control on a small layout. I hope it will be helpful in planning and building your layout.

The Requirements

The layout has 5 turnouts that will be controlled with push buttons. Control is toggle-style: each button push causes the turnout to toggle between positions. Turnouts are run by micro servos. The control panel will have a layout map with turnout push buttons and LED position indicators.

First Decisions

The UNO is the first board many of us encounter and is certainly up to the task of managing 5 turnouts and a control panel, with capacity to spare. There are other Arduino boards suitable for model railroading use; but the UNO is cost-effective and easy to work with.

That said, the issue you have to contend with eventually is the number of connections required to support all the devices and LEDS that will be attached to the microcontroller.

Arduino boards provide three different types of connections/pins:

  • Digital: digital pins are basic on/off binary connections. In output mode they are either fully on (emitting 5 volts, with a max current of 40 mA) or off. In input mode they read the incoming current as either HIGH (on) or LOW (off). When used as inputs, digital pins may need pull-up or pull-down resistors so that they will function correctly.
  • Digital PWM: some, but not all, digital pins are also capable of PWM – pulse width modulation.  The output of a PWM pin, if not fully on or off, is a series of pulses that cause the output to to on a percentage of the time.  The pulses are used to control servos and other PWM devices. PWM with LEDS lets you vary their brightness between 0 and 100%, supporting a variety of interesting lighting effects.
  • Analog: Analog pins are primarily used to read sensors that produce a variable output. Pin inputs are fed to the on-board ADC (analog-to-digital converter) for conversion to a number between 0 and 1024. Current and temperature sensors are example of analog devices read through analog pins / ADC. What you may not know about analog pins is that they can also be used as basic digital pins.

It is essential in early planning to determine all the devices to be connected to the microcontroller and the type of connection each requires to determine what connection issues you will need to resolve. In some cases, going to the UNO’s bigger cousin, the MEGA, will solve connection limits.  But even the MEGA has limits. In some cases it makes sense to use pin-multiplying techniques using external chips to drive banks of LEDS, servos or other devices, even when you otherwise have enough pins.

A Connection Plan

The UNO has 14 digital connections, numbered 0 to 13, of which 6 (pins 3, 5, 6, 9, 10, and 11 ) are PWM. It also has 6 analog connections that can be used as digital connections with digitalRead() and digitalWrite() when referenced in the sketch as A0 through A5. That is a grand total of 20 digital pins, of which 6 are PWM.

Of those, two pins are generally off limits on an UNO: digital pins 0 and 1. They are Serial RX and TX respectively, and should be avoided for other uses on any UNO where you expect to use the USB interface — that would be most of the time. On boards without the built-in USB, pins 0 and 1 are fair game.

For five servos we need five digital pins. Even though PWM is used to control servos, the Arduino servo library creates the necessary pulses on any digital pin. However, using the library disables PWM functionality on pins 9 & 10, so some of the UNO’s native PWM capacity is sacrificed in any case.

For the five turnout control buttons we need five basic digital pins. For the control panel indicators, assuming one LED for each leg of each turnout, we need 10 basic digital pins.

That means we need 20 connections; but with pins 0 & 1 reserved for the USB interface, we’re short 2 connections. Many would want to use bi-color red/green LEDS so the state of each leg is continuously shown. That would require 10 additional basic digital connections.

Need Connections? No Problem!

That’s OK. Its exactly what I expected to happen when I started in on this exercise. Both inputs and outputs can be multiplied with external chips and boards; multiplying the basic digital outputs is far and away the easiest to implement, because the circuits are simple and the compiler includes native software support without add-on libraries.

I would use shift registers to control all the control panel indicators. That reduces the connection load on the UNO to just 3 connections for all LED indicators, no matter how many you end up with. With that, and the 10 pins needed to read the buttons and control the servos, the total digital pins requirement is 13. That leaves 5 available pins, one analog and up to three digital PWM, for other uses.

There is a great tutorial on controlling LEDs with shift registers, and chaining multiple registers together, on the Arduino website. That tutorial is mandatory if you are unfamiliar with shift registers; the circuit(s) shown are what you will be using for control panel LED indicators. The balance of this post assumes the basic knowledge contained in that tutorial.

Build A Control Board

Use a shift register chain to run your panel indicators. I use a TI 74HC595 chips that I buy from DigiKey. At less than $.50 each in lots of 10, they are a bargain. $5.00 worth of chips supports 80 outputs. Its the cheapest way I know of to extend the capabilities of an Arduino and run a lot of low current devices.

Decide how many shift registers you need — the 74HC595 has 8 outputs — and create a board based on the tutorial circuits to hold the chips and provide connection points for your LEDS. A single LED for each leg of each turnout (to show which leg is open to traffic) will need 10 connections—use two shift registers (use the two-chip circuit in the tutorial). Add a third chip (after the tutorial you will know how to do that) and your connection count rises to 24, enough to support red/green bi-color LEDS on each turnout leg on the panel. With 4 connections left, who knows what else you might light up?

Each push button will need a 10kΩ pull-down resistor connecting its pin to ground.  The purpose of the pull-down resistor is to drain stray current and keep the pin LOW unless the button is pushed and full current flow is applied.  See the diagram below. The resistor should be placed as close to the pin as possible.

Servo Control by Button

Basic Servo Control by Button

Power Issues

While you can run one or two servos off the power supplied by the UNO’s +5 volt pin, more servos than that would exceed the board’s power handling capabilities. Accordingly, you will need to supply power to the servos from a separate power source. VERY IMPORTANT: the ground for the servo power source must be tied to UNO ground or the servos will not work correctly.

One Sketch To Run it All

Alright. The control panel is built and wired; the servos are installed (see this post for my latest methods) and connected to power and the UNO. What you need now is a sketch to run the control panel and the servos.

Here is a demonstration sketch to get you started:

//////////////////////////////////////////
//
// Small Layout turnout control
// Demonstration Sketch
//
//////////////////////////////////////////

#include <Servo.h> // include the Servo library

////////////////////////////////////////
//
// Definitions
//
////////////////////////////////////////

////////////////////////////////////////
// Basic parameters; adjust for your actual setup
#define NUMBER_OF_TURNOUTS 5
#define NUMBER_OF_SHIFT_REGISTERS 3
#define STEP_DELAY 70  // servo movement step delay, in milliseconds
///////////////////////////////////////

///////////////////////////////////////
// Data Structures
///////////////////////////////////////

//////////////////////////////////////
// TURNOUT_DEF holds all configuration
// information about turnouts and panel LEDS
//////////////////////////////////////
typedef struct TURNOUT_DEF {
  uint8_t button_pin; // Digital or analog pin for the button associated with this turnout
  uint8_t servo_pin; // Digital pin for the servo associated with this turnout
  int pos_main; // servo position for the MAIN leg, in degrees
  int pos_div; // servo position for the DIVERGENT leg, in degrees
  int panel_LED_main_green; // The position(s)of panel LEDS in the shift register chain
  int panel_LED_main_red; // Example assumes a bi-color (red/green) LED for each turnout leg
  int panel_LED_div_green; // modify these elements to reflect the actual LEDS you are using
  int panel_LED_div_red;
};

/////////////////////////////////////
// TURNOUT_DATA is wrapper structure holding
// both configuration and runtime data for turnout operation
/////////////////////////////////////
typedef struct TURNOUT_DATA {
  TURNOUT_DEF data; // configuration
  bool is_moving;
  byte alignment;
  int pos_now;
  int target_pos;
  unsigned long last_move;
};

// Alignment state values
#define ALIGN_NONE 0
#define ALIGN_MAIN  1
#define ALIGN_DIVERGENT 2


// pin ids for shift register chain controlling panel LEDS
#define LATCH_PIN 7
#define CLOCK_PIN 8
#define DATA_PIN 9

//////////////////////////////////////////
//
// Global variables
//
//////////////////////////////////////////

//////////////////////////////////////////
// TURNOUT_DATA Array
// * A0, A1, etc refer to analog pins which are used for buttons in this example
// * Replace pos_main (93) and pos_div (117) with real values for each turnout
// * LEDS are identified by their output position in the shift register chain;
// the identifier is a number between 0 and (NUMBER_OF_SHIFT_REGISTERS * 8) - 1. 
// Example assumes LEDS are connected to shift register outputs sequentially 
// from the first output of first register. You can connect LEDS to any output in
// any order; just set the identifiers accordingly.
//
// Only the TURNOUT_DEF part of the TURNOUT_DATA structure has to be initialized here; 
// The remaining elements are managed internally and are initialized automatically
//////////////////////////////////////////

TURNOUT_DATA turnouts[NUMBER_OF_TURNOUTS] = {
  {{A0, 2, 93, 117, 0, 1, 2, 3}},
  {{A1, 3, 93, 117, 4, 5, 6, 7}},
  {{A2, 4, 93, 117, 8, 9, 10, 11}},
  {{A3, 5, 93, 117, 12, 13, 14, 15}},
  {{A4, 6, 93, 117, 16, 17, 18, 19}}
};

// servo objects
Servo servos[NUMBER_OF_TURNOUTS];

// array to hold shift register state bytes
byte panel_LEDS[NUMBER_OF_SHIFT_REGISTERS];

void setup() 
{
  // Setup pins for shift register chain
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);
    
  // initialize each turnout 
  for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){
    // attach the servo
    servos[i].attach(turnouts[i].data.servo_pin);
    // set the pin mode for the button pin
    pinMode(turnouts[i].data.button_pin, INPUT);
    // test and position the turnout by moving
    // to divergent then to main positions
    servos[i].write(turnouts[i].data.pos_div);
    turnouts[i].pos_now = turnouts[i].data.pos_div;
    setTurnout(i, ALIGN_MAIN);
    }
} // end of setup

void loop() 
{ 
  // get elapsed milliseconds at loop start
  unsigned long currentMillis = millis();

  // loop through the turnouts array
  for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){
    if (turnouts[i].is_moving) {
      // if sufficient time has elapsed since the last move
      if ( (currentMillis - turnouts[i].last_move) >= STEP_DELAY ) {
        // move the turnout one degree
        turnouts[i].last_move = currentMillis;
        if (turnouts[i].pos_now < turnouts[i].target_pos) { // if the new angle is higher
          servos[i].write(++turnouts[i].pos_now);
        } else {  // otherwise the new angle is equal or lower
          if (turnouts[i].pos_now != turnouts[i].target_pos) { // not already at destination
            servos[i].write(--turnouts[i].pos_now);
          }
        }
      }
      // if target position reached, stop turnout motion
      if (turnouts[i].pos_now == turnouts[i].target_pos) {
        turnouts[i].is_moving = false;
        turnouts[i].last_move = 0;
        setIndicators(i);
      }
    } else {
      // if a turnout is NOT in motion, check to see if its button is pressed
      int button_state = digitalRead(turnouts[i].data.button_pin);
      if(button_state == HIGH){
        // toggle position
        if(turnouts[i].alignment == ALIGN_MAIN){
          setTurnout(i, ALIGN_DIVERGENT);
        } else {
          setTurnout(i, ALIGN_MAIN);
        }
      }
    }
  }
}// end of main loop

////////////////////////////////////////////////////////////////
// Supporting Functions
////////////////////////////////////////////////////////////////

void setTurnout(int id, int align){
    // Set indicators to show turnout in motion
    turnouts[id].alignment = ALIGN_NONE;
    setIndicators(id);
    // Set values to trigger motion on next loop iteration
    switch(align){
        case ALIGN_MAIN:
          turnouts[id].is_moving = true;
          turnouts[id].last_move = 0;
          turnouts[id].target_pos = turnouts[id].data.pos_main;
          turnouts[id].alignment = ALIGN_MAIN;
          break;
        case ALIGN_DIVERGENT:
          turnouts[id].is_moving = true;
          turnouts[id].last_move = 0;
          turnouts[id].target_pos = turnouts[id].data.pos_div;
          turnouts[id].alignment = ALIGN_DIVERGENT;
          break;
      }
}

void setIndicators(int id){
  switch(turnouts[id].alignment){
    case ALIGN_NONE: // means the turnout is in motion and not aligned
      panelWrite(turnouts[id].data.panel_LED_main_red, HIGH);
      panelWrite(turnouts[id].data.panel_LED_main_green, LOW);
      panelWrite(turnouts[id].data.panel_LED_div_red, HIGH);
      panelWrite(turnouts[id].data.panel_LED_div_green, LOW);
      break;
    case ALIGN_MAIN:
      panelWrite(turnouts[id].data.panel_LED_div_green, LOW);
      panelWrite(turnouts[id].data.panel_LED_div_red, HIGH);
      panelWrite(turnouts[id].data.panel_LED_main_green, HIGH);
      panelWrite(turnouts[id].data.panel_LED_main_red, LOW);
      break;
    case ALIGN_DIVERGENT:
      panelWrite(turnouts[id].data.panel_LED_div_green, HIGH);
      panelWrite(turnouts[id].data.panel_LED_div_red, LOW);
      panelWrite(turnouts[id].data.panel_LED_main_green, LOW);
      panelWrite(turnouts[id].data.panel_LED_main_red, HIGH);
      break;
  }
}
/////////////////////////////////////////////////
// Shift Register Functions
/////////////////////////////////////////////////
void panelWrite(int id, byte state) {
  int reg = floor(id / 8);
  int pos = id % 8;
  bitWrite(panel_LEDS[reg], pos, state);
  panelRefresh();
}

void panelRefresh(){
  // Prepare to shift by turning off the output
  digitalWrite(LATCH_PIN, LOW);
  // shift all bits out in MSB (most significant bit first) order
  for(int i = (NUMBER_OF_SHIFT_REGISTERS - 1); i>=0; i--) {
    // shift out the bits
    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, panel_LEDS[i]);
  }
  // turn on the output to activate
  digitalWrite(LATCH_PIN, HIGH);
}

The sketch compiles into a compact package leaving plenty of memory and resources for additional functionality.

The main loop is built around a simple multitasking model, allowing you to control task timing and balance multiple competing tasks.  In this case, the main benefit of this methodology is control of the movement rate of turnout servos. On my test loop this methodology allows block occupancy detection to work in the background along with signal logic.

UP995 at Signal 34. Dual Searchlight Signals, Scratch Made with BLMA Signal Heads.

UP995 at Signals 3 & 4 on the Test Loop. Dual Searchlight Signals, Scratch Made with BLMA Signal Heads.

Troubleshooting

If you build the circuits accurately, everything should work out of the box (as it were). I am an obsessive tester — so I test things at critical stages as I build them.  Build and test your shift register circuits on a breadboard first, before soldering everything to a prototyping board.

To test the sketch I set up a simulation on a breadboard.

To test the sketch for this post I set up a 3 servo simulation on a breadboard.

Getting the connections to the UNO correct is key. If the LEDs don’t light at all, check all three connections, plus power connections; LEDS are polarized, so make sure the anodes are connected to incoming power and the cathodes to ground. Tracing power flow with a multi-tester should help you find problem areas quickly.

If your LEDs light but alternately flash odd/even, you probably reversed the LATCH_PIN and CLOCK_PIN connections.

For 3 or more servos, you must have an independent power supply to power them. BE SURE TO CONNECT GROUND FROM THE SERVO POWER SUPPLY TO ARDUINO GROUND.

Do Something with Unused Outputs

Old style hard wiring, without the help of a microcontroller, is a messy business at best, which tends to limit what you can do. DCC can help bridge the gap, but layout control is something of an afterthought for DCC (it was designed for locomotive control only) and is, frankly, awkward to use (my opinion; your mileage may vary).

To get the kind of functionality we have here without Arduinos — turnout control with a synchronous control panel — it would have to be hard wired. Or you could connect a full computer and run JMRI; that would require DCC (plus stationary decoders for the turnouts and a USB->DCC interface) to work . You would have to use stall-motor type turnout motors or add microcontrollers (Peco now sells a “smart” turnout system using servos and custom controllers) to interface with servo motors. So if you want to use servos instead of stall-motors, you can go Peco or do it the Arduino way from the start. As much as I appreciate Peco’s efforts here, the openness of the Arduino platform is a big part of what makes it useful and cost-effective.

Adding another function to a small layout — lets say a signal to protect a turnout — is a matter of connecting the signal leads to unused outlets and writing some code to run it.  If you’ve gotten this far, you’ll spend far more time thinking about exactly how the signal should run in conjunction with the turnout it is protecting, than you will connecting the device and adding code to the sketch.  Once you get into this way to doing things, I guarantee you’ll never look back.

So what will it be? Signals?  A fire simulation (using PWM and LEDS)? A lighted structure? Let your imagination run wild!


UPDATE

I starting working with shift registers a while back.  They are so effective my habit is to always use shift registers with LEDs, such as for signals, structure lighting and control panel applications.  The habit is so ingrained that I forget to mention the other important reason for using them: power management.

The power handling capability of an UNO is limited to 40 mA per pin and 400 mA for the entire board. LEDs typically draw between 20 and 30 mA.  So if you are directly powering 20 LEDs from an UNO, you are exceeding its power handling capacity and will burn out the board.

In the example given in the post, no more than half the LEDs well be lit at any one time so we are unlikely to exceed the 400 mA limit overall. A few more lit LEDS, though, would put it over the top.  Shift registers duck the problem altogether because each register is powered—and supplies power to connected devices—independently.  Other than the total load on your power supply, adding devices/lights to shift registers or even adding additional registers, puts no significant power load on the UNO.

Above I mentioned that an independent power supply is needed to run the servos.  From a “best practices” perspective, one should always power external devices with an independent power supply. Arduino’s current handling limits are tight; always using external power supplies avoids that problem.


UPDATE

Several readers asked if I have a fritzing image of the 3 servo demo.  I did not, but I put one together for those who might find this helpful.

3 Servo Demo

This circuit is intended to work with the above sketch, with the turnouts variable shortened to 3 elements instead of 5:

TURNOUT_DATA turnouts[NUMBER_OF_TURNOUTS] = {
  {{A0, 2, 93, 117, 0, 1, 2, 3}},
  {{A1, 3, 93, 117, 4, 5, 6, 7}},
  {{A2, 4, 93, 117, 8, 9, 10, 11}}
};

Always cross check all connections on a circuit like this against appropriate data sheets before powering it up for the first time! Be sure to connect the ground of your Arduino to the ground of your external power supply.

Adding Signals to the Test Loop, Part 2

Using shift register/darlington driver nodes for attaching lighting (and other devices) to the layout is easily justified by the conservation of precious Arduino pins. But that’s not necessarily the most important benefit of this approach.

Duino node for station lighting.

Duino nodes for station signal and lighting on the Test Loop.

The principal advantage of organizing lighting control into chains of shift registers—with or without Darlington Drivers to sink instead of source current (at this level it doesn’t matter what the shift register is attached to)—is to create an addressable architecture for lighting and animation.

What do I mean?

An addressable architecture is a system where individual objects can be identified by an “address” that provides sufficient information, in proper context, to allow the object to be accessed (my definition). An “address” should be a direct access mechanism and should not require conversion to a different form in order to use it. However, an address does not necessarily have to be complete if the context within which it is used has “knowledge” of the missing address information.

By that definition a pin number is a valid address. But, since we want to control more objects that we have pins, we need to think on a larger scale.

Arrays

Going beyond pin numbers, an address could be an offset (index) into an array. This works for objects attached to a shift register because you need to have memory set aside to represent state of the shift register; the values in memory are used to generate the stream of bits that sets the shift register state.

An 8-bit shift register could be represented in memory as an array of 8 bytes, either as plain 8-bit values or as boolean values (boolean is the better idea), occupying one byte for each bit on the register:

byte MyRegister[8];
or
bool MyRegister[8];

Having done that, every object on the shift register can be referred to by its position in the MyRegister array, a number from 0 to 7.  When you want to know or change the state of a particular bit on the shift register, you access the bit via its array index, making the index an address.

What about the Pins?

I am cheating in a sense. I’m relying on the fact that the first shift register in a chain has to be attached to three pins, you need to know which pin is which, and we can embed that information in the method that pushes bits out to the shift register. With that housekeeping squared away, all we need to do to turn shift register outputs on or off is maintain the array representing the shift register in memory, using the array indices as addresses for specific objects.

Here is an example method (derived from the Arduino Shift-Out tutorials, and used in the Roundhouse to run stall lamps) that writes to shift registers, using a static byte array to hold the register state information:

const int clockPIN = 3;
const int latchPIN = 4;
const int dataPIN = 5;
void registerWrite(int output, int state) {
  static byte outputStates[8];
  byte bitsToSend = 0;

  // update the outputStates array
  outputStates[output] = state;
  
 // Set bits according to the outputStates Array
 for(int i = 0; i < 8; i++){
     bitWrite(bitsToSend, i, outputStates[i]);
 } 
 // turn off the output while shifting bits
 digitalWrite(latchPIN, LOW);
 // shift the bits out
 shiftOut(dataPIN, clockPIN, MSBFIRST, bitsToSend);
 // turn on the output
 digitalWrite(latchPIN, HIGH);
}

This is what I mean by proper context. Here the context is a known “base address” for the shift register that never changes: the LatchPin, ClockPin and DataPin used to access it. Once context is established with a method that knows the “base address” and writes to the shift register, we no longer need to worry about that aspect of the problem and can supply the unique part of the address — the position of the output we wish to change — as an argument to the registerWrite method. In this instance, the address supplied to the method should be considered a relative address, because it is relative to the static portion of the address stored in the method code.

This simple approach works great for a shift register or two, but gets unwieldy when trying to manage the state of multiple shift register outputs with a single array. Further, memory is a precious resource and using a byte of memory to represent the state of a single bit on a shift register is inefficient at best. For a layout with hundreds of controllable lights for signals, crossings, street lights, building lighting and whatever else you can think of, something more sophisticated is called for.

The Data

So lets start with a better way to hold the values of the 8 bits of a shift register; I call shift registers “nodes”:

typedef struct nodeState {
  byte pins;
};

The 8 bits constituting a single byte of memory represent the 8 bits of a node. This is a big improvement in both memory efficiency and execution efficiency, since the pins byte can be sent directly to the target register without any processing.

Next we need a type to hold all information relevant to a chain of nodes:

typedef struct nodeGroup {
  byte clockPin;
  byte latchPin;
  byte dataPin;
  byte numNodes;
  nodeState *nodes;
};

Now we have all the data we need to handle a chain of shift register nodes in one place. Notice how the nodeState type is used. Once instantiated,  the *nodes element will point to an array of bytes, one for each node.

Notice something else: the door is now open to run multiple, distinct chains of nodes easily by creating a nodeGroup data instance for each chain. This confers even more freedom to structure resources for the convenience and logic of the sketch.

What’s The Address?

So that is how the nodes are attached and accessed. Now we’re ready for an address form that will work with this architecture:

typedef struct nodeAddress { 
  byte chain;
  byte node;
  byte pin;
};

With all node data organized into nodeGroup structures, the nodeAddress type provides what amounts to an absolute address to any resource defined in this way. An absolute address contains all necessary parts of an address, and is processed by methods without having any hidden address elements embedded in the method code.

Station and Signal 5

Practical Application

The test loop has one chain of four nodes.  For that sketch, a single node group is instantiated this way:

nodeState ndata0[] = {0,0,0,0};
nodeGroup nodeGroups[] = {{7, 6, 5, 4, ndata0}};

Here I’ve defined an array of nodeGroups with one member. The node group uses pins 5, 6 and 7 on the Uno, and has four member nodes. An array of nodeState structures, one for each node, is defined as ndata0[], and incorporated into the nodeGroup via the ndata0 pointer.

Signals on the test loop are defined by a different data structure that includes this element

nodeAddress addr;

capturing the base address of a particular signal. When the sketch is ready to set the state of a signal, it passes the nodeAddress to the node setting method, like this:

nodeSet(signal.addr, nodeBits);

All manipulation of the nodes can be accomplished with 4 methods:

void nodeWrite(struct nodeAddress addr, byte state) {
  // write the state to the pin bit defined by nodeAddress addr
  bitWrite(nodeGroups[addr.chain].nodes[addr.node].pins, addr.pin, state);
  nodeRefresh();
}
void nodeSet(struct nodeAddress addr, byte state) {
  // set the pins element with a byte value
  nodeGroups[addr.chain].nodes[addr.node].pins = state;
  nodeRefresh();
}
byte nodeGet(struct nodeAddress addr){
  // get the pins element for a node
  return nodeGroups[addr.chain].nodes[addr.node].pins;
}
void nodeRefresh(){
  // Shift out current node data, one node group at a time
  for(int i = (NODE_GROUPS - 1); i>=0; i--) {
    // shift all bits out in MSB order (last node first):
    // Prepare to shift by turning off the output
    digitalWrite(nodeGroups[i].latchPin, LOW);
    // for each node in the group
    for(int j = (nodeGroups[i].numNodes - 1); j>=0; j--) {
      shiftOut(nodeGroups[i].dataPin, nodeGroups[i].clockPin, MSBFIRST, nodeGroups[i].nodes[j].pins);
    }
    // turn on the output to activate
    digitalWrite(nodeGroups[i].latchPin, HIGH);
  }
}

The nodeSet method used by the signal system—primarily because a signal requires an output for each aspect (red, green, yellow)—sets the pins byte for a random node in one operation.

NodeWrite sets a single output bit on any random node.

NodeGet retrieves the current pin byte for a random node. The signal system uses this method to retrieve the bits on a signal node, before modifying the values and applying them with nodeSet.

NodeRefresh writes the pins bytes to the nodes.

There is, of course, more going on with the signals on the test loop. Deciding what aspect a signal should show at any given time is a matter of logic and data. In the next post in this series I’ll do a deep dive into my first take on making signals operational within an Arduino environment.

Until then, happy railroading!

Adding Signals to the Test Loop

Tomar Signals

Tomar Signals

With block occupancy detection running on the test loop, it was time  to start experimenting with signals. Automated signaling is an important part of the plan for the L&NC.

Signaling potentially involves a great deal of wiring. It isn’t particularly difficult when done the Arduino way, but it does force you to deal with common capacity issues that come into play whenever you want to control a lot of lights or other kinds of devices.

I think of signals as the simplest form of animation a layout can and should have. Creating a signaling system is a good starting point for developing more complex automation and animation for the layout.

Initially, I bought a couple of Tomar Industries n scale signals to try out something off-the-shelf. These particular ones are nicely made and fully wired with red and green LEDS. A three aspect (red, yellow, green) version is also available.

With two outputs required to power each signal, it became clear that directly powering an entire signal system from a microcontroller would be impractical because there aren’t enough pins to work with. Further, The Tomar signals turned out be wired in the common anode configuration, which had additional implications. Common anode wiring is not unusual in off-the-shelf accessories.

Current Limitations

Arduino boards have design limitations when it comes to powering and controlling external devices. The amount of current an Arduino can source or sink on any one pin is limited to 40 mA, enough to light a couple of LEDS. The ground pins can sink a maximum of 400 mA. Accordingly, an UNO could power a maximum of 10 pins with no more than two 20 mA LEDS on each. The I/O pins cannot handle enough current to run most solenoids, relays or motors.

Common Anode Devices

Common anode devices present further problems because Arduinos are common ground devices. Even through the IO pins can sink current, you can’t switch them into a ground state the way you can switch them into a high voltage state.

Most of us are used to common ground — or common cathode — wiring style to control multiple lights or other electronic objects with a minimum number of wires. There, the positive feeds are isolated from each other so individual devices can be controlled, but they all connect to a common ground.

Common anode wiring is the reverse, where multiple devices share a power feed, but their ground sides are isolated from each other for control. Where resistors are needed to control current, as with LEDS, they are put on the cathode side instead of the anode side.

Extending the Pins

Running signals and other animation to any significant extent requires a strategy to multiply the outputs an Arduino can control in a way that is broadly compatible with available devices. Fortunately, there are readily available components that can significantly extend the I/O and current handling capabilities of an Arduino Board and allow control of common anode devices.

Shift Registers

HC595 Shift Registers (I use the 74HC595 variant) are logic ICs offering a basic way to multiply the digital output pins the Arduino can control. Using just three digital pins, an Arduino can control 8 output pins on the shift register.  Better still multiple shift registers can be serially connected, without any additional connections to the microcontroller, to extend the number of outputs under control to span many shift registers. I’ve previously written about shift registers in the Roundhouse rebuild.

To control a shift register, a byte of memory is needed to represent and manage the state of the register’s 8 pins. Accordingly, the maximum number of outputs you can control in a single chain of shift registers is primarily limited by the amount of memory available for managing them.

Consider, though, that a 100 bytes of memory allows you to control 800 digital outputs using just three Arduino pins. Let that sink in for a minute.

Shift registers are serial input, parallel output devices; the Arduino writes the bits serially, then all connected registers output on all data pins at the same time when the write is finished. Shift register outputs maintain their state–on or off–indefinitely until changed.

Darlington Drivers

Another basic tool is a ULN2803APG Darlington Driver, an IC that can switch higher voltages and higher current than an Arduino or shift register can handle. These are current sinking transistor devices, using NPN Darlington pairs; the addition of internal clamping diodes allow them to handle inductive loads such as relays, solenoids and motor driver applications like running unipolar stepper motors. LEDS and incandescent lights work well in common anode configuration controlled through a darlington driver.

Darlingtons allow a logic system (the microcontroller and attached Shift Registers) to control a set of outputs that are powered independently. So, for example, a 5 volt logic system can switch a 12 volt load (up to 50 volt max).  Very useful, yes? For current up to 500 mA per channel, Darlington Drivers can be a viable alternative to expensive relays.

The Good

An HC595 Shift Register plus a Darlington Driver extends the number of digital outputs a single Arduino board can control, using a common anode wiring solution that can handle virtually any kind of layout animation or control device. Using using Shift Register/Darlington Driver pairs and going to common anode wiring as my standard makes all connection and access methods uniform across a variety of devices.

The Bad and the Ugly

In theory, you just connect the output of the shift register to the corresponding inputs of the darlington driver, connect the darlington outputs to your devices, and you are good to go. Trouble is, the chip designers didn’t get the memo on that! The chips are a little difficult to interconnect: you can’t place the chips side by side and have respective outputs and inputs facing each other in the correct order. In fact, the HC595 connections are arranged a little oddly, requiring at least some connections between it and the darlington to cross over each other no matter what.

My first try was the roundhouse controller board. My problem then was trying to run some low voltage incandescent bulbs from 3.3 volt power. The darlington driver allowed me to do that with the 5 volt shift register.

Roundhouse Controller with an Uno

Roundhouse Controller with an Uno

See all those green jumper wires? That was my first solution to the interconnect problem on a single layer board; it works but it is awkward, bulky and hard to replicate. The additional interface for the addressable LEDS further complicates the board.

For signals on the test loop, I decided to try to shrink the board size, incorporate the necessary resistors (they are on a separate board in the roundhouse) and take a two sided approach using my favorite two sided prototyping boards.

Node Prototype 2

Node Prototype 2

As I was planning to record the block occupancy demo, I decided I needed more signals on the test loop to show the block occupancy system in action. I still had four available outputs on the board running the two Tomar signals– except those could not help me with a signal on the other side of the layout [the signals all have short lengths of thin magnet wire].

The HC595 can connect to another shift register serially, but I had not provisioned that on the boards built so far. It takes three connections to link to the next shift register: the two shared timing lines and the data output from the shift register.

Time to build board #3.

Node Prototype 3

Node Prototype 3

The board works fine. But creating these boards with prototyping materials is painful because of the number of jumpers to route and connections to make. As useful as these were going to be, it was going to take a long time to churn out a lot of them accurately. On the L&NC I expect to be controlling hundreds of lights and other devices around the layout. There had to be a better way.

Duino Nodes, Type A, Version 1

I was using fritzing, my favorite circuit design tool, to work on the circuit design for the next board and it became obvious that what I really needed to do was have a printed circuit board produced to my specs. Since I would need several boards for the test loop alone, and I was only just getting going, a small trial run of boards made sense.

I’m glad I did.  Here is the first version of what I call a Type A Duino Node.

Duino Node Type A

Duino Node Type A

These are double sided pc boards, pre-drilled and ready for components, with copper ground fill on both sides for emf control. It takes about 10 minutes to assemble a board for use. The prototypes took over an hour each to build, so the practical time savings for the dozens I’ll need on the L&NC is substantial.

They are 88 mm x 52mm; about 30% bigger than the smallest prototype I built. There are a couple of reasons for that: first, the board has Arduino-style mounting holes arranged to facilitate board stacking. Second, since these boards will run lights and other devices with varying current limits. generous space is available to mount an appropriate resistor for each cathode. A jumper can be used if a resistor is not needed, as might be the case when running a relay, motor or solenoid through a position.

On the right side are three control connectors: power, serial in and and serial out. When stacked, only short three wire jumpers are needed to chain from one board to the next. A terminal block is mounted on the opposite, output side of the board. There are nine positions: the common anode (power) plus eight switchable cathodes.

Deployment

There are four boards deployed on the test loop. One is dedicated to the two Tomar signals above.

Another board runs the dual signals below. The top searchlight is three aspect (red, yellow, green) and the bottom is two aspect (red, green), requiring a total of 5 outputs.

Dual Searchlight Signals, Scratch Made with BLMA Signal Heads.

Dual Searchlight Signals, Scratch Made with BLMA Signal Heads.

The last two Duino Nodes are used together for the station / signal complex.

The Station, and Signal #5

The Station, and Signal #5

The signal is three aspect (red, green, yellow). The station has a total of 8 individually switchable LEDS for internal lighting.  You may notice that the two sections of the depot have distinctly different lighting: the passenger station side has warmer, incandescent lighting (achieved with a mix of led colors); and the freight side has a cooler fluorescent lighting style (cool white LEDS).

One node is for the station signal that connects via four strands of magnet wire.

Duino Node controlling Station Signal

Duino Node controlling Station Signal

The second node mounts on top of the first, and it controls the Station internal lighting. The bottom node receives the incoming serial connection from elsewhere; then a cable connects the bottom serial out with the top serial in. There is no limit to the number of boards that can be chained and/or stacked together.

The Duino node for station lighting is stacked on top another node that runs the signal.

The Duino node for station lighting is stacked on top another node that runs the signal.

Here is a view of the test loop from below with all the Duino nodes in place.

Test loop from below.

Test loop from below.

It may be hard to tell, but the overall effect of using the Duino nodes is to simplify and compartmentalize wiring.

Using the Nodes

The real advantage of this system comes from adopting a uniform addressing system that makes it easy to randomly access and change any element on any node at any time.  I’ll go into that in the next post.


 

Rebuilding & Lighting a Roundhouse

One of the casualties of 15+ years of moving box storage was a Walthers (Heljan) Union City Roundhouse with 6 bays. No longer in the catalog, this was a really nice brick structure with a little extra decorative masonry, as might have been built in a prosperous town in the early 20th century. The “modern” roundhouse models widely available today are more shed-like and (to my mind, anyway) less elegant.

Roundhouse in pieces

Roundhouse in pieces

The damage could have been a lot worse; mostly it came apart at glue joints. A little breakage, but not much. I originally built this twenty years ago as an exterior model; no interior lighting or details. It was nicely enough colored that it worked well unpainted (though I intended to get to that…. some day). No anti-crazing glue was available in those days, so the windows which look fine on the outside look atrocious on the inside.

Decisions, Decisions

The model did not have the common decency to completely disassemble itself, which would have made this much easier, so I had some choices to make. In contrast to the glue joints that failed, the rest were showing no signs of giving up easily.

First and most obvious was whether to rebuild the 6th bay, since most major pieces were intact. For the sake of the space available on the L&NC, cutting back to 5 bays makes sense without diminishing the impact of this model. I could have gone to 4, but the broken frame for the 5th bay door presented a nice weathering opportunity, which we’ll see later.

Secondly, what kind of lighting and how? I was thinking incandescent, and hanging lights would be authentic, so some sort of hanging lamp with an industrial style shade seemed like a good idea. I found both led and incandescent options; I decided to try the incandescent type.

Getting Started

Removing the floor turned out to be the easiest way to open up the model, so I decided to reconstruct the model with a solid top structure that is removable from a separate base. Putting aside the floor, I reassembled the top structure, leaving one roof section off where I planned to route wiring.

Main structure, partly reassembled

Main structure, partly reassembled

That decision, along with the intended orientation on the L&NC, spawned a few other choices.  Now, when in operation, the interior will be viewable primarily through the doors and secondarily through the windows and skylights. Since the most open sight line will be through the doors toward the back, I decided to attempt some improvement of interior finish along the back wall.

Painted Window Castings

Painted Interior Window Castings

I pried off the clear styrene, which was as difficult as I would have expected, requiring some grinding and sanding to get rid of stubborn bits holding on to the green window part.  Then I painted the window part brick, leaving muntins and a thin window frame green. Having done the back wall I re-evaluated the other sight lines and concluded that removing the glazing elsewhere was probably not worth the trouble (I’ll keep that option open for later).

Light coming through simulated glass.

Light coming through simulated glass.

Since the glazing was gone, I decided to try using Testors Clear Parts Cement & Window Maker to make ‘glass’ in one pair of rear windows. It was easy enough to do if you follow the instructions, and the effect is interesting.  I probably used a little too much, but the material seems to have a lens effect in windows this small. This simulates older glass nicely, but does not create a “see-through” window (for purposes of viewing the interior). The way the Roundhouse will be oriented on the L&NC, the back window will face a blocked (by the furnace) area, so you will not be able to directly look through these windows in any case. So I think I will do the rest of the rear windows the same way.

Paint Cheapskate

Model paint is notoriously expensive (over $5 per oz, discounted) and, frankly, nothing special beyond formulating specific colors that duplicate prototype colors. In this respect I’m lucky there is no convenient hobby shop here; that has forced me to look to other solutions which, to my delight, are vastly cheaper.

Liquitex BASIC Acrylic Paint (available at all major art/craft store and on Amazon), at $5 per 4 oz tube (cheaper in even larger quantities, or sets) is a good deal.  It is available in a wide range of standard artists colors that are easily mixed to create any color you want (just keep track of the formula!). These are formulated for general artist use so they are thicker than standard model paints. I mix small amounts of paint with acrylic thinners to get whatever consistency I want.

My brick color is a simple mix of 50%Red Oxide and 50% Burnt Umber. My color for light colored mortar, masonry, stone and concrete is Titanium White with 5% Yellow and 5% Grey (a 50% Grey) – basically a dab of each into a larger amount of white.

Installing Lights, Round 1

I found some Miniatronics parts, counter-intuitively called “Lamp Shade with Bulb,” that I thought would make good hanging lamps for the interior, so I bought 10 of them from Hobbylink.

Miniatronics 'Lamp Shade with Bulb"

Miniatronics ‘Lamp Shade with Bulb”

Here two are mounted in 1/8″ Styrene u-channel that has been painted Floquil Weathered Black (from my limited collection of old paints) to match the interior girders. To size them, I studied the interior clearances relative to locomotives and realized that clearance was limited in the tall section, and non-existent in the shorter fore and aft bay sections.

Hanging Lamps in Bay 1

Hanging Lamps in Bay 1

My feeling at that point was these lamps were not suitable for the short sections, since they would not be visible mounted up against the ceiling. That feeling increased after mounting and lighting the first pair.

Miniatronix Lamp Shade with Lamp - Lit

Miniatronix Lamp Shade with Lamp – Lit

 

I guess I should not have expected much from a 1.5 volt 30mA lamp.  Still, I’d hoped it would cast more light than that! As a decorative lamp it works fine at N scale – you get little peaks of them if you look in and they seem right. For casting light on the broader scene, even if I doubled up on them, another solution is needed.

Addressable LEDS

I’d already been working with Addressable RGB LED strips as a solution to bringing light to the layout, and it occurred to me that adding ALEDS as a hidden light source would allow me to more fully light up the interior. So that is what I did.

RGB LEDS for General Lighting

RGB LEDS for General Lighting

The individual pads are cut from a 5 meter strip and wired together with 30 GA wire. As you can see from the picture of the completed interior below, there are 10 of them with addresses 0 to 9.

Soldering Addressable LEDS

Soldering Addressable LEDS

To solder the very thin wire to the pads, I taped the leads down and slipped the pads underneath. That was more than stable enough to make the soldering fairly easy.  This particular LED is #0, so the left hand leads are heavier (22ga) for incoming power and data (for durability and handling), and the right hand leads out to the rest of the strand.

I fabricated the strand in two halves with 5 LEDS each, soldering leads from the two halves together during installation. Each half strand had to be carefully threaded through the girders.  I did break – and repair – a couple of connections the first time I tried.  After I got them threaded successfully, I glued the pads down to the styrene roof with dabs of Liquid Nails for Projects (low VOC, foam safe). You can bet I tested the  lights before gluing them down!

Completed Roundhouse, from below

Completed Roundhouse, from below

The LED wiring is simple and efficient – 1 connection to a digital pin on the Arduino, plus 1 wire each for power and ground.  The incandescent lamps were more complicated since I had no intention of giving over 10 pins on the Arduino. Further, turning them on and off individually was not necessary, so I decided to run them in “bay pairs.” Unfortunately, the 60 mA draw of a pair of these is more than you want on an Arduino pin, so that meant some sort of relay or transistor would be necessary to switch the current.

 A Shift Register and a Darlington Array

Current isn’t the only problem: there aren’t enough digital pins on an UNO to control everything I have planned.  So a pin preservation strategy is called for.

I decided to use a 74HC595 serial-in-parallel-out shift register. One data pin plus two timing pins (total of 3 pins) allow an Arduino to control 8 digital outputs; additional shift registers can be wired in series to extend the total number of outputs available without additional Arduino pins. The parallel output of these chips means that after the Arduino sends instruction bits serially, all the outputs are turned on or off at the same time (parallel output), a useful property for animation and lighting control.

Because of the higher current (and also different voltage) of the lamps, I put a UNL2803 darlington array — a transistor array that can sink high current — between the shift register and the lights. The only downside of a darlington is some current loss.

Both chips are inexpensive, running about $.60 each in small quantities at digikey.  Now that I’ve worked with them I’d say they are very useful basic parts for the Arduino enthusiast.

Power Distribution to Lamps

Power Distribution to Lamps

I fabricated a little circuit board for the roundhouse, to join the “bay pairs” together and provide a 1/8 watt resistor for each lamp to be able to run at 3.3v. The darlington array sinks current rather than sourcing it, so the circuit is a common anode (common power) with the resistors and control on the ground side.  Works fine. The circuit board was cut from a standard Radio Shack pre-etched PC board, and fits into the wiring space in the back of the Roundhouse.

I fabricated another board–version 1 of what will become a standard, chainable shift register board for layout control (but about half the size of this one) —  to be mounted under the roundhouse base, it interconnects the two ICs, taps into layout power, connects to an Arduino and connects to the structure above. The board uses +5v power for logic and LEDs, and +3.3 for distribution to the incandescent lamps.

Roundhouse Controller with an Uno

Roundhouse Controller with an Uno

The roundhouse board has an unused connector that would allow 3 more +3.3v lights to be added. I’ll probably use that capacity for some lighting outside the roundhouse structure when it is mounted on the layout, but I haven’t decided anything yet. That, by  they way, is part of the essential elegance of the Arduino way; so long as a connection pin is available, adding more lights or functionality is as easy plugging things in and modifying your software to use them.

Here is a video tour of the project and demonstration Roundhouse lighting!



The sketch loaded on the Uno is different enough from previous examples, that I will cover it in Roundhouse Rebuild Part 2.