My UnoJoy project

I made a RC system-to-joystick interface with UnoJoy! It uses the PinChangeInt library to read the signals and maps them to HID values. Then, they are sent to the computer. I use it for the (free) ClearViewRC simulator and a game written in Processing by Paul Lager, Gcp_Tanker. It is an example for his Game Control Plus library, which can be installed by:

  • Open Sketch>Import Library>Add Library (menu.png).
  • Then search "game" in Library Manager (library manager.png).
  • Click "Install" on Game Control Plus and look at the examples for it.

Open Gcp_Tanker and configure your controller.
Click Use and play away! (Tanker.png)

Here is my code:

/*
This is my RC simulator code. 
It reads a 4-channel RC receiver and translates the input to joystick values.
The channel connections are trial-and-error. I have no clue which is which.
There are also 4 active-low buttons on pins 2,3,4,5.
*/
#include <PinChangeInt.h>
#include "UnoJoy.h"

byte RX_PIN_THROTTLE = 14;
byte RX_PIN_YAW      = 15;
byte RX_PIN_ROLL     = 16;
byte RX_PIN_PITCH    = 17;

volatile int rxPrev[4] = {
  0, 0, 0, 0
};
volatile int rxVal[4] = {
  0, 0, 0, 0
};
volatile int rStickXdata = 128;
volatile int rStickYdata = 128;
volatile int lStickXdata = 128;
volatile int lStickYdata = 128;

void setup() {
  setupPins();
  rxInit();
  setupUnoJoy();
}

void loop() {
  // Always be getting fresh data
  mapRcData();
  dataForController_t controllerData = getControllerData();
  setControllerData(controllerData);
}

void setupPins() {
  pinMode(RX_PIN_YAW, INPUT_PULLUP);
  pinMode(RX_PIN_ROLL, INPUT_PULLUP);
  pinMode(RX_PIN_PITCH, INPUT_PULLUP);
  pinMode(RX_PIN_THROTTLE, INPUT_PULLUP);
  pinMode(2,INPUT_PULLUP);
  pinMode(3,INPUT_PULLUP);
  pinMode(4,INPUT_PULLUP);
  pinMode(5,INPUT_PULLUP);
}

void rxInit() {
  attachPinChangeInterrupt(RX_PIN_YAW, rxGoesHigh1, RISING);
  attachPinChangeInterrupt(RX_PIN_ROLL, rxGoesHigh2, RISING);
  attachPinChangeInterrupt(RX_PIN_PITCH, rxGoesHigh3, RISING);
  attachPinChangeInterrupt(RX_PIN_THROTTLE, rxGoesHigh4, RISING);
}

dataForController_t getControllerData(void) {
  dataForController_t controllerData = getBlankDataForController();
  controllerData.triangleOn = !digitalRead(2);
  controllerData.circleOn = !digitalRead(3);
  controllerData.squareOn = !digitalRead(4);
  controllerData.crossOn = !digitalRead(5);
  controllerData.leftStickX = lStickXdata;
  controllerData.leftStickY = lStickYdata;
  controllerData.rightStickX = rStickXdata;
  controllerData.rightStickY = rStickYdata;
  // And return the data!
  return controllerData;
}

void mapRcData() {
  lStickXdata = map(rxVal[0], 1000, 2000, 0, 255);
  lStickYdata = map(rxVal[3], 1000, 2000, 255, 0);
  rStickXdata = map(rxVal[1], 1000, 2000, 0, 255);
  rStickYdata = map(rxVal[2], 1000, 2000, 0, 255);
}
void rxGoesHigh1() {
  attachPinChangeInterrupt(RX_PIN_YAW, rxGoesLow1, FALLING);
  rxPrev[0] = micros();
}
void rxGoesLow1() {
  attachPinChangeInterrupt(RX_PIN_YAW, rxGoesHigh1, RISING);
  rxVal[0] = micros() - rxPrev[0];
}
void rxGoesHigh2() {
  attachPinChangeInterrupt(RX_PIN_ROLL, rxGoesLow2, FALLING);
  rxPrev[1] = micros();
}
void rxGoesLow2() {
  attachPinChangeInterrupt(RX_PIN_ROLL, rxGoesHigh2, RISING);
  rxVal[1] = micros() - rxPrev[1];
}
void rxGoesHigh3() {
  attachPinChangeInterrupt(RX_PIN_PITCH, rxGoesLow3, FALLING);
  rxPrev[2] = micros();
}
void rxGoesLow3() {
  attachPinChangeInterrupt(RX_PIN_PITCH, rxGoesHigh3, RISING);
  rxVal[2] = micros() - rxPrev[2];
}
void rxGoesHigh4() {
  attachPinChangeInterrupt(RX_PIN_THROTTLE, rxGoesLow4, FALLING);
  rxPrev[3] = micros();
}
void rxGoesLow4() {
  attachPinChangeInterrupt(RX_PIN_THROTTLE, rxGoesHigh4, RISING);
  rxVal[3] = micros() - rxPrev[3];
}