Introduction: RC Transmitter to USB Gamepad Using Arduino

Why should I do this?

When it comes to flying RC aircraft using a simulator can be a great way to hone your skills during the off season or even prepare for your first flight. The major disadvantage to using a simulator is that using a mouse, keyboard, touchscreen device, or standard video game controller, can be quite a different experience than the bulky transmitter with gimbals. There are commercial solutions available, depending on your interface type, but if you have an arduino ( and who doesn't? ) you can very easily connect a transmitter that supports PPM trainer / buddy box connections.

I can't say that it works with any transmitter, but I can say that it's compatible with the Spektrum DX6

But what software can I use it with?

I wanted to practice in my favorite simulator RC-AirSim by Fabricated Reality. It's an amazingly simple and accurate simulation (Not Game!) for electric RC airplanes. It's very inexpensive and if you are satisfied with the trainer plane, it has an unlimited use free demo. For less than $10 (the price fluctuates from 5 - 9 US dollars throughout the year) you can unlock all the plane models. They each fly different and realist, so you can learn the basics of a different type of plane before you try it in real life. This tutorial creates a game controller compatible with RC-AirSim with no configuration in the game. It just works.

How does it work?

Many RC transmitters allow you to share control of a plane with a second transmitter, so an inexperienced pilot can try taking over flight without having to hand over the transmitter in the event they loose control of the plane. This is a great feature supported by many transmitters. The setup can be complicated but it depends on the transmitter.

Basically with some transmitters, the data sent though the buddy cable (this tutorial will show you how to interface with a 2 wire cable such as a mono 3.5mm audio cable) is identical to the data that the receiver in the plane receives. They call this PPM, it's a series of pulses that can be turned into numerical values for percentage movement of servos. In Transmitters like the Spektrum DX6. The data can easily be deciphered using an arduino interrupt pin. Mike McCauley released an arduino library called RcTrainer that allows for capturing Spektrum PPM trainer communication in just this manner. I've used this library for the signal decoding.

Creating HID USB devices on the arduino can be accomplished in server different ways. The newer arduinos come with this ability built into the serial adapter chip, and some of the older arduinos can use a firmware hack on their serial adapters to do the same. But I wanted a solution that didn't depend on the arduino form factor and would work with just an atmega (eventually making it into a custom board) The solution here is the VUSB library for Atmel avr micro controllers. It's a software USB HID 1.1 emulation library. it has been ported to arduino as a library multiple times by multiple people. I created a HID gamepad descriptor that appears to the system as a standard gamepad, Works on windows, linux, and mac with no extra drivers needed, and matches the standard pattern for twin joystick controllers to little configuration is typically needed.

Step 1: Required Materials

  • Arduino (I'll be using an uno, but you can use any atmega328p based arduino)
  • A Spektrum compatible transmitter ( they all speak the same language, but the cables are different and the channel order may differ from brand to brand. If you have another brand you can can read the values of each channel out to the serial port and determine what settings need to be changed. The code is dirt simple)
  • For Spektrum you'll need a mono 3.5mm audio cable
  • Either a 3.5mm mono receptacle, or you can just cut the cable as they are cheap
  • a usb cable you can part with (you'll have to cut it up!)
  • 2 - 1N5227 or similar 3.6V biased zener diodes.
  • 2 - 68 ohm resistors
  • 1 - 2.2k ohm resistor
  • breadboard and breadboard wires
  • for optional calibration button you'll need a10K resistor, a tact switch, an led, and a current limiting resistor (value depends on led but 120 ohm - 200 ohm usually works fine with any led and 5v power) this is completely optional as you can just code the values that work into the arduino sketch.

Of course you'll need a computer, the arduino software, and some basic arduino knowledge.

This tutorial is not geared toward someone who has never used an arduino before so if you find any of these steps hard to follow please refer back to a tutorial on basic arduino.

Step 2: Assemble the Circuit on the Breadboard

The schematic included is for a standalone version, that only requires the minimal parts. You can purchase an atmega328p for $4 and use the schematic to make a permanent version. But for simplicity this tutorial will follow a breadboard and full arduino approach.


The usb specification expects 3.3 volt logic, but provides 5 volts of power. Fortunately the arduino runs on 5v and 3.3v is enough to trigger a logic high on a 5v logic. BUT you don't want to throw 5v into the usb host and possibly damage a cheaper usb host like an inexpensive budget laptop with little usb protection. This is why there are 3.6V zener diodes. They are bridged from logic to ground, when the voltage output by the arduino digital pin is over the 3.6v, the diode conducts backwards, pulling the signal voltage down to 3.6v (3.6 is a more common zener value that 3.3 and works just fine)

Also, in order to a usb host that the device is a 1.1 lowspeed device the usb specification says the d- (white wire) line should be pulled high to 3.3v. This is required for the host to see the device. That's where the 2.2k resistor comes in. We don't want the zener diode pulling the full current of the 5v signal down to 3.6v (and exploding into flames) so the 2.2k resistor provides the necessary pullup without letting too much current though.

This design comes straight from the recommended schematic on the VUSB website. You'll notice they use a 1.5k resistor, but 2.2k works better. All we want is the voltage, not the current.


Incorrectly connecting write to your USB port can cause your USB controller to fail. Shorting the Vcc and Gnd connections WILL cause your usb host controller to fail. Be-careful to not short any wires together while they are plugged into your USB port. I take no responsibility for damage to your computer or if these instructions do not work for you. Proceed at your own risk!


Red = 5v
Black = Ground
Green = D+
White = D-

These are the common wire colors used for usb, any respectable quality cable will use this color scheme.

Get connecting!

  1. Red USB wire to the red power bus on the breadboard.
  2. Black USB wire to the blue gnd bus on the breadboard.
  3. Connect the red power bus to "vin" on the arduino.
  4. Connect the blue gnd bus to the "gnd" on the arduino.
  5. Connect the Green D+ USB wire to pin row 1 on the breadboard.
  6. Connect the White D- USB wire to pin row 2 on the breadboard.
  7. Bridge breadboard row pins 1 and 5 together with a 68 ohm resistor.
  8. Bridge breadboard row pins 2 and 6 together with a 68 ohm resistor.
  9. Bridge breadboard row pins 5 to blue gnd bus with a zener diode, making sure that the polarity is flowing from gnd to pin 5 (this means that the black stripe on the diode is on the OPPOSITE side that connects to gnd).
  10. Bridge breadboard row pins 6 to blue gnd bus with a zener dioide, making sure that the polarity is flowing from gnd to pin 6 (this means that the black stripe on the diode is on the OPPOSITE side that connects to gnd).
  11. Bridge breadboard row pins 6 to the red power bus using the 2.2k resistor.
  12. Connect breadboard row pins 5 to the arduino digital pin 2.
  13. Connect breadboard row pins 6 to the arduino digital pin 7.
  14. Connect the center connector of the 3.5mm mono cable to the breadboard row pins 12.
  15. Connect the outer connector of the 3.5mm mono cable to the breadboard row pins 13.
  16. Connect breadboard row pins 12 to the arduino digital pin 3. (connecting the center audio cable pole to the digital pin 3 on the arduino)
  17. Connect the breadboard row pins 13 to the breadboard blue gnd bus. (connecting the outer gnd terminal of the mono audio cable to the gnd bus)

This is all that is technically required! but I'll go ahead and describe the optional calibration button connections.

  1. Plug the tact switch into the breadboard with the long side bridging the gap in the center of the breadboard starting at row pins 16.
  2. Bridge breadboard row pins 16 and breadboard red power bus with the 10k resistor.
  3. Connect breadboard row pins 18 (the bottom tact switch pin) to the breadboard blue gnd bus.
  4. Connect breadboard row pins 16 to the arduino digital pin 10.
  5. Plug the led into the breadboard with the long positive lead into breadboard row pins 22 and the shorter negative lead into breadboard row pins 23.
  6. Bridge the breadboard row pins 23 to the breadboard blue gnd bus using the 150~200 ohm current limiting resistor. (note if you need help calculating the resistor value for your led just search online, there are hundred of online calculators, but it's not the focus of this tutorial)
  7. Connect the breadboard row pins 22 to the arduino digital pin 9.

That's all the connections! You're ready to program the arduino!

Step 3: Programming the Arduino

The libraries

As I mentioned in the intro, two libraries were used and modified to make this project a reality.

VUSB and RCTrainer.

But in order to get the project working, you'll need to download the files I've included here. As the libraries have been modified for this particular purpose, as well as a special class for this game controller case has been developed into it's own isolated VUSB library I've called HIDJoy specifically for this purpose.

I'm giving credit to the original developers, but please in order for this project to work, use the files I've provided here.

Open your arduino user library folder (for help installing libraries look here)

and copy in the RCTrainer and HIDJOY library folders.

Copy the USBtx and USBtxEx sketch folders to your local arduino sketch folder.

!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

There is a gotcha to using VUSB. It consumes INT0_VECTOR which is the definition of the arduino's interrupt 0. If you call attachinterrupt() from any other code in the project (which RCTrainer must do) then the arduino core libraries try to redefine INT0_VECTOR and it will not compile. I've included a workaround for this. If you skip this step, you will get an error on compile that says __vector1_ is already defined.

Included in the VUSB library folder is a file called "WInterrupts.c" This file is a modified version of a core arduino file that will not conflict with any existing arduino project. All that is changed is it has a preprocessor directive for compile that says if INT0_VECTOR is already define, don't try to redefine it.

You must copy this "WInterrrupts.c" file and overwrite the arduino software one in order for this project to work. Find your arduino installation directory. If you used the default path on windows its C:\program files\arduino or C:\program files(x86)\arduino. If you are using another operating system or another install path, find it. (search the web it's easy enough to find) and then navigate to this directory


in that folder exists the previous version of WInterrupts.c, replace it with the one from the HIDJoy library folder.

Now lets get going!

Open the arduino software and open either the sketch USBtx for no calibration, or USBtxEx for optional calibration (if you added the button and led)

Since we have done all the setup work already, you should only have to compile and send the code to your arduino.

note: there are default values calibrated for my SpektrumDX6 transmitter. If you are using the Spektrum DX series you should be able to just upload and use with no calibration or code changes.

you can play with the default range values in the code to get your specific controller working. The code is documented well enough to see where to change default values.

Step 4: Plug and Play!

At this point you are free to unplug the arduino's usb cable and plug in the usb cable you connected to the breadboard, though it's not necessary as both can be plugged in at the same time. This is useful if you want to use the arduino's serial output for debugging or getting an understanding of how the system is working, or more importantly getting this to work with your particular set up. When you plug in your new adapter, you'll likely see something about installing drivers, and then finally in the devices and printers panel you will be able to see your USB game controller, it will be named "Twin USB Joystick" this name was chosen as it's a common gamepad name and will allow for auto configuration in RCAirSim or any standard xbox controller type game platform such as steam.

You'll need to set up your Transmitter to trainer mode. This isn't part of the tutorial as it's specific to many different platforms. But on the spektrum, create a new model with all the default settings, and then enter the trainer menu under system setup, make sure your wired mode settings say "programmable master" and set the throttle, aileron, rudder, and elevator to "master" and not slave. this will ensure that your signal is sent out over the trainer port.


The arduino sketch is set up for the Spektrum DX6. Your transmitter may be compatible, but have the channels in a different order, or need different values. If anyone figures out the settings and configuration for other transmitters, please post them in the comments.

You'll see in the main loop, (for USBtxEx in mode 0) where there are get channel calls, the 3,0,2,1 mapping to lx, ly, rx, ry respectively. The order may differ in another transmitters ppm signal, but otherwise be compatible. This is something to note if the sticks seem to be doing the wrong things but still working. Also the lxul, lxuh ect values are the numbers generated by lowest and highest positions. these must be adjusted for different transmitters as they are surely different.

If a transmitter sends out PPM on a single cable, this system should need only simple code changes to work with that transmitter, and if people with other transmitters figure out those changes, I'll be happy to update the code to work.

There are adapter cables that will convert futaba and hitec round ports into 2 wire spektrum compatible ports. Its something to consider!

Calibration Mode:

If you built the version with the calibration button and used the USBtxEx sketch, anytime the system is plugged into the usb port with the transmitter connected. Click the button and the led should start blinking. Move both sticks to the top left position and hold them there then click the button to confirm the max top left from both sticks, then the led will blink faster, pull both sticks to the bottom right and hold them there, then click the button. The led should go back out. This confirms the max value for the bottom right. This is useful if you're not sure what values your transmitter are sending out, but you know that you aren't getting the full range. (also check rates and expo setting on transmitter as those affect data sent out over the ppm port)

Now that you're set up and plugged in

your device should be working. Simply open up RCAirSim the desktop version not app version as it's the only one that supports external controllers. And take off! Remember that the transmitter is only the joysticks, you'll still need to use the keyboard or mouse to make selections in menus.

Step 5: Final Thoughts

I am a computer engineering student at the University of South Carolina. I love to build things, and I recently picked up the hobby of building and flying electric model planes from foam board. Simulation helped me a lot, especially RCAirSim since I could practice on my iPhone between classes when I knew I'd be trying to fly the coming weekend.

This instructable was an attempt to share this wonderful device with as many people as possible. I actually designed a PCB that can be etched and used to make a stand alone version, though the one pictured in the title of this instructable was my prototype, using a perfboard.

This instructable was not an attempt to win a contest, or to provide a end all solution. I was just hoping to share some of usefulness of the project to other model pilots who have arduinos.


Feel free to post any questions or improvements in the comments. I'm very busy and I don't know when I'll be able to respond. But I will try.



Rickey Ward