May 23, 2018

디바이스마트 미디어:

[26호] ICT 융합 공모전 – 적외선 라인트레이서

적외선 20

적외선 라인트레이서

글 | 고려대학교 세종캠퍼스 제어계측공학과 홍태우

1. 작품 개요

· 적외선 센서를 이용하여, 검은 라인과 흰 바탕으로 구성된 맵의 인식기능 구현
· 검은 라인을 따라가며, 주행 중 스스로 라인에 맞춰 진행 방향을 보정기능 구현

2. 작품 설명
2.1. 제작동기
학술동아리 내에서 프로젝트를 진행하기 위해 기본적인 ATmega128 학습을 진행하였습니다. 그 결과 학습한 것이 DC모터의 방향 제어와, 속도 제어를 위한 PWM 파형 출력 방법이었습니다. 그 외에 센서를 활용해보기 위해, 기본적인 센서인 적외선 센서와, 적외선 센서에 적용 할 수 있는 LOW PASS Filter를 학습 했었습니다. 학습해본 것들을 모두 적용하기 적절한 프로젝트를 찾던 중, 라인트레이서가 제일 적합하다 판단되었고, 제작을 진행하게 되었습니다.

2.2. 주요 동작 및 특징
라인 인식 및 위치 인식 비교원리
전면에 장착된 5개의 적외선 센서를 지면 방향으로 배치하여, 검은 라인을 인식하여 본체의 위치를 비교합니다. 라인 위에서의 라인트레이서 본체의 위치를 파악한 뒤, 이 위치에 따라 구동부인 DC모터의 속력을 조절합니다. DC모터는 후면에 두 개가 장착되어 있으며, 방향 조절은 각각 모터의 속도 차이로 조작하게 됩니다. 라인에서 밖으로 나가게 된 경우, 인식 중이던 나가기 직전까지의 방향 및 라인에서의 위치를 피드백 받아, 다시 라인을 찾아 주행을 지속합니다.

적외선 02
센서의 발광부에서 쏴준 적외선 중, 지면에서 반사된 수광부로 받은 신호 중 고주파 신호는 걸러내고, 저주파 신호만 사용하게 하였습니다.

적외선 03
빛의 특성인 검은색에서는 흡수당하고, 흰색에서는 반사당하는 원리를 적외선 센서에도 적용합니다. 적외선을 방출하는 발광부와 적외선을 수신하는 수광부를 나눠 설치하여, 적외선이 반사되는지(검은 라인 위), 반사되지 않는지(흰 바탕 위)를, 적외선의 수신 강도로 판단하며, 이것을 ADC로 디지털화하여 ATmega128이 인식하게 됩니다.

적외선 04
회로도의 캐패시터(47uF)는 고주파는 GND로 빼어내어 저주파만 통과시키는 Low Pass Filter의 실질적인 역할을 합니다. 저항들은 Low Pass Filter의 Fc값을 적절하게 맞춰주기 위하여 맞춤설정한 것입니다. 따라서 ATmega 128의 ADC로 Low Pass Filter에서 걸러진 저주파가 입력되며, 이것을 사용하여 센서는 기능을 수행하게 됩니다.

2.3. 전체 시스템 구성
라인트레이서의 시스템은 위에서 설명했다시피, 크게 DC모터와 적외선 센서로 구현되어 있습니다. 그 외에는 센서 감지여부 디스플레이용 LED가 장착되어 있습니다.

가. DC모터부
DC모터의 방향제어는 74HC132 NAND gate를 사용하여 포트 하나로 양방향 제어를 하였으며, ATmega 128의 Timer를 이용한 PWM을 출력하여, PWM의 듀티비에 따른 속도의 제어를 하였습니다. 모터 드라이버는 통상적으로 많이 쓰이는 드라이버인 L298N을 사용하였습니다.

DC모터부 적용 소자 데이터 시트
74HC132N-2bit quadra gate

적외선 05

L298N 모터드라이버

적외선 06

나. 센서부
적외선 센서의 발광부에는 ULN2003APG를 적용하여 센서의 적외선 출력을 증폭시켜주었습니다. 수광부에는 위의 회로도와 같이 LOW PASS Filter를 적용하여 주었습니다.

적외선 센서 적용 소자 데이터 시트
ULN2003APG

적외선 07

다. LED 디스플레이어
센서가 센싱하는 값인 ADC를 일정한 값으로 나누어 주어, 검은색/흰색의 두가지 경우로 논리를 나눈 뒤, 검은색일 경우에는 LOW(FALSE), 흰색일 경우에는 HIGH(TRUE)를 출력하여, 검은 라인 위에 있는 센서의 해당 LED는 불이 꺼지도록 만들었습니다. LED 디스플레이를 적용하였을 때, 시각 효과로 인하여 센서와 DC모터의 속도값을 보정하는데 큰 도움이 되었습니다.

라. 전원부
ATmega128에 전원을 공급하기 위하여, 전원인 9V DC를 5V DC로 바꿔주는 LM7805를 사용하여, 전원부를 제작하였습니다. DC모터에 강한 출력을 전달해야 하는 L298N을 제외하고는, 모든 하드웨어 모듈이 전원부에서 나오는 5V 출력을 이용하여 동작합니다.

하드웨어 구성 및 신호전달 체계

적외선 08

2.4. 개발환경
라인트레이서에 사용된 MCU는 ATmega128이며, 소스코드 개발은 Code Vision AVR(CV AVR)로 진행하였습니다.

3. 단계별 제작과정
모듈별 제작 및 학습기간(13/10/7~13/11/25)

적외선 09

가. DC모터 속도 제어용 PWM 파형 생성 실험

적외선 10
나. 1차 하드웨어 제작 및 DC모터 방향, 속도제어 실험

적외선 11적외선 12

다. 적외선 센서 제작 및 작동 실험

적외선 13

적외선 14
라. 2차 하드웨어(완성) 제작 및 LED 디스플레이어 적용, 센서 및 LED 추가

적외선 15

 

 

프레임 및 납땜 제작과정

적외선 16

 

적외선 17

 

적외선 18

 

마. 라인 트레이서 작동 확인

적외선 19

4. 기타(회로도, 소스코드)

가. 소스코드

#include <mega128.h>
#include <delay.h>
#include <stdio.h>

#define First 3
#define Second 2
#define Third 1
#define Fourth 0
#define Fifth 4
#define Sixth 7
#define Seventh 5
#define Eighth 6

unsigned int Fi,Se,Th,Fo,Ff,Si,Sv,Ei;

int start,check,a,b,c,d,e,f,g,h;

#define ADC_VREF_TYPE ((0<<REFS1) | (1<<REFS0) | (1<<ADLAR))
// Read the 8 most significant bits
// of the AD conversion result
unsigned char read_adc(unsigned char adc_input)
{
ADMUX=adc_input | ADC_VREF_TYPE;
delay_us(10);
ADCSRA|=(1<<ADSC);
while ((ADCSRA & (1<<ADIF))==0);
ADCSRA|=(1<<ADIF);
return ADCH;
}
////////////////////////////////발광부 설정
unsigned int sensor(unsigned int si)
{
unsigned int ret;

switch(si)
{
case First:
PORTE.4=0;
delay_us(50);
ret=read_adc(si);
PORTE.4=1;
break;

case Second:
PORTE.2=0;
delay_us(50);
ret=read_adc(si);
PORTE.2=1;
break;

case Third:
PORTE.1=0;
delay_us(50);
ret=read_adc(si);
PORTE.1=1;
break;

case Fourth:
PORTE.0=0;
delay_us(50);
ret=read_adc(si);
PORTE.0=1;
break;

case Fifth:
PORTE.3=0;
delay_us(50);
ret=read_adc(si);
PORTE.3=1;
break;

case Sixth:
PORTE.7=0;
delay_us(50);
ret=read_adc(si);
PORTE.7=1;
break;

case Seventh:
PORTE.6=0;
delay_us(50);
ret=read_adc(si);
PORTE.6=1;
break;

case Eighth:
PORTE.5=0;
delay_us(50);
ret=read_adc(si);
PORTE.5=1;
break;
}
return ret;
}

void main(void)
{
////////////////////모터관련 레지스터 설정
DDRA.0=1;
DDRA.1=1;

DDRB=0xFA;
PORTB=0×00;

TCCR1A=0xA3;
TCCR1B=0×03;

OCR1AH=0×00;
OCR1AL=0×00;

OCR1BH=0×00;
OCR1BL=0×00;

////////////////////센서관련 레지스터 설정
DDRF=0×00;
PORTF=0xFF;

DDRE=0xFF;

ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
ADMUX=ADC_VREF_TYPE;
ADCSRA=(1<<ADEN) | (0<<ADSC) | (0<<ADFR) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (0<<ADPS1) | (1<<ADPS0);
SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);
TWCR=(0<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWEN) | (0<<TWIE);

////////////////////LED관련 레지스터 설정
DDRC=0xFF;
PORTC=0×00;

////////////////////스위치 관련 레지스터 설정
DDRD=0b11111100;

EICRA=0x0a;
EICRB=0×00;
EIMSK=0×03;
SREG=0×80;

/////////////////////////반복문 시작

while (1)
{
///////////////////////센서, 칩 LED 설정
Fi=sensor(First);
Se=sensor(Second);
Th=sensor(Third);
Fo=sensor(Fourth);
Ff=sensor(Fifth);
Si=sensor(Sixth);
Sv=sensor(Seventh);
Ei=sensor(Eighth);

Fi/=55;
Se/=53;
Th/=62;
Fo/=60;
Ff/=50;
Si/=40;
Sv/=40;
Ei/=40;

if(Fi>1)
{PORTD.6=1;a=1;}
else
{PORTD.6=0;a=0;}

if(Se>1)
{PORTD.5=1;b=1;}
else
{PORTD.5=0;b=0;}

if(Th>1)
{PORTD.4=1;c=1;}
else
{PORTD.4=0;c=0;}

if(Fo>1)
{PORTD.3=1;d=1;}
else
{PORTD.3=0;d=0;}

if(Ff>1)
{PORTD.2=1;e=1;}
else
{PORTD.2=0;e=0;}

if(Si>1)
{PORTC.2=1;f=1;}
else
{PORTC.2=0;f=0;}

if(Sv>1)
{PORTC.7=1;g=1;}
else
{PORTC.7=0;g=0;}

if(Ei>1)
{PORTC.4=1;h=1;}
else
{PORTC.4=0;h=0;}
///////////////////////센서, 칩 LED 설정 끝

///////////////////////맵핑 코드 시작
///////////////////////주석의 오차만큼 모터 속도 제어(PWM)

if(a==0&b==0&c==1&d==0&e==0)////////직진
{
PORTA.1=1;
PORTA.0=1;

OCR1AH=0x5E;
OCR1AL=0xAF;

OCR1BH=0xEF;
OCR1BL=0xDF;
}

else if(a==0&b==1&c==1&d==0&e==0)/////////오른쪽오차1
{
PORTA.1=1;
PORTA.0=1;

OCR1AH=0x5D;
OCR1AL=0xAF;

OCR1BH=0xEF;
OCR1BL=0xDF;
}

else if(a==0&b==1&c==0&d==0&e==0)/////////오른쪽오차2
{
PORTA.1=1;
PORTA.0=1;

OCR1AH=0x5D;
OCR1AL=0xAF;

OCR1BH=0xEF;
OCR1BL=0xCF;
}

else if(a==1&b==1&c==0&d==0&e==0)/////////오른쪽오차3
{
PORTA.1=1;
PORTA.0=0;

OCR1AH=0x5E;
OCR1AL=0×00;

OCR1BH=0xFF;
OCR1BL=0x0F;
}

else if(a==1&b==0&c==0&d==0&e==0)/////////오른쪽오차4
{
PORTA.1=1;
PORTA.0=0;

OCR1AH=0x5D;
OCR1AL=0×00;

OCR1BH=0xFF;
OCR1BL=0x0F;
}

else if(a==0&b==0&c==1&d==1&e==0)/////////왼쪽오차1
{
PORTA.1=1;
PORTA.0=1;

OCR1AH=0x5E;
OCR1AL=0xAF;

OCR1BH=0xEE;
OCR1BL=0xDF;
}

else if(a==0&b==0&c==0&d==1&e==0)/////////왼쪽오차2
{
PORTA.1=1;
PORTA.0=1;

OCR1AH=0x5F;
OCR1AL=0xAF;

OCR1BH=0xEE;
OCR1BL=0xDF;
}

else if(a==0&b==0&c==0&d==1&e==1)/////////왼쪽오차3
{
PORTA.1=0;
PORTA.0=1;

OCR1AH=0xFF;
OCR1AL=0xAF;

OCR1BH=0×00;
OCR1BL=0xFF;
}

else if(a==0&b==0&c==0&d==0&e==1)/////////왼쪽오차4
{
PORTA.1=0;
PORTA.0=1;

OCR1AH=0xFF;
OCR1AL=0xAF;

OCR1BH=0×00;
OCR1BL=0xFF;
}

else/////////STOP
{
PORTA.1=0;
PORTA.0=0;

OCR1AH=0×00;
OCR1AL=0x2F;

OCR1BH=0×00;
OCR1BL=0x3F;
}

}

}

////////////////////////////////스위치 인터럽트
interrupt [EXT_INT0] void external_int0(void)
{
start=1;
}

interrupt [EXT_INT1] void external_int1(void)
{
start=0;
}

나. 회로도    

1. 모터 드라이버 회로도

L298N회로도

2. 센서부 회로도

센서 회로도

3. 전원부 회로도

전원부 납땜

4. 스위치 및 LED 회로도 

스위치, LED 회로도

Leave A Comment

*