Most model train are powered and controlled through the rails. But we wanted a different approach. Let's be more realistic and let the train drive itself. We get the power from the outside — over the rails — and just like in the real world, the signaling comes from the signal box. We're going to use the geops-API for the DB data for our local S-Bahn line at the Campeon — the Infineon headquarters right outside of Munich.
The plan is to let our little track layout mirror the next incoming train to our station Fasanenpark, so we'll know when to start walking towards the station for the trip home.
We use a PSOC™ 6 Artificial Intelligence Evaluation Kit (CY8CKIT-062S2-AI) as our model train controller. We use the PSOC™ 6 Wi-Fi BT Prototyping Kit (CY8CPROTO-062-4343W), another variant of the PSOC™ 6 as a stationary controller, e.g. for displaying the station and the estimated time of arrival (ETA). Furthermore, we have to deploy a server python script on any suitable device connected to the same network. We use a raspberry pi for that. The reason for a separate server device is the handling of the complexity the geops-API poses.
We chose H0-gauge, one of the most popular scales in the model train community, as a compromise between "big enough to fit microcontrollers in the model train", and "small enough to fit on a table". It turned out to be quite large anyways.
Here is a video demonstration:
2. Hardware PreparationFirst, we will prepare the hardware by wiring the components, 3D-printing all the models, and finally assemble all parts.
2.1 Track layoutWe picked up a 160 cm x 80 cm x 9mm plywood board from the hardware store as our basis for the layout. We mounted the rails using fitting nails.
The next step was 3D-printing. This is the list of things to print:
- Campeon model
- station
- front train wagon
- back train wagon
- 2x train roof
These files can be found in the resources. We have to split the station into 3 parts, and the Campeon is already split into 4 parts. Supports are recommended for the station and the train wagons.
The Train
The general structure of the onboard system of the train is a PSOC™ 6 AI Evaluation Kit as the brain, receiving commands from the server on the same network. The H-BRIDGE KIT 2GO is used to control the motor by receiving the generated PWM signal from the PSOC™ 6, while the power for the motor comes from rails via the pickups at the wheels. To avoid a cold reboot due to bad contacts with the rails, we power the microcontroller from an onboard power bank. Furthermore, the train uses magnets to identify specific points on the track, therefore we use a TLE4964-3M hall sensor attached to the bottom of the train. Here is the schematic:
Below you can see our wiring. We used connectors for some connections e.g. for the motor.
The Station
We use another, stationary microcontroller — the PSOC™ 6 Wi-Fi BT Prototyping Kit — for our display at the station. It also connects to the server to receive display information. For the the display, we use a module such that we can simply connect it via I²C. Refer to the schematic for correct wiring.
The Tracks
The track layout is simply connected to a 12V power supply. We have to make sure to set the polarity correctly with regards to the train direction. Otherwise, the H-BRIDGE KIT 2GO will block the power as a safety precaution. To avoid that, we'd have to add a full-bridge rectifier, which we skipped due to space constraints.
For the train hinge to work reliably, we have to adjust the socket by re-drilling the hole using a drill-bit with a 1.5 mm diameter.
The next step was to mount all the components in the model. With a little force we insert the motorized bogie in the respective socket at the center below the hinge for maximum wheel traction, whereas the free-rolling bogies are mounted at the remaining sockets at both ends of the train. The PSOC™ 6 AI Evaluation Kit and the H-BRIDGE KIT 2GO are placed inside the front wagon, while the power bank is in the back wagon, with a cable going across the gap at the joint. We wire the powered bogie such that the rail pickups and the motor wires connect to the according pins at the H-BRIDGE KIT 2GO. To detect the magnet on the rails, we mount the TLE4964-3M hall sensor at the underside of the front wagon using double-sided tape, routing the cables through the designated whole in the floor.
After we're done flashing the code of the PSOC™ 6 AI Evaluation Kit, which we'll address later, we can close the wagons with the roofs.
After printing the station in three parts, we connect them together and prepare to mount the LCD display. The display module is controlled by the stationary PSOC™ 6 with the I²C interface. To connect them, the cables need to be long enough to fit through the hollow pole of the station display frame. First we connect the cables to the LCD display, then we route them through the left pole. Finally we can attach the display on the frame using thin strips of double-sided tape. The other ends of the cables need to be connected to the according pins as specified in the schematic.
Here are images of the assembled station:
After the hardware is fully prepared, we can address the software and flash the microcontrollers.
3.1 Server CodeAs explained before, we need a central server in the network to connect to the geops-API and manage the train and the station controller. As long as the device running the server code can run and install the required python packages and has no restrictions on ports, like in our case 8080 and 8081, we should be fine. We chose a Raspberry Pi 4 running Home Assistant. After getting terminal access to the server, we can clone the repository in a safe directory. To ensure all necessary requirements, we create a virtual python environment and run:
python -m venv venv
source venv/bin/activate
pip install -r requirements.txtNote: Make sure you have activated your venv before running the server. To do that, run the following command.source venv/bin/activateTo run the server code, we simply run:
python sbahn.pyThe code connects to the geops-API using the public token from the official S-Bahn Munich Live Map. First, our selected station, Fasanenpark, is scanned for incoming trains. Then, since most of our team has to travel back towards the city, the next train towards the city center is selected for tracking. We listen for any updates regarding that train until the train arrives in Fasanenpark and we reselect a new train to track.
We implemented two different operating modes: active and passive.
3.1.1 Active Operating ModeThe idea is to let the model train drive in circles until the real train arrives at a station. We simulate the station by changing the station name on the LCD display. In the bottom line an estimated time of arrival (ETA) timer is shown. To run this operating mode, run the main.py script.
To keep track of the real train and our model train, we use a state machine. We listen for status messages, such as the tracked train boarding or driving, estimated time of arrival, as well as the GPS-coordinates to determine the station the train is at.
In this mode, we simply progress the train to dedicated positions defined by magnets. We can visualize 5 stations - from Deisenhofen to Fasanenpark - where each magnet marks a station for the train. This is a more suitable version for our office to reduce noise. Use the magnet_station_server.py script to run this operating mode.
In parallel to that, we operate WebSockets to connect the server with the model train controller and the station. The server provides sockets that the microcontrollers can connect to. A watchdog that continuously checks for ping messages makes sure to reconnect in case of a timeout. A simple protocol for commands is implemented on all devices for the communication:
# one command per line, i.e. each command ends with a newline -> \nserver -> model train controller:
PONG # returns ping request
SPEED:X # sets the model train speed in range [0, 1] as float
LOOPS:X # sets the number of passes over a magnet before stopping, negative for infinite
REVERSER:B # specifies travel direction, boolean: True for our forward direction
LED_BUTTON # for debugging purposes, toggles the onboard LED
BRAKE_DECEL:X # sets the braking strength coefficient temporarily, for fine-tuning/calibration
BRAKE_DEAD_ZONE:X # sets parameter determining effective zero speed value for brakingserver -> station controller:
PONG # returns ping request
STATION:name:state # name: station name to be displayed, state: current state name of the state machine
ETA:X # X: unix timestamp of arrival time, "none" for no ETA
ACK # acknowledge successful connection to servermodel train controller -> server:
PING # request ping
HALL # sends trigger event from hall sensorstation controller -> server:
PING # request ping
RESTART # force re-selection of train to track3.3 Model Train Controller + Station ControllerTo run MicroPython on the PSOC™ 6, we follow the straight forward steps in this guide.
Model Train Controller
The model train controller automatically connects to the network using the credentials in the wifi_config.json. In server_config.json the local server address has to be specified. To avoid confusion, we recommend to set a static IPv4 address for the server device in the router settings. Make sure all four files, including wifi.py and main.py, are loaded in the MicroPython directory on the model train controller.
Station Controller
For the station controller, essentially the same setup is required as for the model train controller, except for a different main.py script
Due to the simple communication protocol between the devices, the server code can easily be adjusted to fit your own vision. Be it a manual controller, or adjusting train tracking for your local train network's API, timed departures... be creative!
4. FarewellSince we haven't seen many automated DIY model trains on the internet — a dream for any model train enthusiast — we hope to have unlocked some inspiration and motivation for your own projects, providing a basis for customizing your own automated track layout.
Feel free to share your projects in the comments; we're happy to see what you come up with!
Take care!












Comments