Vinicio Coletti Site - PIC Projects

R/C ship motor controller

Released August 10, 2002

PIC Projects Index IK0WRB Site Vinicio Coletti Site

General description

This controller is part of the homebrew remote controlled ship I built during summer 2002.
The ship engine is a 600BB CC motor and the card described here can control the speed and motion direction (forward or backward).
For a full description of the ship project look here.

Power and features

The controller card gets its power from the 6V lead accumulator that powers all the ship. Actually, the voltage goes up to about 6.7 V for a full charged battery, so a series diode protects the PIC from voltage inversions and drops the voltage by about 0.7 V. The PIC 16F84A should not receive more than 5.5 V but I found that even at 6.0 V there is no problems, so the single diode is the unique regulation of the input voltage.
The PIC oscillator is a classical 4 MHz crystal plus 2 capacitors, giving an istruction time of 1 microsecond.
The controller card has the following connectors and features:

Reading the pulses

The main purpose of the program on the PIC is to read the R/C pulses coming from the radio receiver, compute the desired speed and produce adequate pwm pulses on the output, thus regulating motor's speed.
First of all, it's better to remind how an R/C command works. For example a 4 channel R/C command has 2 paddles in it, able to move both horizontally and vertically (4 commands). The R/C transmitter reads the position of every paddle, then sends the following sequence:

  1. A 4 ms (or longer) pulse to signal the start of the sequence
  2. A 1 ms pause
  3. The position of the first paddle, coded as a pulse going from 1 ms (min) to 2 ms (max)
  4. A 1 ms pause
  5. Steps 3 and 4 are repeated other 3 times, to send all 4 channels.
Thus a whole sequence lasts at most 17 ms and if the trasmitter doesn't pause itself, you can have more than 59 motion commands per second. It's enough even for very fast airplane models, I guess.
The R/C radio receiver de-multiplexes the 4 channels and outputs them on 4 different connectors, as TTL pulses. Even if the card can read all 4 channels (in parallel also), the current version of the software reads only channel 2 (motor control).
The main difficulty writing this program came from the fact that the 16F84A has only one timer module, so the same timer had to be used both to read pulses and to generate the pwm output. But let's describe the workflow.

How it works

When a TTL input goes up, a PORTB interrupt on change is generated. The interrupt service routine reads and saves the current Timer0 value, for future use. When the TTL input goes down, another interrupt is generated and this time the service routine computes the difference with the saved value, stores it and activates a validity flag.
In the main program loop, when a validity flag for channel 2 is detected, a routine reads the value stored by the interrupt service routine, resets the validity flag, sets the motor direction (ON or OFF to the switch output) and computes the pwm value.
When Timer0 goes in overflow (a 16x prescaler is used, so this happens every about 4 ms), if the pwm is not zero the motor is started. In the main loop, when Timer0 value becomes greater than the current pwm value, the motor is stopped. Thus the pwm frequency is about 250 Hz, certainly not the best but to avoid this I should implement a different program logic and reduce the length of the interrupt service routine to the minimum. Anyway it works.
Timer0 is also used to increment several "slow" counters, used in different parts of the program. For example, when no PORT B interrupts are detected for about 1 second, this means that R/C signal is missing, so the motor is stopped. The program then looks for new stable signals and if they come, the normal computing is resumed.
To drive the motor output I use 4 pins of the PORT B in parallel, to have a driving current of 80 mA. This current goes to the base of a 2N3055 transistor, whose output goes to the bases of other 3 2N3055, connected in parallel. I used this big-Darlington configuration simply because I had available an used 4 x 2N3055 module, nicely mounted on a dissipating plate.

The bug

The very first version of the program had a serious bug: there was no total OFF of the motor when the paddle was in the center position and there were always spurious max speed pulses. Debugging was useless, until I went back to the Microchip manuals to read carefully how the "PORT B interrupt on change" really worked. This way I discovered that when I switched ON or OFF the pwm output (4 PORT B pins), I fired at the same time the interrupt, because every write to a port is also a read from that port! Thus, the interrupt service routine was confused by all these false interrupts and mixed wrong readings to the good ones.
Sadly, I already had the circuit mounted and tested when I discovered this, otherwise I would have used a PORT A pin + a small transistor to drive the output. Thus, in the single point where the motor is stopped, in place of a simple clrf PORTB instruction, I put the following:

bcfINTCON,RBIE; disables interrupts on PORTB
clrfPORTB; stops motor
movfPORTB,f; reads again PORTB to clear pins inequalities
bcfINTCON,RBIF; clears PORTB interrupt flag, if just activated
bsfINTCON,RBIE; enables interrupts on PORTB
Cheaper than another transistor, isn't it?
This fixed the bug, but for added security, mainly in case I change radio transmitter, I filtered out all pulses shorter than 0.9 ms and longer than 2.1 ms. Also, the pulses in the range 0.9-1.0 ms were normalized to 1 ms and those in the range 2.0-2.1 ms were normalized to 2 ms.

Future developments

There are many possibilities, if you really want to make your life busier:

The circuit

If you need this drawing at a higher resolution, press here.

The components list

Outside the controller card

PIC Projects Index IK0WRB Site Vinicio Coletti Site

Create your counter