Make RC (Radio controlled) Remote Control presentable as Joystick in Linux without any additional cables. Since we know that servos operate on PWM, I have decided that cheapest way (and easiest) to fly a RC model simulator is to translate PWM from receiver to Joystick data on computer. Mbed board was doing the translation. No need for any special cable and no dependency on RC Transmitter or Receiver whatsoever. If it can move the servos it can also move the model in computer simulator. Requirements and design are available on https://os.mbed.com/users/Letme/notebook/rc-receiver-as-joystick/

Dependencies:   PwmIn USBDevice USBJoystick mbed

RC receiver as joystick

PWMIn class defines your pins which are connected to certain channels on receiver. I suggest you keep the order and just swap pins (since order defines axis identified in computer through USB and generic Joystick driver. You can also calibrate your Joystick.

Tested on mbed boards

  • NUCLEO-F401RE

Initial tests were done with NUCLEO-F401RE and was tested on Chromebook, with PicaSim, Linux PC with CRRCSim and FlightGear. Because it is just Joystick it can be used in any game supporting joysticks (from car simulations to everyday games). No more need for special cables to get your transmitter to the computer.

Requirements, Test Cases and Design

Since this was done before project was started I used a simple notebook to outline the required work. It is still available on https://os.mbed.com/users/Letme/notebook/rc-receiver-as-joystick/

Committer:
Letme
Date:
Thu Oct 18 20:31:36 2018 +0000
Revision:
0:e0d0f401d8a4
Stable version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Letme 0:e0d0f401d8a4 1 #include "mbed.h"
Letme 0:e0d0f401d8a4 2 #include <math.h>
Letme 0:e0d0f401d8a4 3 #include "USBJoystick.h"
Letme 0:e0d0f401d8a4 4 #include "PwmIn.h"
Letme 0:e0d0f401d8a4 5
Letme 0:e0d0f401d8a4 6 //InterruptIn button(USER_BUTTON);
Letme 0:e0d0f401d8a4 7 //#define DEBUG_PRINTF
Letme 0:e0d0f401d8a4 8
Letme 0:e0d0f401d8a4 9 DigitalOut led(LED1);
Letme 0:e0d0f401d8a4 10
Letme 0:e0d0f401d8a4 11 PwmIn a(PB_1); /**< Plug channel 1 from receiver to this pin */
Letme 0:e0d0f401d8a4 12 PwmIn b(PC_4); /**< Plug channel 2 from receiver to this pin */
Letme 0:e0d0f401d8a4 13 PwmIn c(PC_5); /**< Plug channel 3 from receiver to this pin */
Letme 0:e0d0f401d8a4 14 PwmIn d(PC_8); /**< Plug channel 4 from receiver to this pin */
Letme 0:e0d0f401d8a4 15
Letme 0:e0d0f401d8a4 16 /**@note Do not forget to plug ground pin to GND of the board */
Letme 0:e0d0f401d8a4 17
Letme 0:e0d0f401d8a4 18 /** Covert PWM output which is in floats in range of 0.000153231 to -127..128 range
Letme 0:e0d0f401d8a4 19 *
Letme 0:e0d0f401d8a4 20 * PWM pulse width is in float range which needs to be offset a bit and then
Letme 0:e0d0f401d8a4 21 * converted to int8_t range for the PC joystick driver to understand
Letme 0:e0d0f401d8a4 22 *
Letme 0:e0d0f401d8a4 23 * @param[in] pwm PWM float value produced by PwmIn.pulseWidth function
Letme 0:e0d0f401d8a4 24 *
Letme 0:e0d0f401d8a4 25 * @return Converted signed integer value in range of -127..128
Letme 0:e0d0f401d8a4 26 */
Letme 0:e0d0f401d8a4 27 int16_t covert_PWM_to_PC_range(float pwm)
Letme 0:e0d0f401d8a4 28 {
Letme 0:e0d0f401d8a4 29 int32_t ipwm = pwm * 1000000;
Letme 0:e0d0f401d8a4 30 if(ipwm != 0) {
Letme 0:e0d0f401d8a4 31 ipwm = (((ipwm - 1100) * 255) / 870) - 127;
Letme 0:e0d0f401d8a4 32 }
Letme 0:e0d0f401d8a4 33
Letme 0:e0d0f401d8a4 34 return (int16_t) ipwm;
Letme 0:e0d0f401d8a4 35 }
Letme 0:e0d0f401d8a4 36
Letme 0:e0d0f401d8a4 37 int main(void)
Letme 0:e0d0f401d8a4 38 {
Letme 0:e0d0f401d8a4 39 #ifndef DEBUG_PRINTF
Letme 0:e0d0f401d8a4 40 USBJoystick joystick; /**< Joystick object from USBJoystick library */
Letme 0:e0d0f401d8a4 41 #else
Letme 0:e0d0f401d8a4 42 Serial pc(USBTX, USBRX); /**< USB interface through debugger (/dev/ttyACM0) */
Letme 0:e0d0f401d8a4 43 pc.baud(115200); /** Set USB speed for the PC interface */
Letme 0:e0d0f401d8a4 44 #endif
Letme 0:e0d0f401d8a4 45 uint16_t i = 0;
Letme 0:e0d0f401d8a4 46 int16_t throttle = 0;
Letme 0:e0d0f401d8a4 47 int16_t rudder = 0;
Letme 0:e0d0f401d8a4 48 int16_t x = 0;
Letme 0:e0d0f401d8a4 49 int16_t y = 0;
Letme 0:e0d0f401d8a4 50 uint8_t tmp = 0;
Letme 0:e0d0f401d8a4 51 uint32_t buttons = 0;
Letme 0:e0d0f401d8a4 52 uint8_t hat = 0;
Letme 0:e0d0f401d8a4 53
Letme 0:e0d0f401d8a4 54 led = 1;
Letme 0:e0d0f401d8a4 55 #ifdef DEBUG_PRINTF
Letme 0:e0d0f401d8a4 56 pc.printf("Hello World from Joystick!\r\n");
Letme 0:e0d0f401d8a4 57 #endif
Letme 0:e0d0f401d8a4 58
Letme 0:e0d0f401d8a4 59 while (1) {
Letme 0:e0d0f401d8a4 60 /** Get PWM pulsewidth via PwmIn library and covert that to simple
Letme 0:e0d0f401d8a4 61 * int8_t range for all 4 channels */
Letme 0:e0d0f401d8a4 62 x = covert_PWM_to_PC_range(a.pulsewidth());
Letme 0:e0d0f401d8a4 63 y = covert_PWM_to_PC_range(b.pulsewidth());
Letme 0:e0d0f401d8a4 64 throttle = covert_PWM_to_PC_range(c.pulsewidth());
Letme 0:e0d0f401d8a4 65 rudder = covert_PWM_to_PC_range(d.pulsewidth());
Letme 0:e0d0f401d8a4 66
Letme 0:e0d0f401d8a4 67 /*
Letme 0:e0d0f401d8a4 68 #if (BUTTONS4 == 1)
Letme 0:e0d0f401d8a4 69 buttons = (i >> 8) & 0x0F; // value 0 .. 15, one bit per button
Letme 0:e0d0f401d8a4 70 #endif
Letme 0:e0d0f401d8a4 71 #if (BUTTONS8 == 1)
Letme 0:e0d0f401d8a4 72 buttons = (i >> 8) & 0xFF; // value 0 .. 255, one bit per button
Letme 0:e0d0f401d8a4 73 #endif
Letme 0:e0d0f401d8a4 74 #if (BUTTONS32 == 1)
Letme 0:e0d0f401d8a4 75 tmp = (i >> 8) & 0xFF; // value 0 .. 255, one bit per button
Letme 0:e0d0f401d8a4 76 buttons = (( tmp << 0) & 0x000000FF);
Letme 0:e0d0f401d8a4 77 buttons = buttons | ((~tmp << 8) & 0x0000FF00);
Letme 0:e0d0f401d8a4 78 buttons = buttons | (( tmp << 16) & 0x00FF0000);
Letme 0:e0d0f401d8a4 79 buttons = buttons | ((~tmp << 24) & 0xFF000000);
Letme 0:e0d0f401d8a4 80 #endif
Letme 0:e0d0f401d8a4 81
Letme 0:e0d0f401d8a4 82 #if (HAT4 == 1)
Letme 0:e0d0f401d8a4 83 hat = (i >> 8) & 0x03; // value 0, 1, 2, 3 or 4 for neutral
Letme 0:e0d0f401d8a4 84 #endif
Letme 0:e0d0f401d8a4 85 #if (HAT8 == 1)
Letme 0:e0d0f401d8a4 86 hat = (i >> 8) & 0x07; // value 0..7 or 8 for neutral
Letme 0:e0d0f401d8a4 87 #endif
Letme 0:e0d0f401d8a4 88 */
Letme 0:e0d0f401d8a4 89
Letme 0:e0d0f401d8a4 90 #ifndef DEBUG_PRINTF
Letme 0:e0d0f401d8a4 91 joystick.update(rudder, throttle, y, x, 0, 0);
Letme 0:e0d0f401d8a4 92 #else
Letme 0:e0d0f401d8a4 93 pc.printf("x (CH1): %i\t\ty (CH2): %i\t\t throttle: %i\r\n", y, x,throttle);
Letme 0:e0d0f401d8a4 94 #endif
Letme 0:e0d0f401d8a4 95 wait(0.005);
Letme 0:e0d0f401d8a4 96 }
Letme 0:e0d0f401d8a4 97 }