Note for National Robotics Week Robot Contest: I am over 18.  I am a student  at University of Wisconsin Milwaukee. As a mechanical engineering student this project is related to my major. It has also taught me skills that have led to undergrad research work that is taking me on a mechatronics and robotics related career path.

What it is:
This device takes the signal from an RC receiver, the kind you would plug your servos into in an RC car or airplane. Based on that RC signal it outputs controlled power to pair of motors up to 18V and 4A. The control is proportional (variable speed), and goes in both directions without bias in either direction, making it well suited to tank drive vehicles. The logic is based on a PIC18F1320. The best part of this project is not just that it allows you to make a relatively cheap RC dual motor controller, but that using this code and input scheme you can take any PIC microcontroller project and add radio control with as many channels as you like using only one pin to receive it all. Besides using those values to control other robot functions you can still use any of the ports on your receiver, including the ones that are going to the control board, to control servos.

Because it's not that much fun controlling two motors without a robot for them to drive I have built the system into a Lego robot . This motor controller could be used for any skid steer robot, or you could simplify it to one motor, use the other port for a servo and make a vehicle that steers like a car.  If the Lego part of the project is of interest to you the connectors are explained in step 4 and the lego body is layed out in step 5.

This project requires basic electronic tools and a programmer that can work with 18F series chips.

The hardware:
The electronic hardware is fairly simple. The PIC 18F1320 handles all the signal interpretation, requiring only 2 filtering diodes. The same chip generates motor control signals for both motors. The other big chip on the board is a L298n motor driver. This chip contains two H-Bridges capable of driving a motor with up to 4A of current at up to 18V. Besides the chips the one other large component is a 5V regulator to give the PIC a good power supply. Besides those you have a handful of inexpensive diodes and resistors. A specific parts list is in step 1.

The software:
The software for the chip has a portion that interprets PWM* servo control signals into a variable, and another portion that generates two motor control PWM* signals. These parts could each potentially be used to make either a system that does something else based on radio control commands, or a motor controller that is driven by other means. The code could easily be expanded to read many (I'm talking 8 or more) PWM signals. You could take one of those huge $500 airplane remote control systems and have a chip read every channel! What you did with all that control data would be up to you.

A note on PWM:
These are both pulse width modulated (PWM) signals, which simply means the width of the pulses is used to represent values, but the motor control signal pulses on and off to vary the average power, or duty cycle, to accomplish various motor speeds, while the servo signal works by sending different widths of pulse which are read as relative command values.

Step 1: Parts List

RC transmitter/receiver set with at least 3 channels. As is this code only works with stacked PWM signals. I can only say for sure that it will work with traxxas receivers. With modification it could work with any PWM timing, and I am working on making it work with synchronous PWM like the newer Futaba systems use, that is the pulses all begin at the same moment. It will not work with VEX rc systems, which use a different kind of signal.

since this is going to be in a SparkFun sponsored contest, links to the parts on that website are provided, conveniently these pages also have the datasheets

2 9V rechargeable batteries, or any other array of of batteries that gives you 9 to 24 volts.
2x 9V battery connectors
A few feet of 22AWG or similar hook up wire (solid recommended if you don't know which you prefer)

Electronic components:
1x perf board with 0.1" spacing, about 2x3 inches in size
1x L298 Dual bridge driver
1x PIC18F1320
2x 0.1uF ceramic capacitors for regulator. (the code of 0.1uF is "104")
1x 18 pin IC socket (recommended but not strictly needed)
1x 5V regulator
2x small 3mm LEDs for indicators.  (use a green and a red instead of two reds like i did.)
Resistors (2x 1 ohm, 2x 220 ohm, 1x 12k ohm, 1x 3.6k ohm)
10x 1N4148 or similar diodes
1x servo wire with two female ends, you can cut it in half and make both yo

Software needed (all free):
MPLAB and C18 software (free version works fine, only needed if you want to modify the code)
The plan for the board was made in the free version of EAGLE PCB.

PIC programmer such as a PICkit 3, PICkit 2, or one of it's clones like the Junebug.
Soldering Iron with fine tip
Diagonal Cutters, or any kind of wire snipper you favor
Wire strippers
Soldering heat sink (recommended, not required)

Step 2: Software

This step will go through each part of the software and explain what it does. If you have no interest in modifying the software and just want to build the thing, you may go on to the next step. The hex file provided will make the project work as designed.

//Basic configureation of chip periferials
#pragma config OSC = INTIO2, WDT = OFF, LVP = OFF
#include <p18f1320.h>

This sets the oscillator to internal and loads the settings for the 18F1320, if you want to use a different pic this is one of the main things you will have to change


//setup pins for PWM input
#define ReceiverPin PORTBbits.RB3
#define ReceiverTris TRISBbits.TRISB3

This is just giving a name to the pin for receiving the signal so it is clearer to refer to.

//PWM capture variables
unsigned int PWM1RiseTime = 0; //timer value at rising edge capture
unsigned int PWM1FallTime = 0; //timer value at falling edge capture
unsigned int PWM1Width = 0; //calculated width

unsigned int CH1_width = 0;
unsigned int CH2_width = 0;
unsigned int CH3_width = 0;
unsigned int PWMGap = 0; //calculated gap between pulses

char PWM1Edge = 1; //edge currently being monitored 1 = rising, 0 = falling

//button variables
unsigned char button_1_debounce_wait = 0;

Since the PWM signal from the receiver communicates by sending pulses of varying width variables are declared to hold these widths once they are calculated.

unsigned char calibration_mode = 0;
#define mode_operate 0
#define mode_CH1_high 1
#define mode_CH1_med 2
#define mode_CH1_low 3
#define mode_CH2_high 4
#define mode_CH2_med 5
#define mode_CH2_low 6

unsigned int limit_CH1_high = 2381;
unsigned int limit_CH1_med = 3307;
unsigned int limit_CH1_low = 4286;

unsigned int limit_CH2_high = 2022;
unsigned int limit_CH2_med = 2946;
unsigned int limit_CH2_low = 3983;
unsigned int CH_temp = 0;

When calibration mode is on the system will be resetting these "limits" to suit the signal. These are the defaults, how the calibration works will be explained later.

//motor control variables
#define Motor_PWM_Rez 16 //number if different speeds possible forward and reverse
#define center_buffer 20 //this is the fraction of the range before movement starts

These are constants you can adjust if you are using different parts. The center buffer is really the dead zone in the center where the controller wont make the motor do anything. The rezolution is how many different speeds the system will divide it's range of control into.

unsigned char Motor_Phase = 0;//as it cycles this will time the motors

unsigned int CH1_range = 2000;
unsigned char Motor_A_Speed = 0; //this is the speed of motor A, at %100 it will equal the rezolution
unsigned char CH1_forward_increment = 10;//the width of range for each speed output
unsigned char CH1_reverse_increment = 10;

unsigned int CH2_range = 2000;
unsigned char Motor_B_Speed = 0; //this is the speed of motor A, at %100 it will equal the rezolution
unsigned char CH2_forward_increment = 10;//the width of range for each speed output
unsigned char CH2_reverse_increment = 10;

typedef struct
unsigned motor_A_Direction: 1;
unsigned motor_B_Direction: 1;
unsigned button_1_last_state: 1;

unsigned char motor_A_inverted = 1;//this related to calibration
unsigned char motor_B_inverted = 1;
unsigned char motor_calibration_needed = 1;

volatile BITS Bits;

//timing variables
unsigned char slow_count = 0; //this is used to create the scaled timer for slower events

The variable above will just be a counter so that a subsection of the timer interrupt can go off only every one out of many timer ticks.

//set up interrupt
void low_ISR(void);//prototype
#pragma code low_vector = 0x08 //0X08 IS LOW 0X18 IS HIGH
void low_interrupt (void){
_asm goto low_ISR _endasm
#pragma code
#pragma interrupt low_ISR

This part isn't the interrupt in itself but it set's up for the interrupt to occur. The interrupt is just an event that allows something to be triggered so that the program doesn't have to be one big loop.

void main(void)
OSCCON = 0x72; //8MHz clock
while(!OSCCONbits.IOFS); //Wait for OSC to become stable

//configure timer1
PIR1bits.TMR1IF = 0; //clears the timer 1 interupt flag
T1CONbits.TMR1ON = 1; //turn on timer
T1CONbits.T1CKPS1 = 0; //set prescaler
T1CONbits.T1CKPS0 = 0; //set prescaler

//setup timer2
PIR1bits.TMR2IF = 0; //clears the timer 2 interupt flag
PIE1bits.TMR2IE = 1; //enable the interrupt
PR2 = 199;
T2CON = 0b00000100; //(-)always 0 (----) postscale (-)on/off (--) prescale

//configure CCP1
CCP1CON = 0b0000101; //configure CCP1 for capture, rising edge
INTCONbits.PEIE=1; //enable peripheral interrupts
PIE1bits.CCP1IE=1; //enabled CCP1 interrupt
INTCONbits.GIE=1; //enable branching to interrupt
ReceiverTris = 1; //set RB3 for input so the capture can work.
TRISBbits.TRISB2 = 1; //set rb2 for in so it can be used to differentiate channels

The capture module does all the heavy work here. Above it is initialized to wait for the signal to rise, later this will be changed dynamically to capture pulse width.

//configure ports
ADCON1 = 0xff; //all digital
INTCON2bits.RBPU = 0; //port b weak pullups on


//these will be motor outputs
TRISAbits.TRISA0 = 0;
#define Motor_Pin_A1 LATAbits.LATA0
TRISAbits.TRISA1 = 0;
#define Motor_Pin_A2 LATAbits.LATA1
TRISAbits.TRISA2 = 0;
#define Motor_Pin_B1 LATAbits.LATA2
TRISAbits.TRISA3 = 0;
#define Motor_Pin_B2 LATAbits.LATA3

These commands set the pins needed to control the motors to act as outputs. Then the motor pins are named for easy access.

//these will be indicator outputs
TRISAbits.TRISA6 = 0;
TRISAbits.TRISA7 = 0;

//this will be the servo signal input
TRISBbits.TRISB0 = 1;

//initially calibrate the RC ranges
motor_calibration_needed = 1;




This while loops keeps the program from ending. Don't be fooled by the fact that it is empty. Interrupts will trigger events and the timer is still running.

Below is the start of the timer interrupt. It goes off periodically at the highest speed that any function requires, for fast operations such as deciding if it's time to turn the motor on or off, then is subdivided with counters to operate the functions that do not require such high speed, such as monitoring the input and deciding if the speed needs to change.

void low_ISR(void)

//Timer 2 flag (currently set to interrupt at 10Khz)
if(PIR1bits.TMR2IF == 1)
PIR1bits.TMR2IF = 0; //clears the timer 1 interupt flag


So as to not waste time doing things faster than necessary (a good way to look at many kinds of work) the part below uses the variable "slow_count" to only execute every 100 times the outer loop executes.

//withen this function executes at 100Hz***
slow_count ++;
if(slow_count > 100)
slow_count = 1;//reset count for next time

//Handle Calibration Button
if(button_1_debounce_wait > 0){button_1_debounce_wait --;}
if(PORTBbits.RB0 == 0){
if(Bits.button_1_last_state == 0 && button_1_debounce_wait == 0)//button just pressed
button_1_debounce_wait = 10;//set debounce count
if(calibration_mode > 6){calibration_mode = 0;}
Bits.button_1_last_state = 1;
Bits.button_1_last_state = 0;
//end of calibration button

Below the calibration is actually applied. This is done in normal operation mode so the lights are turned both off. The program checks if the calibration range is backwards, high is lower than low and vice versa, and if so sets a flag so that the directions of the motors will act accordingly.

//Handle Led Mode Indicators
if(calibration_mode == mode_operate)
LATAbits.LATA6 = 0;
LATAbits.LATA7 = 0;

if(motor_calibration_needed == 1)
motor_calibration_needed = 0; //clear flag

//recalculate calibration variables for CH1
if(limit_CH1_low < limit_CH1_high)//speed increases as number increases
motor_A_inverted = 0;
else//speed decreases as number increases
//swap them so high is the greater value
CH_temp = limit_CH1_low;
limit_CH1_low = limit_CH1_high;
limit_CH1_high = CH_temp;

motor_A_inverted = 1;

CH1_range = limit_CH1_high-limit_CH1_low;
CH1_forward_increment = (limit_CH1_high-limit_CH1_med -((limit_CH1_high-limit_CH1_med)/center_buffer))/Motor_PWM_Rez;
CH1_reverse_increment = (limit_CH1_med-limit_CH1_low -((limit_CH1_med-limit_CH1_low)/center_buffer))/Motor_PWM_Rez;

//recalculate calibration variables for CH2
if(limit_CH2_low < limit_CH2_high)//speed increases as number increases
motor_B_inverted = 0;
else//speed decreases as number increases
//swap them so high is the greater value
CH_temp = limit_CH2_low;
limit_CH2_low = limit_CH2_high;
limit_CH2_high = CH_temp;

motor_B_inverted = 1;

CH2_range = limit_CH2_high-limit_CH2_low;
CH2_forward_increment = (limit_CH2_high-limit_CH2_med -((limit_CH2_high-limit_CH2_med)/center_buffer))/Motor_PWM_Rez;
CH2_reverse_increment = (limit_CH2_med-limit_CH2_low -((limit_CH2_med-limit_CH2_low)/center_buffer))/Motor_PWM_Rez;

//end of led mode indicators

Below calibration is handled. Each time the button is pressed the calibration mode changes, indicating that a new limit is being set. The pattern is CH1 full forward, middle resting, full backward, then the same three positions again on channel two. The light indicators show off for not in calibration mode, one on for forward, the other for reverse and both for middle resting point. It's not a robust interface but it gets the job done.

if(calibration_mode == mode_CH1_high)

All this LATA stuff is just the lights being turned on to indicate the mode to the user. As you can see it doesnt actually set the limits when you hit the button. It just sets them at whatever spot they are while in that mode, so when you push the button again and that mode ends, that stays the calibration point.

LATAbits.LATA6 = 0;
LATAbits.LATA7 = 1;

limit_CH1_high = CH1_width;

if(calibration_mode == mode_CH1_med)
LATAbits.LATA6 = 1;
LATAbits.LATA7 = 1;

limit_CH1_med = CH1_width;
if(calibration_mode == mode_CH1_low)
LATAbits.LATA6 = 1;
LATAbits.LATA7 = 0;

limit_CH1_low = CH1_width;
if(calibration_mode == mode_CH2_high)
LATAbits.LATA6 = 0;
LATAbits.LATA7 = 1;

limit_CH2_high = CH2_width;
if(calibration_mode == mode_CH2_med)
LATAbits.LATA6 = 1;
LATAbits.LATA7 = 1;

limit_CH2_med = CH2_width;
if(calibration_mode == mode_CH2_low)
LATAbits.LATA6 = 1;
LATAbits.LATA7 = 0;

limit_CH2_low = CH2_width;

motor_calibration_needed = 1;

Now the motor speeds need to be calculated. The  equation gets the width of the pulse for that motor, decides if it is over the midpoint or not to decide direction, then finds it's range using the motor control resolution within the total range of possible widths.

//calculate motor speed A
Motor_A_Speed = 0;
if(CH1_width > limit_CH1_med+((limit_CH1_high-limit_CH1_med)/center_buffer))//upper range
Motor_A_Speed = (CH1_width-limit_CH1_med -((limit_CH1_high-limit_CH1_med)/center_buffer))/CH1_forward_increment;
Bits.motor_A_Direction = motor_A_inverted;
if(CH1_width < limit_CH1_med-((limit_CH1_med-limit_CH1_low)/center_buffer))//lower range
Motor_A_Speed = (limit_CH1_med-CH1_width -((limit_CH1_med-limit_CH1_low)/center_buffer))/CH1_reverse_increment;
Bits.motor_A_Direction = !motor_A_inverted;

//calculate motor speed B
Motor_B_Speed = 0;
if(CH2_width > limit_CH2_med+((limit_CH2_high-limit_CH2_med)/center_buffer))//upper range
Motor_B_Speed = (CH2_width-limit_CH2_med -((limit_CH2_high-limit_CH2_med)/center_buffer))/CH2_forward_increment;
Bits.motor_B_Direction = motor_B_inverted;
if(CH2_width < limit_CH2_med-((limit_CH2_med-limit_CH2_low)/center_buffer))//lower range
Motor_B_Speed = (limit_CH2_med-CH2_width -((limit_CH2_med-limit_CH2_low)/center_buffer))/CH2_reverse_increment;
Bits.motor_B_Direction = !motor_B_inverted;
//end of calculating motor speed

}//end of 100hz section

Here the if statement and counter that cause the above to only execute at 100Hz have ended and we are at the full timer interrupt frequency. The part below handles generating the motor control signal from the speed calculated above

//contol pulses to motor
if(Motor_Phase > Motor_PWM_Rez){Motor_Phase = 1;}

//Motor A
if(Motor_A_Speed >= Motor_Phase && Motor_A_Speed < 20){
if(Bits.motor_A_Direction == 0){
Motor_Pin_A1 = 1;
Motor_Pin_A2 = 0;
if(Bits.motor_A_Direction == 1){
Motor_Pin_A1 = 0;
Motor_Pin_A2 = 1;
Motor_Pin_A1 = 0;
Motor_Pin_A2 = 0;

//Motor B
if(Motor_B_Speed >= Motor_Phase && Motor_B_Speed < 20){
if(Bits.motor_B_Direction == 0){
Motor_Pin_B1 = 1;
Motor_Pin_B2 = 0;
if(Bits.motor_B_Direction == 1){
Motor_Pin_B1 = 0;
Motor_Pin_B2 = 1;
Motor_Pin_B1 = 0;
Motor_Pin_B2 = 0;

}//end of timer interrupt


Below is the beginning of the CCP interrupt. This is the part that handles measuring the pulse width. Earlier it was set to be triggered by a rising edge. When it detects the rising edge it will record the time using CCPR1 then it will switch to watch for falling and change the PWM1Edge variable to match. When it detects falling it switches back and records the time.

//ccp interrupt
if(PIR1bits.CCP1IF == 1)
PIR1bits.CCP1IF = 0; //clear the flag
if(PWM1Edge == 1)//if detecting rising
CCP1CON = 0b0000100;//switch to detect falling edge
PWM1Edge = 0;//switch to indicate falling edge is next
PWMGap = CCPR1 - PWM1FallTime; //calculate gap between pulse starts
PWM1RiseTime = CCPR1;//save the low timer value for the rise time

if(PWMGap < 10000){CH2_width = PWMGap;}

else //if detecting falling
CCP1CON = 0b0000101;//switch to detect rising edge
PWM1Edge = 1;//switch to indicate rising edge is next
PWM1Width = CCPR1 - PWM1RiseTime; //(pwm rise time is the time that the pwm rise occured)
PWM1FallTime = CCPR1;//save the low timer value for the fall time

You will really need to understand the logic behind this part if you need to modify the code to work on other receivers. The traxxas receiver I used puts all of the pulses back to back. This made it so that I couldn't read through just one pin because the whole set of pulses was one long pulse when combined. So I designed the program so the chip is only hooked up to every other output, in this case servo outputs 1 and 3. That way there is a gap. The short gap (the one less than 10000 as detected by the if statement below) is the intermediate one and is the length of the middle pulse, pulse number 2. The first pulse after the long gap is pulse number 1 and the one after the short gap is pulse number 3.

if(PWMGap > 10000){CH1_width = PWM1Width;}
if(PWMGap < 10000){CH3_width = PWM1Width;}



Please feel free to ask questions. The will help me make things clearer so I really do appreciate them.

As I mentioned in that last note this plan revolves around the pulses occurring back to back. Some receivers space them out. If that were the case you wouldn't need to do this trick at all. Instead you would just know that after the long gap was pulse one, then after each additional short gap you were looking at pulse 2, 3, 4 and so on. You would just make a variable to keep track of how many pulses you had caught since the last gap and reset it when you had the long one, then use it to decide which channel you attributed a captured pulse width to.

Step 3: The Circuit Board

I just built mine point to point on a perf board because I didn't feel it was complicated enough to require a etched circuit board. For those who do want to make a PCB the Eagle PCB files are provided, and honestly since I've never made them into a printed PCB they could probably use some improvement. By the way if anyone does make the Eagle schematic into an  etched PCB I'd love to see it and have the files so i can include them here.

Attached are some schematics of components of this circuit to help explain how it works. There are only 3 main elements. The regulator, the L298n dual H-bridge motor driver and of course the PIC 18F1320. Additionally there is one push button, 2 leds, and a handful of resistors and protection diodes.

This schematic explains how the L298n is meant to be used. I'd post it here but I'm not sure I have permission.

Below is a simple diagram of the button wiring. The resistor to +5v is a pull up resistor. It is high resistance and without it when the button wasn't pushed the pin would be connected to nothing, so there would be no guarantee it would be low or high, this resistor just "pulls it up" when the button connecting to 0v is not pushed.

Next to that is a diagram of the regulator. pulled from it's data sheet. It keeps the voltage at 5v for the microchips.

The full Eagle PCB schematic and board layout are available for download. A preview of the schematic is posted below as well, you will have to click on thein the upper left corner and view the original image to actually read it here.

Note that the servo leads from the board should plug into channels 1 and 3 from the receiver.

Step 4: Making Connectors for the Lego Motors

If you want to wire this to Lego motors, but like me you don't want to modify your lego motors or permanently fix Lego wires onto the controller here is how you can make some modified Lego power connectors.

If you are simply sacrificing a good Lego wire then just cut it, split it and strip the ends, then solder on any connector you like.

I had some old Lego wires that were coming apart.  If you are using a ruined Lego wire you will find that If you gently pry the edge opposite the wire back and up with a small screwdriver it will pop out. Inside you'll find that the Lego wires are soldered onto two copper plates that make contacts on the top and bottom.

Hold the part in a clamp or helping hands (the metal kind, not your friend's) and gently pull the wire while applying heat to the solder until it pulls free. Use some good flexible wire to make your replacement. Solder the ends down on the same spot where the old wires were attached since there is a space for the connection on the cover plate here. If you're worried it's too big for the cover plate to fit back on simply press the cover plate back on immediately after soldering and it will melt out a space for itself.

Step 5: Constructing the Lego Body

For anyone interested in the Lego frame design I hope this array of photos goes through the steps.

Step 6: Other Uses

This can be used as shown to drive a tank drive vehicle, totally different motors could be used. But it has many possible alternate uses.

Car-style steering
This circuit can be built as shown but omitting the other motor. Without modifying the code the second line to the RC receiver would still be needed. Then you could connect a servo for steering to the second channel and drive the vehicle with the one motor to make a very compact solid state RC car.

Arms and actuators
If you're good with pic chips you could use the RC signals from additiona channels for control. If not, you could always use channels 3 onward to control servos for anything from a simple grabber to a intricate arm.

Modifying the program
When modifying the program just remember that PWM1Width always holds the last length of high signal and PWMGap always holds the last gap. There is a huge gap between the last pulse and the first, by comparing these lengths to decide how they should be used then sorting them out the program can be extended to capture more channels or to capture pulses from recievers that put out  pulses periodically rather than back to back like the Traxxas receiver used here.

Have fun and don't burn yourself on the soldering iron!

<p>hello, very nice proyect, i am trying something simillar but i am having problems to adapt the program for the pic i am using now(the 18f2420) is suppose to be the same but i cannot compile like it sopuse to be, i got errors after line 80 i gess, how can i fix that??</p>
<p>just wonder if you use some high power/current motors do you need heat sink ?</p>
Now that I look at it, they have some examples of the math to use on pg 10 of the sheet from aavid: http://www.aavid.com/sites/default/files/literature/Aavid-Board-Level-Heatsinks-Catalog.pdf
<p>That depends on some specifics. In non-engineering terms, if it gets too hot to touch it needs a heat sink. In engineering terms, look at the heat dissipation numbers for the motor driver you are using. There is a derived property called thermal resistance. Quoting a sheet from intersil on the topic:</p><p>&quot;A common method of characterizing a packaged device's</p><p>thermal performance is with &quot;Thermal Resistance&quot;, denoted </p><p>by the Greek letter &quot;theta&quot; or &theta;. For a semiconductor device, </p><p>thermal resistance indicates the steady state temperature </p><p>rise of the die junction above a given reference for each watt </p><p>of power (heat) dissipated at the die surface. Its units are </p><p>deg C/W.&quot;</p><p>*<a href="http://www.intersil.com/content/dam/Intersil/documents/tb37/tb379.pdf" rel="nofollow">http://www.intersil.com/content/dam/Intersil/docum...</a></p><p>In fact this paper covers a lot of useful information about heat dissipation</p><p>For example see the bottom of page 2 of the sheet for the L298n:</p><p><a href="http://www.tech.dmu.ac.uk/~mgongora/Resources/L298N.pdf" rel="nofollow">http://www.tech.dmu.ac.uk/~mgongora/Resources/L298...</a></p><p>The value you care about is probably R-ambient. It says the die can handle 130C and the Ra is 35 C/W. So if your putting 3W of power through the chip and the motor, and your ambient air is 72C, you would hit (3W * 35 C/W + 72C) the chip will heat to about 177C, which is too hot. But we can get data on the heat sink as well:</p><p>For example look at page 39 of this sheet: <a href="http://www.aavid.com/sites/default/files/literature/Aavid-Board-Level-Heatsinks-Catalog.pdf" rel="nofollow">www.aavid.com/sites/default/files/literature/Aavid...</a></p><p>From that you can see if the heatsink will work, and if so, what airflow it would require. And furthermore, airflow of a fan at a given voltage would be on the sheet for the fan. Of course you don't have to be this rigorous, you can use the information available to estimate cooling easily 4 times or more higher than what you need to be safe.</p>
Very nice project Paul!...I was wondering if you freelance? I'm in the middle of a project and in need of some PIC programming assistance from someone here in Milwaukee...&quot;If your still in Milwaukee that is&quot;.
I do actually, given that it's in the scope of things I can do in a reasonable amount of time. Feel free to message me about the work you have in mind!
Is there any way in which I can use an Arduino rather than a PIC microcontroller?
Yes, in fact, I'll be posting an instructable on how to do just that soon.
Oh thank you Mr. Paul. Please do send me the link you have made the instructable. <br>
can i use other pic micro controller by just changing the include &lt;&gt;?
That would depend on how different the new PIC is. Porting code can take some work, but you would start by changing the include, then see what errors you get. Often there will be ones about the config bits not being recognized, for that you need to go to the data sheet for the new PIC and find the names that it uses. Most of the time that is enough. If the PIC is too different it may be lacking features that my code uses, and then those uses would need to be reworked.
i'll try with the 18f2550 (i hope still works) or a 18f4550 and i show you my results thanks
I use those particular ones pretty often, they have all the capabilities of a 18F1320, and they are pretty similar, including using the same instruction set. Once you change the include you should, at most, need to change the names of a few settings.
<a href="http://www.jbprojects.net" rel="nofollow">http://www.jbprojects.net</a>Awesome Theres one i'm making on link
srry but what i meant was which pins on the arduino will the pins go to?<br>
This code won't run on an arduino. If you mean what pin would you use for a similar program on arduino, that would depend on the code. Any input would work, in the example code I posted it's pin 8.
Instead of hooking this up to the pic microcontroller how d u hook this up to the arduino? could u please send me the which pins go to wich pins please.
That would require whole different code, and the pin would be set in the code. Here is a good example of capturing servo signals on an arduino:<br>http://diydrones.com/profiles/blogs/705844:BlogPost:39393<br><br>you can find many more examples of servo signal capture, and of motor control using the arduino with a google search. You could still use the motor driver circuit from this instructible.
hey..dude realy nice...i m mechanucal engineer..i want to make simple rc car..bt i dnt have any idea about receiver transmitter...can u help me pls..from wer should i start...<br>
hey bro THANK U VERY MUCH..i will try it..sorry to say..but i have another question..as i m beginner how to make simple forward reverse rc car...and i want to make it my self ..i can buy it from shop..but i will be more happy if i create somethin myself..so please tell me about normal forward reverse rc car,,,THANK U BROTHER
Hi, I'd be happy to help you out. This depends on how low level you want to start from. You could do anything from buying a complete RC car to designing your own transmitter. I opted for somewhere in the middle because I wanted to be able to control whatever device I liked, but the transmitter did not need to be specialized. To take this approach, you can buy a transmitter set. For example traxxas is the cheaper brand that is still decently reliable, a search on ebay for &quot;traxxas transmitter receiver&quot; gives you many results in the $40-$60 range for a 3 channel, just make sure it included the receiver or you'll have to buy a matching one of those too.<br><br>As for the controls, if you just want to build an RC car most people just buy a servo for the steering, which can be plugged right into that receiver, and a motor speed controller, which also plugs into the receiver, to drive the motor. You can also get kits that have the transmitter, receiver, motor control and steering servo.<br><br>If you want to go DIY on the controls and drive, which few people do, but that's what this instructable is about, my directions here explain that. This system still needs the off the shelf transmitter and receiver, but lets you make your own controls. In this example the two channels control two motors. The data, once received by the microchip could be used to run any process that you can find a way to control with a microchip. How to control things like steppers, dc motors, relays, brushless motors, linear actuators, solenoids, lights, pumps ect. are outside the scope of this project but if you find something you want to control, there is a way out there and it can be combined with this. If you just want to control servos it would be a bit goofy to use this because you would be interpreting a servo signal into program data, then using that data to produce a servo signal. For that there is also the option of using this plan to control a motor, and just plugging a servo directly into the receiver.<br><br>Since I may be going way off topic of what you wanted to know I'll stop now, but feel free to ask more questions, since I'm not sure specifically what you would like to do.
NICE! <br><br>One question; Can I replace the lego motors with 12v gearmotors? Does there need to be a bigger battery pack for that? There would obviously be more consumption...<br><br>(yes I know that was really two questions.) lol.
It should still work with 12 volt gear motors if their draw at 12 volts is less than 2A. There is a possibility with some motors that the frequency will need to be changed, but for most motors it's already in the right range. If you build it note the recent change, with some Futaba systems the code would need updating. It's only sure to work with traxxas.
You mean the remote? Because I have an almost ancient RC remote in my garage...
Then it just depends on the timing of the pulses, which I don't know for that particular remote. This system was designed for stacked pulses, ones that occur in series, with each successive pulse starting when the last one ends with a gap before they all start over. Some are synchronous, with all pulses starting at the same time or timed in series, with each pulse starting at a different even timing apart (ie, every 4ms a pulse starts, with a longer gap after the whole chain). Currently the code only works with stacked ones, like traxxas, but another user and I are working on a more universal mode for all PWM methods, and that will be added to this once it is working.<br><br>If you have access to an O scope or the datasheet for your receiver you can probably find out which method it uses.
Ok. after a lot of procrastinating and actually having to dig through a storage facility to find the remotes model number, here is a link to the manual;<br><br>http://manuals.hobbico.com/fut/6nfk-6npk-manual.pdf<br><br>I'm not sure if this is what you meant by datasheet and I'm not quite sure what to look for. (this is only my second radio related project and it is a bit of a leap.)
I don't think I have an Oscilloscope lying around my garage, but the datasheet may be available online. I'll dig the remote up tomorrow and take a gander around the web. If not, I'm sure there is some way to figure it out.
If you explain the code to me (I'm not familiar with PICs.) and give me the pins you use for this project, I can try my best to port it over for Arduino. I have been able to read PWM signals accurately with an Arduino.
This would be very easy to do with an arduino, I think they already have variable speed bi-directional motor control code for arduino out there, and servo signal reading code. The main thing you would need is the motor driver circuit (or shield as arduino users always seem to call add-ons). For that reason I was thinking of just making an instructible on how to build the motor driver unit, then people could use it however they like. Is there another aspect of this project you want to know more about, or is it mainly the driver circuit?
please send 2ND PIC OF THE CIRCUIT BOARD LARGER AND CLEARER at armindersnandra@gmail.com
I don't individually provide support. I'll answer questions here though.
Well, since you asked in all caps...<br>Do you mean the little circuit board? That's just the inside of the Traxxas receiver, I just bought that and if you wanted to make your own it would be a whole other rather large project. If you mean my motor control board, click the [ i ] at the top left of the photo, that will take you to a page about that photo, then under available sizes choose ORIGINAL.
&quot;you showed how to make the receiver but as the sender?
I didn't make a receiver or sender. This is using an off the shelf Traxxas remote and receiver set. What I made is a motor controller that takes the pulses from the receiver and controls motors. These are the signals usually connected to RC servos or to a store bought motor control module.
Hi, it is a very useful project.<br><br>I'm wondering if the same code might work also on pic 18f248 - with external oscilator 10Mhz in HS4 (4 times multiplied) mode ?<br>Thanks Andrej
It should work without much adaptation. The 18F248 has twice the memory of the 1320 and it has a CCP module. You would just change the configuration for whatever ports you are using, and to use an external oscillator.
Do You have the code for ATMEL microcontrolers like ATMEGA's ??
I dont , Atmels are also excellent microconrollers, but for now I have only PIC equipment and software. I'll see if a friend of mine whom uses AVR chips can convert it, it should be pretty similar.
Ok thanks I will try to convert it but I know it is not an easy task
It might not be too difficult. I wrote it in C and AVR chips have a version of C, so the initialization commands will change, and possibly the port addressing, but much of those kinds of details can be handled by find/replace. I'm not sure how different the interrupts are. The people at this forum helped me a lot learning microcontrollers, if you go to their Microcontrollers&gt;AVR section you can get a lot of help. http://www.electro-tech-online.com/
Really cool, I only had time to skim through the instructable but were those just regular motors or lego motors?
They are Lego motors, &quot;Lego technic mini-motors 9v&quot; specifically model 71427, manufactured from 97 to 2002. But this would work with any motor that the L298n motor driver can handle.
I was just curious because we have to make a robot for science olympiad and people are against the tracks. I like them. Lego motors arent the best but they seem to work good in your application. If you were to do it again would you use the tracks or wheels?
Since this is just for fun it doesn't matter much. I chose tracks because they do well to demonstrate skid steering. The choice depends on what you are trying to do. Wheels are better for high speed and high efficiency and with good suspension they can handle a pretty uneven surface. But treads are good for more precise movement, more traction and better maneuvering on loose surfaces like loose dirt, sand or mud. So it depends on what the challenge is.
It is normally on a thin carpet. I think that tracks would be better than the wheels just so nothing is skidding possibly causing it to flip over.
Yeah, for carpet tracks are good. They kind of behave like a loose surface.
Hey thats pretty awesome!<br>

About This Instructable




Bio: I am a robotic engineer, and I like to make things and teach others.
More by PaulMakesThings:Add Radio to a Syma S107 IR Helicopter (or any other IR device) A 3D Print Ready Jack O' Lantern in Solidworks 3D Printed Hanging Internal Gear Clock 
Add instructable to: