Click here to Skip to main content
15,798,508 members
Articles / Programming Languages / C#

RC Car Control Programming

Rate me:
Please Sign up or sign in to vote.
4.96/5 (52 votes)
11 Jan 2012CPOL6 min read 239.2K   15.9K   94   34
High level design of RC car with programming the microcontroller and user interface on a PC


This car is a toy that carries a camera and, being controlled by software from a PC, is driven to the place of user’s interest. Its locomotion is controlled by two DC motors (one on each side) with their speed reduced by gear boxes. I will not discuss the detail of the mechanical and the electronic part of the car and of course the video display part of the software on a PC here. So, inputs and output modules of the car are just represented as blocks. Here is the sketch I have drawn using the Google SketchUp.


In the following figure, the whole project is decomposed into modules.



As I tried to show in the diagram above, there are two main parts of the project: PC and the car. Between the two is an RF link for transmitting commands and a separate wireless video link, which isn’t shown here, for video transmission. I made the RF link a one way communication because the RF components I found support this mode of operation.

At the top-left corner of the diagram, you can see an IR LED and an IR sensor. These are circuits used for avoiding collision with obstacles. Electrical pulses are regularly sent to fire the IR LEDs ON and OFF and two readings are taken during a single period of a pulse, so that the controller “knows” the real reading from the IR sensor. This is done with a simple logic described in the table below.

Output recorded during:


On pulse

Off time



There is an obstacle



The sensor is saturated by ambient light



There is no obstacle



This reading is not logical (Sensor error)

You may refer here about building a simple IR sensor circuit.

The next thing is an RF receiver. Commands are constantly transmitted from the RF transmitter connected to the serial port of a PC as a form of series of bits and received by the RF receiver located on the car. I have created a simple C# application for command bits generation and for video display and replay functionalities. The SerialPort class is responsible for sending these series of bytes depending on user’s inputs. The RF transmitter accepts these data from the serial port and transmits them through its antenna with a proper modulation. I used ICs from Linx for creating an RF link between my car and PC. The transmitter and receiver data sheets with their application can be found here and here.

To control DC motors on my RC car, I used two H-bridges as shown before. These two H-bridges are driven by outputs of micro-controller through one of parallel port pins. A very good introduction and application about H-bridges can be found here.

Using the Code

PC Program

The PC program has two main parts: a video display and replay, and a car control module.

The video display and replay module uses DirectShow libraries to access video data from wireless video receiver but since this software part is not my concern, I am not discussing it right now. As a reference, you may check a really nice article by Andrew Krillov on codeProject (here).

The car control module is implemented using a SerialPort object, seven buttons for direction control and a combo box for listing available serial ports. Just remember to include the following namespace:

using System.IO.Ports;

On form load event handler, I fetch all available ports in a combo box:

// create an array for getting available port on my PC
string[] availablePorts;
// fetch them all 
availablePorts = SerialPort.GetPortNames();
// copy them to a comboBox
for (int i = 0; i < availablePorts.Length; i++)

On each button click, a SendToSerialPort(string data) method is called with its respective string parameter as explained below:

private void SendToSerialPort(string data)
            // create an instance of serial port
            SerialPort ser = new SerialPort();
            byte[] command = new byte[2];
            command[0] = (byte)Convert.ToByte(data, 16);

            // set its properties  
            // i preferred the ff values
            ser.BaudRate = 9600;
            ser.DataBits = 8;
            ser.Parity = Parity.None;
            ser.StopBits = StopBits.One;
            ser.PortName = cboPort.Text;

            // if our command array is not empty then...
            if (command != null)
                // open it if it is closed
                if (!ser.IsOpen)
                // write the byte
                ser.Write(command, 0, 1);    // this sends only a byte to the port
                // then close it

The motor drivers (H-bridges) are connected to the micro controller's Port1 and are arranged as follows:

  • Port1 pin 0 and 1 – for right hand motor driver (H-bridge) and
  • Port1 pin 4 and 5 – for left hand motor driver (H-bridge)

The direction control is realized by controlling both DC motors' directions. For example, to turn right, we drive the left motor forward and stop the right motor. And the individual motor direction is controlled by switching the four transistors ON and OFF which is represented by the byte values in the braces.This lets us decide which series of bits is to be sent from our application to the serial port and then to the RC car. Accordingly, forward (“00100010”), backward (“00010001”), right (“00100000”), left (“00000010”), stop (“00000000”), spin clockwise (“00100001”) and spin counter clockwise (“00010010”).

Micro-Controller Program

Before going through the coding stuff, let us see the flow of the instructions of the whole program.


After initializing ports, the IR sensor is read as a reference for the debugging of IR sensor output and is saved as a variable. Then the IR LED is fired ON and ON state reading of IR sensor is saved as a second variable. Then come a series of comparison of these two readings and follows taking appropriate action.

If the OFF state reading is HIGH, there is either a problem of sensor’s saturation by high ambient light or a problem with the sensor itself which is to be determined by looking at the ON state reading (See table above). For each case, the corresponding debugging LEDs (High Ambient Light and Sensor Error LEDs) are set ON and the program jumps to the next step.

If the OFF state reading is LOW, we have no problem with the issues discussed before. So, if the second (ON state) reading is HIGH, there is definitely an obstacle in front and both motors shall be driven backward for a second. If the ON state reading is LOW, then there is nothing in front of the sensor so the program goes to accepting commands from RF receiver and sends them to DC motors.

This whole process is repeated indefinitely, so I put the code in a while(1) loop.

After each reading from and writing to ports procedure is finished, I wanted to wait for some time. So, I used a 50ms delay function delay_50ms(void) in the program which is implemented using timers in the microcontroller itself. Here the microcontroller frequency is assumed to be 12MHz with 12 oscillation cycles. The definite amount of time (integral multiples of 50ms) to be waited, is given as a parameter to a wait(int sec) function.

void delay_50ms(void)
    // Configure Timer 0 as a 16-bit timer
    TMOD &= 0xF0;      // Clear all T0 bits (T1 left unchanged)
    TMOD |= 0x01;      // Set required T0 bits (T1 left unchanged
    ET0 = 0;           // No interrupts
                       // Values for 50 ms delay
    TH0 = 0x3C;        // Timer 0 initial value (High Byte)
    TL0 = 0xB0;        // Timer 0 initial value (Low Byte)
    TF0 = 0;           // Clear overflow flag
    TR0 = 1;           // Start timer 0
    while (TF0 == 0);  // Loop until Timer 0 overflows (TF0 == 1)
    TR0 = 0;           // Stop Timer 0

The serial port (of the microcontroller) initializing function is given as follows (9600 baud rate, no parity and 1 stop bit are assumed):

// serial port initializing function
void serial_init(void)
     TMOD = 0x20;        // T1 in mode 2, 8-bit auto reload
     SCON = 0x50;        // 8-bit data,  none parity bit, 1 stop bit
     TH1  = 0xFD;        //12MHz freq. 12 osc. cycle and 9600 baud rate
     TL1  = 0xFD;
     TR1  = 1;            // Run the timer

Command reading task from a serial port is to be managed by the following method which returns value that is read as a char.

// serial port reading function
unsigned char serial_read(void)
        bit over = 0;
     while(!RI || !over)
         over = 1;
         RI = 0;
          return SBUF;
     }//wait some time till received flag is set and read the buffer

The whole other stuff is handled in the main function of the program and here are given the main( void ) function and the wait(int sec) function (responsible for delaying the program execution for some time set in the input parameter sec).

// some 'sec' milliseconds wait function
void wait (int sec)
     unsigned int i;
     for (  i = 0; i < (sec / 50); i++   )

//here goes the main function
void main( void )
     P0 = 0;                        // initialize P0
     P1 = 0;                        // initialize P1
     P2 = 0;                        // initialize P2

          unsigned char val = 0x00;
          unsigned char var1 = 0x00;
          unsigned char var2 = 0x00;
          var1 = P2;                  //read IR sensor
          wait(50);                   // delay
          P2 = num[1];                //turn IR LED ON
          wait(200);                  // delay
          var2 = P2;                  //read IR sensor again
          wait(50);                   // delay
          P2 = num[0];                //turn IR LED OFF

          if(var1 == num[2])
              if(var2 == num[1])
                 P0 = num[2];         //Set sensor error flag
             if(var2 == num[3])
                 P0 = num[1];         //Set high ambiet light flag

             val = serial_read();     //Read the serial port
             P1 = val;                //Command motors

         if(var1 == num[0])
             if(var2 == num[3])
                 P1 = num[4];           //drive motors backward
                 wait(1000);            //delay for a second
                 P1 = num[0];

             if(var2 == num[1])
                 val = serial_read();   //Read the serial port
                 P1 = val;              //Command the motors

             P0 = num[0];               //Set the flags to zero


I compiled the C code above and simulated on the Proteus Simulation program with the following diagram:


For simulation purpose, I used Virtual Serial Port Driver (It has 14 days evaluation period and free trial download can be found here to create a virtual port pair and connected my PC software to one of these COM pair's end port and COMPIM serial port of the Proteus Simulation to the other end. The two H-bridges at the bottom are made using NPN and PNP BJT transistors.

That is it. If you want details, just let me know!


  • Article submitted - Nov. 12, 2010
  • Just some grammar editing - Jan. 10, 2012


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Software Developer Self Employeed
Ethiopia Ethiopia
I am just someone from the Horn of Africa. (FYI... Africa is the only continent with a horn)

Comments and Discussions

GeneralMy vote of 5 Pin
johnap22-Mar-11 17:34
johnap22-Mar-11 17:34 
GeneralGreat! Pin
Marcelo Ricardo de Oliveira28-Feb-11 9:42
mvaMarcelo Ricardo de Oliveira28-Feb-11 9:42 
GeneralMy Vote of 5 Pin
RaviRanjanKr15-Dec-10 5:27
professionalRaviRanjanKr15-Dec-10 5:27 
GeneralMy vote of 5 Pin
Petr Pechovic15-Dec-10 2:19
professionalPetr Pechovic15-Dec-10 2:19 
GeneralVery nice presentation Pin
Gunnar Sigfusson28-Nov-10 12:54
Gunnar Sigfusson28-Nov-10 12:54 
GeneralRe: Very nice presentation Pin
solalem1-Dec-10 20:22
solalem1-Dec-10 20:22 
GeneralMy vote of 5 Pin
Luc Pattyn22-Nov-10 12:17
sitebuilderLuc Pattyn22-Nov-10 12:17 
GeneralLove it Pin
Derek Viljoen22-Nov-10 7:23
Derek Viljoen22-Nov-10 7:23 
5 out of 5.

Have you ever considered building a smart robot with a SBC on-board? It could be controlled over Wifi, and also run autonomously with your motion detection algorithms on-board. Who knows? Maybe you could win the DARPA challenge.
GeneralRe: Love it Pin
solalem1-Dec-10 20:27
solalem1-Dec-10 20:27 
GeneralMy vote of 5 Pin
fjdiewornncalwe22-Nov-10 5:39
professionalfjdiewornncalwe22-Nov-10 5:39 
GeneralMy vote of 5 Pin
linuxjr22-Nov-10 3:53
professionallinuxjr22-Nov-10 3:53 
GeneralFantastic Job Pin
Kelvin Armstrong17-Nov-10 7:14
Kelvin Armstrong17-Nov-10 7:14 
GeneralRe: Fantastic Job Pin
solalem22-Nov-10 2:26
solalem22-Nov-10 2:26 
GeneralMy vote of 5 Pin
MarceloFabiano12-Nov-10 8:20
MarceloFabiano12-Nov-10 8:20 
GeneralWell done Pin
Richard MacCutchan12-Nov-10 0:15
mveRichard MacCutchan12-Nov-10 0:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.