Week 10: Analog/Digital – Guess Who’s Murderer (Pi)

Let’s look at what I need to do…

(Post documentation on blog): Get information from at least one analog sensor and at least one digital sensor (switch), and use this information to control at least two LEDs, one in a digital fashion and the other in an analog fashion, in some creative way.

Hmm… so I can do something along the lines of

  • Ultrasonic Sensor (Analog)
  • Switch (is a requirement)
  • 4 LEDs (3 controlled by digitalWrite, and one fade In/Out through analog PWM)

In some creative way?? Hmm, how about we turn the entire project into a detective game, where you have to guess the murderer by pointing at one of the 3 suspects, then Arduino will tell you whether you got it right or wrong.

Guess Who’s Murderer

Hence, my project…

The player step into the shoes of a cunning detective, whose aim is to unravel the identity of the true culprit among the Crimson Enigma, the Emerald Marksman, and the Honey Hitwoman.

Using their hand, the player must point to one of the suspects. An ultrasonic sensor, detects the location of the player’s hand, illuminating the corresponding LED to indicate their suspicion.

To make their guess official, the player presses a pushbutton. If the guess is correct, a green LED softly fades in and out. However, if the player points their accusatory finger at the wrong suspect, the game’s buzzer sounds.

The demo video is below.

Art

All artworks are generated with midjourney… and some photoshop thrown in.

CODE

The code is below. Note that I am implementing a entire thing as a state machine, where the game alternates between the

{ SELECT_MURDERER, GUESS, CORRECT_GUESS, WRONG_GUESS }

states. This makes the code clean. The microcontroller randomly selects the murderer using a random number generation algorithm, which is triggered at the start of each new game loop.

// Pin Definitions
const int buttonPin = 12;   // Pushbutton pin
const int buzzerPin = 7;    // Buzzer pin
const int greenLedPin = 44; // Green LED pin
const int redLedPins[] = {3, 6, 10}; // Red LEDs for murderer selection
const int trigPin = 2;      // Ultrasonic sensor trigger pin
const int echoPin = 4;      // Ultrasonic sensor echo pin

// Game state definitions
enum GameState { SELECT_MURDERER, GUESS, CORRECT_GUESS, WRONG_GUESS };
GameState currentState;

// Variables for game logic
int murderer = 0;
int guess = -1;
int buttonState = 0;
int lastButtonState = LOW;
unsigned long previousMillis = 0; // for non-blocking delays

void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(greenLedPin, OUTPUT);
  for (int i = 0; i < 3; i++) {
    pinMode(redLedPins[i], OUTPUT);
  }
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  randomSeed(analogRead(0));
  currentState = SELECT_MURDERER;
}

void loop() {
  switch (currentState) {
    case SELECT_MURDERER:
      selectMurderer();
      break;
    case GUESS:
      manageGuess();
      break;
    case CORRECT_GUESS:
      handleCorrectGuess();
      break;
    case WRONG_GUESS:
      handleWrongGuess();
      break;
  }
}

void selectMurderer() {
  murderer = random(0, 3); // Randomly select a murderer among 3 LEDs
  Serial.print("Murderer is: LED ");
  Serial.println(murderer);
  currentState = GUESS;
}

void manageGuess() {
  lightRedLEDsBasedOnDistance();
  readButtonState();
  if (buttonState == HIGH && lastButtonState == LOW) {
    Serial.println("Button Pressed");
    checkGuess();
  } else if (buttonState == LOW && lastButtonState == HIGH) {
    Serial.println("Button Released");
  }
  lastButtonState = buttonState;
}

void lightRedLEDsBasedOnDistance() {
  long distance = measureDistance();
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");
  for (int i = 0; i < 3; i++) {
    digitalWrite(redLedPins[i], LOW);
  }
  if (distance >= 2 && distance < 6) {
    digitalWrite(redLedPins[0], HIGH);
    guess = 0;
  } else if (distance >= 6 && distance < 9) {
    digitalWrite(redLedPins[1], HIGH);
    guess = 1;
  } else if (distance >= 9 && distance <= 12) {
    digitalWrite(redLedPins[2], HIGH);
    guess = 2;
  }
}

void readButtonState() {
  buttonState = digitalRead(buttonPin);
}

void checkGuess() {
  if (guess == murderer) {
    currentState = CORRECT_GUESS;
  } else {
    currentState = WRONG_GUESS;
  }
}

void handleCorrectGuess() {
  fadeGreenLED();  // Handles the fading of the LED over 4 seconds
  currentState = SELECT_MURDERER;
}

void handleWrongGuess() {
  buzzBuzzer(3);   // Buzzes the buzzer 3 times
  currentState = SELECT_MURDERER;
}

void fadeGreenLED() {
  for (int i = 0; i <= 255; i += 5) {
    analogWrite(greenLedPin, i);
    delay(30);
  }
  for (int i = 255; i >= 0; i -= 5) {
    analogWrite(greenLedPin, i);
    delay(30);
  }
}

void buzzBuzzer(int count) {
  for (int i = 0; i < count; i++) {
    digitalWrite(buzzerPin, HIGH);
    delay(300);
    digitalWrite(buzzerPin, LOW);
    delay(300);
  }
}

long measureDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  return duration * 0.034 / 2;  // Calculate distance in cm
}

Leave a Reply