산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

DIY 두더지 잡기 아케이드 게임 (버튼 에디션) - 아두이노 프로젝트

부품 및 소모품

부품 수량 비고
Arduino Mega 2560 1
Adafruit 1.4" 4자리 7세그먼트 디스플레이 (I2C 백팩) 2 원하는 색상 선택
Adafruit 대형 아케이드 버튼 (LED 내장, 60mm) 5 5가지 색상 선택
Adafruit Audio FX 보드 16MB 1
Adafruit 2.5W 앰프 2
스피커: 3W, 4Ω 2
Adafruit 온/오프 버튼 (LED 내장) 1
Adafruit 포텐셔미터 10k 2
Adafruit 포텐셔미터 노브 2
와이어 1
카운터싱크 나사 M3 + 너트 1세트
카운터싱크 나사 M4 + 너트 1세트
모든 3D 프린트 파트 1세트
모든 레이저컷 MDF 파트 1세트
커스텀 아두이노 메가 실드 1
아두이노 메가 스택커블 헤더 (간격용) 1
Adafruit DC 스텝다운 컨버터 5V 3A 1
12V PSU 1
암 PSU 버스 1
USB-B 패널 마운트 1

필요 도구 및 기계

앱 및 온라인 서비스

프로젝트 소개

커스텀 두더지 잡기 게임입니다. 현재 기본 게임으로 프로그래밍되어 있지만, 향후 업데이트로 확장 가능합니다.

주요 특징

인클로저 조립

먼저 인클로저 조립부터 시작합니다.

상판 커버에 3D 프린트 마운팅 브래킷을 장착합니다.

원하면 인클로저에 도색합니다.

LED 디스플레이 마운트 장착. 마운트 아래 볼트를 먼저 놓지 않으면 수직 바를 고정할 수 없으니 주의.

아두이노 실드 조립. 스택커블 헤더를 추가해 실드와 아두이노 사이 간격을 벌렸습니다.

후면 컨트롤 패널 조립.

상판 커버 조립 (버튼 & LED 패널).

후면 컨트롤 패널엔 포텐셔미터 2개: 볼륨 제어용, 레벨 선택용.

결론

완성!

왼쪽 LED 디지트 패널에 선택된 레벨 표시(1 쉬움 ~ 10 광기). 오른쪽 패널에 해당 레벨 하이스코어 표시. 게임 중엔 왼쪽 패널에 현재 점수 표시. 녹색 버튼 누르면 게임 시작. 카운트다운 후 게임 개시.

코드

/* Whac_A_Mole_v1.0.0 By WT040 */
#include "Wire.h"
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

Adafruit_7segment matrix1 = Adafruit_7segment();
Adafruit_7segment matrix2 = Adafruit_7segment();

#define debounceTime 10
#define potmeterVolume 0
#define potmeterGameLevel 1
#define ampPower 32

#define btn1Pin 22
#define btn2Pin 24
#define btn3Pin 26
#define btn4Pin 28
#define btn5Pin 30
byte btnArray[] = { btn1Pin, btn2Pin, btn3Pin, btn4Pin, btn5Pin };
#define btn1 0
#define btn2 1
#define btn3 2
#define btn4 3
#define btn5 4

#define btnLed1Pin 9
#define btnLed2Pin 10
#define btnLed3Pin 11
#define btnLed4Pin 12
#define btnLed5Pin 13
byte btnLedArray[] = { btnLed1Pin, btnLed2Pin, btnLed3Pin, btnLed4Pin, btnLed5Pin };
#define btnLed1 0
#define btnLed2 1
#define btnLed3 2
#define btnLed4 3
#define btnLed5 4

#define fx0TriggerPin 29
#define fx1TriggerPin 31
#define fx2TriggerPin 33
#define fx3TriggerPin 35
#define fx4TriggerPin 37
#define fx5TriggerPin 39
#define fx6TriggerPin 41
#define fx7TriggerPin 43
#define fx8TriggerPin 45
#define fx9TriggerPin 47
#define fx10TriggerPin 49
#define fxVolUpPin 51
#define fxVolDnPin 53
byte fxTriggerArray[] = { fx0TriggerPin, fx1TriggerPin, fx2TriggerPin, fx3TriggerPin, fx4TriggerPin, fx5TriggerPin, fx6TriggerPin, fx7TriggerPin, fx8TriggerPin, fx9TriggerPin, fx10TriggerPin };
byte fxVolumeArray[] = { fxVolUpPin, fxVolDnPin };
#define fx0Trigger 0
#define fx1Trigger 1
#define fx2Trigger 2
#define fx3Trigger 3
#define fx4Trigger 4
#define fx5Trigger 5
#define fx6Trigger 6
#define fx7Trigger 7
#define fx8Trigger 8
#define fx9Trigger 9
#define fx10Trigger 10
#define fxVolUp 0
#define fxVolDn 1

signed int currentPlayingSound = -1;
byte btnPressed[5], ledState[5];
unsigned long previousMillisLedBlink = 0;
#define intervalLedBlink 750

unsigned long previousMillisGameStarting = 0;
#define intervalCountDown 1000
byte gameStartCountDown;

unsigned long previousMillisGameStep = 0;
int gameStepLength = 0;
int gameStepBtn = 0;
int valPotmeterVolume = 0;
int volume = 0;
int actualVolume = 35;
int valPotmeterGameLevel = 0;
int gameLevel;
int currentScore;
int highScore;
int highScoreAddr = 1;
byte activeBtn;
bool debug;
byte wackAMoleState;
bool SystemInitialized = false;

#define stateUnknown 0
#define waitForStart 1
#define starting 2
#define running 3
#define gameOver 4
#define stopped 5

void setup() {
  Serial.begin(9600);
  pinMode(ampPower, OUTPUT);
  digitalWrite(ampPower, LOW);
  for (int Pin = 0; Pin < 5; Pin++) pinMode(btnArray[Pin], INPUT);
  for (int Pin = 0; Pin < 5; Pin++) pinMode(btnLedArray[Pin], OUTPUT);
  for (int Pin = 0; Pin < 11; Pin++) { pinMode(fxTriggerArray[Pin], OUTPUT); digitalWrite(fxTriggerArray[Pin], HIGH); }
  for (int Pin = 0; Pin < 2; Pin++) { pinMode(fxVolumeArray[Pin], OUTPUT); digitalWrite(fxVolumeArray[Pin], HIGH); }
  matrix1.begin(0x70);
  matrix2.begin(0x71);
  while (!eeprom_is_ready());
  cli(); highScore = eeprom_read_word((uint16_t*)(gameLevel * 2)); sei();
  matrix1.print(0); matrix1.writeDisplay();
  matrix2.print(0); matrix2.writeDisplay();
  initializeSystem();
}

void loop() {
  checkButtonInputs();
  readVolumePotmeter();
  if (wackAMoleState == waitForStart) {
    playSound(fx0Trigger);
    if (btnPressed[btn4]) wackAMoleState = starting;
    readGameLevelPotmeter();
    ledBlinkStart();
  }
  if (wackAMoleState == starting) startGame();
  if (wackAMoleState == running) {
    playSound(fx1Trigger);
    checkNextGameStep();
  }
}

void checkNextGameStep() {
  unsigned long currentMillisGameStep = millis();
  int amountOfButtonPresses = 0;
  for (int btn = 0; btn < 5; btn++) if (btnPressed[btn]) amountOfButtonPresses++;
  if (previousMillisGameStep == 0) {
    previousMillisGameStep = currentMillisGameStep;
    digitalWrite(btnLedArray[btnLed4], LOW);
    randomSeed(analogRead(2));
    gameStepBtn = random(0, 5);
    gameStepLength = random(3000 / gameLevel, 5000 / gameLevel);
    digitalWrite(btnLedArray[gameStepBtn], HIGH);
  }
  if ((currentMillisGameStep - previousMillisGameStep >= gameStepLength) || (amountOfButtonPresses > 1) || (amountOfButtonPresses == 1 && !btnPressed[gameStepBtn])) {
    playSound(fx2Trigger);
    wackAMoleState = gameOver;
    previousMillisGameStep = 0;
    for (int counter = 0; counter < 5; counter++) analogWrite(btnLedArray[counter], 255);
    for (int brightness = 255; brightness > 0; brightness--) {
      analogWrite(btnLedArray[btnLed1], brightness);
      analogWrite(btnLedArray[btnLed2], brightness);
      analogWrite(btnLedArray[btnLed3], brightness);
      analogWrite(btnLedArray[btnLed4], brightness);
      analogWrite(btnLedArray[btnLed5], brightness);
      delay(10);
    }
    for (int counter = 0; counter < 5; counter++) analogWrite(btnLedArray[counter], 0);
    Serial.println("Game Over");
    if (currentScore > highScore) {
      while (!eeprom_is_ready());
      cli(); eeprom_write_word((uint16_t*)(gameLevel * 2), currentScore); sei();
    }
    int counter = 0;
    do { delay(1); checkButtonInputs(); counter++; } while ((counter < 1000) && !btnPressed[btn1] && !btnPressed[btn2] && !btnPressed[btn3] && !btnPressed[btn4] && !btnPressed[btn5]);
    matrix1.print(0); matrix1.writeDisplay();
    wackAMoleState = waitForStart;
  } else if (btnPressed[gameStepBtn] && (amountOfButtonPresses == 1)) {
    digitalWrite(btnLedArray[gameStepBtn], LOW);
    int counter = 0;
    do { delay(1); checkButtonInputs(); counter++; } while ((counter < 1000) && btnPressed[gameStepBtn]);
    previousMillisGameStep = currentMillisGameStep;
    int tempStepBtn = 0;
    do { tempStepBtn = random(0, 5); gameStepLength = random(3000 / gameLevel, 5000 / gameLevel); } while (gameStepBtn == tempStepBtn);
    gameStepBtn = tempStepBtn;
    digitalWrite(btnLedArray[gameStepBtn], HIGH);
    currentScore++;
    matrix1.print(currentScore); matrix1.writeDisplay();
    if (currentScore > highScore) { matrix2.print(currentScore); matrix2.writeDisplay(); }
  }
}

void ledBlinkStart() {
  unsigned long currentMillisLedBlink = millis();
  if (currentMillisLedBlink - previousMillisLedBlink >= intervalLedBlink) {
    previousMillisLedBlink = currentMillisLedBlink;
    ledState[0] = (ledState[0] == LOW) ? HIGH : LOW;
    digitalWrite(btnLedArray[btnLed4], ledState[0]);
  }
}

void startGame() {
  unsigned long currentMillisGameStarting = millis();
  digitalWrite(btnLedArray[btnLed4], 0);
  currentScore = 0;
  if (gameStartCountDown == 0) {
    playSound(fx3Trigger);
    previousMillisGameStarting = millis();
    gameStartCountDown = 4;
    delay(300);
    matrix1.print(gameStartCountDown, DEC); matrix1.writeDisplay();
  }
  if (currentMillisGameStarting - previousMillisGameStarting >= intervalCountDown) {
    previousMillisGameStarting = currentMillisGameStarting;
    if (gameStartCountDown > 0) {
      gameStartCountDown--;
      matrix1.print(gameStartCountDown, DEC); matrix1.writeDisplay();
      if (gameStartCountDown == 0) wackAMoleState = running;
    }
  }
}

void initializeSystem() {
  digitalWrite(btnLedArray[btnLed1], HIGH); delay(75);
  digitalWrite(btnLedArray[btnLed2], HIGH); delay(75);
  digitalWrite(btnLedArray[btnLed3], HIGH); delay(75);
  digitalWrite(btnLedArray[btnLed4], HIGH); delay(75);
  digitalWrite(btnLedArray[btnLed5], HIGH); delay(1000);
  digitalWrite(btnLedArray[btnLed5], LOW); delay(75);
  digitalWrite(btnLedArray[btnLed4], LOW); delay(75);
  digitalWrite(btnLedArray[btnLed3], LOW); delay(75);
  digitalWrite(btnLedArray[btnLed2], LOW); delay(75);
  digitalWrite(btnLedArray[btnLed1], LOW); delay(1000);
  debug = true;
  wackAMoleState = waitForStart;
  initVolume();
  if (actualVolume > 0) enableAmpPower(true);
}

void checkButtonInputs() {
  static byte previousstate[5], currentstate[5];
  static long lasttime;
  byte index;
  if ((lasttime + debounceTime) > millis()) return;
  lasttime = millis();
  for (index = 0; index < 5; index++) {
    currentstate[index] = digitalRead(btnArray[index]);
    if (currentstate[index] != btnPressed[index]) {
      if ((btnPressed[index] == HIGH) && (currentstate[index] == LOW)) {
        if (debug) { Serial.print("button released: "); Serial.println(index + 1); }
        btnPressed[index] = 0;
      }
      if ((btnPressed[index] == LOW) && (currentstate[index] == HIGH)) {
        if (debug) { Serial.print("button pressed: "); Serial.println(index + 1); }
        btnPressed[index] = 1;
      }
    }
  }
}

void initVolume() {
  valPotmeterVolume = (analogRead(potmeterVolume) / 30);
  if (actualVolume > valPotmeterVolume) {
    do { digitalWrite(fxVolumeArray[fxVolDn], LOW); actualVolume--; delay(20); digitalWrite(fxVolumeArray[fxVolDn], HIGH); delay(20); } while (actualVolume > valPotmeterVolume);
  } else if (actualVolume < valPotmeterVolume) {
    do { digitalWrite(fxVolumeArray[fxVolUp], LOW); actualVolume++; delay(20); digitalWrite(fxVolumeArray[fxVolUp], HIGH); delay(20); } while (actualVolume < valPotmeterVolume);
  }
}

void readVolumePotmeter() {
  valPotmeterVolume = (analogRead(potmeterVolume) / 30);
  if (actualVolume > valPotmeterVolume) {
    digitalWrite(fxVolumeArray[fxVolDn], LOW); actualVolume--; delay(40); digitalWrite(fxVolumeArray[fxVolDn], HIGH);
    if (actualVolume == 0) enableAmpPower(false);
  } else if (actualVolume < valPotmeterVolume) {
    digitalWrite(fxVolumeArray[fxVolUp], LOW);
    if (actualVolume == 0) enableAmpPower(true);
    actualVolume++; delay(40); digitalWrite(fxVolumeArray[fxVolUp], HIGH);
  }
}

void readGameLevelPotmeter() {
  valPotmeterGameLevel = analogRead(potmeterGameLevel);
  if (valPotmeterGameLevel < 102) gameLevel = 1;
  else if (valPotmeterGameLevel < 204) gameLevel = 2;
  else if (valPotmeterGameLevel < 306) gameLevel = 3;
  else if (valPotmeterGameLevel < 408) gameLevel = 4;
  else if (valPotmeterGameLevel < 510) gameLevel = 5;
  else if (valPotmeterGameLevel < 612) gameLevel = 6;
  else if (valPotmeterGameLevel < 714) gameLevel = 7;
  else if (valPotmeterGameLevel < 816) gameLevel = 8;
  else if (valPotmeterGameLevel < 918) gameLevel = 9;
  else gameLevel = 10;
  matrix1.print(gameLevel); matrix1.writeDisplay();
  while (!eeprom_is_ready());
  cli(); highScore = eeprom_read_word((uint16_t*)(gameLevel * 2)); sei();
  if (highScore > -1) matrix2.print(highScore); else matrix2.print(0);
  matrix2.writeDisplay();
}

void playSound(int sound) {
  if (currentPlayingSound != sound) {
    for (int counter = 0; counter < 11; counter++) digitalWrite(fxTriggerArray[counter], HIGH);
    digitalWrite(fxTriggerArray[sound], LOW);
    currentPlayingSound = sound;
  }
}

void enableAmpPower(bool state) { digitalWrite(ampPower, state); }

커스텀 파트 및 인클로저

회로도

회로도 이미지 참조

제조공정

  1. 장비에 적합한 계기 노브(인스트루먼트 노브) 선택 가이드
  2. 버튼 소켓 캡 스크루 선택 가이드: 실용적 접근
  3. 단추: 고대 잠금장치에서 현대 혁신까지
  4. 라즈베리파이, PIR 센서, MQTT로 만드는 모션 제어 AWS IoT 버튼
  5. UnifiedWater v1 - 아두이노 MKR GSM 1400 기반 완전 수질 모니터링 센서 키트
  6. GSM 연결 휴대용 투표 시스템 - 모바일 투표함 만들기
  7. PCB 프로토타입 제작사 선택 완벽 가이드: 놓치면 후회하는 5가지 기준
  8. 밴드쏘 최적 톱 가공 속도 선정: 실용 가이드
  9. 올바른 잠수 펌프 선택: 전문가 팁 및 핵심 특징
  10. 정밀 가공을 위한 수직 터닝 센터 선택의 핵심 이유