Alan Wang
Published © CC BY-NC-SA

A Simple Kerbal Space Program Arduino Leonardo Controller

Just as the title says - with a 20-min gameplay video as proof.

BeginnerShowcase (no instructions)3,279
A Simple Kerbal Space Program Arduino Leonardo Controller

Things used in this project

Hardware components

Arduino Leonardo
Arduino Leonardo
×1
Breadboard (generic)
Breadboard (generic)
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×1
Big Red Dome Button
SparkFun Big Red Dome Button
×1
Slide Switch
Slide Switch
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

Kerbal Controller

Arduino
#include "Keyboard.h"
#include "Talkie.h"
#include "Vocab_US_Large.h"

#define JOYSTICK_UP_KEY 'W'
#define JOYSTICK_DW_KEY 'S'
#define JOYSTICK_LT_KEY 'A'
#define JOYSTICK_RT_KEY 'D'
#define JOYSTICK_SW_KEY KEY_DELETE
#define BUTTON_1_KEY    'M'
#define BUTTON_2_KEY    'H'
#define BUTTON_3_KEY    'N'
#define BUTTON_4_KEY    'Q'
#define BUTTON_5_KEY    'E'
#define STAGE_KEY       ' '
#define ENGINE_ON_KEY   'Z'
#define ENGINE_OFF_KEY  'X'
#define ROTARY_UP_KEY   KEY_LEFT_CTRL // change throttle up key in the game
#define ROTARY_DW_KEY   KEY_RIGHT_CTRL // change throttle down key in the game
#define ROTARY_SW_KEY   'G'
#define SAS_KEY         'T'
#define RCS_KEY         'R'

#define JOYSTICK_X      A0
#define JOYSTICK_Y      A1
#define JOYSTICK_SW     A2
#define BUTTONS         A3
#define ENGINE          A4
#define POWER           A5
#define ROTARY_CLK      2
#define ROTARY_DTA      3
#define ROTARY_SW       4
#define STAGE           5
#define SAS             6
#define RCS             7
#define POWER_LED       8
#define ENGINE_LED      11
#define RCS_LED         12
#define SAS_LED         13
// the speaker is connected to pin 9 (+) and 10 (-)

#define BUTTON_G_V      4400
#define BUTTON_R_V      1000
#define BUTTON_W_V      1500
#define BUTTON_Y_V      500
#define BUTTON_B_V      2500

int joystick_x;
int joystick_y;
int joystick_sw;
int buttons;
int button_pressed;
int buttons_v[5] = {BUTTON_G_V, BUTTON_R_V, BUTTON_W_V, BUTTON_Y_V, BUTTON_B_V};
int rotary_clk = 1;
int rotary_clk_prev = 1;
int rotary_dta = 1;
int rotary_sw;
int rotary_dir;
int stage;
int enabled = 1;
int enabled_prev = 1;
int engine_on = 1;
int engine_on_prev = 1;
int rcs_on = 0;
int rcs_on_prev = 0;
int rcs = 0;
int rcs_prev = 0;
int sas_on = 0;
int sas_on_prev = 0;
int sas = 0;
int sas_prev = 0;

Talkie voice;

void setup() {

  Serial.begin(9600);
  Keyboard.begin();
  pinMode(JOYSTICK_SW, INPUT_PULLUP);
  pinMode(BUTTONS, INPUT_PULLUP);
  pinMode(POWER, INPUT_PULLUP);
  pinMode(ENGINE, INPUT_PULLUP);
  pinMode(ROTARY_CLK, INPUT_PULLUP);
  pinMode(ROTARY_DTA, INPUT_PULLUP);
  pinMode(ROTARY_SW, INPUT_PULLUP);
  pinMode(STAGE, INPUT_PULLUP);
  pinMode(SAS, INPUT_PULLUP);
  pinMode(RCS, INPUT_PULLUP);
  pinMode(POWER_LED, OUTPUT);
  pinMode(ENGINE_LED, OUTPUT);
  pinMode(RCS_LED, OUTPUT);
  pinMode(SAS_LED, OUTPUT);
  digitalWrite(POWER_LED, LOW);
  digitalWrite(ENGINE_LED, LOW);
  digitalWrite(RCS_LED, LOW);
  digitalWrite(SAS_LED, LOW);
  enabled = digitalRead(POWER);
  engine_on = digitalRead(ENGINE);
  rcs = digitalRead(RCS);
  sas = digitalRead(SAS);
  enabled_prev = enabled;
  engine_on_prev = engine_on;
  rcs_prev = rcs;
  sas_prev = sas;

  voice.say(sp5_FLIGHT_1);
  voice.say(sp4_CONTROL);
  voice.say(sp5_INSTRUMENTS);
  voice.say(sp3_START);
  voice.say(sp2_UP);
  voice.say(sp4_AND);
  voice.say(sp4_READY);

  delay(500);

}

void press_key(uint8_t key, int ms) {
  Serial.println("Pressed key: " + String(key));
  if (enabled) {
    Keyboard.write(key);
  }
  delay(ms);
}

void update_led() {
  digitalWrite(POWER_LED, enabled);
  digitalWrite(ENGINE_LED, engine_on);
  digitalWrite(RCS_LED, rcs_on);
  digitalWrite(SAS_LED, sas_on);
}

void loop() {

  joystick_x = analogRead(JOYSTICK_X);
  joystick_y = analogRead(JOYSTICK_Y);
  joystick_sw = !digitalRead(JOYSTICK_SW);
  buttons = analogRead(BUTTONS) * 10;
  button_pressed = -1;
  for (int i = 0; i < 5; i++) {
    if (abs(buttons - buttons_v[i]) < 250) {
      button_pressed = i;
      break;
    }
  }
  rotary_clk = digitalRead(ROTARY_CLK);
  rotary_dta = digitalRead(ROTARY_DTA);
  rotary_sw = !digitalRead(ROTARY_SW);
  rotary_dir = 0;
  if (rotary_clk_prev == 0 && rotary_clk == 1) {
    if (rotary_dta == 0) {
      rotary_dir = -1;
    } else {
      rotary_dir = 1;
    }
  }
  rotary_clk_prev = rotary_clk;

  enabled = !digitalRead(POWER);
  engine_on = !digitalRead(ENGINE);
  stage = !digitalRead(STAGE);
  rcs = digitalRead(RCS);
  sas = digitalRead(SAS);
  rcs_on = (rcs != rcs_prev) ? 1 - rcs_on : rcs_on;
  sas_on = (sas != sas_prev) ? 1 - sas_on : sas_on;

  update_led();

  if (joystick_x < 256) {
    press_key(JOYSTICK_LT_KEY, 5);
  } else if (joystick_x > 767) {
    press_key(JOYSTICK_RT_KEY, 5);
  }
  if (joystick_y < 256) {
    press_key(JOYSTICK_UP_KEY, 5);
  } else if (joystick_y > 767) {
    press_key(JOYSTICK_DW_KEY, 5);
  }
  if (joystick_sw) {
    press_key(JOYSTICK_SW_KEY, 5);
    voice.say(sp2_CONNECT);
    voice.say(sp5_LOCALIZER);
  }

  switch (button_pressed) {
    case 0:
      press_key(BUTTON_1_KEY, 5);
      voice.say(sp5_INFLIGHT);
      voice.say(sp4_AREA);
      voice.say(sp2_DISPLAY);
      break;
    case 1:
      press_key(BUTTON_2_KEY, 5);
      break;
    case 2:
      press_key(BUTTON_3_KEY, 5);
      break;
    case 3:
      press_key(BUTTON_4_KEY, 5);
      break;
    case 4:
      press_key(BUTTON_5_KEY, 5);
      break;
  }

  if (enabled && !enabled_prev) {
    voice.say(sp4_POWER);
    voice.say(sp4_ON);
  } else if (!enabled && enabled_prev) {
    voice.say(sp4_POWER);
    voice.say(sp4_OFF);
  }
  if (engine_on && !engine_on_prev) {
    press_key(ENGINE_ON_KEY, 5);
    voice.say(sp5_ENGINE);
    voice.say(sp5_IGNITE);
  } else if (engine_on_prev && !engine_on) {
    press_key(ENGINE_OFF_KEY, 5);
    voice.say(sp5_ENGINE);
    voice.say(sp3_STOP);
  }
  if (rotary_dir == -1) {
    digitalWrite(ENGINE_LED, !engine_on);
    press_key(ROTARY_UP_KEY, 5);
    digitalWrite(ENGINE_LED, !engine_on);
  } else if (rotary_dir == 1) {
    digitalWrite(ENGINE_LED, !engine_on);
    press_key(ROTARY_DW_KEY, 5);
    digitalWrite(ENGINE_LED, !engine_on);
  }
  if (rotary_sw) {
    press_key(ROTARY_SW_KEY, 5);
    voice.say(sp5_LANDING_GEAR);
  }
  if (stage) {
    press_key(STAGE_KEY, 5);
    voice.say(sp5_LAUNCH);
    voice.say(sp4_SEQUENCE);
  }
  if (rcs_on != rcs_on_prev) {
    press_key(RCS_KEY, 5);
    voice.say(sp4_VECTORS);
    voice.say(sp4_CONTROL);
  }
  if (sas_on != sas_on_prev) {
    press_key(SAS_KEY, 5);
    voice.say(sp5_AUTOPILOT);
  }

  enabled_prev = enabled;
  engine_on_prev = engine_on;
  rcs_on_prev = rcs_on;
  sas_on_prev = sas_on;
  rcs_prev = rcs;
  sas_prev = sas;
}

Credits

Alan Wang

Alan Wang

25 projects • 42 followers
Former novel translator, amateur film photographer. Sometime Maker.

Comments