전문가칼럼

DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.

아두이노와 초음파센서로 생각하게 만들기

전문가칼럼
DBMS별 분류
Etc
작성자
dataonair
작성일
2014-09-01 00:00
조회
20485





아두이노 로봇 만들기 프로젝트

아두이노와 초음파센서로 생각하게 만들기



지난 시간에는 DC 모터를 이용해 로봇의 바퀴(다리) 부분을 만들고 로봇이 주행할 수 있도록 했고, 서보(servo)모터로 로봇의 팔을 움직이도록 구현했다. 이번 시간에는 초음파 센서의 사용법을 익히고, 로봇이 초음파 센서를 활용해 거리를 인식하고 행동에 변화를 줄 수 있도록 구현해 본다.



시리얼 통신

초음파 센서를 사용하기에 앞서 아두이노와 컴퓨터 간의 시리얼 통신 사용법을 알아본다. 시리얼 통신을 이용해 센서로부터 받은 값이나 일정 반응에 어떠한 값을 생성하는 지 확인하고 싶다면 아두이노 IDE의 시리얼 모니터로 확인할 수 있다. 이제 아두이노에서 제공하는 AnalogReadSerial 예제를 사용해 시리얼 통신을 사용해 보자. 시리얼 통신을 확인하기 위해 가변저항을 아두이노의 아날로그핀 0번(A0)에 연결한다. 시리얼 통신을 위해서는 Serial.begin() 함수를 사용한다. Serial.begin()은 시리얼 포트를 열고 데이터 속도를 맞춰주는 역할을 한다. 형태는 Serial.begin(speed);이며, 보통 9600bps의 속도를 사용한다. 시리얼 모니터에 글씨를 띄우려면 Serial.println() 또는 Serial.print() 함수를 사용한다. Serial.println()과 Serial.print() 모두 시리얼 모니터에 글씨를 표현하는 함수지만, Serial.println()은 글씨를 출력함과 동시에 한 줄을 띄우는 역할을 한다. 형태는 Serial.println(변수명); 또는 Serial.println(“문자”);로 사용한다.



column_img_1393.jpg

<리스트 1> AnalogReadSerial 예제
void setup()
{
Serial.begin(9600);
}
void loop()
{
int sensorValue = analogRead(A0);
Serial.println(sensorValue);
delay(1);
}

column_img_1394.png

<리스트 1>의 코드를 아두이노에 업로드하고 아두이노 IDE의 시리얼 모니터를 확인해 보면 가변저항을 움직일 때마다 시리얼 모니터에 나오는 숫자의 값이 바뀌는 것을 확인할 수 있다. 시리얼 모니터에 출력되는 값은 analogRead(A0)의 값으로, 이를 이용해 다양한 센서 값을 받아 시리얼 모니터로 확인할 수 있다.



초음파 센서

초음파란 사람이 들을 수 있는 음역대(가청)를 넘는 음파를 말한다. 초음파는 파장이 짧아 일정한 방향을 가진 음파를 만들어 낼 수 있다. 초음파 센서는 수신부와 발신부를 가지고 있으며, 발신부에서 발생시킨 초음파가 수신부로 반사되는 시간을 토대로 거리를 측정한다. 초음파 센서는 수신부와 발신부가 일체형인 것과 서로 분리된 형태의 두 가지가 있다. 필자는 분리형 초음파 센서인 SR04 모듈을 사용했다.



column_img_1395.png

초음파 센서의 발신부는 일정한 간격으로 초음파를 발사한다. 발신부에서 나온 초음파는 벽 또는 장애물에 부딧혀 돌아오는데, 이를 수신부에서 측정하게 된다. 이렇게 측정되기까지 걸린 시간을 토대로 장애물까지의 거리를 산출하게 된다. 초음파 센서는 장애물의 색상이나 얇은 막의 금속, 액체에 상관없이 음파가 반사돼 돌아오는 거리를 측정할 수 있다. 그러나 이번 시간에 사용할 초음파 센서는 저가의 모델이므로 곡선이나 대각선의 구조를 가진 장애물에 대해서는 잘 인식하지 못한다. 곡선 또는 대각선의 장애물에 대해 필자가 사용할 초음파 센서는 실제보다 훨씬 더 먼 거리의 값을 측정하게 되므로 주의해야 한다.



아두이노 연결

초음파 센서의 Triger 핀을 아두이노의 7번 핀에 연결하고, Echo 핀을 아두이노의 8번 핀에 연결한다.



column_img_1396.jpg

초음파 센서의 Vcc와 GND는 아두이노의 Vcc와 GND에 연결한다. 초음파 센서는 설치 각도와 대각선, 곡선 장애물과 같은 외부 환경에 민감하므로 설치 시 주의해야 한다.



초음파 센서 사용하기

이제 초음파 센서를 사용하기 위한 코드를 작성해 보자. 초음파 센서는 pulseIn() 함수를 사용해 제어할 수 있다. pulseIn() 함수는 해당 핀의 펄스에 대해 HIGH, LOW 값을 읽어서 HIGH 값이 들어오면 LOW 값이 들어올 때까지 기다리고, LOW 값이 들어오면 그 동안의 시간을 microseconds 단위로 반환한다. pulseIn은 pulseIn(pin번호,값);과 같이 입력해 사용한다.



<리스트 2> 초음파 센서로 거리 측정
int TrigPin = 7;
int EchoPin = 8;
int cm;
void setup()
{
Serial.begin(9600);
pinMode(TrigPin, OUTPUT);
pinMode(EchoPin, INPUT);
}
void loop()
{
digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
cm = pulseIn(EchoPin, HIGH) / 58.0;
Serial.print(cm);
Serial.println("cm");
delay(500);
}

초음파 센서는 발신부인 Triger 핀과 수신부인 Echo 핀으로 구성돼 있기 때문에 Triger 핀은 OUTPUT(출력), Echo 핀은 INPUT(입력)으로 설정해야 한다. <리스트 2>의 소스를 아두이노에 업로드하면 초음파 센서로부터 받은 값이 cm 단위로 변환되고, 해당 값을 아두이노 IDE의 시리얼 모니터로 확인할 수 있다. <리스트 2>는 0.5초마다 시리얼 모니터로 확인할 수 있는 소스이며, 시리얼 모니터로 받는 값을 빠르게 또는 더 느리게 받으려면 delay(500);에서 500에 해당하는 값을 변경하면 된다.



column_img_1397.png

팔 동작 만들기

초음파 센서로부터 받은 거리 정보를 토대로 거리에 따라 로봇의 팔 동작이 다르게 움직이도록 구현할 것이다. 로봇의 팔과 연결된 서보모터가 거리에 따라 다르게 반응하도록 함으로써 움직임에 변화를 줄 수 있다.



column_img_1398.jpg

<리스트 3> 거리에 따른 팔 동작 만들기
#include
Servo myservo;
Servo myservo2;
int TrigPin = 7;
int EchoPin = 8;
int cm;
void setup()
{
Serial.begin(9600);
pinMode(TrigPin, OUTPUT);
pinMode(EchoPin, INPUT);
myservo.attach(9);
myservo2.attach(10);
}
void loop()
{
digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
cm = pulseIn(EchoPin, HIGH) / 58.0;
Serial.print(cm);
Serial.println("cm");
if(cm< =5)
{
myservo.write(0);
myservo2.write(180);
delay(100);
}
else
{
myservo.write(0);
myservo2.write(90);
delay(100);
myservo.write(90);
myservo2.write(180);
delay(100);
}
}

초음파 센서에서 받은 거리를 cm 기준으로 원하는 거리 만큼 나눠 서보모터의 동작을 다르게 분리한다. 거리에 따른 동작을 세분화하려면 else if()를 통해 거리를 추가해야 한다. <리스트 3>의 소스를 아두이노에 업로드하면 초음파 센서가 벽과 5cm 이상 떨어져 있을 때 팔을 왔다갔다하는 동작을 반복하게 된다. 반대로 초음파 센서가 벽과 5cm 이하로 접근하면 로봇이 양 팔을 하늘로 번쩍 들어올리는 동작을 취하게 될 것이다.



자동 회피 기능 구현하기

column_img_1399.jpg

초음파 센서로부터 받은 거리 정보를 토대로 장애물과 로봇이 일정 거리 이하로 가까워지면 오른쪽 또는 왼쪽으로 회피하는 기능을 구현할 것이다.



<리스트 4> 자동 회피 기능
int TrigPin = 7;
int EchoPin = 8;
int cm;
int motor1a = 3;
int motor1b = 4;
int motor2a = 5;
int motor2b = 6;
void setup()
{
Serial.begin(9600);
pinMode(TrigPin, OUTPUT);
pinMode(EchoPin, INPUT);
pinMode(motor1a, OUTPUT);
pinMode(motor1b, OUTPUT);
pinMode(motor2a, OUTPUT);
pinMode(motor2b, OUTPUT);
}
void loop()
{
digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
cm = pulseIn(EchoPin, HIGH) / 58.0;
Serial.print(cm);
Serial.println("cm");
if(cm< =5)
{
digitalWrite(motor1a, LOW);
digitalWrite(motor1b, HIGH);
digitalWrite(motor2a, LOW);
digitalWrite(motor2b, HIGH);
delay(500);
digitalWrite(motor1a, LOW);
digitalWrite(motor1b, LOW);
digitalWrite(motor2a, HIGH);
digitalWrite(motor2b, LOW);
delay(500);
}
else
{
digitalWrite(motor1a, HIGH);
digitalWrite(motor1b, LOW);
digitalWrite(motor2a, HIGH);
digitalWrite(motor2b, LOW);
delay(500);
}
}

<리스트 4>는 로봇이 앞으로 나아가다가 벽 또는 장애물을 만났을 때 후진한 후 좌 또는 우회전함으로써 장애물을 피하도록 구현한 코드다.



로봇 구성하기

이제 이전까지 아두이노와 부품을 연결했던 것과 코드를 합쳐 로봇의 전체적인 움직임을 만들어 보자. 아두이노와 부품들의 연결이 다소 복잡해 보이더라도 각 부품별로 하나씩 차근차근 연결하다보면 어렵지 않게 연결을 마칠 수 있다. 아두이노와 부품 간의 연결이 끝나면 구성한 로봇의 내부에 아두이노를 비롯한 부품들을 삽입하고 팔을 구성하는 서보모터와 다리 역할을 하는 DC 모터를 단단하게 고정시킨다.



column_img_1400.jpg

column_img_1401.png

<리스트 5> 전체적인 아두로봇의 소스 코드
#include
#define TrigPin 7
#define EchoPin 8
Servo myservo;
Servo myservo2;
int motor1a = 3;
int motor1b = 4;
int motor2a = 5;
int motor2b = 6;
void setup()
{
pinMode(TrigPin, OUTPUT);
pinMode(EchoPin, INPUT);
myservo.attach(9);
myservo2.attach(10);
pinMode(motor1a, OUTPUT);
pinMode(motor1b, OUTPUT);
pinMode(motor2a, OUTPUT);
pinMode(motor2b, OUTPUT);
}
void loop()
{
int cm;
digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
cm = pulseIn(EchoPin, HIGH) / 58;
delay(50);

if(cm < = 5)
{
myservo.write(0);
myservo2.write(180);
//delay(50);
digitalWrite(motor1a, LOW);
digitalWrite(motor1b, HIGH);
digitalWrite(motor2a, LOW);
digitalWrite(motor2b, HIGH);
delay(500);
digitalWrite(motor1a, LOW);
digitalWrite(motor1b, LOW);
digitalWrite(motor2a, HIGH);
digitalWrite(motor2b, LOW);
delay(500);
}
else
{
myservo.write(0);
myservo2.write(90);
delay(500);
digitalWrite(motor1a, HIGH);
digitalWrite(motor1b, LOW);
digitalWrite(motor2a, HIGH);
digitalWrite(motor2b, LOW);
myservo.write(90);
myservo2.write(180);
delay(500);
}
}

<리스트 5>를 아두이노에 업로드하면 로봇이 장애물의 거리를 파악해 팔의 움직임을 달리하며 이동하게 된다. 로봇의 팔이 예상과 다르게 움직인다면 처음에 연결한 서보모터와 팔의 결합 위치가 달라져 발생하는 것이므로 서보모터의 각도를 변경하거나 원하는 각도에 맞게 팔을 다시 붙여 완성한다. 로봇이 설정해 놓은 거리보다 많이 멀거나 짧을 때 작동한다면 코드의 delay()를 조절하거나 초음파 센서가 전방을 향하고 있는지 다시 점검해 보자. 같은 DC 모터라도 저가의 모터일 경우 모터의 세기가 많이 다를 수 있다. 이 경우 로봇이 직진을 하지 못하고 원을 그리며 움직이게 된다. 이럴 때는 아두이노에 연결된 motor1a, motor1b, motor2a, motor2b 핀을 PWM이 가능한 핀으로 옮겨 모터의 출력을 PWM으로 조절해 직진이 되는 구간을 찾아 코드를 완성한다.



블루투스 무선 조종

지금까지 우리는 자동으로 움직이는 로봇을 만들어 봤다. 이번에는 무선으로 조종할 수 있는 로봇을 구현해 보자. 로봇을 무선 조종하기 위해 필자는 블루투스 모듈을 사용할 것이다. 블루투스는 근거리 무선통신 기술로 약 10m 정도의 통신 범위를 가진다. 이 범위는 일반적으로 100m까지 연장할 수 있다. 블루투스의 무선통신은 ISM 대역을 사용하는데, 다른 통신과의 간섭을 막기 위해 2.402GHz에서 2.480GHz의 79개 채널을 사용한다. ISM은 산업, 과학, 의료용으로 할당된 주파수 대역으로 전파 사용 허가를 받을 필요가 없어 저전력의 전파를 사용하는 개인용 무선 기기에 많이 사용된다. ISM 대역은 일반적으로 무선랜, 블루투스, 아마추어 무선 기기 등에서 사용하고 있다.



column_img_1402.jpg

필자가 사용할 블루투스 모듈은 HC-06 모델이다. 아두이노와의 연결은 블루투스 모듈에서 Vcc, GND, TXD, RXD 핀만 사용한다. TXD는 발신부이고 RXD는 수신부다. 일반적으로 블루투스 모듈은 Vcc에 3.3V를 인가한다.



column_img_1403.jpg

<리스트 6> 블루투스를 이용해 로봇 조종하기
#include
#include
SoftwareSerial BTSerial(11,12);//RX,TX
Servo myservo;
Servo myservo2;
int motor1a = 3;
int motor1b = 4;
int motor2a = 5;
int motor2b = 6;
void setup()
{
BTSerial.begin(9600);
myservo.attach(9);
myservo2.attach(10);
pinMode(motor1a, OUTPUT);
pinMode(motor1b, OUTPUT);
pinMode(motor2a, OUTPUT);
pinMode(motor2b, OUTPUT);
}
void loop()
{
if(BTSerial.available()>0)
{
char a = BTSerial.read();
if(a == 'w')
{
digitalWrite(motor1a, HIGH);
digitalWrite(motor1b, LOW);
digitalWrite(motor2a, HIGH);
digitalWrite(motor2b, LOW);
}
else if(a == 'x')
{
digitalWrite(motor1a, LOW);
digitalWrite(motor1b, HIGH);
digitalWrite(motor2a, LOW);
digitalWrite(motor2b, HIGH);
}
else if(a == 'a')
{
digitalWrite(motor1a, LOW);
digitalWrite(motor1b, LOW);
digitalWrite(motor2a, HIGH);
digitalWrite(motor2b, LOW);
}
else if(a == 'd')
{
digitalWrite(motor1a, HIGH);
digitalWrite(motor1b, LOW);
digitalWrite(motor2a, LOW);
digitalWrite(motor2b, LOW);
}
}
}

column_img_1404.jpg

<그림 11>과 같이 연결하고 <리스트 6>을 아두이노에 업로드하면 로봇에 대한 부분이 완성된다. 이제 앱 마켓에서 블루투스 앱을 검색해 마음에 드는 것을 다운로드하자. 스마트폰과 로봇의 블루투스를 앱으로 연결한 다음 움직이는 명령어를 입력하면 로봇이 움직이는 것을 확인할 수 있다.



어렵지 않은 아두이노 로봇 구현

이번 시간에는 지난 시간에 DC 모터와 서보모터를 활용해 움직임을 구현했던 로봇에 초음파 센서를 추가해 스스로 장애물을 피하도록 만들어 봤다. 또 더 나아가 블루투스를 활용해 스마트폰 앱으로 로봇을 무선 제어하는 것도 시도해 봤다. 이처럼 각종 센서와 아두이노를 활용하면 자신이 꿈꿔왔던 것들을 직접 구현해 볼 수 있다. 아두이노나 레고에 관심 있는 독자들이 이번 연재를 통해 배운 내용을 응용해 자신이 꿈꿔왔던 세계를 직접 구현하며 상상의 나래를 펼칠 수 있길 바란다.