Sunday, 24 May 2015

The Garden Railway and WiFi for the Arduino

The railway has taken a back seat for the last few months, thanks to a hectic period at work as we tried (successfully, we think anyway) to find more funding, not to mention lots of work on the product.

But with Zac's visit only a couple of months away, it was time to get everything working again and even try to make some progress on the automation.

No trains had run for several months, and the rails were filthy both with black oxidization and with general garden gunk. Mr Bouncy, the LGB track cleaner, made a valiant effort but even so the trains wouldn't run smoothly. I gave up and went round the track with a hand sander, which got everything nice and shiny.

Foolishly, I'd left all the electronics outside over the winter, protected from rain and sun but still exposed. But after a few problems it all came back to life again, and the trains were running.

The plan has always been to automate the railway, so all the trains run in turn under computer control. There's already a little automation, to control the reverse loops at either end of the line. That is done strictly with a couple of boxes full of miniature relays. While it's always fun to figure out how to do things this way (ever since I read how the Post Office built the telephone network), running several trains is beyond what's reasonable.

My original idea had been to do everything with one or more Arduinos, with train detectors connected to the inputs and motor shields to operate the LGB point motors. An RS-232 connection to the NCE controller would control the trains. For a simple fixed-function controller this can easily be done. But figuring out the NCE commands from the limited documentation was a real pain.

That was when I thought, JMRI has already done this. It's a comprehensive framework for building control panels, operating all the different DCC control systems, and a bunch of other things too. It allows control scripts to be written in Python (well, actually the Jython dialect, but for most purposes they're the same).

But that means getting train detector information back to JMRI. DCC is superb for controlling trains and accessories, but its great weakness is that it has no way to feed information back. NCE has a proprietary way to do it, but it means running separate wires which kind of defeats the object.

The Arduino is a good way to collect data from a bunch of sensors, but somehow it has to get back to the controller. WiFi seems obvious, but when I started this WiFi shields cost several times more than the Arduino itself. JMRI supports an RS-485 two-wire based protocol called CMRI, and that looked promising. I bought the necessary parts but programming it seemed tricky so it didn't get very far.

By the time I picked up this project again, you could get Arduino WiFi shields based on the TI CC3000 chip for $11.95 on Ebay - Chinese ripoffs of the Adafruit card, which use the same software library. The CC3000 has a complete TCP/IP stack on a chip, as well as the WiFi hardware. This is really the ideal solution, especially for remote locations like the far-end reversing loop.

But when I tried to connect it, nothing happened. I have two WiFi systems at home, one running the old security standard WEP and the other the newer one, WPA. After some messing around - the WEP password has to be presented explicitly as a series of hex bytes - I got the actual WiFi connection to work. But no further. For some reason it would not use DHCP to connect to the router itself.

I took the setup to work the next day. With the WPA2 network there, everything worked fine and the example program did exactly what it should. So at least I knew that the hardware and library worked. But back home, nothing. Running Wireshark showed that the Arduino never transmitted a DHCP request. The only difference between the two networks was WEP versus WPA.

Eventually I convinced it to connect to my other network - the trick is to tell the CC3000 that it's WPA2, even though it is actually WPA. And then - it's a miracle! - DHCP got an address, and my test program worked. Conclusion: the CC3000 doesn't work with WEP. It manages to connect, but probably it gets something wrong in the encryption of data packets, so they can't be read correctly.

Along the way I realised that for the sensor input, JMRI was just getting in the way. My intent had been to use its JSON facility to communicate sensor information, which in turn can be interrogated by the script. But a much better way is to use JSON to control the trains, using JMRI just as a translator to NCE-speak. That way my Python code can run as a standalone program, receiving input from the Arduino(s) directly.

So now, the Arduino sends a UDP message to a well-known broadcast address every second, or whenever a sensor changes, with the current state of all the sensors. I found a nice webpage which explains how to listen for multicast messages from Python.

Now I just need to finish the rest of the code and install the sensors, and I'll have an automatic railway at last. If only the trains would stay on the track - but that's another story.

Update 5/25/2015

Well, I spoke too soon. The CC3000 board I'm using is a reliability disaster. It worked kind-of OK for a while. Then for a while it wouldn't execute DHCP correctly, getting stuck halfway through the message exchange (never sending a Request). Now today it does DHCP OK but resets the whole Arduino when connectUDP is called. It looks as though the chip itself is a Chinese ripoff as well as the board - there is no TI logo on it. I've ordered a "real" one from Adafruit, at nearly four times the cost. I hope that works. I've tried with and without external power, so that isn't the problem.

Update 6/3/2015

The Adafruit CC3000 shield did indeed fix most of the problems. DHCP works reliably at least some of the time. It still isn't perfect though - it often takes a board reset before it will work, and sometimes a power cycle. I'm not sure how this is going to work out for my garden railway application.

The resets were due, I eventually realised, to not having enough data memory. There is only 2K bytes, and if there isn't enough, the stack collides on its way down with the static data, resulting in mayhem. I put the static data structures on a diet and the problem has gone away.

Update 6/4/2015

OK, I give up. The Adafruit shield was better than the Chinese one, but nowhere good enough to be usable. It comes up maybe one time in four. The WiFi and DHCP exchange generally look OK with Wireshark, but the microcode mostly doesn't get to the point where you can send messages successfully.

Just bought a 25 foot USB cable... not as elegant or convenient, but there's a limit to how much time I'm willing to spend on what is obviously a very broken piece of silicon (or software for it).