Arduino 2-in-1 Model Train Controller

Introduction: Arduino 2-in-1 Model Train Controller

Forty years ago I designed an op-amp based model train throttle for a couple of friends, and then about four years ago I recreated it using a PIC microcontroller. This Arduino project recreates the PIC version but also adds the capability to use a Bluetooth connection instead of the manual switches for the throttle, brake and direction control. While the design I present here is targeted for a 12 volt model railroad motor, it can easily be modified for a variety of other DC motor control applications.

Step 1: Pulse Width Modulation (PWM)

For those of you who aren’t familiar with PWM, it isn’t as scary as it sounds. All it really means for our simple motor control application is that we generate a square wave of some frequency, and then we change the duty cycle. Duty cycle is defined as the ratio of time that the output is a logical high compared to the waveform period. You can see that quite clearly in the diagram above with the top waveform at 10% duty cycle, the middle waveform at 50% duty cycle, and the bottom waveform at 90% duty cycle. The dashed line overlaid on each waveform represents the equivalent DC voltage seen by the motor. Given that the Arduino has a PWM capability built in, it is really pretty simple to generate this type of DC motor control. One other advantage of using PWM is that it helps to keep the motor from the lurching startup that can happen when using straight DC. One disadvantage of PWM is that there is sometimes an audible noise from the motor at the frequency of the PWM.

Step 2: Hardware

The first picture shows the Arduino connections for the switches and the LM298 motor driver module. There are weak pull-up resistors internal to the Arduino so no pull-up resistors are needed for the switches. The Direction switch is a simple SPST (single pole single throw) switch. The Throttle and Brake switches are shown as normally open, momentary contact push buttons.

The second picture shows the Arduino connections for the Bluetooth module and the LM298 motor driver module. The Bluetooth TXD output connects directly to the Arduino RX serial input.

The third picture is a L298N dual H-bridge module. The LM298 module has an onboard 5 volt regulator that can be enabled by a jumper. We need +5 volts for the Arduino and Bluetooth but we want +12 volts to drive the motor. In this case we apply the +12 volts to the “+12V power” input of the L298N and we will leave the “5V enable” jumper in place. This allows the 5-volt regulator to output to the “+5 power” connection on the module. Connect that to the Arduino and the Bluetooth. Don’t forget to connect the ground wires for the +12 input and the +5 output to the module “power GND”.

We want the output voltage to the motor to vary based on the PWM generated by the Arduino instead of just being full on or full off. To do that, we remove the jumpers from “ENA” and “ENB” and connect our Arduino PWM output to “ENA” on the module. Keep in mind that the actual enable pin is the one closest to the board edge (next to the “input” pins). The back pin for each enable is +5 volts so we want to make sure we don’t connect to that.

The “IN1” and “IN2” pins on the module are connected to the respective Arduino pins. Those pins control the motor direction and, yes, there is a good reason to let the Arduino control them instead of simply connecting a switch to the module. We will see why in the software discussion.

Step 3: Bluetooth Module

The picture shown here is typical of the Bluetooth modules available. When looking for one to buy, you can search on the terms “HC-05” and HC-06”. The differences between the two are in the firmware and usually in the number of pins on the board. The picture above is of an HC-06 module and comes with simplified firmware that only allows very basic configuration. It is also set as a “Slave” only Bluetooth device. In simple terms that means that it can only respond to commands from a “Master” device and cannot issue commands on its own. The HC-05 module has more configuration possibilities and can be set as either a “Master” or a “Slave” device. The HC-05 usually has six pins instead of just the four shown above for the HC-06. The State pin isn’t really important but the Key pin (sometimes goes by other names like “EN”) is required if you want to do any configuration. Generally, the modules do not need any configuration if you are ok with the default baud rate of 9600 and don’t care to give a specific name to the module. I have several projects where I use these so I like to name them accordingly.

Configuring the Bluetooth modules requires that you either buy or build an interface to an RS-232 serial port or to a USB port. I won’t cover how to build one in this post but you should be able to find information on the web. Or just buy an interface. The configuration commands use AT commands sort of like what were used in the olden days with telephone modems. I’ve attached a user manual here that includes the AT commands for each module type. One thing to note is that the HC-06 requires UPPERCASE commands and the command string must complete within 1 second. That means that some of the longer strings for things like changing baud rates will need to be cut and pasted into your terminal program or you will need to set up text files to send. The UPPERCASE requirement is only if you are trying to send configuration commands. Regular communication mode can accept any 8-bits of data.

Step 4: Software

The software is pretty simple for both the manual version and the Bluetooth version. To select the Bluetooth version simply uncomment the “#define BT_Ctrl” statement.

When I wrote the PIC code I experimented with the PWM frequency and finally settled on 500-Hz. I discovered that if the frequency was too high then the LM298N module wasn’t capable of reacting quickly enough to the pulses. That meant that the voltage output was not linear and could take big jumps. The Arduino has PWM commands built in but they only allow you to vary the duty cycle and not the frequency. Fortunately, the frequency is about 490-Hz so that is close enough to the 500-Hz I used on the PIC.

One of the “features” of train throttles is a sense of momentum for acceleration and braking to simulate how a real train works. To accomplish that, a simple time delay is inserted in the loop for the manual version of the software. With the value shown, it takes approximately 13 seconds to go from 0 to 12 volts or from 12 volts back to zero. The delay can be easily modified for longer or shorter times. The only case where momentum is not in effect is when the Direction switch is changed. For protection purposes the PWM duty cycle is immediately set to 0% whenever this switch is changed. That, in effect, makes the Direction switch also double as an emergency brake.

To ensure immediate handling of the Direction switch I put its code into an interrupt handler. That also allows us to use the “interrupt on change” function so it doesn’t matter if the change is from low to high or high to low.

The Bluetooth version of the software uses single letter commands to initiate the Forward, Reverse, Brake, and Throttle functions. In effect, the received commands replace the manual switches but cause the same responses. The app I use for Bluetooth control is called “Bluetooth Serial Controller” by Next Prototypes. It lets you configure a virtual keypad and set your own command strings and names for each key. It also allows you to set a repeat rate so I set the Brake and Throttle buttons to 50ms to give about 14 seconds of momentum. I disabled the repeat function for the Forward and Reverse buttons.

That's it for this post. Check out my other Instructables. If you are interested in PIC microcontroller projects check out my website at

Be the First to Share


    • Box Challenge

      Box Challenge
    • Explore Science Challenge

      Explore Science Challenge
    • Arduino Contest

      Arduino Contest



    3 months ago on Introduction

    to prevent singing and increase motor life, increase the frequency to 31k instead of 490hz.
    TCCR2B = TCCR2B & B11111000 | B00000001; // for PWM frequency of 31372.55 Hz on D3 and D11


    Reply 3 months ago

    As I explained in the Instructable the LM298N module does not work properly at the higher switching rates.