27 April 2026

Team 11 - SRB2Kart Final Controller

 

Sonic Robo Blast 2 Kart Controller

The final controller we built is for the game Sonic Robo Blast 2 Kart. It is designed as a car radio. The idea is built on the irony that the user is ‘playing with the radio’ while driving. It is a way of symbolizing the havoc and chaos in karting games like this.

The left knob (which is typically associated with volume control on a car radio) is used for the speed controls. As the ‘volume’ ramps up, so does the kart velocity. The potentiometer inputs for it are mapped to a range of 1 to 100. The lowest part of this range is used for reverse, the mostly low section is used for idle (no gas), the section above this uses a PMW system to allow for speed ramping, and the highest section is equivalent to holding the accelerate button.

The right button (which is typically the tune button) is used to control the steering, as the player is making an ‘adjustment’ to their kart. It is mapped to a range of -100 to 100 and also uses a form of PMW to make it so gradual turning is possible in the intermediate zones, with maximum turn at the farther ends on each side.

Both knobs have notches in the 3d design to provide feedback on the current position and allow for the user to normalize their frame of reference while controlling.

The final input device is the slider in the center. The slider is an indicator of the radio's channel, and in this case, it is an indicator of the kart's special state. The input is mapped to create 3 zones; The left is used for drifting, the middle is neutral, and the right activates/uses items.

One question we have about our controller design is: Which input device is the weakest, and if you had to replace it with another type of input device, what would it be?

 

(Final Controller)


(Schematic)

#include <Keyboard.h>
#include <Adafruit_CircuitPlayground.h>
#include <Adafruit_Circuit_Playground.h>


float stopwatch = 0;

bool isWPressed = false;
bool isSpacePressed = false;

int speed;
int steer;
int slider;

void setup() {
  // put your setup code here, to run once:
  CircuitPlayground.begin();
  Serial.begin(9600);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);
  delay(1000);
}

void loop() {

  ReadSensors();

  HandleSpeed();

  HandleSteering();

  HandleSlider();
 
}

void ReadSensors() {
  //  Read Left Knob (Speed): Map the 0-1023 range to a 1 to 100 range
  speed = map(analogRead(A1), 0, 1023, 1, 100);
  //  Read Right Knob (Steering): Map the 0-1023 range to a -100 to 100
  steer = map(analogRead(A2), 0, 1023, -100, 100);
  //  Read Slider: Map the 0-1023 range to a 1-30 range
  slider = map(analogRead(A3), 0, 1023, 1, 30);
}


void HandleSpeed() {

  if (speed <= 10) {
    // 1 Reverse if dial is at the very bottom
    Keyboard.release('a');
    Keyboard.press('d');

  } else if (speed >=11 && speed <= 30) {
    // 2 No movement (gas off, idling)
    Keyboard.release('d');
    Keyboard.release('a');

  } else if (speed >= 85) {
    // 3 Full Speed
    Keyboard.release('d');
    Keyboard.press('a');

  } else {

    // 4 PWM Speed (variable speed ramps when player is between idling and max speed zones)
    Keyboard.release('d');
    Keyboard.press('a');
    delay(speed*4);
    Keyboard.release('a');
    delay(100);
}

}

void HandleSteering() {
    // 1 Neutral (Deadzone) (-15 to 15)
  if (steer >= -15 && steer <= 15) {
    Keyboard.release(KEY_LEFT_ARROW);
    Keyboard.release(KEY_RIGHT_ARROW);

  } else if (steer <= -50) {
    // 2 Full Left (Hard steer) (-50 or less)
    Keyboard.release(KEY_RIGHT_ARROW);
    Keyboard.press(KEY_LEFT_ARROW);

  } else if (steer >= 50) {
    // 3 Full Right (Hard steer) (50 or more)
    Keyboard.release(KEY_LEFT_ARROW);
    Keyboard.press(KEY_RIGHT_ARROW);

  } else if (steer < -15) {
    // PWM Left (Partial steer)
    Keyboard.release(KEY_RIGHT_ARROW);
    Keyboard.press(KEY_LEFT_ARROW);
   
    // Hold then Release
    delay(180);
    Keyboard.release(KEY_LEFT_ARROW);
   
    // Wait a delay based on strength of steer
    int restTime = map(abs(steer), 15, 50, 80, 2);
    delay(restTime);

  } else if (steer > 15) {
    // PWM Right (Partial steer)
    Keyboard.release(KEY_LEFT_ARROW);
    Keyboard.press(KEY_RIGHT_ARROW);
   
    // Hold then Release
    delay(180);
    Keyboard.release(KEY_RIGHT_ARROW);
   
    // Wait a delay based on strength of steer
    int restTime = map(steer, 15, 50, 80, 2);
    delay(restTime);
  }
}

void HandleSlider() {
  // 1 Lowest Zone (Drift)
  if (slider <= 7) {
    Keyboard.release(' ');
    Keyboard.press('s');
    isSpacePressed = false;

  } else if (slider >= 8 && slider <= 17) {
  // 2 Middle Zone (Neutral)
    Keyboard.release('s');
    Keyboard.release(' ');
   
    // Prevents jitter at the 17/18 border and spamming fire of space (item) button
    if (slider <= 15) {
      isSpacePressed = false;
    }
   
  }   else if (slider >= 18) {
    // 3 Highest Zone (Collect/Use Item)
    Keyboard.release('s');

    if (isSpacePressed == false) {
      Keyboard.press(' ');
      delay(50);
      Keyboard.release(' ');
      isSpacePressed = true; // Set lock so player so slider only uses space ONCE per time it enters the zone (prevents item spam)
    }
  }
}

(Code) 








No comments:

Post a Comment

Note: Only a member of this blog may post a comment.