Big Improvements, First real test run
We had our first real life test run with my son in the drivers cab. The trains worked excellently, the interface is smooth and responsive and most importantly; it was fun! The smile on my sons face meant that all the work thus far was worth it, and oh boy has it been a lot of work. The latest changes over the weekends have been code based and a little bit of hardware. Reliability and ease of use have been at the forefront and there was a key issue holding the trains back that we solved.
DCC Protocol Handling
The DCC protocol for getting the trains to move is a serial data packet that is sent through the rails of the train track to each train. These packets are decoded and if the address of the packet matches the address of the train then the train reacts accordingly; whether it's speed up, down, lights on, off or any other functionality that's available. This works really nicely and data transfer is great for handling multiple trains on the same rail line.
Where it breaks down is when the train and the track don't meet together perfectly. A single drop in connection and the train suddenly stops, dead in the water. The system then needs to send a new packet to get the train running again. Even if the drop in connection is a tiny fraction of a second, the train returns to its default state as it experiences a power cycle. For us, this meant we could get the train rolling with a command via the interface but then the train we get to a dirty point on the track and stop moving. Clicking some more on the interface would get it going again but obviously this wasn't what we intended.
In order to solve this issue I reworked the DCC interfacing scripts to periodically refresh the trains by sending out speed and light state packets every 100ms. The script pulls latest data from the database for each train and sends out the data accordingly once the timer fires. As of today, this has worked flawlessly and we're getting a really fast response from the trains via the interface.
Abstract Grouping for fun
Once we had the trains running reliably the next focus was to make the lighting more interactive. Every light has a database entry which includes state, brightness, address and a title. The Django server pulls this data and displays a list of buttons and sliders accordingly which allows us complete control of every single light on the table.
Single light control is cool but a tad tedious. No one wants to have to turn off every single street light individually when what we're trying to achieve is all on or all off. In order to simplify the lighting control down I decided to make an additional object in the database which I refer to as "Light Groups". These light groups can be configured with their own state and brightness and hold a list of all of the individual lights in the group. By toggling the group the Pi sends out a state and brightness command for every light in the group to the Teensy and it adjusts the individual LEDs accordingly.
The key benefit of this is that the light groups are defined at the database level which means no arduino code was required to make it work. The groupings are also managed via the Django Admin page which means they can be set up while the table is running super easy. Even my Dad can manage it :p.
LEDs in Parallel/Series
So we have a whole host of LEDs on the table. One of pieces we bought off the shelf is the N-Gauge cars with front and rear LEDs for headlights. The unexpected side of these off the shelf models is that the LEDs are in series rather than parallel. This means our standard method of 5v PWM wouldn't work for lighting as 4 LEDs in series creates a roughly 9V drop across the LEDs; tested that the light with a 9v battery. Thankfully through the use of a PC power supply, we have a 12V line available for use; that just leaves interfacing.
In order to prevent creating a whole new management method for the Car LEDs, I decided to do a physical layer interfacing board that would allow the use of the I2C LED drivers to drive the Car LEDs but with a step up in voltage in between. Through using the PWM output of the I2C boards with a transistor switching the ground and the cars connected to the 12V output we could achieve the cars lighting whilst still using the same database and teensy code.
Unfortunately there's been some teething issues with the interface board so although we've got the cars lighting, brightness and state control isn't quite there yet. Work in progress!