Self-contained project code for the "Godot Isn't Just for Games" series: Arduino sketches, the Python serial<->UDP bridge, and the Godot 4 projects, one folder per article.
80 lines
2.5 KiB
Arduino
80 lines
2.5 KiB
Arduino
/*
|
|
* JoystickBridge.ino — Arduino Uno <-> Godot (ArduinoGodot/Main.gd)
|
|
*
|
|
* Talks plain serial lines to the UDP<->serial bridge process, which forwards
|
|
* telemetry to Godot on UDP 4242 and relays LED commands from UDP 4243.
|
|
*
|
|
* PROTOCOL (must match Main.gd)
|
|
* OUT (Uno -> host): "x,y,btn\n" raw 10-bit ADC, e.g. "512,498,1"
|
|
* btn = 1 when the stick's push-button is pressed.
|
|
* IN (host -> Uno): "L1" = LED on, "L0" = LED off (newline optional)
|
|
*
|
|
* WIRING (KY-023 2-axis analog joystick + external LED)
|
|
* Joystick +5V / VCC -> 5V
|
|
* Joystick GND -> GND
|
|
* Joystick VRx -> A0
|
|
* Joystick VRy -> A1
|
|
* Joystick SW -> D2 (uses internal pull-up; pressed = LOW)
|
|
*
|
|
* LED: D13 -> 220 ohm resistor -> LED anode (+, long leg)
|
|
* LED cathode (-, short leg) -> GND
|
|
* (D13 is also the Uno's onboard LED, so it flashes during every upload —
|
|
* a free "is this pin alive" check. 220-330 ohm keeps it near ~15 mA.)
|
|
*/
|
|
|
|
const uint8_t PIN_VRX = A0; // joystick X axis
|
|
const uint8_t PIN_VRY = A1; // joystick Y axis
|
|
const uint8_t PIN_SW = 2; // joystick push-button (active LOW)
|
|
const uint8_t PIN_LED = 13; // external LED through a 220 ohm resistor (also onboard LED)
|
|
|
|
const unsigned long BAUD = 115200; // must match the bridge process
|
|
const unsigned long SEND_MS = 16; // ~60 Hz telemetry
|
|
|
|
unsigned long lastSend = 0;
|
|
char cmdBuf[8];
|
|
uint8_t cmdLen = 0;
|
|
|
|
void setup() {
|
|
Serial.begin(BAUD);
|
|
pinMode(PIN_SW, INPUT_PULLUP);
|
|
pinMode(PIN_LED, OUTPUT);
|
|
digitalWrite(PIN_LED, LOW);
|
|
}
|
|
|
|
void loop() {
|
|
handleCommands();
|
|
|
|
unsigned long now = millis();
|
|
if (now - lastSend >= SEND_MS) {
|
|
lastSend = now;
|
|
int x = analogRead(PIN_VRX); // 0..1023
|
|
int y = analogRead(PIN_VRY); // 0..1023
|
|
int btn = (digitalRead(PIN_SW) == LOW) // pull-up: LOW == pressed
|
|
? 1 : 0; // Godot wants 1 = pressed
|
|
|
|
// "x,y,btn\n"
|
|
Serial.print(x);
|
|
Serial.print(',');
|
|
Serial.print(y);
|
|
Serial.print(',');
|
|
Serial.println(btn);
|
|
}
|
|
}
|
|
|
|
// Parse newline-terminated commands. Recognizes "L1" / "L0".
|
|
void handleCommands() {
|
|
while (Serial.available() > 0) {
|
|
char c = Serial.read();
|
|
if (c == '\n' || c == '\r') {
|
|
if (cmdLen >= 2 && cmdBuf[0] == 'L') {
|
|
digitalWrite(PIN_LED, cmdBuf[1] == '1' ? HIGH : LOW);
|
|
}
|
|
cmdLen = 0;
|
|
} else if (cmdLen < sizeof(cmdBuf) - 1) {
|
|
cmdBuf[cmdLen++] = c;
|
|
} else {
|
|
cmdLen = 0; // overflow guard: drop the runt line
|
|
}
|
|
}
|
|
}
|