Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

RC Car Control Programming

0.00/5 (No votes)
11 Jan 2012 1  
High level design of RC car with programming the microcontroller and user interface on a PC
snapshot.JPG

Introduction

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.

carPic.JPG

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

Architecture.JPG

Background

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:

Deduction

On pulse

Off time

1

0

There is an obstacle

1

1

The sensor is saturated by ambient light

0

0

There is no obstacle

0

1

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++)
{ 
    cboPort.Items.Add(availablePorts[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)
                    ser.Open();
                // write the byte
                ser.Write(command, 0, 1);    // this sends only a byte to the port
                // then close it
                ser.Close();
            }
        } 

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.

flowChart.JPG

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)
        {
            wait(500);
            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++   ) 
        { 
            delay_50ms(); 
        }       
   } 

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

        while(1) 
        { 
             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

                serial_init(); 
                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]) 
                { 
                    serial_init(); 
                    val = serial_read();   //Read the serial port
                    P1 = val;              //Command the motors 
                }                              

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

Summary

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

simulation.JPG

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!

History

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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here