Introduction: Steam Turret Tank R/C PIC Servo Controller

About: I'm an electronics design engineer, with a passion for blinky lights, shiny brass parts and live steam power. More of all three the better.

A Microchip PIC based servo controller offering many of the capabilities of digital servos for under $9!

The controllers capture the r/c receiver output, optionally manipulate the samples, then regenerate new servo control signals. As such, they greatly enhance what is possible with cheap servos. They were created for my Steam Turret Tank Instructable.

Here is a list of some of the things possible:

  • Expand number of things that can be controlled.
  • Drive multiple servos (with different ranges) from single input.
  • Limit, increase or reverse range of motion on servos.
  • Change center point on servo.
  • Convert absolute servo position to delta/incremental changes.
  • Convert transmitter actions into on/off toggles (for lighting effects, etc...)
  • Suppress servo control pulses when static to reduce chattering.
  • Encode r/c positions into serial bitstream for a remote controller.

It's programmed using a Microchip 5-pin ICSP (In-Circuit Serial Programming) header. You'll need to install MicroChip's free MPLAB-X - there are versions for Windows, Linux & Mac. You'll also need a device programmer, such as Microchip's PICkit-3.

Step 1: Tools Required

The tools needed are pretty minimal. A soldering iron & solder obviously. Extra liquid flux can be helpful, especially for easily removing solder bridges. Needle pliers for placing parts, and wire cutters for trimming leads.

For programming the PIC microcontroller once the board is assembled, you need a PicKit-3 or equivalent.

Step 2: Bill of Materials

Base Circuit

Qty	Description			Price*		Mouser Part#
(1)	PCB(from OSHPark) 		$2.35/ea	n/a
(1)	PIC16LF1825 14-SOIC		$1.60/ea	579-PIC16LF1825-I/ST
(1)	3.3V voltage regulator		$0.38/ea	579-TC1015-3.3VCT713
(1)	47uf 1210 16V capacitor		$0.74/ea	81-GRM32EC81C476KE5L
(1)	1uf 0805 16V capacitor		$0.06/ea	77-VJ0805V105ZXJCBC
(1)	470pf 0805 50V capacitor	$0.06/ea	77-VJ0805Y471JXAPBC
(1)	1N4148 Diode (300ma)		$0.06/ea	512-1N4148TR
(3)	6 pin female headers		$2.13/qty3	517-929870-01-06-RA
(3)	6 pin headers (gold plated)	$0.87/qty3	649-67996-206HLF
(1)	5 pin header for ICSP		$0.19/ea	538-42375-1247
(1)	2 pin r/a header for power	$0.26/ea	571-826631-2

Optional external transistors:

(1)	SOT23 NPN Transistor		$0.13/ea	771-BC846215
(1)	100 ohm 0805 resistor		$0.10/ea	754-RR1220P-101D

Optional SPI ROM:

(1)	128KBit SPI Bus EEPROM		$1.01/ea	579-25AA128-I/SN

* Prices as of 8/25/2014

Step 3: Servo Control Signals

Servos use a three wire connection: ground, power, and the control signal. For the most part, all vendors use that ordering also (Futaba/JR/Hitec/Airtronics-Z). Old Airtronics servos are an exception (swapped power/ground).

The control pins use pulse-width-modulated signals. Pulses varying in width that repeat periodically. The pulses typically range from 1 to 2msecs and repeat every 20msecs. If the pulses stop, the servo stops at its last position.

A 1msec pulse makes a servo moves to one end of its range. A 2msec pulse, and it goes to the other. A pulse somewhere in between moves the servo accordingly. There are no standards however and some servos move more or less amounts.

Some servos are sold as "digital". They accept the same type of control signals. However, digital flavors use a microcontroller instead of an analog control loop on the servo motor. They can move faster & be programmed to manipulate the ranges/center-points/reverse-range/constant-run/etc... The down side is higher price, more power consumption & more noise.

Now for under $9 you can reuse older servos & get many of those same features.

Step 4: Receiver Outputs

I've only looked at the output of a couple different brands of standard r/c receiver, but both worked the same. ie: sequential/stepped outputs.

The receivers do not pulse all their control outputs at once. The first channel pulses (ie: 1msec to 2msec). After the first pulse deasserts, then the second channel pulses. Repeat for remaining channels.

From the PIC programming perspective, sequential outputs make life easier.

A tighter software loop can be used, meaning larger counts & better resolution. For example, sampling a pulse 100 times instead of 20 times. The former gives five times the resolution - a good thing!

To verify your receiver works the same, use an oscilloscope or logic analyzer. Look at a couple different receiver control signal pins. If they resemble the drawing you're good to go.

Step 5: Multiple Controllers

My steam turret tank has two servo controllers. One in the tank chassis base attached to the receiver, and another in the turret itself.

The base-controller samples the receiver and drives the engine servos, steam whistle servo & head/tail lights. It also supplies a serial bitstream (of the raw receiver inputs) to the turret-controller.

The turret-controller receives the serial bitstream, and drives the turret servo, cabin light, gun elevation servo, gun light, gun solenoid, and the turret WTV020-SD sound module. The latter three all trigger simultaneously but for different amounts of time.

Step 6: Software Flow

The code is written in Microchip assembly language (mpasm). Instead of plowing through gory detail I'll give a hopefully easier to understand overview.

The servo controller software samples the inputs, averages the last few to filter noise, performs range/center-point adjustment, and then regenerates the outputs (optionally suppressing inactive ports).

There are two variants of the code. The only real difference is where the servo inputs come from. The base controller directly samples the receiver. The turret samples a serial bitstream generated by the base.

The same source code supports both variants. See defines TXCHIP (for base) & RXCHIP (for turret version).

Various options have associated timer counts. The code implements timers by tracking the number 20msec loops. For example, if an input has been idle for 32 loops (0.64 sec) the idle input filter will trip.

Step 7: Configuring R/C Adapter

There are numerous configuration options available in the source code. The defines select different features, specify servo ranges, change center points, select pulse suppression, etc... Currently these are all compile time decisions.

The PIC16LF1825 does have EEPROM memory, which can be dynamically updated. Making a run-time adjustable version is on my TO-DO list, to support updating ranges/modes on the fly instead of recompiling every tweak.

Here are brief descriptions of the current options:


  • Generate serial bitstream on output1 (port A, bit0). Used on tank base controller.


  • Sample input 0 (port A, bit 5) for serial bitstream instead of sampling r/c receiver. Used on turret controller.

SWITCH {input}

  • Specify the mode switch. When on, lock servo outputs and update LED outputs instead.

OUTPUT0 to OUTPUT5 {input}

  • Specify input source for an output pin. Allows remapping of transmitter controls to different outputs.


  • Inhibit pulse generation on outputs if within center zone. Used on tank turret servo.

IDLEINPUT0 to IDLEINPUT5 {output mask}

  • Inhibit pulse generation on specified output if input has not moved within 32 loops (~0.64 seconds). Used on tank engine servos.

DEFAULT0 to DEFAULT5 {value}

  • Default value used for inputs (instead of sampling) use during startup delay. Affects -input- port not output.

MIN0_PULSE to MIN5_PULSE {value}

  • Minimum servo value to use on output. Use to change servo range.

MAX0_PULSE to MAX5_PULSE {value}

  • Maximum servo value to use on output. Use to change servo range.


  • New servo center on output.

LED0 to LED5 {input}

  • Turn output on when input moved above threshold. Off when below.


  • Toggle output on/off when input moved above "up" threshold. Used for tank head/tail lights.


  • Toggle output on/off when input moved below "down" threshold. Used for tank head/tail lights.

PULSEUP0 to PULSEUP5 {input,delay}

  • Pulse output for specified delay when input moved above "up" threshold. Delay is in terms of 20msec loops.

PULSEDOWN0 to PULSEDOWN5 {input,delay}

  • Pulse output for specified delay when input moved below "down" threshold. Used to fire tank gun.

    Delay is in terms of 20msec loops.


  • Convert input from absolute to delta mode. Affects -input- not output. In delta mode, the controller maintains the current position. Moving the transmitter stick up increases the "current" position slowly. Moving the transmitter stick down decreases the current position. Used on gun elevation servo in the turret tank. Delay is in terms of 20msec loops.

Step 8: Example Configurations

Configure output and alter range and center point:

#define OUTPUT0 _input2	     ; Output 0 tracks channel 2
#define MIN0_PULSE 90	     ; Reduce output range to 1.3 to 1.7ms (0.014ms/tick).
#define MIN0_PULSE 122	     ;   Nominal range is 64 to 148 (0.9 to 2.1ms).
#define CENTER0_PULSE 102    ; Alter center point to 102 ticks.

#define OUTPUT5 _input3	     ; Output 5 tracks channel 3
#define MIN5_PULSE 50	     ; Increase output range to 0.5 to 2.5msec.
#define MAX5_PULSE 178	     ;   Don't exceed what your servos can handle!

Change output to use delta increments, instead of absolute position from transmitter:

#define OUTPUT1 _input4	     ; Output 1 tracks channel 4
#define DELTAINPUT4 10	     ; Update position of simulated input 4 every 
			     ;  0.2 seconds (10 loops * 20msec)

Convert transmitter movement into on/off toggles:

#define TOGGLEUP2 _input0    ; Toggle output 2 on/off if channel 0 moved up.
#define TOGGLEDN3 _input0    ; Toggle output 3 on/off if channel 0 moved down.
#define PULSEUP4 _input1,50  ; Pulse output 4 for 1 second if channel 1
			     ;  moved up (50 loops & 20msec).
#define PULSEDN5 _input1,25  ; Pulse output 5 for 0.5 secs if channel 1 moved down. 

Suppress servo control pulses when no input changes occur:

#define OUTPUT0 _input2	     ; Output 0 tracks channel 2
#define IDLECENTER0 8	     ; Suppress output 0 when within center zone +- 8 
			     ;  ticks for over 64 loops (1.2 secs).
#define OUTPUT1 _input4	     ; Output 1 tracks channel 4
#define IDLEINPUT4 OUTMASK1  ; Suppress output 1 when input 4 idle for 32 loops.

Step 9: Board Schematics

The board design allows using just the PIC alone, or augmenting outputs with external transistors. There are also spare transistor pads, LED's pads, and space for a SPI ROM.

Power Supply

The various servos, lighting, solenoid can cause momentary droops in the battery power. To avoid brownouts, the controllers have a diode & 47uf capacitor. These feed a 3.3V regulator, then the PIC. There are additional filtering caps on the PIC side.


The PIC can be any of the footprint compatible Microchip PIC's. The 16LF1825 I used is a mid-range part with more memory, a UART & other capabilities. Obviously if you choose a 5V part, change the voltage regulator to match.

I'd intended on using a Microchip SPI EEPROM to store sound samples, but ended up using an external sound module instead. The SPI ROM shares pins used for capturing r/c inputs. Therefore it can't be used unless the controller is receiving input over a serial bitstream.

External Transistor Drivers

PIC's are capable of directly driving an LED. However, for larger loads external drivers are useful. For my turret tank, I used the external transistors mostly for driving head/tail lamps.

Step 10: Board Layout

The PCB layout isn't anything special. The various headers were placed to fit a Spektrum AR6000 receiver. I wanted the controller outputs accessible when installed on the receiver. Function followed form for everything else.

The boards were fabricated by OSHPark. Three for ~$7.05 including shipping. They come with double-sided solder mask & silk screen labels. Very nice.

The boards should work with other receivers, but you may want to redo the form factor. If you have no need for the external transistors/spares the board outline can be much smaller.

Step 11: Board Assembly

Assembly is simple. I recommend using a fine-tip soldering iron.

Start with the PIC, voltage regulator, capacitors & diode. Leave the headers to last.

On the bottom of the PCB are jumper pads for bypassing the external transistors. Bridge the pads if you aren't using the transistors.

Once assembled, check to make sure the power & ground are not shorted. Both on the power connector, and on the ICSP header.

Step 12: Compiling the Code

The projects already contain hex files for convenience. However, recompiling any changes is easy.

The projects contents are MPLAB-X compatible, so just unzip them to a convenient location.

  1. Start the MPLAB-X IDE.
  2. Select "File -> Open Project..."
  3. Navigate to an unzipped project folder & click on the folder name.
  4. Click on "Run -> Clean and Build Project"
  5. Done!

The hex file is found under the project folder at "dist \ default \ production". They really like deep paths. Oh well.

Step 13: Programming With PICkit 3

Unfortunately Microchip doesn't make programming PIC's as simple as I'd like. A simple checkbox for "Supply Power to Target" would be nice. Alas...

  1. Connect PicKit-3 to the ICSP header. Observe the pin 1 indication!
  2. Launch the Microchip MPSIM-X IPE (integrated programming environment).
  3. Load the hex file (File -> Import)
  4. Configure to supply power to the r/c controller:
    • Select advanced mode (Settings -> Advanced Mode)
    • Enter password (defaults to "microchip") & click "Log on".
    • Select "Power" screen on left.
    • Check "Power Target Circuit" option.
  5. Select the "Operate" screen on left.
  6. Pick "PIC16LF1825" from Device drop-down. Double check you selected the 3.3V "LF" version.
  7. Click the "Apply" button.
  8. Click the "Connect" button.
  9. Click the "Program" button.

Hopefully all goes well & you're done!

Note: The PicKit-3 probably won't be happy if you have servos plugged in. I recommend disconnecting everything before updating the chip.

Step 14: Example Movie

The controllers in action!

Microcontroller Contest

Participated in the
Microcontroller Contest

Tech Contest

Participated in the
Tech Contest

Remote Control Contest

Participated in the
Remote Control Contest