WiFi Model Train Controller

by barnstormer50 in Circuits > Arduino

1650 Views, 2 Favorites, 0 Comments

WiFi Model Train Controller

Thanet Flyer 1.jpg

This project arose because I decided to rekindle my childhood interest in railway modelling. I was very surprised to find that the control systems available are still entrenched in technology which dates back 30+ years (for DCC and much longer for analogue), and that now commonplace WiFi technology has not made serious inroads into the hobby. Model trains seem a perfect candidate for using WiFi for direct control so I decided to see what was possible.

Preliminary Work

First step was to purchase a small train set to act as a test bed and then I trawled the internet for ideas. If I was to be able to accommodate all the electronics within the confines of a model train (I have chosen OO gauge) then I clearly needed miniature components and I soon discovered the ESP8266 and a number of dc motor controller modules. Of the latter, I homed in on the Pololu MAX14870 which met my spec and is particularly small, and I decided on the “bare bones” ESP01 for control. This required an interface board so that it could be attached to a pc for programming using the Arduino IDE.

Circuitry

Motor+Controller+Circuit.jpg

Very quickly I had a breadboarded prototype up and running albeit located trackside with the analogue (PWM) voltage applied to the track. At this stage the model train was unmodified. One problem with the ESP01 is its sensitivity to noise on the power supply (3.3v) and unfortunately that is exactly what you get when picking up power from a model railway track (noise and disconnections) particularly when traversing points. DCC also suffers from this problem and a “stay alive” circuit is published widely on the internet. This was used with a slight modification and I was able to proceed with modifications to the model train and incorporate all the components within the tender. Although it would be quite feasible to mount the motor driver in the DCC socket of the locomotive I chose at this stage to put everything in the tender. The diagram shows the full circuit which has the following components:-

ESP8266-01 WiFi controller
Pololu MAX 14870 DC Motor driver

Traco Power TSR 0.5-2433 3.3v switching regulator

Bourns CDTO269-BR1190L Bridge rectifier

IN4002 Diodes (2)

100ohm 1W resistor

3k3ohm resistor

1000microfarad 25v electrolytic capacitor

In the standard “stay alive” circuit there is no D1 but that means that there is a voltage difference of 0.7v between the voltage supplied by the capacitor during disruptions in track power and that direct from the bridge rectifier. Adding D1 seems like overkill when the voltage is further regulated down to 3.3v but I found that the noise level on the 3.3v line was reduced. The surface mount bridge rectifier was soldered direct to the Vin and Gnd pads on the motor driver and the remaining PSU components were accommodated on a small piece of veroboard.

Arduino IDE Code

All the code was written (or put together) using Arduino IDE. I can only claim credit for a small fraction of it and most was found at:-

https://www.instructables.com/Easy-ESP8266-Arduino...

The author of this was very helpful and deserves huge credit for his work.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <EmbAJAX.h>

#define MOTORPIN1 0
#define MOTORPIN2 2
#define DIR 1

// Set up web server, and register it with EmbAJAX
ESP8266WebServer server(80);
EmbAJAXOutputDriverESP8266 driver(&server);

#define BUFLEN 30

// Define the main elements of interest as variables, so we can access to them later in our sketch.
const char* stopstarts[] = {"Stop", "Start"};
EmbAJAXRadioGroup<2> stopstart("StSt", stopstarts, 0);
const char* modes[] = {"Reverse", "Forward"};
EmbAJAXRadioGroup<2> mode("mode", modes, 1);
EmbAJAXSlider speed("spd", 0, 1023, 0);   // slider, from 0 to 1023, initial value 0
EmbAJAXMutableSpan speedvalue("speedvalue");
char speedvalue_buf[BUFLEN];

// Define a page (named "page") with our elements of interest, above, interspersed by some uninteresting
// static HTML. Note: MAKE_EmbAJAXPage is just a convenience macro around the EmbAJAXPage###>-class.
MAKE_EmbAJAXPage(page, "Model Train Speed Control", "",
                 new EmbAJAXStatic("<h1>Thanet Flyer</h1><p>"),
                 &stopstart,
                 new EmbAJAXStatic("</p>"),
                 &mode,
                 new EmbAJAXStatic("</p><p>Speed       "),
                 &speedvalue,
                 new EmbAJAXStatic("%</p>"),
                 new EmbAJAXStatic("</p><p>STOP"),
                 &speed,
                 new EmbAJAXStatic("<i>FAST</i></p>"),

                )

void handlePage() {
  if (server.method() == HTTP_POST) { // AJAX request
    page.handleRequest(updateUI);
  } else {  // Page load
    page.print();
  }
}

void setup() {
  // Example WIFI setup as an access point. Change this to whatever suits you, best.
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig (IPAddress (192, 168, 4, 1), IPAddress (0, 0, 0, 0), IPAddress (255, 255, 255, 0));
  WiFi.softAP("ThanetFlyer", "12345678");
  // Tell the server to serve our EmbAJAX test page on root
  server.on("/", handlePage);
  server.begin();
  pinMode(MOTORPIN1, OUTPUT);
  pinMode(MOTORPIN2, OUTPUT);
  digitalWrite(MOTORPIN1, LOW);
  digitalWrite(MOTORPIN1, LOW);
  digitalWrite(DIR, 1);
}

void updateUI() {
  speed.setEnabled(stopstart.selectedOption() == 1);//Speed control disabled when STOPPED.
  mode.setEnabled(speed.intValue() == 0); //Direction control disabled whilst moving.
  speedvalue.setValue(itoa(speed.intValue() / 10.23, speedvalue_buf, 10));
}

void loop() {
  // handle network
  server.handleClient();
  // And these lines are all you have to write for the logic: Access the elements as if they were plain
  // local controls

  if (stopstart.selectedOption() == 0) { //stop
    digitalWrite(MOTORPIN1, LOW);
    digitalWrite(MOTORPIN2, LOW);
    speedvalue.setValue("0");
    speed.setValue(0);
    mode.setEnabled(1);
  }
  else if (mode.selectedOption() == 0) { // reverse
    analogWrite(MOTORPIN1, (speed.intValue()) / 2); //Reverse speed reduced.
    digitalWrite(MOTORPIN2, 0);
    digitalWrite(DIR, 0);
  }
  else if (mode.selectedOption() == 1) { // forward
    analogWrite(MOTORPIN1, speed.intValue());
    digitalWrite(MOTORPIN2, 1);
    digitalWrite(DIR, 1);
  }

}

Operation

I am sure that the above sketch could be improved on but I hope that as it stands it is sufficiently self explanatory. You will note that a factor of two is used when Reverse is selected - this is purely me playing with the code. Unlike motor vehicles, I believe locomotives can travel just as fast backwards as they do forwards!

In operation, the ESP8266 acts as a web server and all that is required is for the user console (I use an IPAD) to log into the server and then to use the browser to find the the appropriate web page (in this case “Thanet Flyer” - IPAddress (255, 255, 255, 0)).

I am sure that the above sketch could be improved on but I hope that as it stands it is sufficiently self explanatory. You will note that a factor of two is used when Reverse is selected - this is purely me playing with the code. Unlike motor vehicles, I believe locomotives can travel just as fast backwards as they do forwards!

In operation, the ESP8266 acts as a web server and all that is required is for the user console (I use an IPAD) to log into the server and then to use the browser to find the the appropriate web page (in this case “Thanet Flyer” - IPAddress (255, 255, 255, 0)). The intro picture shows the user display with the locomotive in the foreground.

Demonstration

This is a short video showing the model in operation. You will note that speed in reverse is reduced - that’s the factor of two described earlier. What it does show is that at low speed the locomotive is able to traverse points without any problem.

Next Steps

So what next? I plan to consider adding other control functions (lights, sounds etc) though the ESP01 is quite limited in the provision of I/O ports. It is possible to use the Rx and Tx as ports (see Instructables article “ESP8266-01 Building Blocks: Unleash 2 Bonus GPIO Pins”) though that may not be sufficient. An alternative would be to use the ESP8266 12-E which provides access to more I/O ports. Additionally I want, if time permits, to consider over the air (OTA) code upgrades - it would be useful to be able to update the code without having to dismantle the model and of course the addition of further locomotives would require code changes for WiFi setup.