Arduino - Points/turnout Control




Introduction: Arduino - Points/turnout Control

Updated 28 April 2016

The points / turnout controller is built and installed into my railway layout.

The finished system controls 16 points and 15 accessories such as lights, sounds, turntable, etc
The circuit is shown inside a pVC enclosure with 15 volt input socket and 2 flying leads to be connected to the track DCC supply.

Step 1: DCC Turnout Control - 16 Points ( Using 2 X Arduino Modules)

The DCC command station has a turnout control facility for up to 16 turnouts.

The basic Arduino circuit to drive 2 turnouts is shown in the Fritzing diagram above.

A 'packet receiver' circuit is required to provide input to the Arduino - see separate diagram.

Step 2: DCC Packet Receiver - Basic Circuit

Updated 23 March 2016:
Added current sense circuit to protect turnout coils and H-bridge devices etc from over current.

int analogPin = 7;
const int Power_shut_off = 19; // A5 as digital
pinMode(Power_shut_off, OUTPUT);
digitalWrite(Power_shut_off, HIGH);

In void loop():

amp = analogRead(analogPin);
   if (amp > 5){     
      Serial.println(amp);   }   
   if (amp > 200   ){   // approx 2 amps     
      digitalWrite(Power_shut_off, LOW);   }

When 2 amps is exceeded, the TIP 120 shuts off the power (12 volt or 15 volt supply) to the turnouts.

From an excellent tutorial by Geoff Bunza in the Model Railroad Hobbyist Magazine forum. It described how an Arduino Pro Mini (a low cost Arduino board) could be wired and programmed to respond to function keys on a DCC controller. This opens up a wide world of control options for animations, sound and other options on a DCC equipped model railroad.

I have made use of this circuit to capture DCC packets from my Arduino based Command Station
(see instructable). The Command station has also been amended to allow turnout control (8 turnouts so far).

Basic Accessory decoder packet is :

From analysing the packet used by Lenz (Compact / Atlas) for points control, I have used the following binary packet format for bytes 1 and 2 :
tunAddr = 1
Turnout 1a : 1000 0001 1111 1000 / Turnout 1b : 1000 0001 1111 1001
Turnout 2a : 1000 0001 1111 1010 / Turnout 2b : 1000 0001 1111 1011
Turnout 3a : 1000 0001 1111 1100 / Turnout 3b : 1000 0001 1111 1101
Turnout 4a : 1000 0001 1111 1110 / Turnout 4b : 1000 0001 1111 1111
tunAddr = 2
Turnout 5a : 1000 0010 1111 1000 / Turnout 5b : 1000 0010 1111 1001
Turnout 6a : 1000 0010 1111 1010 / Turnout 6b : 1000 0010 1111 1011
Turnout 7a : 1000 0010 1111 1100 / Turnout 7b : 1000 0010 1111 1101
Turnout 8a : 1000 0010 1111 1110 / Turnout 8b : 1000 0010 1111 1111
Turnout 9a : 1000 0011 1111 1000 / Turnout 9b : 1000 0011 1111 1001
etc .........

By manipulation of the binary packet, we can extract the turnouts required and send a pulse of 350 ms.

looking at first byte:

0x80 in HEX = 1000 0000 in Binary

tunAddr = (Msg->Data[0] - 0x80);

looking at second byte:

0xf8 in HEX = 1111 1000 in Binary, then shift bitwise >>1 to eliminate last bit

f1a on:

if (tunAddr == 1){
   if ((((Msg->Data[1]) - 0xf8>>1) + 1) == 1 && (Msg->Data[1] & 0x01) == 1){ 
digitalWrite(FunctionPin1a, 1);             
digitalWrite(FunctionPin1a, 0);     }

The diagram shows LED outputs. Replace LEDs with solenoid drivers e.g. TIP120 (2 off required for each turnout) or SN754410 Quad driver (supplies 2 turnouts per IC).
All digital outputs are used in pairs to produce a pulse that fires the turnout solenoids via motor drivers or power darlington transistors. The code may be changed to match the drivers used from a '1' pulse to a '0' pulse.

Download NMRA library here

Download Arduino Code :

Step 3: Turnout Control - Arduino Circuit

2 off Mini Pro Arduino module were chosen for this part of the project. Each provides 8 turnouts and if more are required, you will need to add more modules or use a larger Arduino (Mega perhaps)



    • Creative Misuse Contest

      Creative Misuse Contest
    • Water Contest

      Water Contest
    • Tiny Home Contest

      Tiny Home Contest

    7 Discussions


    1 year ago

    Hi! Great project! I was wondering if using an Arduino 16 Relay board could be used. That would simplify things considerably as an Arduino can drive the relays directly. I need to drive at least 16 solenoid switches. An Arduino Mega 2560 has enough digital pins on the end header to do the job. Question, which pin does the DCC Signal com in? D2?

    4 replies

    Hi jay

    Thanks for your interest in this project. You could use the 16 relay boards in this circuit. I think you would need 2 relays per railway point giving 8 points served from one board. If you have the space to use these then fine. Remember to add diodes across all solenoid contacts to protect against induction spikes.

    Yes, D2 has the DCC signal input from the packet receiver circuit.

    Good luck and enjoy the project.

    Hi Bill
    The relay board I am using is opto-isolated.
    I have modified the code mapped the outputs to 22 - 53.
    I also removed the current monitoring as it will not be needed.
    My command station is DCC++.
    It goes to the DCC circuit. That feeds pin 2.
    I am using JMRI to test it.
    Nothing is happening.
    I tested the connection from the Mega to the board with a custom sketch. It hits each relay, in order, for 150ms.
    Any ideas?
    Thanks!! Jay

    Hi jay,

    First thing to check is the Arduino serial monitor for the decoded values.

    You should get burst of code printed on the monitor ending with:

    tun = turnout number

    If you want to send me an email directly, please use

    You can send me more detail if required e.g. circuit diagram, code etc

    I will be using this board.
    It takes a 5v logic signal to drive the relays. It has the driver chips on it.
    I am using DCC++ for my DCC System. It doesn't appear that it is sending switch packets. That's another issue I am working on now.
    Thank you!!

    Bill, great Instructable! I wondered if you could share which points you're using? I'm using Hornby R8243 surface mounted point motors, and my sn754410s are struggling to supply enough current. Whilst the point motor switches definitely off-load, when under load (i.e. attached to points), whilst there is movement, it just does not seem to meet the instantaneous current requirements needed to be fully switched in either direction. I have even tried piggybacking the sn754410s and even then, switching is only successful in one direction of travel. I had wondered if you are using points with a high resistance/impedance?

    1 reply

    Hi Simo, glad you like this Instructable. I used Hornby R8014 points motors (not surface mount) but should operate with same voltage and current. Please check the Vcc2 power supply which must be about 15 volts and capable of supplying peak current of at least 1 amp. Do your point motors operate of the track ok i.e. in free air movement? Please check alignment and freedom of movement of lever to points. You may have to adjust the timing in the Arduino sketch. I have 150 to 250 milliseconds on time delay (250);