Reading Values from an RC Receiver using Arduino

Written by: Brandon Tsuge

|

|

Time to read min

In this post, I demonstrate how to use Arduino to read RC values using the "pulsein()" function and by using external interrupts.

Parts Needed

The Remote Control (RC) Transmitter and Receiver

In simple terms, the transmitter takes physical actions from the sticks, knobs, or switches and sends them to the receiver. The receiver then takes this signal and outputs at pulse width modulated (PWM) signal. This is ultimately the signal that can be used by the Arduino. 

Remote Control and Arduino

Most RC receivers output a signal at 50 Hz, which is the same frequency that servos require. This means that the period of the square wave is 1/50 seconds, or 20,000 microseconds. For the RC Receiver, the length of time that the square wave is in the HIGH position is generally between 1,000 and 2,000 microseconds.

RC PWM

Wiring the Circuit

On the receiver, there are 3 pins for each channel. In this example, I used channel 3, which is the stick that is not spring loaded. For every channel, there is a pin for output signal, input voltage, and ground. There should be a label that indicates what each pin is used for on the receiver.
 

If power is provided to one of the channels, then it's not needed for any of the other channels. Only the signal and ground pins need to be connected for the additional channels.

RC Receiver

To wire the circuit, connect 5V and ground from the Arduino to the receiver. Then connect pin 2 on the Arduino to the signal pin on the receiver. These connections can be done with male to female jumper wires, or with a servo connector and male to male jumper wires.

RC Receiver Arduino Wiring Diagram

Arduino Code using "pulseIn()"

The easiest way to read the PWM signal from the RC receiver is by using Arduino's pulseIn() command. Before the setup, start by defining a variable RCPin to 2 and an integer variable RCValue.

#define RCPin 2
int RCValue;

In the setup, set the baud rate to 9600 and the pin mode to an INPUT.

void setup() {
  Serial.begin(9600);
  pinMode(RCPin, INPUT);
}

In the loop, use the pulseIn() command to read the value from RCPin. Set the second argument to HIGH, to measure the length of time that signal is HIGH. Then save this to the RCValue variable and print it.

void loop() {
  RCValue = pulseIn(RCPin, HIGH);
  Serial.println(RCValue);
}

After opening the serial monitor or plotter, a visible response should be seen when the transmitter stick is moved.

Simple RC Read with Arduino and Plot

While this is the easiest way to read an RC value from a receiver, it has a flaw. One of the main issues is that Arduino cannot complete any other tasks while the pulseIn() command is measuring pulses. For example, in this demonstration, the Arduino sketch is measuring the length of time while the PWM signal is, HIGH position. Let's say that at a given point in time, the output of pulseIn() is 1,500 microseconds. Then for those 1,500 microseconds, no other instructions can be carried out. This can be an issue for applications that require the instructions to be carried out at higher frequencies, like controlling a stepper motor.

Arduino Code using External Interrupts

The way around the delay that pulseIn() causes is by using Arduino's external interrupts. This ultimately works by interrupting the main program if a particular external signal is detected.


For this approach, I start again by defining RCPin to 2. Then I need to define volatile long variables, StartTime, CurrentTime, and, Pulses. Then create an integer called PulseWidth.

#define RCPin 2
volatile long StartTime = 0;
volatile long CurrentTime = 0;
volatile long Pulses = 0;
int PulseWidth = 0;

In the setup, I set the baud rate to 9600 and the RCPin variable to an input with the pullup resistor enabled. Then I use the attachInterrupt() command, which ultimately interrupts the program, and then calls a specified function every time a certain type of external signal is detected. This command takes three arguments. The first argument is for the pin is that is detecting the signal that will trigger the interrupt. For the Arduino Uno, only pins 2 and 3 can be used for interrupts, as indicated in Arduino documentation. In this example, I use digitalPinToInterrupt(RCPin) to set the interrupt pin. The second argument is the name of the function that is called when the interrupt is initiated. In this case, I created a function called PulseTimer. The last argument defines if the program should be interrupted when a RISING, FALLING, or CHANGE in the signal is detected. I used CHANGE for this example.

void setup() {
  Serial.begin(9600);
  pinMode(RCPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(RCPin),PulseTimer,CHANGE);
}

For my PulseTimer function, I place the code after the code for the loop. My PulseTimer function is simply measuring the time between the interrupts. I start by setting the variable CurrentTime with the micros() command. This micros() command is the length of time that has passed since the program started running in microseconds. Then, I check if CurrentTime is greater than the variable StartTime. If this is true, then I subtract these two variables and save it to the Pulses variable. Then, I reset the StartTime variable by setting it equal to CurrentTime. Finally, in the loop, I print the Pulses variable.

void loop() {  
  Serial.println(Pulses);
}

void PulseTimer(){
  CurrentTime = micros();
  if (CurrentTime > StartTime){
    Pulses = CurrentTime - StartTime;
    StartTime = CurrentTime;
  }
}

The problem with this code is that when I print/plot the values, I am seeing two consistently different values. This is because I am measuring the length of time that the PWM signal is both high and low.

Arduino Serial Plotter

To solve this issue, I simply added an if statement that only saves the Pulses to the PulseWidth variable if the Pulses is less than 2000, since I know this is the maximum length of time that the PWM signal is in the HIGH state.

void loop() {
  if (Pulses < 2000){
    PulseWidth = Pulses;
  }  
  Serial.println(PulseWidth);
}

Now, when the signal is printed/plotted, I can see a much more consistent signal that isn't delayed by the pulseIn() command. The Arduino sketch for this example can be found here.

RC Consistent Signal

The Bored Robot LLC is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com