[아두이노] 뽑기기계 횟수 락 원리

IOT/아두이노|2019. 7. 29. 09:00

[아두이노] 뽑기기계 횟수 락 원리



오늘은 횟수 락이 걸린 뽑기기계에 대한 아두이노시각으로 그 원리를 이해하는 시간을 가져보도록 하죠. 꼭 이렇게 뽑기 기계가 만들어진게 아니고 비슷한 느낌으로 아두이노에서 표현하여 살펴보도록 하죠.

1. 뽑기기계의 가상 설정



대충 위그림과 같은 뽑기 기계가 있다고 가정해 봅시다. 화살 막대기가 좌에서 우로 이동하면서 사각구멍 위치에 정확히 멈출 때 상품을 꺼낼 수 있게 됩니다. 이런류 게임을 해보신 분들은 뽑기기계가 락이 걸려서 일정 횟수 이상 돈을 넣고 도전을 해야 뽑을 수 있게 되어 있다는 것을 유튜버들의 뽑기영상을 보시면 간접 체험을 여러분들은 해보신 분들이 많을 꺼에요.

유튜버가 하는 말이 정확히 멈췄는데 약간 락이 풀릴 때까지 계속 멈춘 위치에서 좀더 이동해서 멈춘다고 이야기를 하는 소리를 많이 들었을 꺼에요. 계속 정확히 멈추는데 밀린다고 락이 걸려서 일정 횟수 이상 계속 해야지 뽑을 수 있다고 뽑기 락에 이야기를 많이 들었을 꺼에요.

여기서 횟수 락은 도대체 어떻게 하는 것일까 아두이노 시각으로 관찰하고 유사한 실험을 해볼까 합니다.

[특징]

  • 일정 횟수가 안되면 못 뽑는다.
  • 부정확한 위치에서는 그상태로 멈추지만 뽑는 위치에 멈추면 약간 밀리는 느낌으로 좀 더 이동한다.

이 특징을 가지고 이제 실험을 해 보겠습니다.

2. 횟수 락 회로도


  • 준비물 : Servo모터 1개, 스위치 버턴 2개, 아두이노 우노
  • 내용 : 스위치버턴은 인터럽트함수를 이용하기 위해 2,3번에 연결하고 Servo모터는 7번에 연결하시오.

실제 뽑기 기계에는 Stepper Motor로 움직이지만 가상시뮬레이터에서 실험을 간단히 하기 위해서 Servo모터로 대신 실험을 합니다.


횟수 락을 실험하기 때문에 스위치 버턴 2개로 Servo Motor를 제어하하면서 회전을 하는데 특정 각도에 범위에 대한 횟수 락 실험을 하게 됩니다. 그래서 복잡한 회로도 설계를 할 필요가 없고 이 회로도만으로 충분히 횟수 락 실험이 가능합니다.

3. 코딩


[설계]

  • 3번 스위치 버턴은 게임 시작
  • 2번 스위치 버턴은 멈춤(정지)
  • 2번 스위치 버턴을 눌러 멈춘 위치가 상품 범위에 들 때 횟수 카운트 하기
  • 횟수 카운트 할 때 상품 뽑기 횟수가 부족하면 멈춤 위치를 좀더 이동 시킴
  • 상품 뽑기 횟수에 도달하면 멈춤 위치가 상품을 뽑는 위치면 성공

스위치 버턴 동작
3번 스위치 버턴은 뽑기 시작버턴이고 2번 버턴은 뽑기 멈춤 버턴입니다. 인터럽트 함수를 이용하기 때문에 코딩은 다음과 같습니다.

const byte interruptPin1 = 3;
const byte interruptPin2 = 2;
boolean stateStart = false;
boolean stateStop = false;

void setup()
{
  pinMode(interruptPin1, INPUT_PULLUP);
  pinMode(interruptPin2, INPUT_PULLUP);  
  attachInterrupt(digitalPinToInterrupt(interruptPin1), exchange1, FALLING);  //인터럽트 발생 시 호출
  attachInterrupt(digitalPinToInterrupt(interruptPin2), exchange2, FALLING);  //인터럽트 발생 시 호출
}
void loop(){

  if(stateStart==true){
    뽑기시작;   
  }
 if(stateStop==true){ //뽑기정지
    뽑기정지;
 }
}
void exchange1() { //인터럽트스위치버턴  이벤트1
  stateStart=true;  
  stateStop=false;
}

void exchange2() { //인터럽트스위치버턴  이벤트2
  stateStart=false;
  stateStop=true; 
}

위 코딩을 보시면 stateStart, stateStop 변수의 상태 값으로 두가지 뽑기시작과 뽑기정지 버턴의 동작을 수행하게 됩니다.

뽑기시작 코딩은
Servo모터의 회전을 시작하도록 코딩이 이뤄집니다.

Servo servo;
const byte servoPin = 7; 

void setup(){
  servo.attach(servoPin);   
  servo.write(0);
  delay(1000);
}

위의 코딩은 Servo모터 초기상태입니다. 회전이 시작되기전 0도의 위치가 시작지점입니다.

0~180도로 왔다 갔다 회전을 하도록 뽑기시작 명령을 코딩하면 다음과 같습니다.

  if(stateStart==true){ //뽑기시작
    val+=stateNum;
    Serial.println(val);

    if(val==180)stateNum = -1;
    if(val==0)stateNum = 1;    
    
    servo.write(val);
    delay(50);
  }

val은 회전각입니다. stateNum은 180도가 되면 -1로 바뀌고 0도가 되면 1로 바뀌게 if문으로 제어해서 0~180도 회전이 1도씩 움직이게 됩니다. 이렇게 해서 뽑기가 시작되는 걸로 간주하시면 됩니다.

뽑기정지 코딩은
뽑기가 시작되면 이제 Servo모터를 정지시켜야 합니다. 뽑을 각도에 멈춰야 상품을 뽑을 수 있겠죠. 여기에 뽑기 횟수 락을 코딩을 하게 됩니다.

횟수 락은

    if(val>95 && val<105){ //뽑기 성공각도
      if(cnt<2){ //cnt 횟수 락
        cnt++;
        val=106;      
      }
      else cnt++;
    }
    else if(val>80 && val<120){ //상품 A의 횟수 증가 범위
      cnt++;
    } 
        servo.write(val);
    delay(100);

뽑기 성공하는 각도 범위는 95~105도 사이가 되면 뽑기가 성공됩니다. 하지만 횟수 락으로 cnt변수값이 3회이상이여야지만 뽑을 수 있게 락이 걸리게 됩니다. 즉, 아무리 95~105도 사이에 멈추더라도 cnt(횟수) 3회 미만이 되면 강제적으로 106도 각도로 움직이게 하여 약간 밀리는 느낌으로 뽑기 실패가 됩니다.

여기서 여러개의 상품이 있는데 A상품을 뽑는다고 가정한다면 A상품에 대한 뽑기 횟수가 증가해야 겠죠. B상품은 B상품에 대한 카운터를 해야 됩니다. 그렇기 때문에 A상품에 대한 횟수 락을 카운트 할 범위를 지정해 줘야 합니다. 위 코딩은 cnt는 A상품으로 여기면 됩니다.

만약, 여러개의 상품을 한다면 cntA, cntB, cntC 이런식으로 횟수 증가 범위를 개별적으로 증가시켜서 코딩하시면 됩니다.

아무튼 위 코딩으로 횟수락을 완성했네요. 3회 이상이 되지 않는 다면 아무리 완벽하게 성공 범위 지점에 정지시켜도 회적각이 밀리게 됩니다. 뽑기가 어떤 느낌인지 아시겠지요.

종합해보면,

#include <Servo.h>

Servo servo;
const byte servoPin = 7; 
const byte interruptPin1 = 3;
const byte interruptPin2 = 2;

boolean stateStart = false;
boolean stateStop = false;

int val = 0;
int cnt = 0;
int stateNum = 1;

void setup()
{
  Serial.begin(9600);
    
  pinMode(interruptPin1, INPUT_PULLUP);
  pinMode(interruptPin2, INPUT_PULLUP);  
  attachInterrupt(digitalPinToInterrupt(interruptPin1), exchange1, FALLING);  //인터럽트 발생 시 호출
  attachInterrupt(digitalPinToInterrupt(interruptPin2), exchange2, FALLING);  //인터럽트 발생 시 호출
  
  servo.attach(servoPin);   
  servo.write(0);
  delay(1000);
}

void loop()
{
  if(stateStart==true){ //뽑기시작
    val+=stateNum;
    Serial.println(val);

    if(val==180)stateNum = -1;
    if(val==0)stateNum = 1;    
    
    servo.write(val);
    delay(50);
  }
  
  if(stateStop==true){ //뽑기정지
    if(val>95 && val<105){ //뽑기 성공각도
      if(cnt<2){ //횟수 락
        cnt++;
        val=106;      
      }
      else cnt++;
    }
    else if(val>80 && val<120){ //상품 A의 횟수 증가 범위
      cnt++;
    }    
    servo.write(val);
    delay(100);
    
        //결과
    Serial.print("End Val : ");
    Serial.println(val);
    Serial.print("Count : ");
    Serial.println(cnt);
    if(cnt>2 && val>95 && val<105){ //성공 메시지와 cnt 초기화
      Serial.println("success!");
      cnt=0;
    }
    else Serial.println("failure!"); //실패 메시지
    
    //초기화
    val=0;
    servo.write(val);
    delay(200);    
    stateStop=false;    
  }  
}

void exchange1() { //인터럽트스위치버턴  이벤트1
  stateStart=true;  
  stateStop=false;
}

void exchange2() { //인터럽트스위치버턴  이벤트2
  stateStart=false;
  stateStop=true; 
}

4. 결과


원래 뽑기 성공범위는 좀 더 좁은 범위로 해야 하는데 녹화를 딱 맞게 하기 위해서 성공 범위를 좀 넓게 지정했네요. 횟수 락의 카운트 값은 2입니다. 3회부터서 성공 범위에 들면 뽑기 성공이 됩니다. 성공 범위가 아닌 뽑기 범위면 카운트만 세고 성공 범위인데 횟수가 부족하면 강제적으로 성공 범위를 벗어나게 하는 동작 소스입니다.

횟수 락에 의해서 성공 범위인 103각도에 멈췄지만 106도 강제적으로 이동시켜 실패하게 만들었네요.


횟수 락이 풀리고 성공 범위인 97각도에 멈춰고 97각도로 최종적으로 완료 되어 3회만에 성공이 되었네요.


만약에 3회 이후에 성공 범위에서 멈추지 못했다면 계속 성공할 때까지 도전해야 합니다.

아래 도전 영상을 올려 놓았습니다.


마무리


원래는 다른 post를 준비 중이였는데 문득 뽑기 횟수 락이 떠올라서 작성 중인 post를 멈추고 뽑기 횟수 락 실험을 하게 되었네요. 실제 뽑기가 이렇게 코딩이 되어졌다는 의미는 아니고요 관찰을 통해서 대충 이런 느낌이 아닐까 하고 그 느낌을 코딩화 했을 뿐입니다.
아두이노는 재밌는 것은 주변 환경을 관찰하고 그 관찰된 현상을 코딩화를 쉽게 할 수 있다는 점입니다. 최근 post들이 주변에 접할 수 있는 한번쯤은 경험했던 상황들을 아두이노적 시각으로 실험하고 있는데 여러분들도 이런 감각을 배우셨으면 합니다.


댓글()