아두이노 로봇카
Link
Contents
아두이노 로봇카 실습 세부목차
4. 더듬이센서로 주행하기
6. 적외선센서로 주행하기
7. 주행거리 제어하기
※ 본 페이지의 내용은 패럴렉스(Learn.Parallax.com)사의 공식 홈페이지에서 제공되는 자료를 참고하여 작성되었습니다. 또한, 본 내용은 아두이노 neo-로봇카v2 또는 아두이노 로봇카N 키트실습에 사용할 수 있습니다.
본 자료의 원문을 참조하려면 패럴렉스 사의 아두이노를 위한 로보틱스 홈페이지를 방문할 수 있습니다. 이 자료의 로봇카 모든 제어명령 및 센서신호 수집작용은 프라이비 보드 또는 아두이노를 통하여 수행됩니다. 프라이비 보드는 아두이노 우노와 동일한 ATmega328P 마이컴이 사용된 호환보드이며, 아두이노 우노와 동일한 사용법이 적용됩니다.
더듬이센서로 로봇카 주행을 시도해보았다면, 이제 물체와 접촉하지 않고 로봇카 주행을 시도할 차례입니다. 여기서는 광센서로 전방의 물체가 있는지 없는지 디지털신호를 생성할 수 있습니다. 생성된 디지털신호로 로봇카의 주행을 더듬이 센서 주행과 매우 유사하게 사용할 수 있습니다. 조금 더 영리해진 광센서로 주행하는 로봇카를 아래에서 살펴볼 수 있습니다.
아래 세부 내용들을 살펴볼 수 있습니다.
1) 광신호를 전압신호로 변환하기
2) 캐패시터를 사용하여 더 민감하게 광센서 실습하기
3) 두 개의 광센서를 이용한 실습
4) 두 개의 광센서로 로봇카 동작하기
더듬이센서가 물리적인 접촉에 의한 센서라면 광센서는 비접촉 센서에 해당합니다. 이제 로봇카의 동작이 더욱 똑똑하게 생각됩니다. 광센서가 어떤 원리로 동작하는지부터 살펴봅시다. 실제로 광센서는 산업의 다양한 영역에서 이미 효과적으로 이용되고 있는 센서의 한 종류입니다.
광센서의 광원에는 인간의 눈으로 식별할 수 있는 가시광선 영역이 있고, 인간의 눈으로 식별할 수 없는 다양한 주파수의 광선 영역들도 있습니다. 가시광선보다 파장이 긴 영역에는 적외선(Infrared) 빛이 있고, 가시광선보다 파장이 짧은 영역에는 자외선(Ultraviolet)빛 영역이 존재합니다. 이외에도 다양한 비접촉 신호의 종류로서 음파, 초음파, 전파, X선 등으로 분류되는 파장 영역들이 존재합니다.
이제 우리는 직접적인 접촉에 의해서가 아니라 비접촉 신호인 적외선 빛을 사용하여 로봇카를 제어하는 실습을 진행할 것입니다. 그리고 여러분이 손전등을 사용하여 로봇카의 진행을 유도할 수도 있습니다.
이 장의 실습에 사용할 적외선 신호 감지용 광센서인 포토트랜지스터의 모형을 아래 그림으로 소개합니다. 트랜지스터(Transistor)라고 하는 부품은 에미터(E) 베이스(B) 컬렉터(C)라고 하는 3개의 단자로 구성되는데, 3개의 단자중 2개로 흐르는 전류의 양을 나머지 한개의 단자가 조절하는 역할을 합니다. 이런 작용은 마치 수도에서 물이 흐르는 양을 조절하는 밸브와 같은데, 실제로 밸브로는 물이 흐르지 않지만 트랜지스터에서는 밸브로도 전류가 미량 흐른다는 차이점은 존재합니다.
밸브의 개념은 여러분의 이해를 돕기 위한 비유이므로 잊어도 좋습니다. 아래 포토프랜지터의 경우는 밸브의 역할을 수행하는 베이스에 전기적 단자가 연결되지 않지만, 외부의 빛의 양에 따라 밸브의 역할을 수행하여 컬렉터(C)와 에미터(E) 사이를 흐르는 전류의 양을 조절하는 구조입니다.
포토트랜지스터 부품의 외형만 보면 마치 LED 부품과 동일하게 느껴질 수 있지만, 전혀 다른 동작원리와 사용법을 익혀야 합니다. 포토트랜지터도 양극과 음극을 구분하여 사용해야만 정상적인 전류의 흐름과 빛의 감지효과를 사용할 수 있습니다. 부품의 양극이 어떤 것인지 이해되지 않으면 다리가 긴쪽이 양극(컬렉터: C) 이고, 다리가 짧은 쪽이 음극(에미터: E)으로 사용하십시오.
실습에 사용할 포토트랜지터는 850nm 파장의 적외선 빛에 가장 민감하지만, 다른 파장의 빛에 대해서도 덜 민감하게 반응할 수 있습니다. 따라서 여러분의 실습환경에서 형광등, 백열등, 직사광선등 다양한 빛에 대하여 주의를 기울일 필요가 있습니다.
특히, 실습을 진행하는 동안 형광등 빛이나, 태양광 직사광선 빛이 존재하는 환경 조건에서 포토트랜지스터가 손전등 빛을 식별할 수 있어야 합니다. 이런 점에서 환경조건으로의 빛을 분위기 광선이라고 하는데, 분위기 광선이 어떤 빛의 종류인가는 여러분의 실습에 큰 영향을 미칠 수 있다는 점을 명심해야 합니다. 그리고 가능하면 분위기 광선의 조건은 일정하게 유지하는 것이 좋습니다. 만약 더 다양한 분위기 광선 변화에도 동작하는 로봇카를 구상하지 않는다면 말입니다.
실습에 필요한 부품들은 다음과 같습니다. 포토트랜지스터(phototransistor) 2개 점프선(jumper wires) 1개 2kΩ (빨강-흑색-빨강)저항 1개 추가 저항으로 220Ω (빨강-빨강-갈색)저항 1개 470Ω (노랑-보라-갈색)저항 1개 1kΩ (갈색-흑색-빨강) 저항 1개 4.7kΩ (노랑-보라-빨강) 저항 1개 10kΩ (갈색-흑색-주황) 저항 1개를 준비합니다.
광신호 실습용 부품 중에는 포토트랜지스터 부품과 적외선 LED 모습이 비슷해서 혼동할 수 있습니다. 아래 그림을 참고하세요!
포토트랜지스터의 컬렉터(C)를 Vdd 5V 전원에 연결하고, 에미터(E) 단자를 2kΩ 저항과 직렬로 연결한 후 접지에 연결합니다. 그리고 에미터단자와 저항의 접점을 점퍼선으로 아두이노 아날로그 3번핀(A3)에 연결하면 됩니다. 이제 하드웨어 구성이 끝났으므로, 스케치를 사용하여 포토트랜지스터에 얼마나 많은 빛이 비춰지는지를 전압값으로 변환하여 관찰할 수 있습니다. 아래 스케치를 업로드하여 광센서의 신호를 시리얼모니터로 출력해봅시다.
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.print("analog value = ");
Serial.println(analogRead(A3));
delay(200);
}
지금 출력되는 값은 아날로그 입력핀의 값을 표시한 것으로 실제 입력 전압범위 0~5V사이의 전압을 0~1023 사이의 값으로 표시합니다. 그래서 시리얼모니터 출력값을 전압으로 표시하려면 아래와 같이 스케치를 변경하면 됩니다.
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.print("A3 = ");
Serial.print(volts(A3));
Serial.println(" volts");
delay(1000);
}
float volts(int adPin) {
return float(analogRead(adPin)) * 5.0 / 1024.0;
}
이제 광센서의 감지값으로 로봇카의 동작을 유도할 수 있습니다. 간단한 실습으로 광센서에서 감지되는 전압이 3.5V 보다 크면 로봇카가 동작하도록 할 것입니다. 어떻게 스케치를 작성할 수 있을까? 부저회로와 함께 포토트랜지스터 회로가 구성된 로봇카에 아래 스케치를 업로드해봅시다.
#include <Servo.h>
Servo servoLeft;
Servo servoRight;
void setup() {
tone(4, 3000, 1000);
delay(1000);
servoLeft.attach(13);
servoRight.attach(12);
}
void loop() {
if(volts(A3) > 3.5) {
servoLeft.writeMicroseconds(1700);
servoRight.writeMicroseconds(1300);
delay(200);
}
else {
servoLeft.writeMicroseconds(1500);
servoRight.writeMicroseconds(1500);
delay(200);
}
}
float volts(int adPin) {
return float(analogRead(adPin)) * 5.0 / 1024.0;
}
이제 여러분의 스마트폰 불빛이나 손전등으로 로봇카의 전진동작을 유도할 수 있습니다. 만약 3.5V 이하의 불빛에서는 전진하다가 3.5V 보다 큰 값이 되면 로봇카가 정지하도록 바꿀 수도 있습니다. 스케치를 변경해보세요!
이제 map() 함수를 활용해세요. map() 함수는 하나의 정수범위를 또 다른 정수범위로 대응시키는 매핑함수입니다. 예를 들어 광센서에서 감지되는 빛의 세기에 따라 로봇카의 주행속도를 각각 다르게 설정하려면 어떻게 해야 할까요? 가장 어두운 조건에서는 정지상태 또는 매우 천천히 움직이다가 빛의 세기가 점차 강해질수록 로봇카의 전진속도도 비례하여 증가하도록 동작하고 싶습니다. 이때 map() 함수를 사용하여 간단하게 표현할 수 있습니다. 아래 소개하는 map()함수는 0~1023 사이의 아날로그 입력값을 1500~1700 사이의 또 다른 정수값으로 매핑하기 위한 것입니다. 매핑의 선택범위는 여러분의 선택에 따라 변경될 수 있습니다.
int adcVal = analogRead(A3);
int newAdcVal = map(adcVal, 0, 1023, 1500, 1700);
map() 함수의 파라미터 값 선택에 따라 로봇카의 동작을 다양하게 변경하여 표현할 수도 있을 것입니다. 어두운 환경에서는 후진을 하고 밝은 환경조건에서는 전진 그리고 중간 정도의 빛의 세기인 512 에서 로봇카가 정지하도록 설계할 수도 있습니다.
로봇카 광센서 실습이 분위기 광선의 양이 아주 많은 야외 또는 밝은 낮에 진행될 수 있고, 때로는 분위기 광선의 양이 아주 작은 밤중에 어두운 형광등 불빛아래에서 진행될 수 있습니다. 이때 광센서에서는 감지 특성이 매우 다르게 나타납니다. 이런 현상에 대하여 살펴봅시다.
분위기 광선의 양에 따라 베이스의 전류밸브가 연동되어 동작하는 원리이고, 베이스 전류밸브에 따라 컬렉터에서 에미터로 전류의 흐름이 결정됩니다. 이때 에미터와 접지사이의 저항 크기는 아두이노 아날로그 핀에서 감지하는 전압의 감도와 관계합니다. 2kΩ 저항을 1kΩ 저항으로 교환하거나 470Ω 저항으로 교환하면 외부의 광신호에 덜 민감해지고, 10kΩ 저항으로 교체하면 약 5배의 감도가 증가하게 됩니다. 이제 당신은 이런 원리를 적용하여 분위기 광선에 따른 저항을 선택해서 실습을 진행할 필요가 있습니다.
이전의 광센서 실습과제는 빛의 변화에 따른 전류변화를 저항에서의 전압변화로 감지하는 방식이었습니다. 대부분의 센서 응용에 있어서 저항양단의 전압값 변화로 감지하는 방법은 감도가 뛰어나지 못합니다. 즉 측정 전압값의 변화 범위가 작아서 민감한 빛의 변화를 감지하기 어렵다는 의미입니다.
여기서는 캐패시터를 추가로 사용하여 빛의 센기변화를 0 ~ 75,000 사이의 값으로 표현할 수 있기 때문에 매우 민감한 빛의 세기 변화를 읽을 수 있는 특징이 있습니다. 캐패시터(Capacitor)라는 전자부품에 대하여 살펴봅시다.
캐패시터란?
캐패시터란 전기의 작은 단위인 전하를 충전하거나 방전하는 역할의 부품입니다. 본 실습에서는 캐패시터의 충전,방전 특성을 이용하여 외부 빛의 세기를 민감하게 축정할 것입니다.
캐패시터의 크기는 숫자로 표시되기도 하는데, 예를 들어 104 숫자는 0.1 μF 의 크기를 나타냅니다. (여기서 μ 는 백만분의 1을 나타냅니다.)
실습을 위한 전자회로는 두 개의 포토트랜지스터를 1kΩ 저항을 사용하여 아두이노 디지털핀 6번과 8번에 각각 연결합니다. 그리고 두 개 포트트랜지스터의 에미터를 접지에 연결하고, 포토트랜지스터 컬렉터와 에미터 사이에 0.1 μF 캐패시터를 각각 연결하면 됩니다.
광센서 감지값을 적용한 스케치 코드의 예를 다음과 같이 표현할 수 있습니다.
if (tLeft > 2500) { }
이 문장에서 사용된 2500 이라는 감지 값은 절대 값이므로 당신의 분위기 광선 조건이 변화한다면 적절하지 않은 실습 조건 값일 수 있습니다. 그리고 해당되는 분위기 광선 조건에 맞춰서 절대 값을 변경해야만 합니다. 이제 본 실습에서는 절대 값을 사용하지 않고도, 로봇카가 빛을 감지하고 어떤 동작을 할 수 있는 방법에 대하여 살펴볼 것입니다.
이제 간단한 원리를 적용해보자! 오른쪽 센서 감지값을 두 개 센서의 합으로 나누어봅시다. 이 경우 결과 값은 항상 0~1 사이의 값이 됩니다. 이것을 우리는 정규화 미분(normalized differential)이라고 부릅니다.
소개한 공식에 따르면, tRight 와 tLeft 의 측정값이 서로 동일한 경우에는 항상 0.5 가 될 것입니다. 그리고 두 개의 광센서 측정값이 차이가 나면 최종 결과 값은 커지거나 작아질 수 있습니다. 이제 조금더 위 공식을 변형해봅시다.
이제 공식의 결과값은 왼쪽 광센서의 값이 오른쪽 광센서 값보다 큰지 또는 작은지를 음수 또는 양수로 구분하여 계산해줄 수 있습니다. 이미 로봇카에 사용하는 서보모터는 1500 을 기준값으로 큰 수와 작은 수에 따라 바퀴의 회전방향이 다르다는 것을 알고 있습니다. 그래서 두 개 광센서의 사이의 감지값 차이를 음수 또는 양수로 표현할 수 있다는 의미는 로봇카의 동작에 적용하기 용이하다는 것으로 생각할 수 있습니다.
아래 스케치는 두 개 광센서의 감지회로를 캐패시터를 사용하여 구성하고, 두 개 광센서 사이의 RC시간으로 빛의 밝기를 감지하는 스케치에 관한 것입니다.
void setup() {
tone(4, 3000, 1000);
delay(1000);
Serial.begin(9600);
}
void loop() {
float tLeft = float(rcTime(8));
float tRight = float(rcTime(6));
float ndShade;
ndShade = tRight / (tLeft+tRight)-0.5;
Serial.println("tLeft ndShade tRight");
Serial.print(tLeft);
Serial.print(" ");
Serial.print(ndShade);
Serial.print(" ");
Serial.println(tRight);
Serial.println(' ');
delay(1000);
}
long rcTime(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
delay(5);
pinMode(pin, INPUT);
digitalWrite(pin, LOW);
long time = micros();
while(digitalRead(pin));
time = micros() - time;
return time;
}
두 개의 광센서를 사용하여 좌측과 우측의 빛을 감지하는 원리를 이해하였다면, 이제 로봇카의 주행동작과 연결해봅시다. 아래 스케치를 참고하면 됩니다.
#include <Servo.h>
Servo servoLeft;
Servo servoRight;
void setup() {
tone(4, 3000, 1000);
delay(1000);
servoLeft.attach(13);
servoRight.attach(12);
}
void loop() {
float tLeft = float(rcTime(8));
float tRight = float(rcTime(6));
float ndShade;
ndShade = tRight/(tLeft+tRight)-0.5;
int speedLeft, speedRight;
if (ndShade > 0.0) {
speedLeft = int(200.0 - (ndShade * 1000.0));
speedLeft = constrain(speedLeft, -200, 200);
speedRight = 200;
}
else {
speedRight = int(200.0 + (ndShade * 1000.0));
speedRight = constrain(speedRight, -200, 200);
speedLeft = 200;
}
maneuver(speedLeft, speedRight, 20);
}
long rcTime(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
delay(5);
pinMode(pin, INPUT);
digitalWrite(pin, LOW);
long time = micros();
while(digitalRead(pin));
time = micros() - time;
return time;
}
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);
}