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/

main.cpp

Committer:
Letme
Date:
2018-10-18
Revision:
0:e0d0f401d8a4

File content as of revision 0:e0d0f401d8a4:

#include "mbed.h"
#include <math.h>
#include "USBJoystick.h"
#include "PwmIn.h"

//InterruptIn button(USER_BUTTON);
//#define DEBUG_PRINTF

DigitalOut led(LED1);

PwmIn a(PB_1); /**< Plug channel 1 from receiver to this pin */
PwmIn b(PC_4); /**< Plug channel 2 from receiver to this pin */
PwmIn c(PC_5); /**< Plug channel 3 from receiver to this pin */
PwmIn d(PC_8); /**< Plug channel 4 from receiver to this pin */

/**@note Do not forget to plug ground pin to GND of the board */

/** Covert PWM output which is in floats in range of 0.000153231 to -127..128 range
 *
 * PWM pulse width is in float range which needs to be offset a bit and then
 * converted to int8_t range for the PC joystick driver to understand
 *
 * @param[in] pwm PWM float value produced by PwmIn.pulseWidth function
 *
 * @return Converted signed integer value in range of -127..128
 */
int16_t covert_PWM_to_PC_range(float pwm)
{
    int32_t ipwm = pwm * 1000000;
    if(ipwm != 0) {
        ipwm = (((ipwm - 1100) * 255) / 870) - 127;   
    }
    
    return (int16_t) ipwm;
}

int main(void)
{
#ifndef DEBUG_PRINTF
    USBJoystick joystick; /**< Joystick object from USBJoystick library */
#else
    Serial pc(USBTX, USBRX); /**< USB interface through debugger (/dev/ttyACM0) */
    pc.baud(115200); /** Set USB speed for the PC interface */
#endif
    uint16_t i = 0;
    int16_t throttle = 0;
    int16_t rudder = 0;
    int16_t x = 0;
    int16_t y = 0;
    uint8_t tmp = 0;
    uint32_t buttons = 0;
    uint8_t hat = 0;

    led = 1;
#ifdef DEBUG_PRINTF
    pc.printf("Hello World from Joystick!\r\n");
#endif
    
    while (1) {
        /** Get PWM pulsewidth via PwmIn library and covert that to simple
         * int8_t range for all 4 channels */
        x = covert_PWM_to_PC_range(a.pulsewidth());
        y = covert_PWM_to_PC_range(b.pulsewidth());
        throttle = covert_PWM_to_PC_range(c.pulsewidth());
        rudder = covert_PWM_to_PC_range(d.pulsewidth());

/*
#if (BUTTONS4 == 1)
        buttons = (i >> 8) & 0x0F;   // value    0 ..  15, one bit per button
#endif
#if (BUTTONS8 == 1)
        buttons = (i >> 8) & 0xFF;   // value    0 .. 255, one bit per button
#endif
#if (BUTTONS32 == 1)
        tmp     = (i >> 8) & 0xFF;   // value    0 .. 255, one bit per button
        buttons =           (( tmp <<  0) & 0x000000FF);
        buttons = buttons | ((~tmp <<  8) & 0x0000FF00);
        buttons = buttons | (( tmp << 16) & 0x00FF0000);
        buttons = buttons | ((~tmp << 24) & 0xFF000000);
#endif

#if (HAT4 == 1)
        hat    = (i >> 8) & 0x03;   // value 0, 1, 2, 3 or 4 for neutral
#endif
#if (HAT8 == 1)
        hat    = (i >> 8) & 0x07;   // value 0..7 or 8 for neutral
#endif
*/
        
#ifndef DEBUG_PRINTF
        joystick.update(rudder, throttle, y, x, 0, 0);
#else
        pc.printf("x (CH1): %i\t\ty (CH2): %i\t\t throttle: %i\r\n", y, x,throttle);
#endif
        wait(0.005);
    }
}