So you want to create a remote controlled device using an Arduino? To put an Arduino between your RC receiver and servos, you’re going to need to know how to read PWM signals. Getting your Arduino to read signals from an RC receiver is an easy task if you don’t mind doing it badly. If you want to do it elegantly, it’s slightly more challenging. First we’ll go over some PWM theory.

PWM Signals

RC receivers output pulse width modulated (PWM) signals on each channel. These pulses generally are between one and two milliseconds long. I say generally because there are probably some manufacturers who deviate from this rule of thumb. A pulse length of 1500 microseconds will drive a standard servo to half way. 1000 microseconds is full travel in one direction and 2000 seconds is full travel in the other direction. There are 20 milliseconds between each pulse.

A 1.5ms PWM signal like this would drive a standard RC servo to its centre point.


PWM signal pulses produced by a typical RC receiver
PWM Pulses. Pulses are shown 6ms apart, but this space depends entirely on the brand and manufacturer.

Reading PWM Signals – The Easy Way

Arduino comes with a beautifully simple function called pulseIn().

So to read from a PWM source you could do something like this

This would read PWM from a single channel connected to digital pin 34. More channels could be easily added in the same way. It’s simple, it works.

The downside is that each call to pulseIn() could take 20 milliseconds. This is because pulseIn() waits for the pin to go from digital LOW to HIGH and back to LOW again. If you’ve got 5 channels, for example, it could take up to 100 milliseconds just to read from the receiver. For most intents and purposes this is far too slow.


It’s possible to read PWM signals using hardware interrupts. A hardware interrupt is a signal that is generated by the hardware that literally interrupts the processor. With Arduino, hardware interrupts can be generated by a pin changing value, going LOW, going HIGH, rising or falling. The processor responds to interrupts by suspending its current activity and handling the interrupt with an interrupt handler function (also known as an ISR – interrupt service routine). After the interrupt handler has returned, the processor resumes its previous activity.

Unlike the easy way, reading PWM inputs with interrupts allows the processor to continue with other tasks except for that very brief moment when an interrupt is handled.

To read PWM inputs we must know when a pin goes HIGH and LOW, and so we are only really interested in CHANGE interrupts. When a PWM pin goes HIGH, a timer is started. When the pin goes LOW, we can measure the pulse time by checking how much time has passed.

Arduino has the function attachInterrupt(), which allows us to supply an interrupt handler for a particular event and pin number. The micros() function allows us to measure the time, in microseconds, between the pin going HIGH and returning to LOW.

The micros() function isn’t particularly precise on AVR based Arduinos. Gabriel Staples over at has written a library for precision timing. It’s available here.

Here is an example sketch. It simply prints out the PWM pulse time in microseconds over the serial port.


The End

10 thoughts on “Reading PWM Signals From An RC Receiver With Arduino”

  1. You should also explain how to do this on UNO or Mega, they dont have an interrupt capability on pin 34 for instance.

    I used pin 18, but the attacheInterrupt line had to be changed to:
    attachInterrupt(5, calcSignal, CHANGE); – Interrupt 5 is on pin 18 on mega.

    Nice work, it helped,.

  2. Hey, nice work.

    Would you know how to then convert the pulse time into a signal that varies as the pulse width does? I’m trying to control servos attached to my Mega 2560 through an RC and I obviously can’t write the pulse time to move the servos. What further processing need I do?

    Many thanks 🙂

    1. Hi Alan,

      You could generate PWM signals for servos by ‘banging’ GPIO pins

      digitalWrite(10, HIGH);
      digitalWrite(10, LOW);

      But, I think the Arduino servo library might be what you’re after.

      It’s my understanding that the servo library uses hardware timers to generate the pulse width modulated signals to drive servos. GPIO banging wastes a lot of time by delaying 1 – 2ms every time. The servo library doesn’t really waste any time at all.

      Cheers, Sam

  3. I created a library for an ATTiny 85 based on this technique: Thank you for getting me started!

    My little library It can take two inputs and transform them into two simple PWM outputs.
    There is also an auto-calibration system, so that different max/min values can be recorded as needed.

    If anyone want to use it, it can be found on GitHub here:

  4. Hi, I’ve been looking at your program for some time and i believe that there could be some improvements although i like the basic idea of it. First thing that may cause problems is if your runs up to 70 min’s as 70 is the limit and afterwards it would restart the timer value. And the other thing is that theres always fluctuations coming from the input which can be filtered out using a low pass filter to have a smother input value without to many fluctuation.

  5. I was about to buy a receiver for my quadcopter. Can any one please suggest me which 6ch rc receiver having PWM communication with arduino I have to buy?

  6. i rescive the pitch and roll values true between(1000 – 2000)
    but when in the throttle and yaw the value true in the range 1000 – 1500 but when i increase the sticks level the value become very big or negative

  7. Very nice work an clear explaination. Could you perhaps post an example where you use the Timer2_counter library of Is it just a matter of replacing micros() by get_T2_count()?

    thanks for you help!

Leave a Reply

Your email address will not be published. Required fields are marked *