Saturday, January 15, 2011

Controlling Model Trains with an Arduino

‎Hear My Train a Coming

I was back home a few months ago, and I was in the auld fella's shed. He was giving me the grand tour of the model railway setup he was building (OO guage, I believe). Dad's kinda more into the scenery, building buildings, and wiring the tracks rather than playing with the trains. But what interested me was the operation of the trains - he could have a couple of trains on the tracks and control them seperately, going at different speeds and directions. But there's only two wires! What kind of magic was this?
Turns out it was Digital Command Control, or DCC.

The Golden Age of Steam

Back in olden times, the motors onboard model trains got their power (either AC or DC) from the tracks that the train ran on. This was cool if you had only the one train, you could control its speed by varying the voltage on the tracks, and if you had a DC setup, its direction by flipping the polarity. But if you wanted to run two or more trains at the same time on the same tracks, they'd go at the same speed in the same direction. Not too realistic. Or fun, I can imagine.
That's unless you split up the track layout into separate zones electrically. So a train on zone 1 say, would go at a different speed from a train on zone 2. This setup worked but was very flakey in a number of dimensions. It was especially troublesome at the boundaries between these sections, usually at the points. Points, if you don't know, are those things on a railway which direct a train onto one branch of a track or the other. In model railway land, with the tracks being electrically conductive and all, the points are essentially DPDT switches which can end up shorting the zones if things are not properly controlled. I'm a bit fuzzy on the details here to be honest, so I'll continue...


Anyways, DCC is the solution to all this. It's quite cool. Instead of DC or a sinewave on the rails, you drive a digital control packet at roughly +-15V. The motor on the train takes its power from this DCC signal (rectifies it, I think), and a chip onboard each train decodes the control packet to set the direction and speed of the train. Since each DCC train can be programmed with an address, each train on a layout can be individually addressed and controlled all without tricky zone wiring! Brill! For a train that's not being addressed, it can still rectify the signals on the rails to power its motor. And if its not being addressed, the train keeps doing what it's doing.

I had a spare Arduino

This was very interesting to me. Digital control, eh? I had a spare Arduino - I'd brought my RGB LED project to show the nephew/nieces. Digital Control. A spare Arduino. A plan was forming. Could I possibly program my Arduino to digitally control my dad's trains?


The first problem was electrical. The Arduino pumps out 5V, and the trains would require a swing of ideally ±15V and quite a bit of current. So I was thinking MOSFET H-Bridge switching a hefty power supply and controlled by the Arduino's outputs. But I had no MOSFETs to hand. Luckily, my dad had a few L293D's lying about (he's cool like that). So with a bit of stripboard and a chopped up DIL socket I had a quick and dirty power driver circuit ready to go. A dusty wall wart rated for 12V DC (giving me ±6V) sourced from the bottom drawer in my dad's shed would supply the necessary power. The general idea of the circuit is shown below:

I used two of the four H-Bridge legs in the L293D to steer the 12V across the tracks. By controlling inputs 1A and 2A carefully, I could put +12V on one rail and 0V on the other, and vice versa, giving a swing of ±6V. This is not exactly to spec, but seemed to work for two trains at least.

The Grand Plan

Now that I was happy with the physics, it was time to get metaphysical. The basic DCC spec defines a packet made up of the train address, its direction and its speed. So I thought it would be nice if I could send an address:direction:speed triplet from a computer GUI to the Arduino via the USB/serial port. My firmware on the Arduino would then convert this command triplet string into voltage waveforms on its output pins, that would drive the power H-Bridge made from the L293D to, in turn, control the train.

So that's what I did. Although I didn't get it completed at home, so the auld fella tacked a few sections of track onto a length of 2x1 and let me borrow a train.
(Warning! as pointed out by Sergei in the comments, if you build this circuit on a breadboard and use it for long periods of time, the chip will heat up and melt your breadboard! So please build it on stripboard and connect pins 4,5,12 & 13 to as much copper as you can to act as a heatsink.)


So when I got back to base, I started on the firmware. The firmware to implement the basic DCC spec is interesting enough and would make an interesting post on its own. So that's what I'll do.


will said...

So I'm curious, do you actually have a working dcc controller that uses only an Arduino and a few bits of hardware?

I wonder if you could post some pictures, or some further instructions? Is this thing safe, or will it risk damaging the train you might be trying to control?

Have you tried to extend this enough to control everything the decoder is capable of?

Could this be developed into a real open source project?

-- Will

Marty said...

1: Yip, an arduino, an L293D, a DC power supply and a few resistors. Oh, and a laptop to run the GUI to control the trains.

2: What would you like pictures of? The stripboard? What instructions did I miss (I thought I'd explained most of what was needed to get this going, I'd be interested to find out what I missed)

3: As far as damaging the train - I don't think so. AFAICT, the only way to damage a train would be to supply too-high a voltage on the rails.

4: I haven't tried extending this. I just wanted to see if I could get the train to move.

5: Again, I just wanted to get the train to move. The code is my github repo if you want to take it and use it as the basis for an opensource hardware/software project.

I take it you're into model railways then?

Ryan said...

Hi Martin,

Any specific email i can catch you on?



Chris said...

This is an excellent project good work. I am trying to build a layout using your DCC controller with a web gui frontend. I have an issue which i was hoping you could help me with. I need to get the controller to controlthe R8216point decoder, I have been trying to get my head around the packet that I need to build but I am not having any luck. Could you help me out?

Marty said...

@Chris - I have no idea!

I had a quick look on the internet for an R8216 datasheet, but I couldn't find anything that shows the packet format that it expects. If we had this, we'd be flying. Or, rolling if you prefer!

If you had:
* a point controller
* a hornby command station
* some track
* and oscilloscope
you could reverse engineer the packets.

Sorry I can't help more, but I'm chuffed you've found the project useful. If you wouldn't mind, I'd love to see your web GUI when you're done with it!

Sam said...

Hi i really like this project

At the moment i have used my ipod and touchosc to send data over the serial port and that changes the points for me. do you think i could insted of using your GUI i could use sliders in touchosc to control the trains.

Another thing was that i was woundering if you could link the output pins from the arduino straight up to a booster box or something like that so there is definatly no chance of damaging things. finally does a booster box remaster or rectify the packets so to speak or does it just boost them.

Im only 14 and i would like to take my modeling a bit further.

Thanks for the great project.

Marty said...

My DCC controller as it stands, does not know how to talk to points. If we knew what packet format the points expect, it probably wouldn't be a huge job to update the code.

The touchosc thing sounds like a cool idea. I'd imagine that using touchosc to send commands to the arduino would be possible. As long as the ipod can recognise the USB connection to the Arduino as a serial port, and as long as it can send text over this serial link from touchosc, I'd say it could work, but I've no experience working with either ipods or touchosc so I can't say for sure. (Do ipods even have USB ports?)

Put another way, the GUI I built for my DCC driver is not required, but you do need to send text commands over the USB serial port to the Arduino board. See the Python script examples in the code - I've one for finding train addresses and another just to move a train forwards and backwards.

I'm not a railway modeler myself, so tbh I don't know what the DCC booster boxes are designed to do. If you find out, I'd be interested to know.

Jon said...

Hello Martin,
Thanks for posting your project!

I tried it out myself and generalized your code to handle any arbitrary DCC command packet from the PC (for controlling track switches, special decoder functions, or other accessories). I also had the Arduino read a potentiometer and some buttons to control the speed of the train and turn on the head light etc.

It turns out that a TamvalleyDepot 5Amp DCC booster I got at my local train shop will run right off the 5V output from the Arduino so you don't even need the h-bridge if you go that route. That might work with other DCC boosters but I don't know.

Anyway, it's been great fun learning about DCC right down to the bare bits and since I can manipulate each data packet directly, I'm not limited to just the options provided by a particular controller or manufacturer.

Thanks again,

Marty said...

@Jon: Thanks for letting me know you found this stuff useful! It's always interesting to know what folks do with your stuff.

Sounds like you've made lots of mods that one or two other commenters would be interested in, for example the packet formats for other controllers. Do you have your mods documented anywhere? I'd also love to see the code...

Jan said...

This is an interesting project, I' am just in the start of trying to put sorting together with DCC controlled train and arduino.
It would be nice to see what you have come up with Jon

Best regards Jan

Dan John said...

hi there
where can i buy an ld93d
and what sort of decoder will be requiered in trains

Marty said...

@Dan: You can get L293Ds anywhere that sells electronic components: Element14, Sparkfun, Adafruit etc.
As for the trains, they'll need to be DCC compatable - it usually is written on them.

Dan John said...

wont the train need to have a decoder installed in it first

F1p said...

Is your code available?


Marty said...

@Dan John: Yeah, the trains will need a decoder, I probably should've mentioned that! You can buy trains with decoders in them, or buy a decoder board and install it yourself.

@F1p: code is in github:

LT said...

Hehe nice, i started googling the dcc arduino and came up here. Gonna try that too =)

F1p said...

Hey Marty,

Many thanks for the reply.
I have built my H-Bridge to your circuit diagram as above out of N-Channel MOSFETS.

I have a 16VAC power supply from an old DCC controller, or i use a 12VDC power supply.
What would you recommend?
I can supply my circuit diagram if it would help.


F1p said...

Apologies for my last comment, thinking about it again it wouldn't work.

Any suggestions on the best way to add DCC "bytes" into a 16VAC power supply from the Arduino?


Marty said...

@Phillip: What is the amps rating on your 12VDC supply? If it's anywhere near 1A, then why not use that instead of the AC supply?

I can't think of a way of using the AC supply, unless you want to put it thru a bridge rectifier first.

Unknown said...

Nice work so far but your component diagram for the H-bridg doesnt seem right to me. Surely when eith 1A or 2A goes high, both the uper and lower transistors will switch on and there will be a short from the 12v to gnd.

Or have i missed something?

Also, do you have any idea of how you would be able to programme a new address to a train with this setup?



Marty said...

@Ray: Yeah, that cct diagram showing the transistors and the rails is bad. Thanks for spotting that.

I've no idea how to go about reprogramming the address of a DCC receiver, sorry...