Wii Nunchuk Controlled Model Train




Using an Arduino microcontroller, an Adafruit motor shield, and a Wii Nunchuk, you can create a intuitive, programmable, model train controller to run your layout.  Amaze your friends.  Entertain your kids.  Not quite DC, not quite DCC.  You're headed for the hacker lands of PWM (pulse-width modulation).

Why do this?
 - Pulse-width modulation allows smooth operation at slow speeds.
 - Set realistic rates of acceleration and braking.
 - Set maximum speed to avoid derailments.
 - Program operational responses to meet your operating style.
 - Control train based on sensors, auto reversing, whatever.
 - Because you can, and it is cool.

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Beg, Borrow, or Build

You will need to beg, borrow, or build a couple of things, all well documented.  Don't be afraid.

1.  Wii Nunchuk.  - The only part of this that isn't "open source" or completely hackable.  It is, luckly, relatively inexpensive, easy to obtain (you may already have one on hand), and incredibly versatile.  For $20 you are getting:
          2-axis joystick
          3-axis accelerometer
          2 pushbuttons
          Countless hours of Nintendo product engineering (priceless)

2.  WiiChuck Adapter.  - While you can cut your cable to access the wires, your kids will hate you when they go to play Lego StarWars next time.  A couple of bucks will get you an adapter and guilt-free access to a software library written by the guy that came up with it (www.sparkfun.com/commerce/product_info.php), or your could build your own using this Instructable.

3. Arduino Microcontroller - You can buy or build one of these.  They are easy and fun to use, and with the shields, can be put to a number of uses, repeatedly.  They come in a number of variants.  I like the newer Duemilanove since it has USB built in.  Here is one source: www.adafruit.com/index.php

4. Motor Controller - As versatile as the Arduino is, it can't drive a DC motor on it's own.  You can breadboard something together using a H-Bridge chip like the SN754410, as shown here, or buy a shield kit that fits right on the Arduino and comes with software libraries and examples.  I'm using one I built from Adafruit shown here.

5. Model Train - (Sold separately). Or any small DC motor you might want to drive.  I'm actually doing this for a small "switching puzzle" layout I've got built.  It is only 1' x 4', and I want it to be easily (and safely) operated by children.  It involves a lot of slow-speed back-and-forth, unlike the typical full-throttle round-and-round stuff.  You can learn more about the layout on the last page.

Step 2: Putting the Hardware Together

In assembling the hardware, I'm assuming you are going the easy route like I did.  Hacking is fun, but I certainly don't want to reinvent the wheel.  Stray from the path at your own risk.

The connections are as follows:

Arduino: 12V power supply plugged into the 2.1mm jack.  The board can get power from the USB connected to program it, but USB cannot supply enough power to run the train.  Trust me, I've accidentally tried more than once.

Motor Shield: The two leads from the train track go to the motor shield instead of that cheap plastic transformer made in China.  I've got them hooked into the "M1" terminals.  Change this, and you will have to change in your program.  Certainly not hard to do, just one more got-cha.  Another little detail: the white jumper on the "PWR" leads tells the board to get power from the Arduino, which as we saw earlier, is coming from a 12V wall wart.  See the website if that confuses you. It did me. Alternatively, you can wire power right into the shield.  The voltage doesn't need to be exact.  You could even run the wires from your original transformer into the shield and just set it to full power.  I think they put out 16VDC or so. 

WiiAdapter:  Confusingly, this can go into the chuk in either of two ways.  The correct way is for the contact on the adapter marked "NC" to go where there is no contact on the Wii.  I've got the connector pins going to the Arduino analog pins A2, A3, A4, A5.  Again, not set in stone, but will have to match the program.  There are some good diagrams and such at todbot's website.

Step 3: Software or Firmware?

The difference between "firmware" or "software" is slight. Your "sketch", or the program you load on to the Arduino could be considered "firmware", but the program you use to get it loaded is "software". To make it worse, people start calling the latter a "programming environment". Confusing, eh? Let's not start talking about "bootloaders", because I don't know squat.

Setting up an Arduino programming environment could be a whole Instructable by itself (I don't see one, so feel free to write it). For now, I'll point you to the "horse's mouth", Getting Started at the Arduino site.

With an Arduino "environment" in place, you are going to need a couple of extra's.
- The motor shield comes with a library called "AFMotor ". You need to down load it from LadyAda's website and place it in the "Arduino/hardware/library " folder. If you breadboarded your own controller, you know enough to write your own functions for it.
- My demo software "WiiChuck_Train_Controller " (attached below). My advice is to paste it into the Arduino environment and save it with a really, really clever name. You'll have to supply that yourself.
- The WiiMote adapter also has a library called "nunchuck_funcs.h " available here . This single file will have to be placed in the same folder as the sketch, something like "Arduino/WiiChuck_Train_Controller " folder. In the newer Arduino environment (0017), it shows both the sketch and the nunchuck_funcs.h on separate tabs (see image).

Update (December 2014):

I had compatibility problems with the newer Arduino versions and switched to a newer nunchuk library from:

Take a look at the demo sketch that comes with it.

Step 4: Just the Start!

With the Arduino connected to your computer, compile and upload the sketch.  Again, I'll leave you to Arduino's website to get all that sorted out.

With the sketch uploaded, hit the "Serial Monitor" button in the right-hand corner of the "environment".  This will let you look at what is going on under the hood, so to speak.

The initial part is just the preliminaries.   It assume the nunchuk is plugged and centered.  It will also show you the current speedLimit (out of 255), and stallSpeed, which is the lowest setting at which the engine will move.  It will depend on your engine and power supply. You can easily change any of these in the "environment" and reload the sketch.

Once you hit the joystick, the monitor will begin to stream variables that will tell you what is going on.  throttle is based on the X joystick position with centered = 0 and ranging from about -100 to 100.  speedSet is the setting it is trying to reach, and curSpeed is the current setting (out of 255) supplied to the track. 

Operator's Manual (Ken's Version):
 - Left & right on joystick will move the train in the direction moved.  If your engine moves opposite to the way you want, swap wires to track (easier) or change variables FORWARD and BACKWARD in sketch (harder).  I guess that is where you find out if you are a hardware or software person!
 -  When the joystick centered, the train will slowly coast down based on a variable called "drag".
 - Z-button applies the brakes.
 - C-button is "cruise control".  It will light LED 13 on board and hold train at current speed.  You can speed up, or hit the brake to disengage it.

That is it.  Make it yours.  HACK AWAY.  Use the accelerometer!  Please write some better "firmware"  and share it. 

I hope that if nothing else, this inspires you to get an Arduino and explore the possibilities!  Let me know what you come up with! 


Step 5: Gratuitous Layout Video and Picture

All this has all been a rough "proof of concept" for my actual layout, which currently uses a 1980's era transformer for DC operation.  The video shows my 11 year old daughter running the layout. You can learn more about the layout here.  We'll have to redo the video with the new controller!

Other "micro-controller" implementations under consideration for the layout:

IR or CdS sensors at end of tracks to prevent running off the ends (check out www.instructables.com/id/A-very-simple-proximity-detector/).

Use sensors for auto-reversing for unattended layout operation (probably just back-and-forth on center spur).

Micro-controlled throwout operation using servos or this ingenious analog device.  Use sensors to prevent throwout operation while train on top of it (causes derailment).

Lady Ada's wave shield to provide audio feedback on events like "off the track" or "on the switch".  Unfortunately, you can't stack the wave and motor shields (no enough pins available to run both simultaneously).  I may just wire up a single motor controller and use the wave shield.

Let me know what else you think it could benefit from.



    • Indoor Lighting Contest

      Indoor Lighting Contest
    • Make It Fly Challenge

      Make It Fly Challenge
    • Growing Beyond Earth Maker Contest

      Growing Beyond Earth Maker Contest

    33 Discussions


    4 years ago on Step 5

    Dear ken.

    Now is our code completed !! We are very happy about it. But the only problem is that our train doesn't move. Now we think it is because our train only drives with at least 100 V.

    What kind of train do you use ? And if we want to buy a new train what kind of detail we have to look for ?

    Kind regard,

    Claire & Chantalle


    4 years ago on Introduction


    I have declared the wire but now we get these errors, I hope you can help us!

    sketch_trein-nunchuk.ino: In function 'void nunchuck_init()':
    sketch_trein-nunchuk.ino:35: error: 'class TwoWire' has no member named 'send'
    sketch_trein-nunchuk.ino:36: error: 'class TwoWire' has no member named 'send'
    sketch_trein-nunchuk.ino: In function 'void nunchuck_send_request()':
    sketch_trein-nunchuk.ino:45: error: 'class TwoWire' has no member named 'send'
    sketch_trein-nunchuk.ino: In function 'int nunchuck_get_data()':
    sketch_trein-nunchuk.ino:65: error: 'class TwoWire' has no member named 'receive'

    2 replies

    Reply 4 years ago on Introduction

    I would completely abandon my example code and start by going to https://github.com/GabrielBianconi/ArduinoNunchuk and downloading his library (look for the "Download Zip" button).

    Unzip the download and copy the 'ArduinoNunchuk' folder, located in the same folder as this 'README' file, to the Arduino libraries folder (Arduino/libraries).

    Restart your Arduino IDE and then open the demo code [File]->[Examples]->[ArduinoNunchuk]->[ArdunioNunchukDemo]

    Upload the sketch and see if you can get readings from your Chuk, and we'll work from there.


    Reply 4 years ago on Introduction

    Sounds like it is time to update the sketch to get a working example again.

    Shoot me an email at 648.ken@gmail.com and you guys can help me get one written and tested.


    4 years ago on Introduction

    I hope somebody is still active. My friend and I are working on this for our assignment for school. But we are having struggles with some errors. I hope somebody can help us.

    WiiChuck_Train_Controller.ino: In function 'void nunchuck_init()':

    WiiChuck_Train_Controller:32: error: 'Wire' was not declared in this scope

    WiiChuck_Train_Controller.ino: In function 'void nunchuck_send_request()':

    WiiChuck_Train_Controller:43: error: 'Wire' was not declared in this scope

    WiiChuck_Train_Controller.ino: In function 'int nunchuck_get_data()':

    WiiChuck_Train_Controller:61: error: 'Wire' was not declared in this scope

    We hope somebody knows these errors and can help us.

    1 reply

    Reply 4 years ago on Introduction

    Hey Guys!

    Sounds like a fun class if you get to use an Arduino!

    I had compatibility problems with the newer Arduino versions and switched to a newer nunchuk library from:

    Take a look at the demo sketch that comes with it.

    Let know how it goes!



    Reply 5 years ago on Step 5

    I haven't had a chance to use the new one yet, but it looks like it would work fine for driving a train. Let us know if you try it out!


    7 years ago on Introduction

    very nice project!!
    I need some help with the program.
    these are the errors that i get:

    nunchuck.cpp:324:28: error: nunchuck_funcs.h: No such file or directory
    nunchuck.cpp:325:21: error: AFMotor.h: No such file or directory
    nunchuck.cpp: In function 'void nunchuck_init()':
    wii_train_controller:152: error: 'Wire' was not declared in this scope
    nunchuck.cpp: In function 'void nunchuck_send_request()':
    wii_train_controller:163: error: 'Wire' was not declared in this scope
    nunchuck.cpp: In function 'int nunchuck_get_data()':
    wii_train_controller:181: error: 'Wire' was not declared in this scope

    Can some one help Please

    2 replies

    Reply 7 years ago on Introduction

    It sounds like the sketch can't find the extra libraries. You need to download and install both the motor library from Adafruit and the Nunchuck library. Check the Arduino forum if you need help with that.


    Reply 7 years ago on Introduction

    when i go to get hub which of the files should i get(motor-shield)? it wont let me download all of them at once and how to i save them properly?


    7 years ago on Step 5

    Have you thought about using magnetic reed switches to detect when a train is approaching the end of tracks? All you need is a couple of small bar magnets glued to the underside of the loco and trailing vehicle (for reverse operation). The reed switches, which are very cheap, can be easily disguised as 'between track' fittings and can be painted without affecting their operation. If you're using a common ground, just connect one side of the (normally open) reed switch to that and take the other side back to one of the Arduino pins, held at 5v by a 1k resistor. Poll that pin to detect when it's grounded and apply the brakes! The magnets should have the same orientation as the reed switches (don't have them at right angles to each other) otherwise you may get a double switching as the N and then the S poles move over the switch.
    You can also use reed switches for train differentiation. Imagine two locos, one with two magnets spaced 1" apart and the other with the magnets 2" apart. With 3 reed switches spaced 1" and 1" you can detect if switches 1 and 2 are closed at the same time or if switches 1 and 3 are closed at the same time. Simply ground one end of switch 1 and connect the other end to both switches 2 and 3. The outputs of switches 2 and 3 will tell you which train is present.
    My idea is for an automatic 'hump' shunting yard. The wagons would have a bar code stuck to the underside and a bar code reader in the hump would read the barcode and switch the points to the appropriate track. I don't yet know how to do this, but I'm sure that it could be done with an Arduino!

    Great Instructable Ken, and Dawson Station is an exceptional piece of craftsmanship.


    8 years ago on Step 3

    Hello, this is a great project but I cant download the code! could you put another link up so I could get the code please? this link gives me a tmp file!? Regards Richard

    2 replies
    Doc Holliday

    9 years ago on Introduction

    Has anybody used this with DCC?  I wouln't want to burn out a lot of locos, turnouts,  and other controlled stuff.

    On my DC garden layout, this might be perfect.