아두이노 로봇카
Link
Contents
아두이노 로봇카 실습 세부목차
4. 더듬이센서로 주행하기
6. 적외선센서로 주행하기
7. 주행거리 제어하기
※ 본 페이지의 내용은 패럴렉스(Learn.Parallax.com)사의 공식 홈페이지에서 제공되는 자료를 참고하여 작성되었습니다. 또한, 본 내용은 아두이노 neo-로봇카v2 또는 아두이노 로봇카N 키트실습에 사용할 수 있습니다.
본 자료의 원문을 참조하려면 패럴렉스 사의 아두이노를 위한 로보틱스 홈페이지를 방문할 수 있습니다. 이 자료의 로봇카 모든 제어명령 및 센서신호 수집작용은 프라이비 보드 또는 아두이노를 통하여 수행됩니다. 프라이비 보드는 아두이노 우노와 동일한 ATmega328P 마이컴이 사용된 호환보드이며, 아두이노 우노와 동일한 사용법이 적용됩니다.
여기서는 적외선 송수신 수단을 이용하여 조금 더 성능이 개선된 로봇카 주행동작을 실습할 수 있습니다. 단순히 외부의 빛을 감지하는 것에 그치지 않고, 적외선 송수신 수단을 이용하여 전방의 물체를 인식하는 것에 관한 것입니다.
훨씬 더 영리해진 센서로 주행하는 로봇카를 아래 세부 내용들을 살펴볼 수 있습니다.
1) 적외선 송수신 장치 만들기
2) 적외선 감지센서 현장 테스트
3) 적외선 감지센서로 로봇카 주행하기
4) 로봇카 낭떠러지 감지하기
적외선(Infrared) 빛은 IR 이라고 부르기도 합니다. 이 빛은 사람의 눈으로 볼 수 없지만, 주변에서 많이 사용되는 빛이기도 합니다. 예를 들면 TV 리모콘으로 TV를 켜고 끄거나 채널을 변경하는 동작들을 적외선 빛의 신호로 수행할 수 있습니다.
이 장에서는 적외선 수신부가 적외선 빛을 감지하는데, 앞 장에서처럼 적외선 빛의 세기를 감지하는 것이 아니라 적외선 빛이 있는지 없는지를 매우 빠르게 감지하도록 설계되어 있습니다. 적외선 빛의 깜박임 정도는 38KHz (초당 약 38,000회) 로 매우 빠르게 깜박이면서 데이터를 전송합니다. 이런 동작은 TV 리모콘 동작에 사용하는 방식과 같습니다.
지금부터 아두이노 로봇카에 설치할 적외선 송수신장치를 만들고, 테스트할 것입니다. 아래 부품들을 준비합니다.
이번 실습에 사용될 부품은 제6장에서 사용했던 포토트랜지스터가 아니라, 적외선 LED 부품이어야 합니다. 아래 그림을 참고하여 적외선 LED 부품을 준비하도록 합니다.
IR LED를 사용하여 아래 그림처럼 전조등을 만듭니다.
IR 전조등을 만들었다면 아래 회로도를 참고하여 감지회로를 구성해야 합니다.
전자회로 구성이 완성되었다면, 이제 아두이노에 업로드할 스케치를 살펴볼 차례입니다. 아래 소개하는 코드를 살펴보기 바랍니다. 적외선 감지센서 수신부는 980 nm 파장의 빛을 38KHz 가까운 속도로 감지하는 것입니다. 이와 같은 적외선 빛의 ON/OFF 신호속도를 만들기 위해, 부저(또는 피에조스피커)에서 사용했던 tone() 함수를 사용하여 특정 주파수의 소리를 내는 것과 비슷하게 IR LED 부품을 다룰 수 있습니다.
적외선 감지 단계
1) IR LED ON/OFF 속도를 38KHz 속도로 비춘다.
2) 물체에서 반사된 적외선 빛을 보내기 위해 IR 수신부는 1/1000초 정도 더 지연시킨다.
3) IR 수신부 상태를 확인한다.
tone(9, 38000, 8); // IRLED가 38 kHz 로 최소 1 ms 지속
delay(1); // Wait 1 ms
int ir = digitalRead(10); // IR receiver -> ir variable
스케치에서 IR LED 는 디지털핀 9번에 연결하고, IR 수신부는 디지털핀 10번에 연결되어야 합니다. tone() 함수에서 실제 지속시간은 8 ms이지만, 아두이노 소프트웨어 버전 V1.0 에서는 1.1 ms 시간동안만 유지됩니다.
다음 스케치는 세 개의 매개변수로 irDetect 라고 하는 함수를 정의합니다. 하나는 IR LED 핀이고, 다른 하나는 IR 수신부 핀을 정의하고, 나머지는 IR LED 가 깜박이는 주기를 설정하기 위한 것입니다.
int irDetect(int irLedPin, int irReceiverPin, long frequency)
스케치에서의 3개 매개변수를 사용하여, 함수는 적외선으로 물체를 감지할 때와 감지하지 않았을 때 0 과 1 의 값을 리턴할 수 있습니다. 이 리턴값은 irLeft 또는 irRight 에 저장될 수 있습니다.
void setup() {
tone(4, 3000, 1000);
delay(1000);
pinMode(10, INPUT);
pinMode(9, OUTPUT);
Serial.begin(9600);
}
void loop() {
int irLeft = irDetect(9, 10, 38000);
Serial.println(irLeft);
delay(100);
}
int irDetect(int irLedPin, int irReceiverPin, long frequency) {
tone(irLedPin, frequency, 8);
delay(1);
int ir = digitalRead(irReceiverPin);
delay(1);
return ir;
}
지금부터 적외선 센서로 물체 감지를 점검할 것입니다. 그렇지만, 형광등 불빛아래에서 적외선 감지 실습을 진행하는 경우 형광등 내부 안정기에서 38.5 KHz 적외선 신호가 발생하는 문제 때문에 신호의 간섭이 생길 수 있습니다. 또한, 적외선 신호는 눈에 보이지 않기 때문에 실습상황을 보다 정확히 관찰하기 위하여 추가로 LED 회로를 구성합니다. 아래 회로를 참고하여 구성하세요.
LED 회로가 추가로 디지털핀 7번과 8번에 연결되었다면 아래 예제 스케치를 업로드하여 결과를 관찰해봅시다.
void setup() {
tone(4, 3000, 1000);
delay(1000);
pinMode(10, INPUT); pinMode(9, OUTPUT);
pinMode(3, INPUT); pinMode(2, OUTPUT);
pinMode(8, OUTPUT); pinMode(7, OUTPUT);
Serial.begin(9600);
}
void loop() {
int irLeft = irDetect(9, 10, 38000);
int irRight = irDetect(2, 3, 38000);
digitalWrite(8, !irLeft);
digitalWrite(7, !irRight);
Serial.print(irLeft);
Serial.print(" ");
Serial.println(irRight);
delay(100);
}
int irDetect(int irLedPin, int irReceiverPin, long frequency) {
tone(irLedPin, frequency, 8);
delay(1);
int ir = digitalRead(irReceiverPin);
delay(1);
return ir;
}
여기서 irDetect 함수는 물체가 감지되지 않으면 1, 물체가 감지되면 0 을 반환하여 irLeft 와 irRight 값으로 저장합니다. 그리고 irLeft 와 irRight 에 0 이 저장되면 각각 연결된 빨간색 LED 를 켜고 1이 저장되면 LED 를 끕니다. 물론 물체가 감지될 때 not 연산자를 사용하여 LED 불빛을 반대의 동작으로 끌 수도 있습니다.
적외선 센서를 사용하여 물체와의 거리를 감지하거나, 색상에 따른 결과를 측정해볼 수도 있습니다. 그리고 형광등 불빛에 의한 간섭효과를 관찰할 수도 있습니다.
적외선 센서로 0 또는 1 의 감지값을 반환받는 원리는 더듬이 촉각센서와 동일한 원리입니다. 따라서 더듬이 센서를 이용한 로봇카 주행동작 스케치를 수정하여 사용할 수 있습니다. 수정된 스케치를 아래에서 소개합니다.
#include <Servo.h>
Servo servoLeft;
Servo servoRight;
void setup() {
pinMode(10, INPUT); pinMode(9, OUTPUT);
pinMode(3, INPUT); pinMode(2, OUTPUT);
tone(4, 3000, 1000);
delay(1000);
servoLeft.attach(13);
servoRight.attach(12);
}
void loop() {
int irLeft = irDetect(9, 10, 38000);
int irRight = irDetect(2, 3, 38000);
if((irLeft == 0) && (irRight == 0)) {
backward(1000);
turnLeft(800);
}
else if(irLeft == 0) {
backward(1000);
turnRight(400);
}
else if(irRight == 0) {
backward(1000);
turnLeft(400);
}
else {
forward(20);
}
}
int irDetect(int irLedPin, int irReceiverPin, long frequency) {
tone(irLedPin, frequency, 8);
delay(1);
int ir = digitalRead(irReceiverPin);
delay(1);
return ir;
}
void forward(int time) {
servoLeft.writeMicroseconds(1700);
servoRight.writeMicroseconds(1300);
delay(time);
}
void turnLeft(int time) {
servoLeft.writeMicroseconds(1300);
servoRight.writeMicroseconds(1300);
delay(time);
}
void turnRight(int time) {
servoLeft.writeMicroseconds(1700);
servoRight.writeMicroseconds(1700);
delay(time);
}
void backward(int time) {
servoLeft.writeMicroseconds(1300);
servoRight.writeMicroseconds(1700);
delay(time);
}
더듬이 센서로 로봇카 주행하는 스케치에서 적외선 센서를 사용하는 조건으로 변경한 것입니다. 위 스케치는 더듬이 센서로 주행할 때는 꽤 유용했지만, 적외선 센서로 주행하는 경우에는 유용하게 느끼지 못할 수 있습니다.
우선, 더듬이 센서는 직접 물체와 접촉한 이후 로봇카의 동작을 제어하지만, 적외선 센서는 물체와 직접 접촉하기 이전에 어떤 동작을 실행해야만 합니다. 그래서 동작을 제어하는 타이밍을 잘 조절할 필요도 존재합니다. 아래 새롭게 소개하는 스케치는 장애물을 조금 더 효율적으로 피하거나 복잡한 코스에서도 성공적으로 방향조정할 수 있도록 20ms 단위로 감지하여 로봇카의 감지 감도를 증가시켰습니다.
#include <Servo.h>
Servo servoLeft;
Servo servoRight;
void setup() {
pinMode(10, INPUT); pinMode(9, OUTPUT);
pinMode(3, INPUT); pinMode(2, OUTPUT);
tone(4, 3000, 1000);
delay(1000);
servoLeft.attach(13);
servoRight.attach(12);
}
void loop() {
int irLeft = irDetect(9, 10, 38000);
int irRight = irDetect(2, 3, 38000);
if((irLeft == 0) && (irRight == 0)) {
maneuver(-200, -200, 20);
}
else if(irLeft == 0) {
maneuver(200, -200, 20);
}
else if(irRight == 0) {
maneuver(-200, 200, 20);
}
else {
maneuver(200, 200, 20);
}
}
int irDetect(int irLedPin, int irReceiverPin, long frequency) {
tone(irLedPin, frequency, 8);
delay(1);
int ir = digitalRead(irReceiverPin);
delay(1);
return ir;
}
void maneuver(int speedLeft, int speedRight, int msTime) {
servoLeft.writeMicroseconds(1500 + speedLeft);
servoRight.writeMicroseconds(1500 - speedRight);
if(msTime==-1) {
servoLeft.detach();
servoRight.detach();
}
delay(msTime);
}
로봇카가 물체를 감지하고 회피하는 프로그래밍을 연습하였습니다. 이제 로봇카에 장착된 적외선 센서를 사용하여 물체를 감지하지 않고, 책상 끝부분 낭떠러지를 감지하고 회피하도록 프로그래밍할 것입니다. 이런 작업은 흰색 종이위에 그려진 라인을 따라서 로봇카가 주행하는 실습과도 상당히 유사한 점이 있습니다. 적외선 센서가 동작하는 원리를 생각하면서 실습을 따라해보세요! 책상위 낭떠러지를 아래 그림과 같이 검은색 테이프를 사용하여 구분해도 됩니다.
#include <Servo.h>
Servo servoLeft;
Servo servoRight;
void setup() {
pinMode(10, INPUT); pinMode(9, OUTPUT);
pinMode(3, INPUT); pinMode(2, OUTPUT);
tone(4, 3000, 1000);
delay(1000);
servoLeft.attach(13);
servoRight.attach(12);
}
void loop() {
int irLeft = irDetect(9, 10, 38000);
int irRight = irDetect(2, 3, 38000);
if((irLeft == 0) && (irRight == 0)) {
maneuver(200, 200, 20);
}
else if(irLeft == 0) {
maneuver(-200, 200, 375);
}
else if(irRight == 0) {
maneuver(200, -200, 375);
}
else {
maneuver(-200, -200, 250);
}
}
int irDetect(int irLedPin, int irReceiverPin, long frequency) {
tone(irLedPin, frequency, 8);
delay(1);
int ir = digitalRead(irReceiverPin);
delay(1);
return ir;
}
void maneuver(int speedLeft, int speedRight, int msTime) {
servoLeft.writeMicroseconds(1500 + speedLeft);
servoRight.writeMicroseconds(1500 - speedRight);
if(msTime==-1) {
servoLeft.detach();
servoRight.detach();
}
delay(msTime);
}