20 April 2025

Team 11: The Game of Life Controller

 Kevin Rivera and Andrew Bryant

Controller:

Description:

    Our Controller is extremely simple in its design and went through different changes to make it easier to use. In the beginning, we were planning to use just the accelerometer to control the mouse movement. We then realized this wasn’t very intuitive to control the mouse so we added a magnetometer to control the x axis of the mouse while the accelerometer controls the y axis of the mouse. We decided to use the idea of a knob at the top of the car to control the left click and a sound sensor to control the spacebar. So inside the 3D printed car model that was inspired from the vehicles in the chosen game, The Game of Life, the magnetometer is plugged into the Playground Express and is aligned so that it controls the mouse accurately. The most difficult part was attaching everything inside the car securely but not permanently. We decided to keep everything inside and hot glue the car together which was time consuming as we had to redo it a couple of times because we forgot to attach a wire to the Playground Express. The signifier is the car which is picked up and the mouse movements is the feedback, the knob as it sticks out at the top and the player would twist it and the feedback is that it would select in game. Overall the way the controller works, the knob on top of the car serves as a select button when choosing cards, the car itself serves as a mouse to navigate the screen and menus, and sound sensor to pick if the player says “spin the wheel” to spin the wheel in game.

    Andrew did most of the coding and making sure everything worked well with the game, Kevin did the modeling of the car and some coding. Together we created the controller and made sure it worked.

    One question we have is how can we create a signifier so that the player knows to use the sound sensor and say “spin the wheel” to spin the wheel in game.

Schematics:

Code:

#include <Adafruit_CircuitPlayground.h>

#include <Adafruit_Circuit_Playground.h>

#include <Mouse.h> // Include the Mouse library

#include <Keyboard.h>

#include <Adafruit_ICM20X.h>

#include <Adafruit_ICM20948.h>

#include <Adafruit_Sensor.h>

#include <Wire.h>


const int soundPin = A1;  // Sound sensor connected to analog pin A1

const int threshold = 280; // Adjust this threshold based on your sound sensor's response

const int potPin = A3;  // Adjust this to the pin you connected to

Adafruit_ICM20948 icm;

uint16_t measurement_delay_us = 65535; // Delay between measurements for testing

// For SPI mode, we need a CS pin

#define ICM_CS 10

// For software-SPI mode we need SCK/MOSI/MISO pins

#define ICM_SCK 13

#define ICM_MISO 12

#define ICM_MOSI 11


void setup() {

  // Start serial communication

  Serial.begin(200);

  while (!Serial)

    delay(10); // will pause Zero, Leonardo, etc until serial console opens


  Serial.println("Adafruit ICM20948 test!");

  // Initialize the Circuit Playground

  CircuitPlayground.begin();

  // Start the Mouse library

  Mouse.begin();

   // Initialize the Keyboard library

  Keyboard.begin();


  // Try to initialize!

  if (!icm.begin_I2C()) {

    // if (!icm.begin_SPI(ICM_CS)) {

    // if (!icm.begin_SPI(ICM_CS, ICM_SCK, ICM_MISO, ICM_MOSI)) {


    Serial.println("Failed to find ICM20948 chip");

    while (1) {

      delay(10);

    }

  }

  Serial.println("ICM20948 Found!");

  // icm.setAccelRange(ICM20948_ACCEL_RANGE_16_G);

  Serial.print("Accelerometer range set to: ");

  switch (icm.getAccelRange()) {

  case ICM20948_ACCEL_RANGE_2_G:

    Serial.println("+-2G");

    break;

  case ICM20948_ACCEL_RANGE_4_G:

    Serial.println("+-4G");

    break;

  case ICM20948_ACCEL_RANGE_8_G:

    Serial.println("+-8G");

    break;

  case ICM20948_ACCEL_RANGE_16_G:

    Serial.println("+-16G");

    break;

  }

  Serial.println("OK");


  // icm.setGyroRange(ICM20948_GYRO_RANGE_2000_DPS);

  Serial.print("Gyro range set to: ");

  switch (icm.getGyroRange()) {

  case ICM20948_GYRO_RANGE_250_DPS:

    Serial.println("250 degrees/s");

    break;

  case ICM20948_GYRO_RANGE_500_DPS:

    Serial.println("500 degrees/s");

    break;

  case ICM20948_GYRO_RANGE_1000_DPS:

    Serial.println("1000 degrees/s");

    break;

  case ICM20948_GYRO_RANGE_2000_DPS:

    Serial.println("2000 degrees/s");

    break;

  }


  //  icm.setAccelRateDivisor(4095);

  uint16_t accel_divisor = icm.getAccelRateDivisor();

  float accel_rate = 1125 / (1.0 + accel_divisor);


  Serial.print("Accelerometer data rate divisor set to: ");

  Serial.println(accel_divisor);

  Serial.print("Accelerometer data rate (Hz) is approximately: ");

  Serial.println(accel_rate);


  //  icm.setGyroRateDivisor(255);

  uint8_t gyro_divisor = icm.getGyroRateDivisor();

  float gyro_rate = 1100 / (1.0 + gyro_divisor);


  Serial.print("Gyro data rate divisor set to: ");

  Serial.println(gyro_divisor);

  Serial.print("Gyro data rate (Hz) is approximately: ");

  Serial.println(gyro_rate);


  // icm.setMagDataRate(AK09916_MAG_DATARATE_10_HZ);

  Serial.print("Magnetometer data rate set to: ");

  switch (icm.getMagDataRate()) {

  case AK09916_MAG_DATARATE_SHUTDOWN:

    Serial.println("Shutdown");

    break;

  case AK09916_MAG_DATARATE_SINGLE:

    Serial.println("Single/One shot");

    break;

  case AK09916_MAG_DATARATE_10_HZ:

    Serial.println("10 Hz");

    break;

  case AK09916_MAG_DATARATE_20_HZ:

    Serial.println("20 Hz");

    break;

  case AK09916_MAG_DATARATE_50_HZ:

    Serial.println("50 Hz");

    break;

  case AK09916_MAG_DATARATE_100_HZ:

    Serial.println("100 Hz");

    break;

  }

  Serial.println();


}


void loop() {

  // Read the accelerom   eter values (x, y, z)

  float x = CircuitPlayground.motionX();

  float y = CircuitPlayground.motionY();


  // Map the accelerometer values to screen coordinates (make sure the values are within screen size)

  int mouseX = map(x, -10, 10, -10, 10);  // Adjust the mapping range based on the screen size

  int mouseY = map(y, -10, 10, -10, 10);


  // Move the mouse based on the accelerometer values

  Mouse.move(mouseX, mouseY);


  // Read the analog value from the sound sensor

  int soundValue = analogRead(soundPin);


  // Print the value for debugging 

  Serial.println(soundValue);             

  // If the sound exceeds the threshold, simulate a spacebar key press

  if (soundValue > threshold) {

    // Send spacebar key press

    Keyboard.press(' ');

    delay(100);  // Short delay to simulate the key press duration

    Keyboard.release(' ');

  }


   // Read the potentiometer value (0-1023)

  int potValue = analogRead(potPin);

  // Print the value to the Serial Monitor

  Serial.println(potValue);


  if (potValue > 100){

    Mouse.click();

    delay(200);

  }


  // Add a delay to avoid excessive movement

  delay(10);


   //  /* Get a new normalized sensor event */

  sensors_event_t accel;

  sensors_event_t gyro;

  sensors_event_t mag;

  sensors_event_t temp;

  icm.getEvent(&accel, &gyro, &temp, &mag);


  Serial.print("\t\tMag X: ");

  Serial.print(mag.magnetic.x);

  Serial.print(" \tY: ");

  Serial.print(mag.magnetic.y);

  Serial.print(" \tZ: ");

  Serial.print(mag.magnetic.z);

  Serial.println(" uT");


  /* Display the results (acceleration is measured in m/s^2) */

  Serial.print("\t\tGyro X: ");

  Serial.print(gyro.gyro.x);

  Serial.print(" \tY: ");

  Serial.print(gyro.gyro.y);

  Serial.print (" \tZ: ");

  Serial.print(gyro.gyro.z);

  Serial.println(" radians/s ");

  Serial.println();


  delay(100);


 

}

Video:





No comments:

Post a Comment

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