본문 바로가기
  • 우당탕탕속의 잔잔함
Programming/Arduino

[Arcade Button] Arduino에서 아케이드 버튼 사용하는 방법

by zpstls 2023. 1. 9.
반응형

 

 

이번 포스트에서는 Arduino와 Arcade Button으로 Hardware를 구성하고 해당 Hardware로 부터 버튼이 Push되었는지 Unity에 전달하고 이를 활용하는 과정에 대해 다뤄볼 것입니다.

 

우선, HW 부분을 구성해봅시다.

HW

  • Arduino-Uno Board & USB b Cable x 1
  • Arcade Button x 1
  • 점퍼 케이블

 

이때 Arcade Button의 경우 제조사마다 다르지만 보통 VCC, GND로 구성되며, LED가 포함된 제품일 경우 LED VCC, GND가 따로 구성되어 있습니다. 이미지로 보면 다음과 같이 구성됩니다.

LED 및 Switch는 모두 Digital Signal로 제어할 수 있기에 Digital Port를 사용합니다.

LED의 경우 다리가 긴 쪽이 +이며, 짧은 쪽은 -입니다. 이를 단일하게 연결한다면 +는 VCC에, -는 GND에 연결합니다. Arcade Button의 경우는 결국 Switch이며, 이는 단자가 붙어있게 되면 ON, 떨어지게 되면 OFF를 의미합니다. 단자 역할을 하는 부분이 위 이미지의 초록 박스이며, 이 부분 또한 VCC와 GND로 구성됩니다. 해당 부분을 Board의 올바른 Port에 연결합니다.

대략적인 연결도는 다음과 같습니다.

HW Structure

Switch의 VCC는 Digital 2번 Port, LED의 +는 Digital 3번 Port에 연결하고 각각의 GND는 GND Port에 연결합니다. 연결 후 다음 C Code를 Arduino에 Import 시킵니다.

#define RELEASED 0
#define SW_THRESHOLD  500

#define PUSH0 1
#define PULL0 4
#define BUTTON0 2
#define LED0 3

void setup() {
  pinMode(LED0, OUTPUT);
  pinMode(BUTTON0, INPUT_PULLUP);
  
  Serial.begin(115200);
  Serial.println("Connected");
}

void loop() {

  static unsigned long last0;
  int buttonState = read_button();
 
  if (PUSH0 == buttonState) {
    Serial.println("B_ON");
  } 
  if (PULL0 == buttonState) {
    Serial.println("B_OFF");
  } 
  
  if ((millis()-last0) >= 500) {
    last0 = millis();
  }
  
  if(digitalRead(BUTTON0) == LOW) digitalWrite(LED0, HIGH);
  if(digitalRead(BUTTON0) == HIGH) digitalWrite(LED0, LOW);
}

int read_button()
{
  static boolean prev0 = HIGH;
  static unsigned long last0;
  boolean curr0;

  if ((millis() - last0) >= 10) {
    curr0 = digitalRead(BUTTON0);
    if ((HIGH == prev0) && (LOW == curr0)) {
      prev0 = LOW;
      return PUSH0;
    } 
    else if ((LOW == prev0) && (HIGH == curr0)) {
      prev0 = HIGH;
      return PULL0;
    }
    last0 = millis();
  }
  
  return RELEASED;
}

Serial 통신을 이용해 Data를 Arduino → PC로 전송하며 Baud Rate는 115200을 사용하도록 합니다. 처음 Serial 통신이 성공적으로 연결되면 "Connected" message를 PC로 전송하며, Button이 Push 되면 LED가 ON이 되고 PC로 "B_ON"을 전송합니다. 그리고 Button이 Pull 되면 LED가 OFF 되고 PC로 "B_OFF"를 전송합니다.

 

여기까지가 HW 부분, 즉 Arduino 부분입니다.

 

 

 

 

 

이제 HW(Arduino)를 구성했으니, 연동을 위한 PC Program을 개발해야 합니다. PC Program은 Unity를 이용해 개발할 것입니다.

Serial 통신을 통해 Arduino와 PC가 Communication을 진행할 것입니다. 

우선, 다음과 같이 Serial 통신 부분을 구현합니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO.Ports;
using System.Threading;
using UnityEngine.Events;

public enum PortNum
{
    COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8
}

[System.Serializable]
public class SensorResult
{
    public string value;

    public SensorResult(string _value)
    {
        this.value = _value;
    }
}

[System.Serializable]
public class DataReceiveEvent : UnityEvent<SensorResult> { }

public class ArcadeButton_Event : MonoBehaviour
{
    [SerializeField]
    DataReceiveEvent onDataReceive;

    public PortNum Comport;
    SerialPort SP;
    
    Thread button_thread;
    private bool m_thread;
    private Queue<SensorResult> received_data;

    void Start()
    {
        try
        {
            received_data = new Queue<SensorResult>();

            SP = new SerialPort(Comport.ToString());
            SP.BaudRate = 115200;
            SP.Parity = Parity.None;
            SP.StopBits = StopBits.One;
            SP.DataBits = 8;
            SP.Handshake = Handshake.None;
            SP.RtsEnable = true;
            SP.Open();

            m_thread = true;
            button_thread = new Thread(() => { ReadButton(); });
            button_thread.Start();
        }
        catch (System.Exception e)
        {
            Debug.Log(e.Message);
        }
    }


    void Update()
    {
        try
        {
            if (received_data.Count > 0)
            {
                var cr = received_data.Dequeue();
                if (cr != null)
                {
                    onDataReceive.Invoke(cr);
                }
            }
        }
        catch (System.Exception e)
        {
            Debug.Log(e.Message);
        }
    }

    private void ReadButton()
    {
        try
        {
            while (m_thread)
            {
                string indata = SP.ReadLine();
 
                if (indata != null)
                {
                    if (indata == "B_ON")
                    {
                        received_data.Enqueue(new SensorResult("B_ON"));
                    }

                    if (indata == "B_OFF")
                    {
                        received_data.Enqueue(new SensorResult("B_OFF"));
                    }
                }
            }
        }
        catch (System.Exception e)
        {
            Debug.Log(e.Message);
        }
    }


    private void QuitThread()
    {
        try
        {
            if (button_thread != null)
            {
                button_thread.Abort();
                button_thread = null;
            }

            m_thread = false;
            SP.Close();
        }
        catch (System.Exception e)
        {
            Debug.Log(e.Message);
        }
    }
    private void OnApplicationQuit()
    {
        QuitThread();
    }
    private void OnDestroy()
    {
        QuitThread();
    }
}

Serial과 관련된 부분을 구현합니다. 앞서 Baudrate를 115200을 사용하자고 하였으므로 이를 맞춰줍니다. 그리고 이외의 것은 일반적으로 Default로 사용게 되는 값을 그대로 사용합니다. (특별히 정의한 Protocol이 없으므로) 해당 부분이 완료되었다면 Arduino를 PC에 연결하였을 때 연결된 Comport 번호를 통해 Connect 할 수 있도록 Comport 번호도 지정합니다.

Serial Data는 Thread 환경에서 Read 할 것입니다. ReadLine 단위로 읽을 것입니다. Read 된 Data를 비교하여 사전에 정의한 Message 비교하고 이에 따른 Event를 수행하도록 합니다.

 

위와 같은 Protocol과 관련된 Code 작성이 완료되었다면, 이에 따른 Event를 수행할 Script를 구현합니다.

우선, Scene과 Script는 다음과 같습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GetButtonEvent : MonoBehaviour
{
    [SerializeField]
    Text displayText;

    public void OnData(SensorResult result)
    {
        displayText.text = "UN-CLICKED";

        switch (result.value)
        {
            case "B_ON":
                displayText[0].text = "BUTTON PUSHED";
                break;
            
            case "B_OFF":
                displayText[0].text = "BUTTON PULLED";
                break;
        }
    }

    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
    }
}

동작은 간단합니다. Button이 Push 되었다는 신호를 받으면 Screen에 BUTTON PUSHED Message를 출력하고 Button이 Pull 되었다는 신호를 받으면 BUTTON PULLED Message를 출력합니다.

 

 

이와 같이 아주 간단하게 Arduino Arcade Button을 구성하고 이를 PC와 연동하는 것까지 수행해 보았습니다.

이와 같은 개발물을 통해 게임을 구현할 수도 있을 것이며, 어떠한 기계를 동작시킬 트리거를 만들 수도 있을 것입니다.

 

이번 포스트는 여기서 마무리하도록 하겠습니다!

 

 

반응형

댓글