cd ~

Published on 1ST SEP 2024

Railway System

Private

Fully autonomous model railway system with real-time train detection, distributed Rust microservices in Docker, and custom embedded hardware for DCC train control. University project at the Chair of Real-Time Systems, RPTU Kaiserslautern-Landau.

Railway System

The Project

The Railway System is a university project developed at the Chair of Real-Time Systems at RPTU Kaiserslautern-Landau. The goal is to build a fully autonomous miniature railway system in which trains operate without any manual driving. The software handles everything: based on real-time sensor data, the system decides which trains should stop, which should move, and when track turnouts should switch, closely mimicking how a real-world dispatching system operates.

At the physical level, the system uses Märklin H0 scale model trains running on a C-track layout, with DCC (Digital Command Control) as the communication protocol between the central controller and the trains. Sensors embedded along the track detect train positions in real time, and that data feeds into a distributed software system running in Docker containers that orchestrates all control decisions automatically. The result is a closed-loop real-time system: trains move, sensors fire, software decides, hardware responds.

This is an ongoing project. The core system is functional but further improvements and features remain in progress. It was initiated by the Real-Time Systems department, not by me personally, though I was responsible for significant parts of the design and implementation. The repository is private and cannot be shared directly.

Railway System test

showing how railway system works on simple scenario

Hardware

The physical system is composed of several layers of hardware that work together: the model trains and track, a central track controller, train detection microcontrollers with sensors, and custom-built electronic circuits for turnout control. Each layer was selected or designed to meet the real-time and reliability requirements of the system.

01. Märklin H0 Trains & C-Track

Märklin ICE 2 H0 model train
Märklin ICE 2 H0 model train

The trains used in this project are Märklin H0 scale models, specifically the ICE 2 (model 29792). These are digitally equipped locomotives that support the DCC protocol among others (mfx, MM). In DCC mode, the factory-assigned decoder address is 3, which is what the software system uses to issue speed, direction, and function commands. The onboard decoder automatically detects the operating protocol and rectifies the track signal internally to power the motor and electronics.

The track is Märklin C-Track, which uses a three-rail configuration. The two outer rails are electrically connected together and form the return path (common). The center rail, a row of metal contact studs running down the middle of the track, carries both the power supply and the digitally encoded DCC command signal simultaneously. Although the waveform alternates polarity and resembles AC, it is actually a digitally modulated signal: the voltage transitions encode command bits that the onboard decoder interprets. Each locomotive picks up the center rail signal via a contact shoe underneath the chassis.

C Track three-rail design diagram

The system operates at 12V, which is the minimum for DCC operation on this track (the nominal recommended voltage is 16V). The three-rail design simplifies wiring considerably: reverse loops require no polarity switching, and multiple trains can share the same track section independently.

  • Märklin ICE 2 H0 scale model, DCC address 3, supports mfx / DCC / MM protocols
  • Three-rail C-track: outer rails = common return path, center studs = power + DCC signal
  • Digitally modulated waveform: voltage transitions encode DCC commands, not true AC
  • Operating voltage: 12V (DCC minimum); nominal 16V recommended
  • Onboard decoder rectifies and regulates track signal to power motor and electronics
  • Reverse loops require no polarity switching due to three-rail design

02. Main Track Controller

The central hardware unit for track control is an Arduino Mega 2560 stacked with two shields: an Arduino Ethernet Shield 2 and an Arduino Motor Shield. Together, these three boards form the command station that physically connects to the track, supplies power to it, and transmits DCC signals to the trains.

Arduino Mega 2560 with Ethernet and Motor Shields

The Arduino Mega alone cannot supply the minimum 12V required for DCC operation, so the Motor Shield provides an independent power path to the track. The Motor Shield's A port connects to the main running track and its B port is reserved for the programming track. Currently a single track handles both roles via jumpers. The Ethernet Shield adds network connectivity over a standard RJ45 port using the W5500 chip, enabling TCP/IP communication with the rest of the Docker-based software system.

Stacking all three boards required solving a pin conflict: both the Ethernet Shield and the Motor Shield use pins 11, 12, and 13 for SPI. To resolve this, the conflicting Motor Shield pins were physically bent outward and rerouted via jumper wires to pins 2, 5, and 6 on the Arduino. Additionally, the Motor Shield's Vin pin was bent outward to isolate its power supply from the Arduino's supply and prevent over-voltage damage. The DCC-EX firmware was updated to reflect the reassigned pins.

Main track controller hardware stack: Arduino Mega with Ethernet and Motor Shields

Power is kept simple: the Arduino Mega runs off USB from the connected PC. The Motor Shield has a dedicated external 12V supply connected to its screw terminals, positive to Vin+ and negative to GND.

  • Arduino Mega 2560: central controller, runs DCC-EX firmware
  • Arduino Motor Shield: supplies 12V to the track, drives DCC signal via A and B ports
  • Arduino Ethernet Shield 2 (W5500): TCP/IP network connectivity over RJ45
  • Pin conflict resolved: Motor Shield pins 11/12/13 physically bent out and rerouted to 2/5/6 via jumpers
  • Vin pin on Motor Shield bent outward to isolate power supplies, preventing over-voltage
  • Arduino powered via USB from PC; Motor Shield powered by separate external 12V supply

03. Train Detection: RP2350 & Reed Switches

Train position detection is handled by RP2350-ETH MINI microcontrollers, one per track section, each connected to a pair of reed switches mounted along the rails. Magnets are attached to both the front and rear of each train. As a train passes a detection point, the magnets trigger the reed switches in sequence, giving the system both the presence of a train and its direction of travel.

Two reed switches per section are used deliberately. A single switch can only confirm that something passed; two switches in sequence reveal the direction of travel based on which one triggers first. This directional data is critical for the routing logic. The system needs to know not just where a train is, but where it is heading, in order to make correct stop, go, and turnout decisions.

The RP2350 transmits detection events over the real-time Ethernet network to the software system's Axle container. In addition to the reed switches, traffic light signals are installed at block boundaries: red when a block is occupied, clear when available. These serve as a realistic visual element on the layout and as a practical debugging aid during development and testing.

Train Detection Node hardware stack: RP2350-ETH MINI with two reed switches and traffic light signals

This reed switch approach is the current production design. Earlier in the project, other detection strategies were explored, including a custom block detector circuit built around a GBU4D bridge rectifier and an IL250 optocoupler. The reed switch solution was adopted for its simplicity, reliability, and ease of physical installation on the track.

  • RP2350-ETH MINI microcontroller per track section: handles detection and Ethernet reporting
  • Two reed switches per section: detects both train presence and direction of travel
  • Magnets on front and rear of each train trigger reed switches as it passes
  • Direction of travel inferred from which switch triggers first
  • Traffic light signals at block boundaries: visual block status indicator and debug aid
  • Earlier block detector design (bridge rectifier + optocoupler) explored and superseded

04. Turnout Control Circuit

Track turnouts are controlled electrically using a custom circuit built around an IRL520 N-channel MOSFET. The MOSFET receives a control signal from the RP2350 microcontroller and drives the Märklin 74492 electric turnout mechanism, the coil-based actuator that physically moves the track switch.

Two 10kΩ pull-down resistors on the gate prevent the MOSFET from conducting randomly when no input signal is present. Two flyback diodes protect the MOSFET from the voltage spike generated when power to the turnout coil is suddenly removed. Without them, the collapsing magnetic field in the coil would produce a high-voltage transient that could destroy the transistor.

Electrical turnout mechanism circuit schematic

The turnout controller nodes run on the same RP2350 platform as the detection nodes, so each turnout node also handles train detection via reed switches and traffic light status. After each track switch actuation, the node sends a status confirmation back over the network, allowing the routing logic to verify that the turnout reached the correct position before proceeding.

  • IRL520 N-channel MOSFET drives the Märklin 74492 electric turnout coil mechanism
  • Two 10kΩ pull-down resistors on gate prevent unintended MOSFET conduction
  • Two flyback diodes protect against inductive voltage spikes on coil de-energisation
  • Same RP2350 platform as detection nodes: turnout nodes also detect trains
  • Status confirmation sent to software after each actuation for verified routing decisions

3D Printed Components

To mount the detection hardware cleanly onto the physical track layout, custom enclosures were designed in FreeCAD and 3D printed. Each enclosure houses an RP2350 microcontroller, the pair of reed switches, and the status LEDs in a single compact unit that attaches directly alongside the track. This made physical installation far more practical. Components that would otherwise be loose, fragile, and awkwardly positioned are secured in a purpose-built housing designed around the specific dimensions of the Märklin C-Track.

3D Model designs for train Detection Node enclosure
3D Model designs for train Detection Node enclosure

DCC-EX Firmware

DCC-EX is an open-source command station firmware that runs on Arduino hardware and generates the DCC track signal used to control model trains. It translates high-level commands (set speed, change direction, activate function, emergency stop) into the precise voltage waveforms that encode DCC packets onto the track. It exposes a straightforward text-based command protocol over USB or network, making it easy to integrate with external software systems.

In this project, DCC-EX runs on the Arduino Mega and serves as the bridge between the software decision layer and the physical trains. The DCC container in the software system translates internal routing commands into DCC-EX protocol messages and sends them to the Arduino over TCP. The Arduino then drives the Motor Shield to produce the correct signals on the track.

Because the standard DCC-EX firmware assumes the default Motor Shield pin mapping (pins 11, 12, 13), and those pins were physically rerouted to resolve the Ethernet Shield conflict, the MotorDrivers.h configuration file in the DCC-EX library had to be modified to use the new assignments (pins 2, 5, 6). This is a small but critical customisation. Without it, the firmware would drive the wrong pins and the track would receive no signal at all. The project started with the automated EX-Installer and later migrated to a manual Git-based setup for finer control over the configuration.

  • Open-source Arduino firmware: generates DCC track signal for train control
  • Simple text-based command protocol: speed, direction, power on/off, emergency stop
  • MotorDrivers.h modified to remap Motor Shield pins from 11/12/13 to 2/5/6
  • Started with EX-Installer; later migrated to manual Git setup for custom configuration
  • DCC container in the software system sends commands to DCC-EX over TCP

Software System

The control logic runs as a set of specialised microservices inside Docker containers, all written in Rust. Each container has a single clearly defined responsibility, and they communicate over a shared Docker bridge network (train-network, subnet 172.28.0.0/16). The system is orchestrated with Docker Compose, and all inter-container addresses and ports are configurable via environment variables, making the setup portable across different machines and network configurations without code changes.

Container network connections and data flow diagram
Container network connections and data flow diagram

Containers

LogicCentral orchestrator. Reads the railway layout from etcd on startup, makes all routing and safety decisions based on incoming block occupancy data, and coordinates the actions of all other containers.
AxleReceives train detection events from the RP2350 microcontrollers over the network and forwards them to the Logic container for processing. Named for the axle counter concept used in real railway systems.
DCCTranslates routing commands from the Logic container into DCC-EX protocol messages and sends them to the Arduino Mega track controller to move, stop, or change the speed of trains.
DestinationDetermines the optimal routing path for each train based on current block occupancy and the destination assigned by the logic layer. Keeps routing decisions separate from orchestration logic.
TurnoutReceives switch commands from the Logic container and relays them to the RP2350 turnout control nodes, then reports actuation confirmation back so the logic layer can proceed safely.
Railway StudioBridges the Logic container with the Railway Studio desktop application, forwards real-time block status updates to the monitor and receives layout data or simulation commands from it.

The connection to Railway Studio is a deliberate architectural decision. The layout that the software system operates on is the same one created, stored, and visualised in Railway Studio. When the system is running, Railway Studio's monitor page connects through this container and displays live train positions and block occupancy states in real time. The same tool used to author the layout becomes the live operational display during runtime. Railway Studio and the RTS DCC Train System are two separate repositories that form one integrated system.

Technologies & Learnings

Applied

TCP/IP communicationUsed throughout: between containers, microcontrollers, the Arduino, and Railway Studio
SolderingBuilt custom circuits for the reed switch detector and turnout control boards
3D modelling (FreeCAD)Designed enclosures for detection hardware to mount cleanly on the physical track
PythonWritten for development utilities, helper scripts, and automation tooling
SchematicsDrew circuit diagrams for the block detector, reed switch, and turnout control circuits
C programmingUsed for developing firmware for the RP2350 microcontrollers and Arduino Mega

Newly learned

RustFirst production use of Rust, written across all six Docker container services
Docker & Docker ComposeFirst experience building and orchestrating a multi-container microservices system
Reed switches & embedded sensingPhysical sensor selection, placement, and integration with microcontroller firmware
DCC-EX libraryUnderstanding, integrating, and customising an open-source embedded firmware project
Märklin DCC & track electronicsModel railway protocols, three-rail track electrical behaviour, DCC signal encoding
etcdUsing etcd as a distributed configuration store shared between the software system and Railway Studio

Project Info

InstitutionRPTU Kaiserslautern-Landau
DepartmentChair of Real-Time Systems
Project typeDepartment-initiated, team project
StatusOngoing
RepositoryPrivate (GitLab)