This is my first contribution here. I use linux and wanted to see if it would be possible to use an arduino nano and a few pots to fly X-plane. It is.
I used the "Gravis Stinger" protocol, which talks to the PC via serial interface. Since all the nanos have serial, it was quite easy.
Downside is the "Gravis stinger" only has 2 analog axis and 10 buttons. But it is a start, and very fun to sim with this homebrew controller.
Now I'm going to checkout the "XPlane direct plugin" to do more advanced things directly interfacing X-plane itself, but this comment here is a generic PC joystick made with any arduino that has a serial port and it will work with any game/application, not only X-plane.
Code: (no libraries, just plain arduino copy-and-paste code)
/*
"Gravis Stinger" 10-button, 2 axis joystick for ANY arduino, connected as the serial port used for programming the arduino
Resolution is 0-127, that is -63 to +63 aprox. That is multiplied up to 2 bytes in linux native resolution.
https://github.com/torvalds/linux/blob/master/drivers/input/joystick/stinger.c
The stinger protocol has a resolution of 7 bit, that is 0..128 decimal or 0x00..0x7F hex.
## (Linux:)
## dump values output by arduino to debug this program:
# inputattach --baud 9600 --dump /dev/ttyUSB0
## attach joystick in linux to use it in applications:
# sudo inputattach --baud 9600 --always --stinger /dev/ttyUSB0
## becomes /dev/input/js0 on linux mint anyway
## after attaching: to test the joystick:
# jstest /dev/input/js0
## Minimum value (pot zero) should be reported as -32767 and max should be 32767
Physical build instructions:
* no power needed if you use something like Arduino Nano. It feeds on the PC's USB port.
* connect pot wiper to analog pin, and the other two pot pins to 5V and GND respectively
* connect digital pins to GND to activate
Arno Teigseth (L) GPL 2021
arno at teigseth dot no
*/
// you can specify which axis is
int sensorPinX = A0; // select the input pin for the potentiometer
int sensorPinY = A1; // select the input pin for the potentiometer
// you can specify which button is which digital input here
int btnPin0 = 2; // Digital pin 2 = just "2"
int btnPin1 = 3;
int btnPin2 = 4;
int btnPin3 = 5;
int btnPin4 = 6;
int btnPin5 = 7;
int btnPin6 = 8;
int btnPin7 = 9;
int btnPin8 = 10;
int btnPin9 = 11;
unsigned long sensorValueX = 0; // variable to store pot value X (0..1023)
unsigned long sensorValueY = 0; // variable to store pot value Y (0..1023)
int btnValue0 = 0;
int btnValue1 = 0;
int btnValue2 = 0;
int btnValue3 = 0;
int btnValue4 = 0;
int btnValue5 = 0;
int btnValue6 = 0;
int btnValue7 = 0;
int btnValue8 = 0;
int btnValue9 = 0;
void setup() {
// one-time, initial setup here
pinMode(btnPin0, INPUT_PULLUP);
pinMode(btnPin1, INPUT_PULLUP);
pinMode(btnPin2, INPUT_PULLUP);
pinMode(btnPin3, INPUT_PULLUP);
pinMode(btnPin4, INPUT_PULLUP);
pinMode(btnPin5, INPUT_PULLUP);
pinMode(btnPin6, INPUT_PULLUP);
pinMode(btnPin7, INPUT_PULLUP);
pinMode(btnPin8, INPUT_PULLUP);
pinMode(btnPin9, INPUT_PULLUP);
// serial port speed
Serial.begin(9600);
}
void loop() {
// read analog values
sensorValueX = analogRead(sensorPinX);
sensorValueY = analogRead(sensorPinY);
// read digital values
btnValue0 = digitalRead(btnPin0);
btnValue1 = digitalRead(btnPin1);
btnValue2 = digitalRead(btnPin2);
btnValue3 = digitalRead(btnPin3);
btnValue4 = digitalRead(btnPin4);
btnValue5 = digitalRead(btnPin5);
btnValue6 = digitalRead(btnPin6);
btnValue7 = digitalRead(btnPin7);
btnValue8 = digitalRead(btnPin8);
btnValue9 = digitalRead(btnPin9);
byte buf[4]; // this is what we will feed the PC with
buf[0] = 0;
if (!btnValue0) bitSet(buf[0], 5);
if (!btnValue1) bitSet(buf[0], 4);
if (!btnValue2) bitSet(buf[0], 3);
if (!btnValue3) bitSet(buf[0], 2);
// bit (4) = btn 3
// bit (8) = btn 2
// bit (10) = btn 1
// bit (20) = btn 0
buf[3] = 0;
if (!btnValue4) bitSet(buf[3], 5);
if (!btnValue5) bitSet(buf[3], 4);
if (!btnValue6) bitSet(buf[3], 3);
if (!btnValue7) bitSet(buf[3], 2);
if (!btnValue8) bitSet(buf[3], 1);
if (!btnValue9) bitSet(buf[3], 0);
// LSB (1) = btn9
// bit (2) = btn8
// bit (4) = btn7
// bit (8) = btn6
// bit (10) = btn5
// bit (20) = btn4
// AXIS 0 (x)
byte sensvalX = floor(sensorValue / 8 ) ; // return 0-127
if (sensvalX > 63) {
buf[1] = (sensvalX - 64) & 0x3f;
} else {
bitSet(buf[0], 0);
buf[1] = (sensvalX) & 0x3f;
}
// AXIS 1 (y)
byte sensvalY = floor(sensorValue2 / 8 ); // return 0-127
if (sensvalY > 63) {
buf[2] = (63 - sensvalY) & 0x3f;
bitSet(buf[0], 1);
} else {
buf[2] = (63 - sensvalY) & 0x3f;
}
Serial.write(buf, sizeof(buf));
delay(100); // aproximately 10 updates per second (1000ms/100)
}