[아두이노] 초음파레이더 만들기(기본동작제어)

IOT/아두이노|2019. 2. 21. 10:16

[아두이노] 초음파레이더 만들기(기본동작제어)



이번시간에 초음파레이더를 기본동작 원리를 실험하는 시간을 갖도록 하겠습니다. 가장 많이 검색되는 주제이기도 하죠. 현재 초음파센서가 없는 관계로 실제 구동 장면은 추가하고 싶었는데 아쉽게 못 보여 드리네요. 그래도 가상시물레이터에서 충분히 표현이 되니깐 실제 만드는 것은 그리 어렵지 않을꺼에요. 물론 거리계산에 따른 오차율 보정 작업이 필요하지만요. 오늘은 서보모터를 회전시키면서 초음파센서로 거리를 측정하고 그 값을 아두이노 IDE 시리얼모니터로 거리 값이 동시에 출력되게 표현 함으로 초음파레이더의 기본 원리를 배워보도록 하죠.

1. 초음파센서 복습


제 블로그에서 정리할 때 함수로 표현했었습니다. 초음파센서로 거리를 측정하는 로직을 따로 외부함수로 만든 것을 그대로 인용해서 적용하겠습니다.int distance = duration / 57.5; 이것은 가상시뮬레이터에 대충 거리를 보정한 값이고 실제로는 공식을 해보고 거리값의 오차가 있으면 약간씩 값을 바꾸면서 거리값을 보정하시면 됩니다.

  • 공식 : ((float)(340 * duration) / 10000) / 2; (340은 초음기종에 따라 달라질 수 있는점 참고)
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; //거리값 리턴
}

이렇게 함수로 만들어 놓으면 나중에 초음파센서를 사용할 때 이 함수를 복사하시면 되겠죠. 이건 3핀 초음파센서여서 사실 4핀 초음파센서에서는 TRIG, ECHO핀이 따로 존재하기 때문에 setup()함수에서 각 핀을 선언해주시면 되기 때문에 CallDistance()함수에서 핀의 출력/입력모드를 선언할 필요가 없습니다. 가상시뮬레이터에서는 3핀이여서 어쩔 수 없이 추가된 것이기 때문에 실제로 1200원 짜리 4핀 초음파센서를 사용하시면 핀모드 선언을 지워주셔서 함수를 사용하시면 됩니다.
쏘는것은 TRIG, 받는 것은 ECHO 핀인 것만 기억하시면 쉽게 변경되시겠지요. 즉, 3핀 초음파센서에서 출력모드일 때 TRIG이고 입력모드일 때 ECHO라고 생각하시면 됩니다.

2. 서보모터 복습


#include <Servo.h>
 
 Servo servo;
 int servoPin = 9;
 
 servo.attach(servoPin); //angle (0~180)
 servo.write(m_angle);
 delay(50);
 
 m_angle+=1; or m_angle= m_angle+1;

9번핀을 servo모터의 출력핀으로 연결하고 servo.write()로 각도(angle)만큼 이동하는데 마지막 라인의 m_angle은 +1씩 증가합니다. 즉 0도에서 1도씩 계속 servo모터를 회전하게 되는 것이죠. 딜레이시간은 1도여서 아주 짧게 0.05초를 줬습니다.

3. 회로도 구성


  • 준비물 : 서보모터 1개, 초음파센서 1개, 아두이노우노
  • 내용 : 0~180도 서보모터를 회전시키면서 초음파센서로 거리를 측정해보자.


가장 간단한 회로도 입니다. 대충 회로도를 보시고 해당 위치의 핀에 선을 연결하시면 됩니다.

4. 코딩


  • 사용함수 : attach(사용핀), write(각도), pulseIn(입력핀, HIGH), Serial.begin(9600), Serial.print(출력값),Serial.println(출력값)
  • 내용 : 간단히 0~180의 범위를 1도씩 회전하면서 초음파로 거리를 측정하여 아두이노시리얼모니터에 거리값을 출력한다.

설계는 위의 1, 2에서 복습 차원의 코딩을 그대로 사용했습니다. 중요한 것은 0에서 180도 까지 1도씩 회전시키고 다시 180에서 0도까지 1도씩 회전하는 것이죠.

설계

(1) 제어 변수를 만든다.

Servo servo; 
int servoPin = 9;

int m_distance=0;
int m_angle=0;
int m_chk=0;
  • servo : 서보클래스 객체 선언
  • servoPin : 서보모터 제어하는 핀번호
  • m_distance : 거리 계산값(초음파센서로 거리측정동작을 수행하는 CalDistance()함수로 구한 값이 저장)
  • m_angle : 서보모터의 회전각(write()함수로 서보모터를 실제 회전)
  • m_chk : 회전 방향 상태값(초기값 0은 0에서 180도로 회전을 뜻하고 1은 180도에서 0도로 회전을 뜻한다.)

(2) m_chk 변수가 회전 방향 상태를 나타내고 제어하는 방법

if(m_chk==0){
    if(m_angle<180)m_angle+=1;
    else m_chk=1;
  }
  else{
    if(m_angle>0)m_angle-=1;
    else m_chk=0;
  }

if 조건문으로 m_chk변수의 초기값이 0이다 m_angle(각)도 0도이다. 조건식이 m_chk==0 으로 m_chk가 0과 같은가 아닌가로 물어본다. 두가지 패턴으로 분리되는 순간이다. 0가 같다면 참인문장이 1이면 거짓문장이 수행 되겠죠. m_chk변수가 초기값으로 0임으로 참이 된다. 그 안에 다시 if문으로 m_angle(각)이 180도보다 작은가가 조건식이 걸려있다. 180도보다 작으면 m_angle+=1;로 m_angle=m_angle=+1과 같은 문장이다. 즉, m_angle(각)은 1도ㅀ 증가하게 된다. 그런데 만약에 m_angle(각)가 180도 이상이 되면 else 이하 문장이 수행됩니다. m_chk=1로 회전 방향 상태값이 바뀌게 됩니다. 그러면 다음 루프때 if 조건문 m_chk가 0이 아니기 때문에 else 이하 문장이 수행되고 반대로 m_angle 변수가 0보다 크냐고 붇고 크면은 m_angle-=1로 -1도로 감소하게 된다. 위 코딩하고는 반대 동작을 수행하는 것이죠.

다시 종합해서 설명하자면 m_chk변수 기준으로 0이면 m_angle 값이 180도가 될때까지 1씩 증가하고 180도가 되면은 m_chk변수를 1로 변경하고 m_chk변수가 1이면 m_angle 값이 0도가 될때까지 -1씩 감소하게 된다. 그리고 0도가가 되면 m_chk변수를 0으로 변경한다. 이렇게 무한 반복하게 되는 로직입니다.

(3) 결과는 아두이노 IDE 시리얼모니터로 출력

Serial.begin(9600);

Serial.print("d : ");
Serial.println(m_distance);

begin(9600)은 setup()함수에 선언하고 나머지 모니터 출력은 print(출력값)와 printIn(출력값)함수가 있는데 print()은 출력값을 출력하고 새로운 라인으로 넘어가지 않고 현재 라인에 머문다. printIn()은 출력값을 출력한뒤에 새로운 라인으로 넘어가라는 의미 입니다. 문서 장성할 때 키보드 Enter 명령으로 생각하시면 됩니다. C언어에서는 '\n'로 생각하시면 됩니다.

Serial.print("d : ");
Serial.println(110);

결과 => d : 110

대충 의미를 이해하셨겠죠.

코딩을 하면

#include <Servo.h>

Servo servo; 
int servoPin = 9;
int m_distance=0;
int m_angle=0;
int m_chk=0;

void setup() {
  Serial.begin(9600);
  servo.attach(servoPin); //angle (0~180)
}

void loop() {
  servo.write(m_angle);
  delay(50);
  
  m_distance=CalDistance(7);  //초음파센서로 거리계산함수   
  Serial.print("d : ");
  Serial.println(m_distance);
    
  if(m_chk==0){
    if(m_angle<180)m_angle+=1;
    else m_chk=1;
  }
  else{
    if(m_angle>0)m_angle-=1;
    else m_chk=0;
  }
}

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; //거리값 리턴
}

5. 결과


가상시뮬레터에서 실험 결과는 깔끔하게 나왔는데 실제 표현에서는 보정 작업이 꼭 필요 합니다.

그리고, 원래 실제로 초음파레이더를 만든다면 그래픽작업으로 레이더를 만들어 레이더에 검색된 물체를 현재회전각과 거리값으로 (x,y)의 좌표를 구할 수 있고 그걸 그래픽작업한 모니터에 원하는 형태로 그래픽모양을 출력하면 좀 더 그럴싸해 지겠죠.

여기에서는 단지 아두이노 IDE 시리얼모니터에 거리값만 출력했습니다. 그게 기본 초음파레이더의 정보입니다. 서보모터의 각도와 거리만 있으면 측정된 물체의 (x,y) 좌표를 구할 수 있고 그것을 프로세싱이나 스크래치로 이미지화 하면 보기가 더 좋겠지만 핵심은 그게 아니로 회전과 거리 측정을 동시에 수행한다는 것에 있습니다. 이미지 시각화를 단지 보여주는 부수적인 효과일뿐이죠. 동영상을 보시고 서보모터가 회전하면서 시리얼모니터에 초음파 센서의 거리가 측정되어 출력되는 걸 잘 보시고 상상을 해보세요. 서보모터에 초음파센서가 부착되어 회전되는데 그 회전하는 각도에 정면의 물체와의 거리를 측정하는 모습을요. 그러면 아마 대충은 이해가 되실 꺼에요.

마무리


간단히 초음파레이더의 기본 로직만 설명했습니다. 그리고, 오늘 포스팅한 코딩은 사실 정교한 제어라고 할 수 없습니다. 왜냐면 서보모터 종류에 따라 좀 다르게 회전이 되는 경우가 있습니다. 참고로 코딩에서 servo.attach(servoPin, Min, Max)로 범위를 설정하고 servo2.writeMicroseconds(각도시간값)으로 제어하시면 더 정교하게 제어가 가능할꺼에요. 실제로 테스트 할때는 위 방식대로 해보다가 안되면 이 방식으로 바꿔서 서보모터의 각도를 제어하시면 됩니다. 4핀이였으면은 현실 4핀 서보모터랑 동일해서 더 편했을텐데 3핀 초음파센서여서 약간 코딩이 아쉽습니다.

추가로 스크래치나 프로세싱 프로그램을 다룰 수 있는 분이라면 그걸 통해서 초음파레이더에 그래픽처리를 통해 실제 레이더처럼 표현이 가능할 꺼에요. 프로세싱을 제대로 공부한적이 없고 잠깐 맛보기로 함수만 몇개 써본게 전부라 프로세싱 프로그램을 사용하여 레이더 그래픽효과를 다음편에 추가해서 보여주고 싶긴 하는데 할까 말까 고민되네요. 잠깐 프로세싱에서 레이더 표현 그래픽 함수 몇개만 공부해서 로직을 짜면 되기는 한데 프로세싱을 새로 설치하고 공부하기가 좀 귀찮아서 생략할지 아니면 표현을 할지 고민을 해 봐야 겠네요.

오늘의 포스팅의 내용은 서모모터회전을 하면서 초음파센서로 거리를 측정한다 이것만 머리속에 넣으시면 됩니다.


댓글()