I created a live updating trainmap of the UK, complete with a laser-etched map, and blinking LEDs that illuminate on a trains arrival at a certain station. The project was spawned out of a requirement from my engineering course to show aptitude in certain skills (laser cutting and woodworking), but after completing the fairly lax requirements, I decided I wanted to see the project to completion. Here’s how I did it.
Designing and planning
In all honesty, I’m not much of a planner when it comes to projects like these — I prefer to just go for it, and see what happens.
However, there were some parts which needed to be carefully designed, as I didn’t want to be continually laser cutting material until I got it right (inevitably, this did happen once, likely due to tolerance stack up). Unfortunately, I can’t take credit for making the case design — it was generated by Makercase, an excellent site for generating laser cutting plans
I then further modified the case to overlay an editted UK train map (source), making sure to etch and cut in appropriate places.
I might point out that some modifications were required to bend the edges to form a complete corner — the spacing needed to be increased and they needed to be wet, but eventually I managed to form them.
It took me a while to find the right components for the project (which admittedly I did forget about for a few months), but here they are:
- 19 3mm Red LEDS
- 19 330Ω resistors
- 39 jumper wires (19 female to female) (20 female to male)
- Random breadboard
- Raspberry Pi 3A
The jumper wires were the most important, as it was difficult to find wires that could directly connect to LEDs with a clean fit — there doesn’t really seem to be a jumper wire standard, so when I got a kit as a birthday present, I thought I would see if the jumper wires would work. Lo and behold they fit perfectly.
I added a dot of hot glue on the LED’s, and then connected them up to the jumper wires, making sure to take note of the positive and negative ends.
The ground wires were connected to the breadboard, along with a 330Ω resistor, all connected to a lane wired to the ground pin on the RPi. The positive wires were connected to controllable GPIO pins on the RPi.
Some masking tape and bodging later…
And yes, I did just jam the back panel on and hope for the best. Yes, I know. And yes, it all still worked.
This was easily the most frustrating, complex and time-consuming part of the project. Thankfully, I had this repo to help me, but it was still an absolute nightmare.
GitHub - openraildata/stomp-client-python: Example code to use the Darwin v16 feed in Python 3
This repository contains an Python 3 example of how to use the Darwin v16 messages from the National Rail Open Data…
After reading through more NetworkRail API Wiki entries than anyone should ever have to endure, I eventually got an understanding of how I was going to approach the problem. Here’s the massively oversimplified rundown:
- Subscribe to the Darwin Push Port which provides a live data feed of basically every single train and station update in the UK
- Parse and filter the XML feed items to only get status updates to trains arriving at the stations
- Start a timer for each station, which calls a function to illuminate the corresponding LED
Of course, it wouldn’t be proper programming without a myriad of bugs and issues cropping up. Some of the more frustrating issues, with the more complex solutions were as follows:
- Creating a timer for every train arrival and depature is not very performant — each timer creates a thread, and the threads will very quickly add up, until you are out of memory
To allievate this, I made modifications to my scheduling process to schedule the next station LED routine, after they get called — essentially daisy chaining the scheduling. I also include a few statements for catching occasional outlier trains (i.e. trains which are scheduled to arrive earlier than the next scheduled LED).
2. The connection to the Darwin Push Port has a tendency to crash fairly regularly, meaning the timer and station data stored in memory will be removed when the app auto-restarts
This was a significantly simpler challenge to fix — I used a wonderful little caching library for Python which would be loaded into memory every time the app restarted.
GitHub - grantjenks/python-diskcache: Python disk-backed cache (Django-compatible). Faster than…
DiskCache is an Apache2 licensed disk and file backed cache library, written in pure-Python, and compatible with…
I threw the entire script into a Linux service, set it to start on boot, and always restart, and… It worked!
If you’re curious, here’s my code for the map. Beware, there aren’t many comments, and it’ll likely be confusing, as I didn’t initially plan to share it: