아두이노 초음파 센서 자동 주차 - adu-ino cho-eumpa senseo jadong jucha

안녕하세요. 제로윈코딩입니다.

주차장 초음파센서를 아두이노 보드를 이용하여 구현해보았습니다.
2개의 차고 센서를 아두이노 보드 하나로 제어해야 하기 때문에 쓰레드를 생성하여 구현하였습니다.

준비물
아두이노 우노 1개
초음파센서 2개 : 차 진입시 감지 센서
부저 소리 2개 : 차 뺄때 부저 알람 소리나도록 구현
LED 2개 : 차있는지 표시 (빨간등: 차있슴, 녹색등: 비었슴)
LCD Display : 정보 표시(차 아이콘, 차 입고 경과 시간 표시) 

*만들어볼 것)

키패드와 서보모터 연동 후

암호가 맞지 않는다면 서보모터는 동작하지 않고

암호가 맞는다면 서보모터를 90도 동작하고 3초간 유지.

이를 다했다면

LCD Displays로 안내 문구를 보여주고

키패드에서 암호를 입력 시

암호가 맞다면 서보모터를 동작하고

초음파 센서로 차가 지나가는 동안

서보모터가 다시 돌아오지 않도록 구현.

#include <Password.h> //http://www.arduino.cc/playground/uploads/Code/Password.zip #include <Keypad.h> //http://www.arduino.cc/playground/uploads/Code/Keypad.zip #include <Servo.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 20, 4); #define TRIGPIN 11 // 트리거(송신쪽) 핀 (쏘다) trigger #define ECHOPIN 12 // 에코(수신쪽) 핀 (반향) #define CTM 10 // HIGH인 시간(µ 초) int dur; // 시간 차(µ초) float dis; // 거리(cm) Servo myservo; Password password = Password( "1234" ); const byte ROWS = 4; // Four rows const byte COLS = 4; // columns // Define the Keymap char keys[ROWS][COLS] = { {'*', '0', '#', 'D'}, {'7', '8', '9', 'C'}, {'4', '5', '6', 'B'}, {'1', '2', '3', 'A'} }; int p = 5; byte rowPins[ROWS] = { 9, 8, 7, 6 }; byte colPins[COLS] = { 5, 4, 3, 2, }; // Create the Keypad Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); void setup() { lcd.init(); lcd.backlight(); myservo.attach(10); lcd.setCursor(2, 0); lcd.print("PRESS THE KEY"); Serial.begin(9600); pinMode(TRIGPIN, OUTPUT); // 트리거 핀을 디지털 출력으로 설정 pinMode(ECHOPIN, INPUT); // 에코 핀을 디지털 입력으로 설정 keypad.addEventListener(keypadEvent); //add an event listener for this keypad } void loop() { keypad.getKey(); digitalWrite(TRIGPIN, HIGH); delayMicroseconds(CTM); digitalWrite(TRIGPIN, LOW); dur = pulseIn(ECHOPIN, HIGH); // HIGH가 되기까지 걸리는 시간을 측정 dis = (float) dur * 0.017; // 음속을 사용해서 거리 계산 } //take care of some special events void keypadEvent(KeypadEvent eKey) { switch (keypad.getState()) { case PRESSED: Serial.print("Pressed: "); Serial.println(eKey); lcd.setCursor(p, 1); lcd.print(eKey ); p ++; switch (eKey) { case '*': checkPassword(); break; //비밀 번호가 맞는지 체크하는 부분이 * case '#': password.reset(); break; //비밀번호를 리셋 default: password.append(eKey); } } } void checkPassword() { if (password.evaluate()) { Serial.println("Success"); //일치하면 Success lcd.clear(); lcd.setCursor(2, 0); lcd.print("OPEN"); int speedA = 180; myservo.write(speedA); p = 5; delay(5000); if (dis >= 100) { myservo.write(0); lcd.clear(); lcd.setCursor(2, 0); lcd.print("CLOSE"); delay(1000); lcd.clear(); lcd.setCursor(2, 0); lcd.print("PRESS THE KEY"); delay(10); p = 5; } } else { Serial.println("Wrong"); //불일치하면 Wrong lcd.clear(); lcd.setCursor(2, 0); lcd.print("WRONG"); delay(2000); lcd.clear(); lcd.setCursor(2, 0); lcd.print("PRESS THE KEY"); delay(10); p = 5; } }

코드는 위와 같이 작성함.

(비밀번호 입력 후 오픈 후 5초간의 딜레이 후

거리가 10 이상이된다면 다시 클로즈.

5초의 딜레이 후 거리가 10 미만이라면 오픈 유지)

아두이노 주차장 출입구 차량차단장치(아두이노)


  • 온라인 가상시뮬레이터 : https://www.tinkercad.com
  • 공개회로도 : https://www.tinkercad.com/things/dYmaAdhFfDA

일상을 주제로 주변에 상황을 아두이노로 표현하는 실험을 계속 진행 중입니다. 오늘은 아파트나 일반 주차장 또는 특정 건물에 차량을 진입하는 입구 쪽에 차량 차단장치가 설치되어 있는 곳들이 많습니다. 이 차량 차단장치를 아두이노적 시각으로 한번 실험을 해보도록 하겠습니다.

1. 주차장 출입구 차량차단장치 설정


아두이노 초음파 센서 자동 주차 - adu-ino cho-eumpa senseo jadong jucha

위와 같이 상황은 근접감지센서를 다른 것을 이용해야 하는데 실험에서는 초음파센서를 이용하여 근접감지를 하도록 상황을 만들고 차량이 출입구 쪽으로 다가오면 근접감지가 되고 그 감지되었을 때 차량차단막기 올라가게 됩니다. 차량차단막이 내려져 있을 때는 Red LED에 불이 들어와 있는 상태이고 차단막이 올라가면 Green LED에 불이 들어오고 차량이 통과된다는 설정입니다.

2. 아두이노 주차장 출입구 차량차단장치 회로도


  • 준비물 : 적색 LED 1개, 녹색 LED 1개, 저항 220옴 2개, 초음파센서, Servo모터, 아두이노우노
  • 내용 : 8,9번핀은 LED에 연결하고 초음파센서핀은 7번, Servo모터은 6번 핀에 연결하시오.

실제 초음파센서는 4핀이지만 가상시뮬레이터에서는 3핀 초음파센서로 7번핀으로 Trig, Echo 역활을 수행합니다.

아두이노 초음파 센서 자동 주차 - adu-ino cho-eumpa senseo jadong jucha

회로도는 복잡하지 않죠. 위 회로도는 각 역활은 아래 그림으로 이해하시면 되겠습니다.

아두이노 초음파 센서 자동 주차 - adu-ino cho-eumpa senseo jadong jucha

3. 코딩


  • 사전학습 :
    서보모터 제어(아두이노)
    초음파센서 제어(아두이노)

사전학습으로 Servo모터와 초음파센서에 대해서 한번 읽고 오세요. 사용하실 수 있는 분들은 그냥 넘어가셔도 됩니다.

[설계]

  • 초기신호등은 적색LED에 불이 들어온 상태가 되면 차량 정지를 의미한다.
  • 초음파센서로 근접거리가 일정거리이하가 되면 차량감지로 간주한다.
  • 차량감지가 되면 차량차단막이 올라간다는 느낌으로 Servo모터를 90도 회전한다.
  • Servo모터가 90도 회전이 되었다가 간주한 시점에 "적색->녹색" 등으로 변환시킨다.
  • 차량은 통과하는데 통과가 완료되었다고 생각되는 감지 시간을 기준으로 차단만은 일정시간 유지한다.
  • 마지막 차량 감지된 시간을 기준으로 일정시간 차단막이 올라가 있다가 차량이 통과했다고 생각 되는 시간에 차단막이 내려온다는 느낌으로 Servo모터를 0도로 회전시킨다.
  • 0도 회전을 할 때 "녹색->적색"등으로 변환시킨다.(정지)

차량감지

거리를 측정은 위 초음파센서 post의 거리 계산를 함수로 거리값을 구하게 됩니다.

int CalDistance (int Pin){  //초음파센서(3핀) 예제를 그대로 외부함수로 빼냄
  pinMode(Pin,OUTPUT); //출력모드로  사용
  digitalWrite(Pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(Pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(Pin,LOW);   
  
  pinMode(Pin,INPUT);    //입력모드로 사용
  int duration = pulseIn(Pin, HIGH);  
  int distance = duration / 57.5;  //가상시뮬레이션의 오차율을 줄이기 위해 이걸로 테스트 함.
  return distance; //거리값 리턴
}

거리를 구하게 되면 차량이 감지판정은 if문으로 만든다.

if(m_distance<50){ //50cm미터 미만일 때 차량 감지로 간주             
  차량감지 후 동작;
}

차량이 감지 후 동작은

  if(m_distance<50){   //50cm미만일 때 차단막 올리기 동작       
    if(state==false){  //초기값은 state=false상태로 처음에는 이 if조건문이 무조건 참이 된다.
      servo.write(90); //감지 되었기 때문에 Servo모터 90도 회전
      delay(2000);   //2초 동안 강제로 Servo모터가 회전하도록 설정
      state=true;     //다시 이 if조건문을 수행할 필요가 없기 때문에 state=true 설정     
      digitalWrite(rPin, LOW); //차단막이 올라갔으니 적색등 끄기
      digitalWrite(gPin, HIGH); //차량 통행하도록 녹색등 켜기
    }
    timeVal=millis(); //마지막 차량 감지된 시간을 저장함
  }  
  if(state==true){ //차단막 내리기 동작
    if(millis()-timeVal>=2000){ //마지막 차량 감지된 시간을 기준으로 차단막 유지시간이 지났는가 체크
      servo.write(0); //차단막 내리기
      state=false; //차단막이 내려졌으니 이 if조건문을 수행할 필요가 없기 때문에 state=fasle 설정
      digitalWrite(gPin, LOW); //차단막이 내려오니깐 녹색등은 끄기
      digitalWrite(rPin, HIGH); //차량 정지하도록 적색등 켜기
    }    
  } 

주석을 일일히 다 달아놓았으니깐 주석을 살펴보시기 바랍니다. 왜! if문을 state의 상태값으로 두가진 차단막 올리기/내리기 동작을 구분하였을 까요. 두 동작을 구분을 지어서 동작하게 하기 위해서요. 자세히 보시면 만약 차단막이 올라간 상태에서 계속 현재 차량이 감지되거나 계속 새로운 차량이 들어올 경우는 계속 차단막 올리는 명령을 내려야 합니다. 이미 올라갔는데 구지 반복 명령을 내릴 필요는 없이 현상태만 유지하면 됩니다. 그래서 if문으로 올라갔으면 내려가는 상황만 체크하면 되지 올라가는 상황을 동작할 필요없는 없습니다. 여기서, timeVal은 올라가는 상황 코딩 안에 다 넣지 않고 밖에다 빼낸 이유는 계속 초음파센서로 감지했을 때 마지막으로 감지된 시간을 기준으로 차단막의 유지시간을 결정하게 하기 위해서 입니다.

종합해보면,

#include <Servo.h>

Servo servo;
const byte servoPin = 6;
const byte pingPin = 7;
const byte gPin = 8;
const byte rPin = 9;
int m_distance=0;
boolean state = false;
unsigned long timeVal=0;

void setup()
{
  pinMode(gPin, OUTPUT);
  pinMode(rPin, OUTPUT);  

  servo.attach(servoPin); 
  servo.write(0);
  delay(1000);
  
  digitalWrite(rPin, HIGH);
}

void loop()
{
  m_distance=CalDistance(7);  //초음파센서로 거리계산함수  
  if(m_distance<50){            
    if(state==false){
      servo.write(90);
      delay(2000); 
      state=true;          
      digitalWrite(rPin, LOW);
      digitalWrite(gPin, HIGH);
    }
    timeVal=millis();
  }  
  if(state==true){
    if(millis()-timeVal>=2000){
      servo.write(0);
      state=false;
      digitalWrite(gPin, LOW);
      digitalWrite(rPin, HIGH);
    }    
  }  
}

int CalDistance (int Pin){  //초음파센서(3핀) 예제를 그대로 외부함수로 빼냄
  pinMode(Pin,OUTPUT); //출력모드로  사용
  digitalWrite(Pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(Pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(Pin,LOW);   
  
  pinMode(Pin,INPUT);    //입력모드로 사용
  int duration = pulseIn(Pin, HIGH);  
  int distance = duration / 57.5;  //가상시뮬레이션의 오차율을 줄이기 위해 이걸로 테스트 함.
  return distance; //거리값 리턴
}

loop()함수 내 로직만 설계에 맞게 코딩만 하면 오늘 코딩의 전부입니다. loop()함수 내 코딩은 몇줄 안되지만 설계의 내용을 다 포함되어 있네요. 글보다 코딩이 더 짧은 케이스네요.

4. 결과


가상시뮬레이터에서 결과입니다.

아두이노 초음파 센서 자동 주차 - adu-ino cho-eumpa senseo jadong jucha

5. 실제 테스트


정상적으로 동작하는지 실제로 구현해 봤네요.

1) 아두이노 주차장 출입구 차량차단장치 회로도


4핀짜리 초음파센서로 대충 실제 제작 모습과 동일하게 디자인 했네요.

아두이노 초음파 센서 자동 주차 - adu-ino cho-eumpa senseo jadong jucha

위 회로도를 실제 배치하고 선을 연결하니깐 아래와 같은 모습으로 좀 지져분하게 되었습니다.

아두이노 초음파 센서 자동 주차 - adu-ino cho-eumpa senseo jadong jucha

2) 코딩


  • 사전학습 :
    newPing 라이브러리로 초음파센서 제어(아두이노)

위의 가상시뮬레이터 코딩에서 newPing 라이브러리를 사용해서 그부분만 수정했습니다. 그리고 초음파센서가 4핀이니 trig, echo 핀을 정확하게 지정해 줘야 합니다.

코딩은 가상시뮬레이터 소스에서 newPing 라이브러리를 이용한 방식과 4핀 초음파센서 부분만 수정하면 됩니다.
그리고 주의할 점은 실제 초음파센서에서는 거리 측정값이 오류가 발생합니다. 이 오류를 해결하기 위해서 초음파센서값에 대한 평균값을 구해서 오류값을 막을 수 도 있지만 간단하게 오류값을 무시하는 방식을 취했습니다.

  if(m_distance>오류값 && m_distance<감지거리){       
      동작;
  }

제가 쓰는 초음파센서는 가끔 0과 10이하의 값들이 찍히네요. 그래서 실험에서는 10이상의 값들만 거리 판정을 내렸네요. 만약 결과가 정상적으로 나오지 않는다면 거리측정값을 시리얼통신을 통해 시리얼모니터로 그 결과를 찍어보시고 여러분들이 원하는 값으로 수정해 주시면 됩니다.

수정해보면,

#include <NewPing.h>
#include <Servo.h>

Servo servo;
const byte servoPin = 7; 
const byte gPin = 8;
const byte rPin = 9;
int m_distance=0; //거리
boolean state = false; //차단막 제어를 위한 상태값
unsigned long timeVal=0;

NewPing sonar(6, 5, 200); // (Trig, Echo. 거리제한)

void setup() {
  
  Serial.begin(9600);
  pinMode(gPin, OUTPUT);
  pinMode(rPin, OUTPUT);  

  servo.attach(servoPin); 
  servo.write(0);
  delay(1000);
  
  digitalWrite(rPin, HIGH);
}

void loop() {  
  delay(50);            
  m_distance=sonar.ping_cm();  //초음파센서로 거리계산함수  
  Serial.println(m_distance);
  if(m_distance>10 && m_distance<20){  //20cm는 의미가 있는 것은 아닙니다.
    if(state==false){
      servo.write(90);
      delay(2000); 
      state=true;          
      digitalWrite(rPin, LOW);
      digitalWrite(gPin, HIGH);      
    }
    timeVal=millis();
  }  
  if(state==true){
    if(millis()-timeVal>=3000){
      servo.write(0);
      state=false;
      digitalWrite(gPin, LOW);
      digitalWrite(rPin, HIGH);
    }    
  } 
}

3) 결과


10cm이하는 차량감지로 판정을 하지 않습니다. 그리고 20cm미만일 때 차량감지 파전을 내렸네요. 스마트폰으로 촬영하기 위해서 거리값을 최대한 줄여서 실험 했네요.