Connessione Joystick DB9 (C64) su Windows tramite Arduino e Python

Con un modulo Arduino e qualche riga di Python รจ possibile utilizzare un Joystick del Commodore come periferica di input.

Nel test ho utilizzato un Joystick Alberici Albatros.

Materiale occorrente:

  • Joystick con connessione DB9
  • Connettore DB9 Maschio da collegare ad Arduino
  • Arduino
  • Python
  • Software Vjoy

Ecco lo schema generale di funzionamento: Arduino legge l’input grezzo proveniente dal joystick e lo converte in un messaggio inviato tramite porta seriale, python processa questo messaggio e governa il virtual Joystick (che viene visto da Windows come una periferica di gioco fisica).

Sketch Arduino:

const int pinUp    = 2;
const int pinDown  = 3;
const int pinLeft  = 4;
const int pinRight = 5;
const int pinFire  = 6;

unsigned long lastSend = 0;
const unsigned long interval = 20; // ms (50 Hz)

void setup() {
  pinMode(pinUp,    INPUT_PULLUP);
  pinMode(pinDown,  INPUT_PULLUP);
  pinMode(pinLeft,  INPUT_PULLUP);
  pinMode(pinRight, INPUT_PULLUP);
  pinMode(pinFire,  INPUT_PULLUP);

  Serial.begin(115200);
}

void loop() {
  if (millis() - lastSend >= interval) {
    lastSend = millis();

    int up    = !digitalRead(pinUp);
    int down  = !digitalRead(pinDown);
    int left  = !digitalRead(pinLeft);
    int right = !digitalRead(pinRight);
    int fire  = !digitalRead(pinFire);

    Serial.print("U:");
    Serial.print(up);
    Serial.print(" D:");
    Serial.print(down);
    Serial.print(" L:");
    Serial.print(left);
    Serial.print(" R:");
    Serial.print(right);
    Serial.print(" F:");
    Serial.println(fire);
  }
}

Programma python per processare i dati provenienti dalla seriale:

import re
import serial
import pyvjoy

# --- CONFIG ---
PORT = "COM7"      # <-- cambia qui
BAUD = 115200
VJOY_ID = 1
# --------------

LINE_RE = re.compile(r"U:(\d)\s+D:(\d)\s+L:(\d)\s+R:(\d)\s+F:(\d)")

AX_MIN = 0x0001
AX_MAX = 0x8000
AX_CEN = 0x4000

def axis(neg, pos):
    if neg and not pos: return AX_MIN
    if pos and not neg: return AX_MAX
    return AX_CEN

ser = serial.Serial(PORT, BAUD, timeout=1)
j = pyvjoy.VJoyDevice(VJOY_ID)

# reset iniziale
j.reset()
j.set_axis(pyvjoy.HID_USAGE_X, AX_CEN)
j.set_axis(pyvjoy.HID_USAGE_Y, AX_CEN)
j.set_button(1, 0)

print("OK - leggo seriale e mando a vJoy (CTRL+C per uscire)")

last = None
try:
    while True:
        line = ser.readline().decode("ascii", errors="ignore").strip()
        m = LINE_RE.match(line)
        if not m:
            continue

        up, down, left, right, fire = map(int, m.groups())
        state = (up, down, left, right, fire)
        if state == last:
            continue
        last = state

        j.set_axis(pyvjoy.HID_USAGE_X, axis(left, right))
        j.set_axis(pyvjoy.HID_USAGE_Y, axis(up, down))  # su = min, giu = max
        j.set_button(1, 1 if fire else 0)

except KeyboardInterrupt:
    pass
finally:
    # rilascia tutto
    j.set_axis(pyvjoy.HID_USAGE_X, AX_CEN)
    j.set_axis(pyvjoy.HID_USAGE_Y, AX_CEN)
    j.set_button(1, 0)
    ser.close()
    print("\nChiudo.")

Si consiglia di testarlo su WinUAE e Sensible Soccer ๐Ÿ™‚