Last Updated: 11/08/2025

Interlock++ Interlocking signal box and block signalling system for model railways

Projects >> Interlock++ Interlocking signal box and block signalling system for model railways

Latest News

11/08/2025

Version 0.6 released.

0.6 adds 3 new features that make working with block signalling easier.

New Functions:

loadSignalDuelMonitors() function to allow  a signal to monitor 2 signal when tracks diverge, written for panel box type block signal control

void listDuelMonitors(void); List all the loadSignalDuelMonitors() rules

byte getItemStatus(uint16_t itemID);//get the items current position status of any itemID

loadSignalMonitors() Error message 12 (see iserGuide.ino) Reduced to a warning but will not flag as error. This is when 2 signals are monitoring the same signal. This is now allowed to happen (with a warning) as it's required for converging track situation.

 

 

Contents

I have decided to do seperate tutorials for the different features. This will make it easier to add things as new features come along.

Click on the titles below to jump to the section.

I will try and add video tutorils to each section as I get time.

Introduction What is Interlock++ (Video Intro)
Hardware requirements Microprocessor boards and other components (Circuit diagram)
How it Works A short guide on how to use Interlock++
Download the sketch Download the latest version of Interlock++ or the original 0.1 version
Instructions v0.5 or greater

Instructions on how to use interlock++

Main sketch overview and set up instructions. (Includes how to use custom functions to get information out of Interlock++).

Input functions (How to send data and instructions to interlock++)

How to...

Short tutorials on using different aspects of the Interlock++ system (Usually created in response to information or help requests).

Virtual Signals What are they and how do they work?

Converging Track Block Signals How to set up block signal monitoring when two tracks come together

Diverging Track Block Signals How to set up block signal monitoring at junctions

Additional resources Links to other tutorials that may help with an Interlock++ project sych as how to use servos, various types of shift registers, types of buttons and switches etc.

Interlock++ - Introduction

Interlock++ Getting Started
Code and circuit diagram download the video (Click to download)

What is Interlock++

I was asked to help with a project that would allow interlocking of signals and points/turnouts in the same way that they work on real railways. Instead of building a project specific to a single layout I decided to build an open system that would be useable with any track plan, big or small.

What is an interlock?

In it's simplest for imagine a straight piece of track with a signal allowing trains onto it at each end. For safety reasons it should be impossible to set a signal to green if the signal in the opposing direction is green.

Another example would be a level crossing. If the signals are set to green the interlock would prevent the signalman from opening the crossing gates to traffic and once opened under a red signal the interlock would prevent te signalman from setting signals to green in either direction.

These of course are simple rules. When it comes to points (turnouts) there may be a number of signals that need to be set to red before the point can be moved and there may need to be a number of points set before signals can be set to green.

Block signalling:

As well as the rules for signal box style interlocking from version 0.5 block signal control was added for routes. This allows the signals to change aspect automatically so for a 3 Aspect signal (red, yellow, green) The yellow or green will display depending on if the next signal is set at red or yellow. Interlock++ v0.5 handles signal types up to 5 aspects and almost unlimited blocks.

Click here for more information on mechanical and electronic interlocking systems.

Hardware Requirements

From version 0.5 interlock only requires an arduino Mega 2560 or an ESP32 Dev Module (Interlock++ will not run on an UNO due to the SRAM requirements).

It is even possible to run a test system without anything else connected using the Serial monitor as an output to the success or failure of commands or blocks.

The user now has more freedom to choose their own screen/button type/touch screen as well as a choice of outputs (direct to servo or solenoid or to DCC EX etc).

This has been done to add as much flexibility as possible for the user to make it work with as many layout set ups as possible rather than trying to force users down a restricted route.

I will add example set ups as time permits. Please email from the link at the bottom of this page or via YouTube to request specific sample set ups.

Arduino Mega 2560 ESP32 Dev Module

How it works

To give an example of how Interlock V0.5+ works I will use the track plan below (Click image for larger version).

Example Track Plan

Signal Box example

At the top of the diagram is a basic point/turnout with 4 signals.

To run the system interlocking rules must be added.

An easy example id the turnout (given an ID of 4). Before the point/turnout can change direction all signals in both directions must be set to Red (danger). Otherwise the point/turnout could be changed under a moving train.

So the following rules would be added to the system using the loadRule() function.

So to turn left (Straight on or 0 in my example all signals must be at danger (stop). Either using the value 0 or the definition SIGST

mySignalBox.loadRule(4, POINTLEFT, 1, SIGST); //Point 4 to move left, check signal 1 is Stopped
mySignalBox.loadRule(4, POINTLEFT, 2, SIGST);
mySignalBox.loadRule(4, 0, 3, 0); //can be written without definitions
mySignalBox.loadRule(4, 0, 5, 0);

The same is true if I want to turn the point right/turnout (direction 1)

mySignalBox.loadRule(4, POINTRIGHT, 1, SIGST); //Point 4 to move right, check signal 1 is Stopped/Danger
mySignalBox.loadRule(4, POINTRIGHT, 2, SIGST);
mySignalBox.loadRule(4, 1, 3, SIGST); //can be written without definitions
mySignalBox.loadRule(4, 1, 5, SIGST);

Rules also need to be set for signals.

As an example, for signal 1 to be set to Green/Clear the following rules would apply

//Signal 1 Go
mySignalBox.loadRule(1, SIGGO, 4, POINTLEFT); //signal 1 to go green, point 4 must be set left
mySignalBox.loadRule(1, SIGGO, 2, SIGST); //signal 1 to go green, signal 2 must be set stop/danger
mySignalBox.loadRule(1, SIGGO, 3, 0); //signal 1 to go green, signal 3 must be set stop/danger
mySignalBox.loadRule(1, SIGGO, 5, 0); //signal 1 to go green, signal 5 must be set stop/danger

Once the rules have been added for all signals and points/turnouts. As the system receives a command each rule will be checked to see if it applies and if it has been broken.

In Trainee mode an alert will be given (error message) to say that a rule has been broken but will allow the operator to continue to set the signal/point/turnout

In Interlock mode an alert (error message) will be given but any command to the track/signalling will NOT be implemented as it breaks an interlock rule.

So for the basic interlock system it is just a case of the operator adding rules, be aware that as track plans become more complex the number of rules increases dramatically just as in the real thing.

Also although the example uses signals and points/turnouts. Other rules can be added for block occupancy, crossings etc.

Block Occupancy Example

In this example we will look at modern panel box signalling that is often semi automatic. Interlock v0.5 or greater can mimic this route setting and automate the signal chnages although it will require some form of block/train detection on the layout.

For the example above I am using 4 aspect UK signal, Red (Stop/danger), Yellow (proceed under caution), Double Yellow (Proceed under Caution), Green (Proceed).

As can be seen Train A is approaching a Green signal (11), as it has passed signal 10 that is set to Red (danger) as train A occupies the track behind it. Signal 9 is set at Yellow warning the driver to expect a red signal at the next block. Signal 8 is double yellow (expect the next signal to be single yellow). Signal 7 is green and signal 6 is green with Train B approaching it. As Train A moves exits the differnt blocks the signal behind change up one apsect.

In interlock++ this feature is controlled by the loadSignalMonitors() function. This allows a signal to base the colour it displays based on the aspect displayed by the signal in the next block.

So for example in the diagram above the monitorsd would be set as:

mySignalBox.loadSignalMonitors(6, 7);
mySignalBox.loadSignalMonitors(7, 8);
mySignalBox.loadSignalMonitors(8, 9);
mySignalBox.loadSignalMonitors(9, 10);
mySignalBox.loadSignalMonitors(10, 11);

So the first signal 6 will be monitoring the state of signal 7. Signal 7 will monitor the state of signal 8. You can add in as many monitors as required but can also add virtual signals that are monitored.

Virtual signals are signals that are not physically on the layout. So in our example Signals 10 and 11 may not exist on the layout but would be off the layout (in the fiddle yard or staging area).These can be triggered via timers so as the train enters the staging area Signal 10 would go to red and a timer starts. After X amount of time Signal 11 goes to danger (train has virtually reached that block), and so signal 10 would no move to single yellow. This allows full block control of the line ahead even if that section has not been built on the layout.

 

The Software - The interlock++ sketch



Version Changes
Future versions


If you find a bug or have a suggestion for an new feature email me with the address at the bottom of this page.

Ability to have outputs as DCC commands sent to DCC-EX or NCE CAB BUS (I only own 2 systems to test with).


interlock V0.6

Download includes the main sketch and 2 demostration examples, one for converging tracks, the other for diverging tracks.

New Features

interlock++ 0.6 has a few extra functions added to enable block signalling control over converging and diverging tracks.

This means that at a converging turnout/point, 2 signals can both monitor the next block signal.

For diverging tracks a new function has been added that allows a block signal to monitor 2 different signals (the next signal for either direction). This will then allow users to create multi headed signals with correct colour changes or signals with additional route indicators.

A further function has been opened up to allow users to get the status of any item (signal, turnout, point, block etc) for integration into your own code logic.

New Features:

loadSignalDuelMonitors(uint16_t itemID, uint16_t monitor1ID, uint16_t monitor2ID) function to allow  a signal to monitor 2 signal when tracks diverge, written for panel box type block signal control

void listDuelMonitors(void); List all the loadSignalDuelMonitors() rules

byte getItemStatus(uint16_t itemID);//get the items current position status of any itemID

loadSignalMonitors() Error message 12 (see iserGuide.ino) Reduced to a warning but will not flag as error. This is when 2 signals are monitoring the same signal. This is now allowed to happen (with a warning) as it's required for converging track situation.



interlock V0.5

New Features

interlock 0.5 has been written as a class and has more standard fuinctions to make using the program easier.
The new version will also allow better backwards compatibility with future versions and easier intergration with other systems such as nowRail, DCC EX and the NCE Cab Bus.

This version allows for far greater flexibility on screens, buzzers, buttons etc and now runs on the Mega2560 and ESP32 Dev Module.

New Features:

Class (library style) functions to allow easier use and less chance of conflicts with other libraries or code.

Automating signal monitoring to allow auto changing of block signal up to 5 aspects (UK Red, yellow, Double Yellow, Green, Flashing Green). With occupancy detectors this will allow for automated signal changes on routes that integrates with the original signalbox style interlocking system.

interlock V0.1

Original version

Fully working system that has been tested but needs more real world testing.

This version required the LCD1602A back pacj screen, a monetary switch and piezo sppoeaker


How to Use version 0.1, includes video tutorial.

 

Interlock v0.5(or greater) sketch basics and instructions

Tab Name Instructions

Basic System requirements (Default sketch)

Sketch set up.


The Default sketch (as of version 0.5) consists of 6 Tabs

interlockV0_5.ino

customFunctions.ino

interlock.cpp

interlock.h

interlock_setup.h

userGuide.ino

interlockV0_6.ino



The first tab contains the version number in it so may change as new versions are released.

It contains certain items that MUST be in the sketch for interlock++ to run but also is a tabe that you can add your own libraries and code to process inputs (buttons, switches, block detectors etc).
However certain key lines must be on this page.

1) The following lines must be at the top of the sketch as they set up the system.


#include "interlock.h" //include the interlock class in the sketch
interlock mySignalBox; //create an instance of the class called mySignalBox. You may choose a different name but I will use tis name in all examples.

2) Definitions Part 1: These define the different types of item on the layout, Points, Turnouts, Signals, Block, Crossings and Other 1 - Other 3. DO NOT change the definition values but the names of OTHER1 - OTHER3 can be changed to your own names for items I had not thought of.

The examples are:

#define POINT 1
#define TURNOUT 2
#define BLOCK 3
#define CROSSING 4
#define OTHER1 5 //Change definition name as required
#define OTHER2 6 //Change definition name as required
#define OTHER3 7 //Change definition name as required

3) Definitions Part 2: These define a value of 0 or 1 (0 or 1 can be used instead of the definitions) to make it easier to understand what is being set up in the rules. as you become more experienced you may wish to use the values 0 or 1 instead.
The names may be edited of new definistions added as required.

The examples are:

#define POINTLEFT 0 //I define left and right as viewed from the point frog, change definition names to suit
#define POINTRIGHT 1
#define TURNOUTLEFT 0 //I define left and right as viewed from the point frog, change definition names to suit
#define TURNOUTRIGHT 1
#define SIGST 0 //signal stop (red)
#define SIGGO 1 //Green/yellow/ Go
#define CROSSINGST 0 //crossing stop
#define CROSSINGGO 1 //crossing Go
#define OTHERST 0 //other stop
#define OTHERGO 1 //other Go
#define BLOCKCLEAR 0
#define BLOCKOCCUPIED 1

4) setup()

The setup() function must contain the following lines:

The first 2 start the Serial monitor (chage speed if required). Serial monitor is used for diagnostic and error messages even if a screen is added.
The 2nd line just prints out the file path of the file loaded on the Arduino/ESP32 so that you can keep track of what version you have running.

Serial.begin(9600);
Serial.println(F(__FILE__ " " __DATE__ " " __TIME__));//File details

After the Serial monitor the following line is required to initialises interlock++. This cause various arrays to be created in the background ready for rules or monitors to be added.

mySignalBox.init(); //This functions sets up the interlock system

5) loop()

The loop requires the line:

mySignalBox.runInterlock();//This needs to be in the main loop to run the interlock system

This line is called as often as possible and is constantly looking at signal monitors and waiting to process any rules that are triggered.

WARNING: adding delay() in your code will cause problems with interlocks processing. Millis() should be used for timings. See Lesson 3 Controlling timings with if() and millis() for more information on using millis() for timing.


customFunctions.ino


This tab contains a number of functions that receive information fomr Interlock++ when rules have been processed successfully or not as well as other items that may be useful to drive screen and outputs such as signals, points/turnouts, crossings etc.

The functions all contain Serial.print() outputs as standard and allow the user to decide what to do with the data passed.

These are the functions that are used to drive signals/points/turnouts/crossings or send information to nowRail, DCC EX or other systems.


Functions:

void interlockModeState(uint8_t modeState)

This function receives a 0 or 1. 0 = Training Mode, 1 = Interlock mode.

void intErrorTone()

This function is called when a rule has been broken and allows the users to trigger an aidible or visual warning for the operator.

void intUpdateLayout(uint16_t itemID, uint8_t instruction)

This function is called when a successful command has passed the rule test OR when an item has passed or failed the test in trainee mode.
The itemID contains the point/turnout/crossing/signal ID, the instruction contains a 0 or 1 representing the instruction that was passed.

This function would be used to send inputs to the layout usually by creating a switch() statement for the itemID and an if() statement in each of those instructions for the direction of movement/signal setting.


void intCheckResults(uint8_t interlockState,uint16_t itemID,uint8_t instruction,String itemName,uint16_t checkItemID,uint8_t checkInstruction,String checkItemName)

Thi function is used for screens for displaying error messages as well as successes. It could also be used for logging error. This function is called every time a rule is processed successfully or if a rule has been broken.

Values passed are:

int8_t interlockState: 0 = Success, 1 = interlock rule broken

uint16_t itemID: The itemID of the signal/point/turnout/crossing that triggered a rules check.

uint8_t instruction: The instruction/direction (0 or 1 for turnouts, 0 - Number of aspects for signals) that was checked against the rules.

String itemName: The String of the item processed "Poin" "Turnout" "Signal" etc.

uint16_t checkItemID: 0 if rule passed or the Item number of the item that cvaused the rule to be broken

uint8_t checkInstruction: The instruction state the item should have been in of 0 if passed rule (Item ID will also be 0)

String checkItemName: String of the name of item that failed rule OR Blank if interlock successful.

interlock.cpp
interlock.h


These tabs contain the main files that make Interlock++ run. Do not make alterations unless you fully understand the code.


The only mod that you may wish to make is in the array is in interlock.h and the char array that stores the item names. If you are using Other1 - Other3 in your system you may change the names to something more meaningful but with a maximum of 8 characters.

char myItemNamesArray[8][9] = {
"Signal", //0
"Point", //1
"Turnout", //2
"Block", //3
"Crossing", //4
"Other1", //5
"Other2", //6
"Other3" //7
};

interlock_setup.h


This tab contains customisable features of Interlock++ that allow you to make the system best suited to your layout and processor (Mega 2560/ESP32)

You will find a number of definitions:

#define STARTMODE 0 //0 = Learning Mode, set to 1 for full interlock mode. Sets the start up mode of the system.

#define INTPROCSPEED 10 This value sets the time in milliseconds between processing instructions. Can be lowered to 1 for faster processing of increased if you want to run a batch of commands to simulate delays between each item being set... by a slow signalman.

The following 3 items effect the size of the data storage Interlock++ sets aside. Reducing these values will free up memory for your own processing code. Note the ESP32 has a lot more memeory so can handle a lot more items.

#define INTNUMINPUTS 100 The default number iof inputs (Signals, blocks, crossings, turnouts, points) is 100 this value runs OK on the Mega2560 but can be over 400 for the ESP32. The larger the number the more SRAM is used.

#define INTNUMINTERLOCKRULES 1000 The default number of rules for the Mega2560 is 1000, much more than this will cause memeory issues on the Mega2560. The ESP32 can handle much larger volumes, I have only tested up to 4000 but it will handle more.

#define INTMONITORBLOCKSIGNALS 80 This is the default number if signal monitor rules in the system, increase or decrease to suit your system. The ESP32 handled 400 monitors with ease. Reduce to 1 if not using monitors to save memory.

#define INTDUELMONITORBLOCKSIGNALS 40 This is the default number of Duel signal monitors, increase or decrease as required.


Diagnostics: Outputs to serial monitor

#define SIGNALMONITORDIAGNOSTICS_ON This line is commented out by default as it slows the system down but is useful for viewing batches of monitoring instructions to see the block sigbnal values changing in the Serial monitor.

#define RULECHECKDIAGNOSTICS_ON Displays various diagnostic information to the Serial monitor, cann be commented out for production code once everything is working.

userGuide.ino


To save as much memory as possible the code uses very few strings.

Instead the system sends error messages to the Serial monitor in a code format. This page lists the error message codes, the function and the item that caused the issue. It also gives the reason and solution to the error if one is available.

 

Interlock v0.5 (or greater)sketch input functions

Function Instructions

void loadInput(uint16_t itemID, uint8_t inputTypeID);

This function is used to load non signal components into interlock. Non signal items include Points/Turnouts, Crossings, Blocks and Other1 - Other 3

uint16_t itemID : This is the unique item ID number assigned to each item including signals (Values between 1 and 65,535). ID numbers must be unique but DO NOT need to be sequential.

uint8_t inputTypeID : This is the item type, see the definitions for the value of the items in the first tab.

#define POINT 1
#define TURNOUT 2
#define BLOCK 3
#define CROSSING 4
#define OTHER1 5  //Change definition name as required    
#define OTHER2 6  //Change definition name as required    
#define OTHER3 7  //Change definition name as required

You can input the definition name or the definition values as follows.

This function MUST be in the setup() AFTER the line mySignalBox.init();


Examples:

mySignalBox.loadInput(4, POINT); //Item ID = 4 (track plan) Type = 1 POINT from definitions

mySignalBox.loadInput(12, CROSSING); //Item ID = (track plan) Type = CROSSING from definitions


The above lines could be written as follows if you do not want to use definition names.

mySignalBox.loadInput(4, 1); //Item ID = 4 (track plan) Type = 1 POINT from definitions

mySignalBox.loadInput(12, 4); //Item ID = (track plan) Type = CROSSING from definitions

void loadSignal(uint16_t itemID, uint8_t aspects);

This function is used to load signals into Interlock++

uint16_t itemID : This is the unique item ID number assigned to each item including signals (Values between 1 and 65,535). ID numbers must be unique but DO NOT need to be sequential.

uint8_t aspects : This is the number of aspects a signal has. Interlock has a maximum 5 aspects.



This function MUST be in the setup() AFTER the line mySignalBox.init();


Examples:

mySignalBox.loadSignal(1, 2); //Item ID = 1 (track plan), 2 Aspects = 2 Aspect signal (red/Green) (red/yellow)
NOTE semaphore/mechanical signals are treated as 2 aspect signals

mySignalBox.loadSignal(5, 4); //Item ID = 5 (track plan), 4 Aspects = 4 Aspect signal (red/yellow/double yellow/Green)


void loadRule(uint16_t itemID, uint8_t itemStatus, uint16_t checkItemID, uint8_t checkItemStatus);

This function loads a rule into Interlock++

uint16_t itemID ItemID that will be moved

uint8_t itemStatus The directions/state the item will be set to

uint16_t checkItemID The item ID of the item that should be checked

uint8_t checkItemStatus The state the check item should be in.

This function MUST be in the setup() AFTER the line mySignalBox.init();

Examples:

mySignalBox.loadRule(4, POINTRIGHT, 1, SIGST); //Point 4 to move right, check signal 1 is Stopped

mySignalBox.loadRule(4, POINTRIGHT, 2, SIGST); //Point 4 to move right, check signal 2 is Stopped

mySignalBox.loadRule(4, 1, 3, 0); //can be written without definitions Point 4 to move right, check signal 3 is Stopped

mySignalBox.loadRule(2, SIGGO, 4, POINTLEFT); //signal 2 to go green/Yellow, point 4 must be set left

mySignalBox.loadRule(2, SIGGO, 1, SIGST); //signal 2 to go green/yellow, signal 1 must be set stop

void loadSignalMonitors(uint16_t itemID, uint16_t monitorID);

This function is used to load signals monitors into Interlock++

uint16_t itemID ItemID of the signal

uint16_t monitorID ItemID of the signal that is being monitored

This function MUST be in the setup() AFTER the line mySignalBox.init();

Examples:

mySignalBox.loadSignalMonitors(5, 6); Signal 5 is monitoring signal 6

mySignalBox.loadSignalMonitors(6, 7); Signal 6 is monitoring signal 7

mySignalBox.loadSignalMonitors(7, 8); Signal 7 is monitoring signal 8



void loadSignalDuelMonitors(uint16_t itemID, uint16_t monitor1ID, uint16_t monitor2ID);

Version 0.6 or greater

This function is used to load duel signals monitors into Interlock++
Duel signal monitors are usually used when a track diverges meaning there are two potential signals to monitor depending on the direction of the point/turnout.

uint16_t itemID ItemID of the signal

uint16_t monitor1ID ItemID of the first signal that is being monitored

uint16_t monitor2ID ItemID of the second signal that is being monitored

This function MUST be in the setup() AFTER the line mySignalBox.init();

Examples:

mySignalBox.loadSignalDuelMonitors(5, 6, 10); Signal 5 is monitoring signals 6 and 10

void listInputTypes(void);

This function outputs the input types within the Interlock++ data array to the Serial Monitor.

This items is best placed at the end of the setup()

mySignalBox.listInputTypes();


void listInputs(void);

This function outputs the list of inputs that have been entered into Interlock++ through the function void loadInput(uint16_t itemID, uint8_t inputTypeID); The output is sent to the Serial monitor.

This items is best placed at the end of the setup() and best used to check all items have loaded correctly.

mySignalBox.listInputs();

void listRules(void);

This function lists all the rules that have been added though the function void loadRule(uint16_t itemID, uint8_t itemStatus, uint16_t checkItemID, uint8_t checkItemStatus);

This items is best placed at the end of the setup() and best used to check all rules have loaded correctly.

mySignalBox.listRules();

void listMonitors(void);

This function lists all the rules that have been added though the function void loadSignalMonitors(uint16_t itemID, uint8_t monitorID);

This items is best placed at the end of the setup() and best used to check all monitors have loaded correctly.

mySignalBox.listMonitors();



void listDuelMonitors(void);

Version 0.6 or greater

This function lists all the rules that have been added though the function void loadSignalDuelMonitors(uint16_t itemID, uint16_t monitor1ID, uint16_t monitor2ID);

This items is best placed at the end of the setup() and best used to check all monitors have loaded correctly.

mySignalBox.listDuelMonitors();

void setModestate(uint8_t mode);

This function sets the interlock mode within Interlock++

This function can be called at any time from a button press or other input trigger.

This function can be called by a button press or any other input at any time so should be triggered within the main loop or a function within the main loop.

Examples:

mySignalBox.setModestate(0); // 0 sets system to trainee mode

mySignalBox.setModestate(1); // 1 sets the system to full interlock mode

void checkInterlocks(uint16_t itemID, uint8_t checkItemStatus);

This function that is used to check against the rules.

uint16_t itemID The unique Item ID of the item to be checked

uint8_t checkItemStatus The direction (turnout/point), signal state etc of the item to be checked. This item is always a 0 or 1 even in multi aspect signals

This function can be called by a button press or any other input at any time so should be triggered within the main loop or a function within the main loop.

Definitions or the definition values can be used.

Examples:

mySignalBox.checkInterlocks(4, POINTLEFT); //Move point ID 4 to position Left (0)

mySignalBox.checkInterlocks(414, TURNOUTRIGHT); //Move turnout ID 414 to position direction(1)

mySignalBox.checkInterlocks(7, SIGGO); // Sset signal 7 to Clear/Go

The above can be written without using the definitions

mySignalBox.checkInterlocks(4, 0); //Move point ID 4 to position Left (0)

mySignalBox.checkInterlocks(414, 1); //Move turnout ID 414 to position direction(1)

mySignalBox.checkInterlocks(7, 1); // Sset signal 7 to Clear/Go



byte getItemStatus(uint16_t itemID);

Version 0.6 or greater

This function lreturns the current state of an item. For most items the return value will be a Zero or 1 and are related to the values of the definitions below however SIGNAL can have values from Zero to 5 depending on the number of aspects selected.
Zero = Danger, other values can be used to work out the signal colour to show.

#define POINTLEFT 0 //I define left and right as viewed from the point frog, change definition names to suit
#define POINTRIGHT 1
#define TURNOUTLEFT 0 //I define left and right as viewed from the point frog, change definition names to suit
#define TURNOUTRIGHT 1 #define SIGST 0 //signal stop (red)
#define SIGGO 1 //Green/yellow/ Go
#define CROSSINGST 0 //crossing stop
#define CROSSINGGO 1 //crossing Go
#define OTHERST 0 //other stop
#define OTHERGO 1 //other Go
#define BLOCKCLEAR 0
#define BLOCKOCCUPIED 1

uint16_t itemID ItemID of the signal, block, turnout, crossing etc.


This items is best placed at the end of the setup() and best used to check all rules have loaded correctly.

mySignalBox.getItemStatus(5); returns the state of item 5

 

interlockV0.1 - Instructions

Interlock++ Model Railway interlocking signalbox

This video shows how to use version 0.1. Click to download the code for the video example (Click to download)

Interlock++ Version 0.1 was written as a normal sketch that could be adapted to each layouts needs while later versions have been written as a class.

The original version has fixed hardware requirements while later version add more flexibility but the 0.1 version is a good platform to learn on as instructions have been kept.

This version ONLY runs on the Mega 2560 (although can be made to run on the ESP32 despite the LCD library warnings).

Hardware Requirements (0.1 Version)

For the Interlock++ system itself the hardware requirements are:

Arduino Mega 2560 (System will not run on an UNO due to SRAM requirements).

I2C 1602 LCD Screen

1 Push button momentary switch (Mode Switch).

4.5K - 10K resistor (button pull down).

Buzzer/Piezo Speaker

For inputs from the layout push to make/ Stud and Probe type connections are best. The system will work with toggle type switches but operators will need to manually reset the switch if an interlock fails.

Outputs can be to solenoids, servos or any other type of driver for signals, crossings and turnouts/points.

Interlock++ Circuit Diagram (0.1 version)

The system can be made to work with DCC systems such as DCC EX and NCE Cab Bus

The circuit diagram below is all that is required for the base Interlock++ code to run.

Other connections will need to be made for inputs from buttons, switches and sensors as well as outputs to servos, solenoids and motor drivers.

Interlock++ Circuit Diagram

How to use Version 0.1

To give an example of how Interlock++ works I will use the track plan below (Click image for larger version).

Interlock++

The first thing that needs to be set up is the number of item types.

The default number is 5, OTHER, POINT (Swap to TURNOUT as required), TSIGNAL, BLOCK, CROSSING

If more item types are added just change the value of

NUMINPUTTYPES 5

Then add or change the associated labels in the array:

The defaults are:

String inputTypes[NUMINPUTTYPES] = {
  "Other",
  "Point",
  "Signal",
  "Block",
  "Crossing" //last item does NOT need ,
};


Next add in your list of point/turnouts, signals, blocks, crossings, Others. These are the items you want to have included in your interlocking system.

For the track plan above I have 8 signals and 3 points/Turnouts

Each item must have a unique reference number (I have used 1-11). Once you have listed all your items make sure you update the line

#define NUMINPUTS 11 to make it the same as the number if items you have added.

#define NUMINPUTS 11  //the number of inputs signals, points, blocks etc, this sets up the array size.
//This array stores all the signal, points/turnouts, blocks or Others
unsigned int inputArray[NUMINPUTS][3] = { //Item number , item Type, State
 
  {1,TSIGNAL,0}, //ID (must be unique), Type (from Input definitions OTHER, POINT,TSIGNAL etc), Default value...leave as Zero)
  {2,TSIGNAL,0},
  {3,TSIGNAL,0}, // could be written {3,2,0}, if you want to skip definitions
  {4,TSIGNAL,0},
  {5,TSIGNAL,0},
  {6,TSIGNAL,0},
  {7,TSIGNAL,0},
  {8,TSIGNAL,0},  
  {9,POINT,0},
  {10,POINT,0},
  {11,POINT,0}//remember the last element of the array does not have a comma after }
};

Next you can add or edit the status definitions, the defaults are:

#define SIGSTOP 0 //signal stop (red)
#define SIGGO 1 //Green/yellow/ Go
#define POINTLEFT 0   //I define left and right as viewed from the point frog, change definition names to suit
#define POINTRIGHT 1
//#define TURNOUTLEFT 0   //USA version
//#define TURNOUTRIGHT 1
#define BLOCKEMPTY 0
#define BLOCKOCCUPIED 1
#define CROSINGCLEAR 0  //cars stopped train can proceed
#define CROSSINGBLOCKED 1 //barriers open, card crossing, train must stop
#define OTHERSTOP 0
#define OTHERGO 1


Try not to make the names too long as it's easier to make error.
If you add extra definitions they must be in pairs, with a value of Zero and 1.

Once all of that is done you can enter your rules into the InterlockRules array as shown in the example below.
After adding your rules count them up and update the line

#define  NUMINTERLOCKRULES  83  //Number of interlock rules in system, increase as new rules added


unsigned int InterlockRules[NUMINTERLOCKRULES][4] = { //Interlock number from inputArray, Interlock item direction/State, interlock to be checked, state that is required
  //Turnout/point 9 left
  {9,POINTLEFT,1,SIGSTOP}, // Point number 1 to turn left must have signal 1 set to stop
  {9,POINTLEFT,2,SIGSTOP}, // Point number 1 to turn left must have signal 2 set to stop
  {9,POINTLEFT,5,SIGSTOP}, // Point number 1 to turn right must have signal 5 set to stop
  {9,POINTLEFT,6,SIGSTOP}, // Point number 1 to turn right must have signal 6 set to stop


The rules above show what interlocks must be in place for Point/Turnout 9 in the diagram above to turn to direction 0.

So it requires signals 1,2,5 & 6 to have a status of SIGSTOP (Zero) that emans the signal is set at red.

Setting the rules can take some time and the bigger the layout the more rules you will need. It will give you a real appreciation of the railway engineers who build mechanical and electronic signal boxes.

These are the rules that will be checked before the system allows a movement to take place. In reality the point/turnout could not be thrown until all the interlocks had been passed.

Thankfully Interlock++ has 2 modes.

Trainee mode (mode 0) will show you the errors you have made, but still allow the point change/signal change.... you atke responsibility for the accident.

Interlock Mode (mode 1) will display the error and reject the command, preventing you in real life from setting a dangerous set of signals/turnouts.



How To tutorials

These tutorials are added insresponse to information or help requests on how to use specific features or work with different components/systems.

If you have a specific request please email me from the link at the bottom of the page or add a comment below the You Tube video.

Virtual Signals


Due to the limited size of model railways there are times when a signal or block that would be in the staging area/fiddle yard would impact the signals being set on the layout.

The simplist example of this is modern block signalling when the signal aspect is limited by the next signal.
Another example would be a station leading to a staging area. If The signals to depart is multi apsect of has a Distant signal once again the aspect and the distant signals interlocking rules would be imacted by a signal that does not exist on the layout.

Interlock++ allows the use of "Virtual Signals". These are signals or blocks that exist in Interlock++ but do not exist on the layout and are virtually cotrolled usually by some kind of sensor on the exit to the staging area/fiddle yard.

Interlock++ Model Railway interlocking signalbox virtual signals

Click to download the code for the video example

Block Signals
Converging Tracks



Block signalling is easy to set up in interlock++ but what happens when you get to a set of points or turnouts and two tracks come together.

This video shows how to set up signal monitors for this situation with two monitors checking the same signal.

Interlock++ Model Railway interlocking signalbox Block signalling converging tracks

Click to download the code for the video example

Block Signals
Diverging Tracks



Block signalling is easy to set up in interlock++ but what happens when you get to a set of points or turnouts and one track splits into two.

This video shows how to set up signal monitors for this situation meaning that the correct aspects will show on either multi head signals or route indicator signals.

Interlock++ Model Railway interlocking signalbox Block signalling diverging tracks

Click to download the code for the video example

Additional Resources


Comments


For help or suggestions on new projects, please email the address in this image: and use Interlock++ Interlocking signal box and block signalling system for model railways as a reference.