Projects Research & Design Hub

Build an RF-Controlled Robotic Car

Using Two PIC32 MCUs

In this project article, learn how these Cornell students implemented an RF wireless vehicle, using two PIC32s that can be controlled using a steering-wheel-like interface equipped with an accelerometer to make the controls intuitive. The MCUs communicate between the wheel and the robot using 434MHz RF technology.

  • How to build an RF-controlled robotic card using 2 PIC32 MCUs

  • How to develop the steering controller circuitry

  • How to design the RF transmit and receive functionality

  • How to use the e Protothreads library

  • Microchip Technology PIC32MX250F128B MCU

  • 433.92MHz Remote Transmitter from Sparkfun

  • 433.92MHz Hi-Sensitivity Receiver from Sparkfun

  • 3-axis Kionix KMX62

  • Protothreads library

Today, remote motion-control applications have an ever-growing presence in areas such as robotics and video games, so we thought it would be a great idea to become acquainted with this type of technology ourselves. In this project, we designed and implemented a remote-control car with a motion-controlled steering wheel interface. We wanted a user interface that was immediately intuitive and familiar, which we accomplished with a rotating controller. Additionally, we wanted a system that could realize reliable real-time remote communication. We felt that an RF-controlled vehicle would be a viable way to see this through.

Our system featured two primary structural components (Figure 1): the steering wheel interface and the robot. Each housed a Microchip Technology PIC32MX250F128B microcontroller [1] (referred to from here on as PIC). The steering wheel PIC performed accelerometer readings and RF transmission, whereas the robot PIC received the RF messages and performed servo operation.

FIGURE 1 – Final project, showing steering controller (left) and robot car (right)

When the user rotates the controller board, the first layer that comes into play is the accelerometer system (3-axis Kionix KMX62) [2] deployed on the steering wheel (transmit side). The accelerometer registers user-controlled motion from the steering wheel and relays the information to one of our PIC units via I2C protocol.

The next stage of our project flow involves remote communication from the steering wheel to the car. First, using UART functions, this transmit-side PIC sends the movement information to a transmitter (433.92MHz Remote Transmitter from Sparkfun) [3] on the steering wheel. Information from the accelerometer was our pertinent payload; however, the PIC packaged this information with other necessary bits for control and termination.

Our transmitter was connected via an RF channel to a receiver (433.92MHz Hi-Sensitivity Receiver from Sparkfun) [4] on the car. An “ignition” button on the steering wheel was incorporated to toggle whether or not to send a stop or control signal. The final stage first consists of sending information from the receiver to the receive-side PIC (both on the car) using UART functions. Upon decoding the received packet’s contents, the PIC controls two hardwired servo motors to operate the wheels. Each distinct payload corresponds to a specific command for wheel movement. The two servos are continuous rotation servos from Parallax.


The steering controller (Figure 2) consisted of the accelerometer mounted on a KMX61 evaluation board that we attached to a piece of wood (our “steering wheel”). Figure 3 is the schematic of the steering controller. As the controller was tilted, we were able to detect the motion of the steering controller using the accelerometer, and to convert the motion into driving directions for the car. The KMX62 stores the accelerometer values recorded from all three axes in registers divided into high and low bytes. These are read by the PIC via I2C channel 1. These bytes are then converted to represent the direction in which the steering controller is tilted, which corresponds to a driving direction.

FIGURE 2 – The wiring and electronics of the steering controller. It consists of the accelerometer mounted on a KMX61 evaluation board that we attached to a piece of wood (our “steering wheel”).
FIGURE 3 – Schematic for the transmit-side hardware, including the PIC32, accelerometer, the RF 434 transmitter and the ignition button

As illustrated in Figure 4, tilting the controller in the –Z direction corresponds to the car driving forward, and tilting it in the +Z direction corresponds to the car driving backward. Similarly, rotating the controller toward the –X direction corresponds to turning right, and rotating it in the +X direction corresponds to turning left. All of these motions have two thresholds—normal and fast—to indicate two different speeds. When the accelerometer is not tilted in either the X or Z directions past these threshold values, the transmitter sends a stop signal to turn off the servos.

FIGURE 4 – The steering controller, showing the orientation of the accelerometer axes (with +Z coming out of the page). An image of a car steering wheel is overlaid to illustrate how the turning was interpreted from physical motion to software. White arrows on the left and right indicate how the controller can be tilted forward and backward to make the car move forward and backward. The ignition button (green square) is in the top left corner of the controller.

We included a button on the front side of the steering controller to serve as an ignition. It is connected to pin RA2 on the PIC using an internal pull-down resistor, and the PIC only reads the accelerometer values when the button is pressed. Thus, until the button is pressed, the transmission side sends a stop signal to the robot. When the button is pressed, the transmitter sends valid directions to the robot to cause it to move.

All the directional commands, including stop, are converted into a hexadecimal byte that is recognized by both the transmit and receive sides for the corresponding command. This byte is then packaged as part of the payload that is sent through the RF 434 transmitter to the robot.

Given the byte representing the direction for the robot to move, we packaged it into a series of 8 bytes, which were then transmitted. The extra bytes were necessary to calibrate the receiver gain. The purpose of each byte and the payload mappings for each car response are shown in Figure 5.

FIGURE 5 – Display showing each byte’s purpose in the package, along with payload mappings for each car response

If we had sent our payload without preamble, the gain factor on the receiver would have obscured our data, since there was a delay on how the receiver adjusted the gain. We sent 2 bytes of 0xaa (alternating 1 and 0 bits) as a signal, to allow the receiver to calibrate to the appropriate gain for the values we were using.

Next in the succession was our 0xff byte, which was used to synchronize UART. The next 2 bytes were our start signal: 0xfa, 0xfa. This value was distinctive enough that it would unlikely be emulated by noise and trigger a start upon a false positive. We used 2 bytes (as opposed to 1) to make this signal unique.

The next byte was our payload. Based on what we read from the accelerometer, we put a specific byte in the sequence that encoded a direction for the car. The seventh byte was the UART termination character on the receive side that we defined in the program. The eighth byte was the C string termination character, ending the string that we were transmitting.

After all of this processing, the data were sent to the transmitter. This was accomplished by the UART functions in the Protothreads libraries [5], one of which printed the 8-byte transmission sequence into a buffer. Another Protothreads function sent the information in this buffer to the transmitter via UART2.

The transmitter had four pins, ground (4), power (2), data input (3) and an antenna (1). We soldered a 22pF capacitor onto the antenna pin, and then a wire to create a 17cm long antenna overall. The antenna was made to be 17cm so that it worked as a quarter-wave antenna. We used the PIC’s 3.3V as power. However, we also placed a choke on the power from the MCU. This choke was just a piece of coiled wire that acted as an inductor at high frequencies (such as 433MHz). The choke blocked RF to the power supply. Ground was also connected to the PIC’s ground, the only addition here being that we placed a 10µF capacitor between power and ground on the breadboard. We also placed a 0.1µF capacitor between ground and power again, but this time directly on the board for the transmit module. Last, the data-in pin was connected to the UART2 TX pin. These additions to our transmitter circuitry, achieved a sufficiently strong transmission that the receiver could consistently interpret from a range of about 2.5m to 3m.

The schematic of the robot (receive) side is shown in Figure 6, and the car itself is shown in Figure 7. The receiver had three pins for ground (1, 6, 7) and two pins for VCC (4, 5), which we connected to the MCU ground and power. We again used a choke between power and ground, as with the transmit circuit, to block RF to the power supply. We also had a 10µF capacitor between ground and power. The receiver module also had a pin (8) that worked as the antenna, on which we connected a 22pF capacitor and soldered a 17cm wire. We also made sure to keep the orientation of the antennas the same on the transmit and receive ends, meaning that they were pointed in the same direction, for example, upward, so that the polarization of the signal would be the same. Last, the receiver had a digital-out pin (2), on which were sent the signals it was reading. We connected this pin to PIC pin RA1, which was programmed to be the UART2 RX pin. All of these factors in our receiver circuitry helped to improve signal strength and reliability.

FIGURE 6 – Schematic for the receive-side hardware on the car, including the PIC32, the RF 434 receiver and the servos
FIGURE 7 – Top view of the receive-side circuitry on the robot carBuild an RF-Controlled Robotic Car Using Two PIC32 MCUs

We used the Protothreads library here again to facilitate the UART communication to read values from the receiver into a buffer that could, in turn, by sent to the servos via PWM. We made a few modifications to function provided in Protothreads [5], one of which was adding a check for framing errors and exiting from the current loop. The reason for this was that the receiver amplified whatever signal it received, including noise, to what it considers a valid level. When the receiver was amplifying noise, a framing error almost always occurred, because the noise was unstructured. Thus, by checking for framing errors and timing out, we essentially were able to ignore the noise from our surroundings.

We also implemented a time-out system in case transmission stopped to prevent the robot from waiting indefinitely for transmission to resume. If there was a timeout, we cleared the information in the buffer, and therefore did not send a valid value for the wheels to turn. However, when we sent valid data, we read the contents of the buffer into our cmd variable, of which the second command byte contained our encoding for the direction that we wanted the wheels to follow. Now, we had multiple case blocks based on this command byte value that set the wheels according to the payload byte that was encoded on the transmit side (sixth byte in the transmission package). Upon reading the seventh byte (receive-side stop signal), the receiver was programmed to stop processing transmitted information.

We decoded the valid payload to determine in which direction the car should drive, based on the way that the steering controller was tilted. From this direction, we could output PWM signals to two servos serving as the wheels. This was done using two output-compare channels running on the same clock, with 20ms pauses between pulses. We then used this to control the servos by modulating the pulse width between 1.3ms and 1.7ms for the full range of speeds of continuous rotation. This allowed us to easily make the car move in different speeds and directions, and to stop. In addition, we had to fit the car with a 4.5V battery pack, because the 3.3V provided by the PIC32 was not sufficient to power the servos.


Our design worked well, especially considering the noise sensitivity of RF 434MHz wireless transmission. We were able to achieve a range of more than a meter, in which the car responded consistently. This consistent response was achieved by sending data quickly, so if a few transmission misses occurred, the response by the receiver was not delayed too much. However, sending the data faster caused the robot to jitter more often, possibly because the receiver does, in fact, receive data, but those data may have been corrupted.

Receiving a byte of data that does not match one of the directions simply causes the robot to stop, until it received the next direction to move. Thus, while calibrating the robot’s movement, we had to determine the best transmission rate accounting for this trade-off. In the end, we settled on a 150ms delay in between transmissions. We also reduced the baud rate of our data transmission from 4,800bps to 2,400bps, to make the data transmission slower but cleaner.

In addition, the robot never moved in the incorrect direction during our testing; either it moved in the proper direction as dictated in the steering controller, or it received an invalid input and stopped. Other than this, it is hard to quantify the performance of our robot, since the range highly depends on the environment and the angles at which the steering controller is pointed relative to the robot.

Since we used RF transmission, we had to guard against the possibility of RF interference with our design. Our design used UART to preclude any potential errors, and then each transmission contained two start characters of 0xfa. Both start characters had to be read to determine that any data received were valid, so the system was quite robust to other sources of RF interference. Even if we received incorrect or corrupted data somehow, the robot just stopped moving, keeping it safe from crashing and damaging anything.

Overall, we created a device that works well, given the transmission technology that we used. Although RF 434 transmission was difficult, it made us define our own protocol that is robust to noise and interference. We were also able to ensure that the car stops when going out of range, ensuring safety. Our design was meant to have a natural feel, with the movement of the steering controller mimicking that of a car’s steering wheel. Tilting the controller forward and backward made the car move accordingly. Usability was further improved by having two different speeds for each direction, by tilting the controller at different angles.


Our final results definitely realized our expectations for the project—an intuitive interface coupled with a responsive RC component. The reliability of our system surpassed our initial expectations, because we were unsure how consistent our transmission of signals would be. In addition, we added two different speeds for the robot, based on the angle of tilt of the steering controller. This was a convenient feature that we did not originally expect in our final results.

If we replicate this project or do something similar in the future (and use 434MHz RF again), we will be more cognizant of how to deal with signal strength from the beginning. While trying to improve signal strength, we constantly found ourselves confused during the debugging process for scoping the values we were transmitting and receiving with RF. If we implement RF again, we will research what hardware measures (chokes, capacitors) to incorporate to improve our signal strength. Additionally, we will be more careful in how we checked for the signal at different stages. In other words, we often checked to see if the signal was being transmitted across, without meticulously checking that the integrity of the signal was being maintained across every previous step in its path.

Our project could be improved by using a transmission technology that is easier to work with and has a higher range. We chose RF 434 mainly because using a simpler technology would have been less interesting in terms of a classroom project. If we had not used it, we would not have learned nearly as much. Realistically, we recognize that this choice was not necessarily a choice of feasibility but rather a choice to make our project more interesting and intellectually stimulating. In addition, the RF module we used was selected because it fit our budget. However, if we were to try and improve upon this, we would most likely opt for a higher performing module to improve signal strength. 

Authors’ Note: This project was created as part of ECE 4760, Digital Systems Design Using Microcontrollers, a course taught by Bruce Land at Cornell University.


[1] PIC32MX250F128B
[2] Kionix KMX62 User Manual
[3] 434 RF Link Transmitter
[4] 434 RF Link Receiver
[5] Bruce Land’s Protothreads

Inspiration from Hand Motion Controlled Robot Vehicle
Pose: An Arm Tracking System

Kionix |
Microchip Technology |
Parallax |
SparkFun Electronics |


Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.

Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article

Drew Mera is a Master’s Student studying Electrical and Computer Engineering at the University of California, San Diego. He received his Bachelor’s Degree in Electrical and Computer Engineering at Cornell University. He is interested in hardware design and its application to medical devices.

Rohit Krishnakumar is a Software Engineer working at Microsoft. He completed his Bachelor’s and Master’s Degree in Electrical and Computer Engineering at Cornell University. He is interested in software engineering and embedded systems.

Asad Marghoob is a Software Engineer for UnitedHealth Group. He obtained his B. Sc. and M. Eng. degrees in Electrical and Computer Engineering at Cornell University. He is interested in software engineering, IoT and data science.

Supporting Companies

Upcoming Events

Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2024 KCK Media Corp.

Build an RF-Controlled Robotic Car

by Drew Mera, Rohit Krishnakumar and Asad Marghoob time to read: 12 min