This Blog describes the ongoing development of a 16mm scale 45mm gauge garden railway situated in the North West of England, UK from 2004 to the present day.
This blog describes ongoing progress in the development of a G gauge / 15mm scale / 1:20.32 / Fn3 scale Garden Railway from its inception to the present day.
NEW (October 2025)
The Fruit Special Train (featuring containerisation)
When I became interested in building my own garden railway I spent a considerable amount of time (and money) on books, videos, DVDs and scouring the internet for information, ideas and inspiration. When I eventually started construction, I used some of the ideas I had discovered, but also experimented with my own approaches. This blog outlines how I have gone about constructing my own garden railway. My aim is to provide the sort of information I was looking for when I was getting started, and also to share what I've learned (or 'borrowed' from others). I've tried to include a few 'How I ........' postings interspersed with occasional 'Progress Reports'. I do not profess to be any kind of expert - what I offer here is an opportunity for you to metaphorically look over my shoulder to see how I have gone (and am going) about this fascinating hobby.
As this is a blog, the various posts are presented in reverse chronological order (ie the most recent first). To see a categorised list of contents, go to the Blog Contents Page.
If you are thinking about building your own garden railway, then why not join the 16mm Association or the G Scale Society - you'll get plenty more advice and opportunities to visit other peoples' garden railways. Alternatively, browse through theG Scale Central website - there's plenty more guidance here and an opportunity to sound out the views of others through the G Scale Central discussion forum or the GardenRails.org forum
The Blog
The advantages of blogging are that it is immediate and uncomplicated when creating and uploading information. The other, of course, is that with Blogger it is free. The major disadvantage is that I have minimal control over how the postings are presented. The blogging system adds the most recent information to the start of the blog, hence the postings appear in reverse chronological order (most recent first, oldest last). Whilst there is a list of postings on the right-hand side, it's not particularly easy to see what is there. This introduction is an attempt to provide you with a contents list of the postings organised into categories so, hopefully, you see if what you are looking for is presented in this blog. To ensure that it always appears at the start of the blog, I update its content and set its presentation date into the future each time I add a new posting.
The only development with rolling stock since the last progress report has been the introduction of containerisation to the PLR - in the form of a couple of LMS A-Type containers to ease the transshipment of fruit from the PLR to the mainline. With regard to permanent way, a fair amount of effort has been expended in finishing off and ballasting the trackwork at Beeston Market and the Copper Mine. I also took the opportunity to sort out a couple of issues with the trackwork at Bickerton and relay the ballast across the whole station. In addition, I have been exploring the feasibility of producing 3D printed trackwork and points levers. And, at last, the signals which I constructed originally over ten years ago now have sockets to allow them to be deployed across the whole system.
An indirect influence on rolling stock was inspired by another visit from Zach Bond who, in response to a video I produced on battery power, was determined to show that I could operate some aspects of my railway using live steam.
Finally, I have managed to squeeze in a couple of operating sessions.
In addition, although it is not directly related to the PLR, I took the opportunity to visit my fellow garden railway modelling mate, Greg, in Australia and was able to take one of my PLR locos to run on his and his friends' garden railways. Whilst in that part of the world, I was also able to travel on a few Australian and later New Zealand and Vietnamese railways.
Permanent Way
Ballasting at Beeston Market
In the previous Progress Report, I described how the baseboards at Beeston Market and the Copper Mine had been replaced owing to rot being found in the original timbers. After ensuring that the revised track layouts were workable, I got around to ballasting all the newly relaid track.
I tried a slightly different approach to ballasting the station and yard areas, based on the methods I have developed over the years.
Firstly, a strong mix of horticultural potting grit, sharp sand and cement (1:1:1) was applied dry - an old 1.5" paintbrush being used to push the dry mix into place.
This was then fixed in place with a fine spray of water from a misting hose attachment. After a couple of days, the surfaces in the yard areas were top-dressed with a mix of soil and sharp sand, fixed into place with diluted SBR (1:1).
Finally, the yard areas were toned down with a watery mix of cement dyes (brown and black)
As previously, the base of the platform was made from a pressure treated fence rail. The sides were covered in scribed and painted PVC foamboard and the surface covered with roofing felt (tar paper) - See How I constructed the platform at Beeston Market
Ballasting at Bickerton
Regular viewers of my videos may have noticed some unevenness in the trackwork on the throat of Bickerton station. Over the years, the track leading to the station has "settled" by a few mm whereas the track in the station itself has remained fairly stable, mainly due to it being mounted on concrete slabs resting on brick pillars.
After lifting the track, I realised it was going to be easier to shave those few mm off the concrete slabs rather than trying to raise the trackwork leading up to the platforms. The slabs were somewhat resistant to being shaved, but half a day's work with an angle grinder (and three grinding wheels) plus considerable effort with a lump hammer and cold chisel.
Once the slabs had been contoured, it was a case of relating the track and then ballasting, using the same methods outlined above.
[Awaiting photo]
Signal bases
Over the past couple of progress reports, you will have seen that I finally found a way of remotely controlling my 20 semaphore signals, so each was self-contained with its own li-ion cell, Arduino microprocessor and linear servo.
All that was needed to allow them to be deployed around the railway was a series of sockets into which the signal bases could be slotted. They were made simply by gluing together four pieces of 5mm PVC foamboard. The bases were left open to allow water to freely drain away.
Once painted black (with an aerosol rattle can), some were screwed into place on the wooden raised sections ....
... while the others were concreted in.
Once more, the cold chisel was needed where sockets needed to be installed in the breeze block concrete track foundations.
When not in use, each socket is covered with a 3D printed removable lid, to prevent debris from filling the socket (though it doesn't discourage slugs and woodlice).
I'm pleased to say, that it now only takes about ten minutes for all the signals to be set out and another ten minutes to retrieve them.
When I relaid the track at Beeston Market, I decided to try a third method - wire-in-tube point rodding.
Time will tell how effective this approach will be in the long-term, but for now I have found to it be a lot more reliable than some of my previous attempts.
3D printed track
I am toying with the idea of creating a portable indoor layout which I can use during the winter and maybe even take to exhibitions. After experimenting with various track layouts .....
..... I also wondered about the efficacy of using 3D printed track. The files for pointwork, and straight and curved track sections were downloaded from Thingiverse.com. These have been printed out, and I will carry out further experiments to decide whether (or not) the track would be viable.
Points levers
in the past, I have made my own metal and plastic points levers (see How I made some points levers). These have been deployed in a limited way to areas where I am unlikely to walk when, for example, cleaning the track or cutting the hedges as they are vulnerable. To operate the plastic pointwork, I adapted the design to produce a couple of versions of 3D printed points levers as I was not happy with the versions provided on Thingiverse.
Rolling stock
Live steam
As mentioned above, my long-term friend and fellow modeller, Zach Bond, made a second visit to the PLR, this time to explore the feasibility of managing the daily pickup goods train with live steam.
Zach is undoubtedly the most well-informed and experienced person I know with all matters relating to live steam - in both model and full-scale forms.
I must say, that I was impressed with the capabilities of the live steam loco he used - particularly as it was not equipped with a Slomo device and yet it performed all the required shunting operations and inter-station duties with ease (except when I took over the controls).
Containerisation
I have probably reached the stage in the development of the PLR where I no longer need any more rolling stock - in fact, I probably need to thin out some of my accumulated passenger and goods stock to both rationalise what is needed and also to make better use of my storage facilities.
However, when planning one of my videos, I decided that transportation of the soft fruit harvest from Bulkeley could benefit from some form of containerisation. After a quick bit of online research, I discovered that the LMS actually introduced A and B Type containers in the early 1930s - which fits in very well with my imagined history of the PLR.
And so, using Tinkercad, I produced two versions of the early LMS A Type containers.......
....... and used them in the video.
Ongoing maintenance
Of course, no railway, whether model or full size, can operate without a regime of ongoing maintenance. I have a shelf in the workshop which I refer to as "The Casualty Bay", where poorly locos and other stock sit awaiting their turn for remedial attention. At the time of writing, two locos are receiving intensive care; ex GVT loco #24, Cholmondeley is having additional weight added after struggling with adhesion when on a modest train up Gallantry Bank.
[Awaiting photo]
And loco #2, Beeston, is having its wiring checked after throwing a repeated continuity error when being charged.
[Awaiting photo]
Since the previous update, various wagons and coaches have passed through the workshop having minor adjustments to their running gear or having buffers or couplings replaced or tweaked.
Running sessions
In addition to the two videos shown above, since my last Progress Report I have made six videos:
Decisions, Decisions! Outlining how many decisions I make during a typical running session
Freight Handling with a free phone-app - showing how I make use of a free phone-app to help generate weighted randomised freight movements during a running session
All in a Day - An overview of all the trains which run during a running session which depicts a typical day on the PLR - also includes a couple of unexpected / special trains.
The Midday Passenger - follows the midday passenger train as it proceeds Down and then back up the line as the 1:00pm Up passenger
Battery Power and Radio Control - my views based on twelve years of running my railway with battery power
Breakdown - What happens when the morning mixed loco breaks down
James on Tour
Eleven years ago, my Australian friend, Greg, and his wife, Pauline, visited Peckforton Light Railway. I vowed that one day I would visit Greg but, for various reasons, I was unable to fulfil this ambition.
This year, that has changed. I spent three weeks in Sydney and Melbourne, taking the opportunity to run one of my locos, #25 James, on Greg's, and two of his friends', railways.
James on a short goods train on Lilyvale viaduct
James on the trestle between Termite and Melaluca
James with a Down passenger train on Greg's indoor pottery line
Greg and his friend Keith at Keith's indoor line
James on a mixed goods train on Keith's outdoor line
James on Geof's indoor line
Me and Geof with his indoor line
Magazine Articles
Finally, since my last progress report, I have had a couple of articles published in the Garden Rail magazine.
After experimenting with Arduino Bluetooth control systems (eg see Arduino-based Bluetooth control for model trains - Part 1) and finding that I disliked having to look at my phone screen whenever I wanted to control the loco, I decided to explore using Arduino as the basis for a 2.4GHz radio control system.
I'll say from the start, that it isn't perfect. It works OK for about 90% of the time, but occasionally it seems to have a mind of its own. I haven't yet figured-out why. I have enquired on a couple of Arduino forums, but nothing useful has been suggested. However, I find this system is still preferable to trying to view what is on my phone screen whilst out in the garden when the sun is shining.
I am no expert with Arduino; I have just acquired sufficient information to solve each problem as it arises. However, you might find this is helpful if you are also a novice, as I will not try to blind you with technical knowledge - because I don't have any.
The receiver
Firstly, I acquired the equipment needed for the receiver: an Arduino Nano, an NRF24L01 radio module and an L298n motor driver. These can readily be bought online for modest sums (c £17.50GBP at the time of writing - or cheaper (c£4.50GBP) if bought directly from China via AliExpress).
Basically, all I had to do then was connect the components together. Note: I used an adapter board with the NRF24 module as this provides the required voltage without the need for an additional voltage regulator.
For testing, I used DuPont jumper cables, but once I had tested everything, I soldered the connections.
The connections to the Arduino Nano were:
Nano
pin
Connected
to
Comments
D2
Forward
facing LED (+ve)
via
a 100 ohm resistor
D3
ENA
pin on L298N
D3
provides PWM output
D4
IN1
pin on L298N
When
high loco moves forward (IN2 Low)
D5
IN2
pin on L298N
When
high, loco moves in reverse (IN1 Low)
D6
Rear
facing LED (+ve)
Via
a 100R resistor
D7
CE
pin on NRF24
D10
CSN
pin on NRF24
D11
MOSI
pin on NRF24
D12
MISO
pin on NRF24
D13
SCK
pin on NRF24
This
pin must be used exclusively for SCK
The next step was to program the Arduino Nano to respond to the signals it received from the NRF24 receiver.
To do this, the Arduino IDE software needed to be downloaded from the Arduino website ( https://www.arduino.cc/en/software/ ) and installed on my laptop computer.
/* Basic receiver code without sound * Adapted from the code provided by Electronoobs - http://www.electronoobs.com/eng_arduino_tut25.php */
#include <SPI.h> // This library is included as part of IDE #include <nRF24L01.h> //The nrf24 libraries must be installed for the code to work - available from https://www.arduinolibraries.info/libraries/rf24 #include <RF24.h>
const uint64_t pipeIn = 0xE8E8F0F0E1LL; //This 'pipe' code must be the same as in the transmitter sketch RF24 radio(7, 10); //CSN and CE pins
// The size of this struct should not exceed 32 bytes which is why the byte variable is used for each channel struct Received_data { byte ch1; //Throttle data from Tx byte ch2; //Not used this time but defined in case you want to add additional features (eg sound triggers, user-controlled lights etc) byte ch3; byte ch4; };
Received_data received_data;
int ch1_value = 127; //127 is the mid-point value for the potentiometer output int ch2_value = 255; int ch3_value = 255; int ch4_value = 255; int ch1_oldval = 127;
//Pin connections int motorSpeedPin = 3; #define IN1 4 //motor Fwd #define IN2 5 //motor Reverse #define fwdLED 2 //Front facing LED pin #define revLED 6 //Rear facing LED pin
// Variables // int val = 0; // speed
void reset_the_Data() { // 'safe' values to use when NO radio input is detected received_data.ch1 = ch1_oldval; //Throttle (channel 1) - keeps the speed constant if the signal is lost (change this to 0 if you want the loco to stop if the signal is lost received_data.ch2 = 127; //Resets Ch2 to its mid setting received_data.ch3 = 255; // Resets Ch3 to High received_data.ch4 = 255; // Resets Ch4 to High }
// Initialising LED pins as outputs pinMode(fwdLED, OUTPUT); pinMode(revLED, OUTPUT); digitalWrite(fwdLED, HIGH); //Turns on the forward facing LED - confirming the loco is switched on }
//Here we define the function that will read the data void receive_the_data() { while ( radio.available() ) { radio.read(&received_data, sizeof(Received_data)); //Here we receive the data lastRecvTime = millis(); //When the data was received } }
void loop() { //Receive the radio data receive_the_data();
//////////This will reset the data if signal is lost for 2 sec. ///////////////////////////////////////////////////////////////////////// unsigned long now = millis(); //Time now if ( now - lastRecvTime > 2000 ) { //Checks now time with when the data was last received - if greater than 2 secs assume signal is lost // If signal lost reset_the_Data(); //Use the values set above } ch1_oldval = ch1_value; ch1_value = received_data.ch1; //Assign the values received to the relevant variables ch2_value = received_data.ch2; ch3_value = received_data.ch3; ch4_value = received_data.ch4;
// Direction and Stop if (ch1_value > 140) { // Go forward if throttle is greater than 140 digitalWrite(IN1, HIGH); //Tells the motor control board to go forward digitalWrite(IN2, LOW); digitalWrite(fwdLED, HIGH); //Turns on the forward facing LED digitalWrite(revLED, LOW); //Turns off the reverse facing LED val = map (ch1_value, 141, 255, 0, 255); //Maps the received throttle output from 141-255 to 0 to 255 } else if (ch1_value < 121) { // Go in reverse if throttle setting is less than 121 digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); //Tells the motor controller to go in reverse digitalWrite(fwdLED, LOW); digitalWrite(revLED, HIGH); val = map (ch1_value,0, 120, 255, 0); //Maps the throttle output from 0-121 to 255 to 0 } else { // Stop if the throttle control on the Tx is between 122 and 139 (ie in the centre)NOTE A broad range is used to take account of variations in the tolerances of potentiometers used digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(fwdLED, LOW); //Delete these two lines of code if you want the LED to remain on when the loco is stationary digitalWrite(revLED, LOW); // ditto }
analogWrite(motorSpeedPin, val); // Throttle
}//Loop end
The code then needs to be uploaded to the Arduino Nano.
If you are not familiar with this process, then here's a quick guide.
Step 1 - The sketch for the receiver has been downloaded and opened in
Arduino IDE.
Step 2 - Connect the Arduino Nano to your computer – any USB to
mini USB connector cable can be used. You may already have one
available from another device, or they can be readily and cheaply
purchased from eBay.
Step 3 - Before
uploading the sketch, the Arduino IDE application needs to configured
to communicate with the Nano. In the Tools menu click on Arduino Nano from the drop-down field beside Board:
Step 4 - If, like me, you
bought your Nano from eBay, you will need to tell IDE to use the Old
Bootloader. In the Tools menu, select Atmega328P (Old Bootloader) from the drop-down list beside Processor:
Step 5 - Before
uploading to your Nano, check the syntax of the code is OK by
clicking on the tick button. If no errors are detected, then click
the Upload (arrow) button. If there are errors, try downloading the
code again and re-opening it in IDE or check the erroneous bit of
code highlighted by the error checker.
Step 6 – A
couple of ‘libraries’ of commands will need to be added to the
basic Arduino program to enable the Nano to communicate with the
NRF24 board (nRF24L01.h and RF24.h). Adding libraries is dead easy. Go to the relevant
website (https://www.arduinolibraries.info/libraries/rf24
) and download the libraries as a .ZIP file (this contains both libraries).
Step 7 – Once
these have been saved to your computer hard drive, they are installed
in IDE by going to the Sketch menu, clicking on Include
library and then on Add .ZIP library. Navigate to where you
saved the libraries and they will then be unzipped and installed in
IDE.
The Transmitter
With the receiver constructed and programmed, I now turned my attention to the transmitter. While running RC Trains a few years ago, I developed knowledge and skills to construct Deltang transmitters and so it was a simple process to transfer this knowledge to constructing one for Arduino components.
The components needed for the transmitter were:
Arduino Nano
NRF24
NRF24 adapter
Three push buttons (momentary)
Illuminated push-push on/off switch
SPDT toggle switch
10k linear potentiometer
PP3 battery snap connector
PP3 battery
Small instrument case with PP3 battery compartment
The first job was to connect together the components.
The adapter for the NRF24 wasn't essential, but I decided to use one as it obviates the need for the voltage regulator. I also, eventually, swapped the NRF24 with external antenna, for the standard model as I found the one with the antenna drained the PP3 battery within an hour. The range from the standard NRF24 module was perfectly adequate in my garden.
The case (a KE32 Enclosure with Battery Compartment, Grey, 110 x 66 x 27mm) was bought from Eltop Electronics
You could connect several push buttons or switches to the Nano, in the end I just opted for one push button and one two way switch.
The connections to the Nano were:
Nano
pin
Connected
to
Comments
D2
SPDT
switch centre pin (other two pins of switch connected to ground
and 5v output from Nano
Enables
the D2 to be switched high(5v) or Low (0v)
D3
Push
button 1
Other
pin of button connected to 0v
D4
Push
button 2
Other
pin of button connected to 0v
D5
Push
button 3
Other
pin of button connected to 0v
D6
Not
used
Could
be used for additional switches or buttons
D7
Not
used
Could
be used for additional switches or buttons
D8
Not
used
Could
be used for additional switches or buttons
D9
CE
pin on NRF24
D10
CSN
pin on NRF24
D11
MOSI
pin on NRF24
D12
MISO
pin on NRF24
D13
SCK
pin on NRF24
This
pin must be used exclusively for SCK
A0
To
centre pin of 10k pot
A1
To
centre pin of two-way switch
A2
– A7
Not
used
Could
be connected to other potentiometers for live steam loco control
3v3
To
+ve leg of LED in illuminated on/off switch via 30R resistor
5v
To
one of the outside pins on the potentiometer
The
other outside pin of the pot connected to 0v (ie ground)
Initially, the connections were made with Du Pont connectors but once it had been tested, the connections were soldered.
The Nano was connected to my laptop as above and programmed with the following code:
/* Transmitter code - adapted from that provided on the Electronoobs websitehttp://www.electronoobs.com/eng_arduino_tut25.php*/#include<SPI.h>#include<nRF24L01.h>//The nrf24 library must be installed first - avaiable from https://www.arduinolibraries.info/libraries/rf24#include<RF24.h>constuint64_tmy_radio_pipe=0xE8E8F0F0E1LL;//This code should be the same for the receiverRF24radio(9,10);//CE and CSN pins on the Nano// The size of this struct should not exceed 32 bytes which is why we are defining each variable as a byte.structData_to_be_sent{bytech1;//Throttle channelbytech2;//Switch direction 1bytech3;//Switch direction 2bytech4;//Button 1bytech5;//Button 2bytech6;//Button 3};//Create a variable with the structure above and name it sent_dataData_to_be_sentsent_data;voidsetup(){radio.begin();//These statements set up the NRF24 as a transmitter to enabe it to send dataradio.setAutoAck(false);radio.setDataRate(RF24_250KBPS);radio.openWritingPipe(my_radio_pipe);//Default channel valuessent_data.ch1=127;//The mid position for the speed controller (0 = Low, 255=High)sent_data.ch2=255;//Sets each channel initially to HIGH (Could use 'HIGH' instead of '255')sent_data.ch3=255;sent_data.ch4=255;sent_data.ch5=255;sent_data.ch6=255;}/**************************************************/voidloop(){sent_data.ch1=map(analogRead(A0),0,1024,0,255);//Reads the potentiometer value and and then maps the reading of 0 to 1024 to 0 to 255sent_data.ch2=digitalRead(2);//Reads the input from the SPDT switch's pin 1sent_data.ch3=digitalRead(3);//Reads the input from the SPDT switch's pin 2sent_data.ch4=digitalRead(4);//Reads the input the push button connected to pin 4sent_data.ch5=digitalRead(5);//Reads the input on pin 5sent_data.ch6=digitalRead(6);//Reads the input on pin 6radio.write(&sent_data,sizeof(Data_to_be_sent));// Sends the values to the receiver}
Once the code had been checked with the receiver, the case was drilled to take the switches, push buttons and potentiometer and the components and battery carefully (!) placed inside.
An overlay was printed on to self-adhesive vinyl and stuck to the outside of the case. BTW, I also coat the vinyl with clear sticky-backed plastic to protect the printing.
Adding sound to the receiver
I like my locos to make noises - preferably sounds related to the type of loco. Before doing anything else, I tracked down what I felt were appropriate sounds. After drawing a blank with YouTube videos, I eventually came across a set of sound files for an old Famulus RS1430 tractor on the SoundSnap website. I felt they were well worth the $15USD required to download five files.
NOTE: Soundsnap now seems to have changed its pricing to subscription only. It would appear you now have to buy a month's subscription for $29USD.
After being downloaded, the files were edited using Audacity (a free sound editing program). In addition, I found the sound of an air horn on YouTube and incorporated that into some of the files until I ended up with the following set of files:
001 -
Silence (1 min)
002 -
Silence plus horn sound (3 seconds)
003 - engine
start-up to idle (4 seconds)
004 - idle
(15 secs)
005 - idle
plus horn (4 seconds)
006 - slow
run (15 secs)
007 - slow
run plus horn (4 secs)
008 - medium
run (15 secs)
009 - medium
run plus horn (4 secs)
010 – fast
run (15 secs)
011 – fast
run plus horn (4 secs)
012 - shut
down (5 secs)
I then purchased a DF Mini Player module from eBay (for £3.49GBP) and uploaded the files to a mini SD card. Note: It's important that the files are uploaded in the order as shown above otherwise the Nano won't be able to play the requisite track when needed.
The DF Mini Player was connected into the receiver circuitry thus:
Nano
pin
Connected
to
Comments
D2
Forward
facing LED (+ve)
via
a 100 ohm resistor
D3
ENA
pin on L298N
D3
provides PWM output
D4
IN1
pin on L298N
When
high loco moves forward (IN2 Low)
D5
IN2
pin on L298N
When
high, loco moves in reverse (IN1 Low)
D6
Rear
facing LED (+ve)
Via
a 100R resistor
D7
CE
pin on NRF24
D8
Rx
input pin on DF mini player
Via
1k resistor to help protect the mini player
D9
Tx
output pin on DF mini player
D10
CSN
pin on NRF24
D11
MOSI
pin on NRF24
D12
MISO
pin on NRF24
D13
SCK
pin on NRF24
This
pin must be used exclusively for SCK
A0
– A7
Not
used
Could
be used as output triggers for soundcards etc
...... and the following code was uploaded to the Nano.
/* Receiver code for PLR rc system with sound synchronisation * Adapted from code provided on Electronoobs website - http://www.electronoobs.com/eng_arduino_tut25.php*/#include<SPI.h>//This library is normally included as part of the IDE download#include<nRF24L01.h>//This library can be downloaded from https://github.com/maniacbug/RF24#include<RF24.h>//This library can be downloaded from https://www.arduinolibraries.info/libraries/rf24#include<SoftwareSerial.h>//This library is normally included as part of the IDE download#include<DFPlayerMini_Fast.h>//This library can be downloaded from https://github.com/PowerBroker2/DFPlayerMini_Fast// SOFTWARE SERIALSoftwareSerialmySerial(8,9);// RX and TX pins for SD playerDFPlayerMini_FastmyMP3;// Initialises SD Playerconstuint64_tpipeIn=0xE8E8F0F0E1LL;//This code must be the same as the transmitter codeRF24radio(7,10);//CSN and CE pins// This struct should not exceed 32 bytes in total//The number of channels can be increased or reduced dependent on the number of controls on your transmitterstructReceived_data{bytech1;// Throttle channel (connected to potentiometer)bytech2;//Switch (forward direction)bytech3;//Switch (reverse direction)bytech4;//Button (Red)bytech5;//Button (F1)bytech6;//Button (F2)};Received_datareceived_data;intch1_value=127;//defines the variables as integers and sets their initial valuesintch1_oldval=127;intch2_value=255;intch3_value=255;intch4_value=255;intch5_value=255;intch6_value=255;//Pin connectionsintmotorSpeedPin=3;#defineIN14//motor Fwd #defineIN25//motor Reverse#definefwdLED2//Front facing LED pin#definerevLED6//Rear facing LED pin// Variables //intval=0;// speed intTrack=1;// which track is playing - sets this initially to track 1 (silence)intslowVal=70;// idle speed max - change to suit your locointmedVal=120;// slow speed max - change to suit your locointfastVal=180;// med speed max - change to suit your locovoidreset_the_Data(){// 'safe' values to use when NO radio input is detectedreceived_data.ch1=ch1_oldval;// Resets the throttle to its old value (ie for cruise control if the signal is lost - put 0 if you want the loco to stopon the loss of rc signalreceived_data.ch2=255;// Sets the inputs from the buttons and switch to HIGHreceived_data.ch3=255;received_data.ch4=255;received_data.ch5=255;received_data.ch6=255;}/**************************************************/voidsetup(){//Reset the received values (as above)reset_the_Data();// Initializing SerialSerial.begin(9600);mySerial.begin(9600);myMP3.begin(mySerial);//Initialises MP3 playermyMP3.volume(30);//Sets the volume of the MP3 outputmyMP3.loop(1);//Starts the MP3 player by looping track 1 (silence)//Begin and radio configurationradio.begin();radio.setAutoAck(false);radio.setDataRate(RF24_250KBPS);radio.openReadingPipe(1,pipeIn);//Sets up the NRF24 as a receiver//We start the radio comunicationradio.startListening();// Initialising Motor-DriverpinMode(motorSpeedPin,OUTPUT);pinMode(IN1,OUTPUT);pinMode(IN2,OUTPUT);analogWrite(motorSpeedPin,0);// Initialising LED pinspinMode(fwdLED,OUTPUT);pinMode(revLED,OUTPUT);digitalWrite(fwdLED,HIGH);}/**************************************************/unsignedlonglastRecvTime=0;//The function which reads the data from the Txvoidreceive_the_data(){while(radio.available()){radio.read(&received_data,sizeof(Received_data));//Here we receive the datalastRecvTime=millis();//Records the time when the data were received}}/**************************************************/voidloop(){//Receive the radio datareceive_the_data();//////////Resets the data if signal is lost for 2 sec./////////////////////////////////////////////////////////////////////////unsignedlongnow=millis();if(now-lastRecvTime>2000){// Compares time now with time when the data were last received// signal lost?reset_the_Data();}ch1_oldval=ch1_value;ch1_value=received_data.ch1;ch2_value=received_data.ch2;ch3_value=received_data.ch3;ch4_value=received_data.ch4;ch5_value=received_data.ch5;// Direction and Stopif(ch1_value>140){// Forward if the speed knob turned to right (127 is central position value)digitalWrite(IN1,HIGH);digitalWrite(IN2,LOW);digitalWrite(fwdLED,HIGH);digitalWrite(revLED,LOW);val=map(ch1_value,141,255,0,255);//Maps the throttle value of 141 - 255 to 0 to 255}elseif(ch1_value<121){// Reverse if the speed knob is turned anticlockwise from the central position (127)digitalWrite(IN1,LOW);digitalWrite(IN2,HIGH);digitalWrite(fwdLED,LOW);digitalWrite(revLED,HIGH);val=map(ch1_value,0,120,255,0);// Maps the throttle output from 0 to 120 on to 255 to 0 (ie when knob is at zero position (full left) speed in reverse is full}else{// Stops the loco if the speed knob is in central position (ie between 122 and 139)digitalWrite(IN1,LOW);digitalWrite(IN2,LOW);digitalWrite(fwdLED,LOW);digitalWrite(revLED,LOW);}analogWrite(motorSpeedPin,val);// Gives the motor driver module the required speed setting//Playing the SD card tracks//There are twelve tracks on the SD card//001 - Silence (1 min)//002 - Silence plus horn sound (4 seconds)//003 - engine start-up to idle (3 seconds)//004 - idle (15 secs)//005 - idle plus horn (4 seconds)//006 - slow run (15 secs)//007 - slow run plus horn (4 secs)//008 - med run (15 secs)//009 - med run plus horn (4 secs)//010 - fast run (15 secs)//011 - fast run plus horn (4 secs)//012 - shut down (5 secs)if(ch2_value==LOW&&Track==1){//Has engine start button been pressed on Tx and is there no sound?myMP3.play(3);//If so, play engine start-updelay(4000);//If your engine start-up track is not 4 secs you will need to change this delay (1000 = 1 sec)myMP3.loop(4);//Now play the engine idle soundTrack=4;}if(ch3_value==LOW&&Track==4){//Has engine stop button been pressed on Tx and is the idling track playing?myMP3.play(12);//If so, play engine shut-down trackdelay(5000);//If your engine shut down track is not 5 secs long you will need to change this delay (1000 = 1 sec)myMP3.loop(1);//Now play silence trackTrack=1;}if(Track==4&&val>slowVal){//Move from idling to slow run soundmyMP3.loop(6);Track=6;}if(Track==6&&val<slowVal){//Move from slow run to idle soundmyMP3.loop(4);Track=4;}if(Track==6&&val>medVal){// Move from slow run to med run soundmyMP3.loop(8);Track=8;}if(Track==8&&val<medVal){//Move from med run to slow run soundmyMP3.loop(6);Track=6;}if(Track==8&&val>fastVal){// Move from med run to fast run soundmyMP3.loop(10);Track=10;}if(Track==10&&val<fastVal){//Move from fast run to med runmyMP3.loop(8);Track=8;}if(ch4_value==0&&(Track==1||Track==4||Track==6||Track==8||Track==10)){// Has horn button been pressed?myMP3.play(Track+1);//Play relevant horn trackdelay(2000);myMP3.loop(Track);}}//Loop end
You can see that the horn sounds whenever Channel 4 is sent low (ie when the button is pressed on the transmitter connected to Pin4 on the Nano) by moving to the next engine sound plus horn track and back again. The sound of the engine increases in speed in three steps as the voltage to the motor increases. The code can be tweaked if you want to increase the number of speed steps or include additional effects such as gear change sounds.
Basically, that's all there is to it. As long as you have the confidence to have a go, I can't see any reason why you couldn't follow in my footsteps and make a similar RC control system for around £30GBP or even less if you source your components directly from China via AliExpress.