[43호]Hand Control & LineTracing Stepping Car
2017 ICT 융합 프로젝트 공모전 우수상
Hand Control & LineTracing Stepping Car
글 | 국민대학교 유동규
심사평
칩센 “스테핑 모터를 이용한 라인트레이서” 자체는 특별하다는 생각이 들지않지만, 컨트롤용 웨어러블 장치를 통해 매뉴얼 구동 및 방향 전환이 가능하다는 것에 가점을 줄만한 기능이었습니다. 자동차의 주행은 바닥의 1개의 라인을 따르는 것이 아닌 양쪽에 존재하는 두개의 라인 사이에서 운행을 하게 되는 내용이므로 라인트레이서를 실제 도로 주행상황에 맞도록 설계하는 것이 어떠했을까 하는 아쉬움이 듭니다. 제안한 작품은 자율주행의 단계중 사용자 적극적 개입을 필요로 하는 1단계 혹은 2단계의 수준에 해당하는 것으로 보이지만 컨트롤부 구현 내역으로는 기존 무선 RC카와 컨트롤과 같은 매우 낮은 단계입니다. 조금 더 자율주행에 가까운 컨트롤부 구현에 대한 고민이 필요할 것으로 보입니다. 구현된 작품의 시제품의 완성도는 매우 높아 보이고, 외관형태 또한 흥미를 끌수 있도록 잘 설계한 듯 합니다.
뉴티씨 장갑으로 장비를 조종하는게 꽤 흥미 있었습니다. 장갑 자체가 메인인 느낌이 납니다. VR 등으로 결합하면 좀 더 재미있을 것 같습니다.
위드로봇 손의 모션을 장치 제어의 인터페이스로 활용하려는 시도는 지속적으로 있습니다만 아직까지 답이다라고 할 만한 것이 나오지 못하고 있습니다. 웨어러블 디바이스쪽의 완성도를 높이는 연구가 추가 진행되면 좋을 것 같습니다.
작품 개요
최근 자율주행 기술은 스마트카의 핵심기술로 꼽힌다. 주요 자동차 메이커는 물론 소프트웨어 회사들도 자율주행차 개발에 적극적으로 나서고 있는 상황이다. 따라서 자율주행의 기본인 라인트레이싱 카를 만들게 되었다.
또한 웨어러블과 자동차에 연관에 대한 기술들이 많이 출시되고 있다. 전자 통신을 통한 이모빌라이저의 발전은 스마트 디바이스의 발전과도 맞물려 자동차 의미를 본질적으로 바꾸고 있다. 세계적인 컨설팅 기업인 프로스트 앤 설리번은 웨어러블 기기가 자동차 산업을 정의하는 새로운 키워드로 자리잡아가고 있다는 점에 주목할 것을 제안하고 있다.
이미 2015년 국제전자제품박람회(CES)에서 웨어러블 타입의 기기를 통해 원격 엔진 스타트와 보안 및 다양한 통신 기능을 갖춘 블루링크 시스템을 선보인 현대자동차부터, 재규어 역시 2015년에 ‘액티비티 키’라는 손목 시계형 웨어러블 기기를 활용하고 있다. 이 웨어러블 기기를 활용한 스마트키는 향후 커넥티드 시스템과 연계되어 자동차의 조작뿐만 아니라 일상의 다양한 영역에 그 능력을 확장적으로 사용할 수 있을 것으로 기대되고 있다. 이러한 기사들과 제품에서 아이디어를 얻어서 Atmega8을 이용하여 사용자가 직접 차를 조종할 수 있는 기본적인 디바이스를 구현해 보았다.
웨어러블 디바이스의 핵심은 장착했을 때 불편함이 없어야 하므로 최대한 작은 부피를 가지는 Atmega8을 이용하고 배터리를 제일 적게 소모하도록 구현하였다. 웨어러블 디바이스를 통해서 라인트레이싱을 하는 모드와 직접 차량을 조종하는 모드를 바꿀 수 있고 플렉서블 센서와 MPU 센서를 이용하여 속도와 방향을 제어할 수 있도록 구현하였다.
이번 RC카에 쓰이게 된 스테핑 모터는 전기 모터의 한가지로 입력 펄스 수에 대응하여 일정 각도씩 움직이는 특성을 가지고 있어, 펄스모터 혹은 스텝모터라고도 한다. 입력 펄스 수와 모터의 회전 각도가 완전히 비례하므로 회전 각도를 정확하게 제어할 수 있다.
스테핑 모터을 선택한 이유는 기존에 DC모터와 서보모터의 제어로 방향과 속도를 나눠서 제어하게 되면 후륜 구동으로 DC모터의 힘이 모자라는 경우가 많고 방향제어가 급격하게 되면 매우 속도도 느려지고 차량이 전진하지 못하는 경우도 많이 발생하게 되었다. 그에 반해 이번에 제작한 RC카는 두 개의 스테핑 모터의 속도차를 이용해서 방향과 속도를 제어하여 좀 더 정확한 방향제어와 급격한 방향이 바뀌는 구간에서도 모터의 힘 즉 토크가 죽지 않고 진행할 수 있게 구현하였다.
작품 설명
이 작품은 8bit micro controller인 Atmega칩을 이용하여 구현하였다.
우선 자동차 본체와 controller 장갑에 각각 Atmega128과 Atmega8을 장착하였고, 각 칩들은 UART(Universal Ansyncronous Receiver and Transmmiter)를 이용하여 data를 주고받기 위해 블루투스 모듈을 설치하게 되었다. controller 장갑에 장착된 터치센서를 통해 자동차가 라인을 따라 자율주행 하는 모드와 직접 장갑으로 차를 control하는 모드를 선택 할 수 있게 설계하였다. 터치 센서를 통해서 사용자가 원하는 어느 시점에서든 두 모드를 자유롭게 변경할 수 있게 하였고 자율주행 모드에서는 속력을 일정하게 하고 사용자의 컨트롤에도 영향을 받지 않게 하였다.
사용자가 직접 control하는 모드에서는 손가락을 구부리는 개수에 변화에 따른 플렉서블 저항의 변화를 ADC 값으로 변환하여 이를 통해 속도 제어를 할 수 있게 하였고 손등에 부착되어 있는 MPU 센서에 X축과 Y축의 변화를 통해서 자동차의 전·후진과 좌·우 회전 제어를 할 수 있다. 플렉서블 저항의 경우 구부러지는 정도에 따라서 저항이 변하게 되는데 이를 사용하기 위해서 플렉서블과 전원 사이에 저항을 설계하여 전압분배를 이용하여 원하는 전압폭을 가져올 수 있도록 하였다. 전압에 변화가 급격하게 하여서 구부러지는 손가락의 개수를 이용해 속도를 제어하도록 구현하였다. MPU 센서는 손을 기울이는 정도에 따라서 방향제어의 정도를 결정하였기 때문에 Z축에 의한 영향이 미치지 않도록 구현하였다.
자율 주행 모드에서는 차 앞부분에 부착된 수광센서와 발광센서로 이루어진 센서부 값을 Atmega128의 포트 입력으로 받아 선의 상황에 따라 차가 라인을 따라 일정 속도로 자율 주행할 수 있다. 센서부에서는 수·발광센서와 비교기를 사용하였는데 발광센서에서 나오는 적외선을 수광센서에서 출력되는 전압과 입력전압이 가변저항을 통해 나오는 전압과 비교하여 High, Low 값을 출력한다. 일반적으로 검은색 선은 빛을 흡수 하므로 수광센서에 전압이 걸리지 않게 되고 흰색 배경에서는 적외선이 반사되어 수광센서에 전압이 걸리게 된다.
주요 동작 및 특징
하드웨어 동작 및 특징
○ RC카 센서부
센서부에서는 수·발광 센서와 비교기를 사용하였는데 발광센서에서 나오는 적외선을 수광 센서에서 받아 나오는 전압과 입력전압이 가변저항을 통해 나오는 전압과 비교를 하여 High, Low 값을 출력하게 된다.
일반적으로 검은색 선은 빛을 흡수하므로 수광센서에 전압이 걸리지 않게 되고 흰색 배경에서는 적외선이 반사되어 수광센서에 전압이 걸리게 된다.
RC카 구동부
기존의 DC모터와 서보모터로 방향 제어와 속도제어를 나누어서 한 방법에서, 이번 제작한 작품은 두 개의 스테핑 모터의 속도차를 이용해서 방향과 속도를 제어하여 좀 더 정확한 방향제어와 급격한 방향이 바뀌는 구간에서도 모터의 힘, 즉 토크가 죽지 않고 진행할 수 있게 구현하였다.
컨트롤러 장갑
플렉서블 저항의 변화를 ADC 값으로 변환하여 이를 통해 속도 제어를할 수 있게 하였고 손등에 부착되어 있는 MPU 센서의 X축과 Y축의 변화를 통해서 자동차의 전·후진과 좌·우 회전 제어를 할 수 있다.
플렉서블 저항의 경우 구부러지는 정도에 따라서 저항이 변하게 되는데 이를 사용하기 위해서 플렉서블과 전원 사이에 저항을 설계하여 전압분배를 이용하여 원하는 전압폭을 가져올 수 있도록 하였다. 전압에 변화가 급격하게 하여서 구부러지는 손가락의 개수를 이용하여 속도를 제어하도록 구현하였다. MPU 센서는 손에 기울이는 정도에 따라서 방향 제어의 정도를 결정하였기 때문에 Z축에 의한 영향이 미치지 않도록 구현하였다.
소프트웨어 동작 및 특징
RC카
컨트롤러부터 UART를 통해 들어오는 통신 값들을 Atmega128에서 처리하여 각 동작에 맞는 행동을 판단하고 Stepping Motor를 제어하게 된다.
자동모드의 경우 Stepping Car에 수·발광 센서 값을 이용하여 라인을 인식하고, Stepping Motor를 제어하여 방향을 조절하게 된다.
Stepping Motor의 경우 입력 펄스 수와 모터의 회전각도가 완전히 비례하므로 회전각도를 정확하게 제어할 수 있다. 타이머/카운터를 이용하여 stepping 모터를 제어하게 된다. 따라서 타이머/카운터를 사용하여 4개의 펄스를 발생시키고 차례대로 입력해 주어야 한다. 단지 입력방법에서 딜레이를 이용한 방법에 경우 하나의 펄스라도 입력시기에 약간의 오차가 생기게 되면 스테핑모터가 순서가 꼬여 제대로 돌지 못하는 경우가 발생하므로 해당 작품에서는 각 펄스가 계속해서 차례대로 입력되도록 타이머 인터럽트를 이용하여 구현하였다.
컨트롤러 장갑
장갑에 장착된 MPU 센서를 이용하여 X축과 Y축 센서 값을 추출하고, Atmega8을 이용하여 추출한 센서 값들을 처리하고 각도를 계산하여 RC카에게 UART를 이용해 명령 지시를 내리게 된다.
장갑에 장착된 Flexible 저항을 ADC와 연결하여 ADC값 추출하고 RC카에게 UART를 이용해 명령 지시를 내리게 된다.
장갑에 장착된 Touch 센서를 이용하여 모드를 변경할 수 있게 되는데 해당센서의 경우 입력전압 5V와 0V를 출력하므로 이는 Atmega8의 GPIO를 통하여 High/Low로 처리하여 RC카에게 UART를 이용해 명령 지시를 내리게 된다.
전체 시스템 구성
개발 환경(개발 언어, Tool, 사용 시스템 등)
Soft Ware
· AVR studio Version 4.19
· Visual Studio 2013
· PSIM 10 32bit
Hard Ware
단계별 제작 과정
Hardware 제작
기본 차체
■ 차체에 직접 부착할 수 있게 하기위해 스테핑모터를 지지할 구동부 받침대 제작
■ 구동부 받침대와 직접 제작한 차체를 연결
센서부
■ 라인트레이싱을 할 수 있도록 수발광 센서를 이용한 센서부 제작
■ 센서부와 차체를 연결
구동부
■ 스테핑모터 드라이버와 Atmega128을 구동하기 위한 전원시스템 구성과 스테핑모터를 구동위한 핀을 추출
구동부와 센서부 통합
■ 라인트레이싱을 위한 센서부와 Atmega128를 연결, 컨트롤 모드를 위한 블루투스 연결, 전체적 통합 후 배터리 연결하여 완성
컨트롤러 장갑 제작
센서부
■ Atmega8과 MPU센서, 터치센서를 부착하기 위하여 회로기판을 제작하여 장갑에 부착
전원부
■ 전 컨트롤러 디바이스에서 전원을 어댑터로 하는 불편함을 보완하기 위해서 따로 전원부를 제작하여 추가적으로 부착
Software 제작
타이머를 이용하여 스테핑모터 구동 실험
#define F_CPU 16000000UL ///util_delay.h 를 위한 헤더
#include <avr/io.h> ///avr을 위한 헤더
#include <avr/iom128.h> ///atmega128을 위한 헤더
#include <util/delay.h> ///_delay_us()를 사용하기 위한 헤더
#include <avr/interrupt.h> ///인터럽트 헤더
ISR(TIMER3_COMPA_vect);
ISR(TIMER1_COMPA_vect);
void InitTimer3(void)//
{
TCCR3A=0b00000000;
TCCR3B=0b00001100;
TCCR3C=0b00000000;
ETIMSK=0b00010000;
}
void InitTimer1(void)
{
TCCR1A=0b00000000;
TCCR1B=0b00001100;
TCCR1C=0b00000000;
TIMSK=0b00010000;
}
ISR(TIMER3_COMPA_vect)
{
i++;
i=i%4;
PORTA=a[i];
}
ISR(TIMER1_COMPA_vect)
{
j++;
j=j%4;
PORTA=L_CW[j];
}
컨트롤러와 UART통신 실험
void InitUart(void)
{
UBRR0H=0×00;
UBRR0L=0×67;
UCSR0A=0×00;
UCSR0B=0×10;
UCSR0C=0×06;
}
char recive(void)
{
unsigned char data;
while((UCSR0A & 0×80) == 0×00);
data=UDR0;
return data;
}
//ctc 256 timer 1,3 (16000000/(256*(OCR+1))
int main(void)
{
char data;
DDRA=0xFF;
DDRD=0xFF;
PORTD=0×00;
DDRC=0xFF;
PORTC=0xFF;
InitTimer3();
InitTimer1();
InitUart();
UBRR0H=0×00;
UBRR0L=0×67;
UCSR0A=0×00;
UCSR0B=0×10;
UCSR0C=0×06;
DDRE = 0×00;
OCR1AH=0×00;
OCR1AL=0x7C;
OCR3AH=0×00;
OCR3AL=0x7E;
SREG|=0×80;
while(1)
{
data=recive();
Step(data);
}
return 0;
}
UART 데이터에 따른 방향 지시 실험
char CW[4]={0×11, 0×22, 0×44, 0×88};
char R_CW[4]={0×01, 0×02, 0×04, 0×08};
char L_CW[4]={0×10, 0×20, 0×40, 0×80};
char CCW[4]={0×88, 0×44, 0×22, 0×11};
char R_CCW[4]={0×01, 0×02, 0×04, 0×08};
char L_CCW[4]={0×10, 0×20, 0×40, 0×80};
char a[4]={0×11, 0×22, 0×44, 0×88};
unsigned char data;
int i=0;
int j=0;
void Step(unsigned char data);
char recive(void);
void InitTimer3(void);
void InitTimer1(void);
void InitUart(void);
void Step(unsigned char data)
{
int k;
if(data==’a'){//전진
TIMSK=0×00;
OCR3AH=0×00;
OCR3AL=0x7E;
for(k=0;k<4;k++)
{
a[k]= F_CW[k];
}
}
else if(data==’b'){//후진
TIMSK=0×00;
OCR3AH=0×00;
OCR3AL=0x7E;
for(k=0;k<4;k++)
{
a[k]= B_CCW[k];
}
}
else if(data==’c')//앞 좌회전-timer3가 더 빠름
{
TIMSK=0×10;
OCR1AH=0×00;
OCR1AL=0×80;
OCR3AH=0×00;
OCR3AL=0×83;
for(k=0;k<4;k++)
{
a[k]= R_CW[k];
}
}
else if(data==’d')//앞 우회전-timer1이 더 빠름
{
TIMSK=0×10;
OCR1AH=0×00;
OCR1AL=0×83;
OCR3AH=0×00;
OCR3AL=0×80;
for(k=0;k<4;k++)
{
a[k]= R_CW[k];
}
}
else if(data==’e')//뒤 좌회전-timer3가 더 빠름
{
TIMSK=0×10;
OCR1AH=0×00;
OCR1AL=0×80;
OCR3AH=0×00;
OCR3AL=0×83;
for(k=4;k>0;k–)
{
a[k]= R_CW[k];
}
}
else if(data==’f')//뒤 우회전-timer1이 더 빠름
{
TIMSK=0×10;
OCR1AH=0×00;
OCR1AL=0×83;
OCR3AH=0×00;
OCR3AL=0×80;
for(k=4;k>0;k–)
{
a[k]= R_CW[k];
}
}
}
라인트레이싱을 위한 GPIO에 따른 방향 지시 실험
void lineTracking(void)
{
int k;
if(PINB== 0xE7)
{
putch_USART0(CW_1);
OCR1AH=0×00;
OCR1AL=0×80;
OCR3AH=0×00;
OCR3AL=0×80;
for(k=0;k<4;k++)
{
a[k]= CW[k];
b[k]= CW[k];
}
}
else if((PINB==0xE3)||(PINB==0xF3)) //약 우회전
{
putch_USART0(RCW_1);
OCR1AH=0×00;
OCR1AL=0×80;
OCR3AH=0×00;
OCR3AL=0×70;
for(k=0;k<4;k++)
{
a[k]= CW[k];
b[k]= CW[k];
}
}
else if((PINB==0xC7)||(PINB==0xCF)) //약 좌회전
{
putch_USART0(LCW_1);
OCR1AH=0×00;
OCR1AL=0×70;
OCR3AH=0×00;
OCR3AL=0×80;
for(k=0;k<4;k++)
{
a[k]= CW[k];
b[k]= CW[k];
}
}
//else if(PORTB==0xE0)//큰 좌회전
//else if(PORTB==0×07)//큰 우회전
}
컨트롤러 장갑 MPU센서값 축정 실험
void twi_init(void) ///twi 초기화
{
TWSR=0×00; ///상태레지스터-SCL주파수 분주비 1 ///상태코드 상위5비트는 Read only 이다
TWBR=0x0C; ///비트레이트레지스터-0b00001100 SCL주파수 400kHz
TWCR|=0×84; ///제어레지스터
}
void mpu6050_init(void) ///mpu 초기화
{
MPU6050_write(0x6B,0×00); ///mpu는 초기에 슬립모드이다
MPU6050_write(0x6C,0×00);
MPU6050_write(0x1B,0b00011000); ///자이로 범위셋팅 2000′/s -> 3,4번 비트 00일때 250′/s부터 2배씩 증가
MPU6050_write(0x1C,0b00011000); ///가속도 범위셋팅 16g -> 3,4번 비트 00일때 2g부터 2배씩 증가
MPU6050_write(0x1A,0×06); ///DLPF 0×06 대역폭5Hz 딜레이19ms
}
byte MPU6050_read(byte addr) ///mpu6050의 내부레지스터의 값을 수신하여 읽는함수
{
byte data; ///함수의 반환형과 일치시킨다
TWCR=0xA4; ///START bit 전송
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×08))
{
; ///1.플래그가 셋 되었고 2.상태코드-START전송완료 두조건이 만족되면 while()을 빠져나옴
}
TWDR=0xD0; ///mpu6050의 주소 0b110100x + Write비트 0 x는 mpu6050의 AD0핀의 상태로 결정됨
TWCR=0×84; ///플래그를 소프트웨어에서 클리어하려면 1을 입력한다
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×18))
{
; ///1.플래그가 셋 되었고 2.상태코드-확인비트ACK 수신완료 두조건이 만족되면 while()을 빠져나옴
} ///SLA+W 전송완료
TWDR=addr; ///마스터가 Read하고싶은 레지스터의 주소를 송신
TWCR=0×84; ///플래그를 소프트웨어에서 클리어하려면 1을 입력한다
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×28))
{
; ///1.플래그가 셋 되었고 2.상태코드-DATA송신완료 두조건이 만족되면 while()을 빠져나옴
}
TWCR=0xA4; ///REPEATED START
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×10))
{
; ///1.플래그가 셋 되었고 2.상태코드-REPEATED START전송완료 두조건이 만족되면 while()을 빠져나옴
} ///제어권을 잃지않고 계속해서 통신을 지속
TWDR=0xD1; ///mpu6050의 주소 0b110100x + Read비트 1 x는 mpu6050의 AD0핀의 상태로 결정됨
TWCR=0×84; ///플래그를 소프트웨어에서 클리어하려면 1을 입력한다
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×40))
{
; ///1.플래그가 셋 되었고 2.상태코드-확인비트ACK 수신완료 두조건이 만족되면 while()을 빠져나옴
} ///SLA+R 전송완료
TWCR=0×84; ///플래그를 소프트웨어에서 클리어하려면 1을 입력한다
///데이터 수신대기상태
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×58))
{
; ///1.플래그가 셋 되었고 2.상태코드-DATA수신완료 두조건이 만족되면 while()을 빠져나옴
} ///TWCR6번비트가 ’0′이므로 마스터는 ACK신호를 생성하지않는다 그렇기때문에 상태코드는 0×58;
data=TWDR; ///수신data를 읽는다
TWCR=0×94; ///STOP bit 전송
return data; ///레지스터로부터 읽은값을 반환
}
void MPU6050_write(byte addr,byte data) ///mpu6050의 내부레지스터에 값을 송신하는 함수
{
TWCR=0b10100100; ///START bit 전송
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×08))
{
; ///1.플래그가 셋 되었고 2.상태코드-START전송완료 두조건이 만족되면 while()을 빠져나옴
}
TWDR=0xD0; ///mpu6050의 주소 0b110100x + Write비트 0 x는 mpu6050의 AD0핀의 상태로 결정됨
TWCR=0×84; ///플래그를 소프트웨어에서 클리어하려면 1을 입력한다
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×18))
{
; ///1.플래그가 셋 되었고 2.상태코드-확인비트ACK 수신완료 두조건이 만족되면 while()을 빠져나옴
} ///SLA+W 전송완료
TWDR=addr; ///마스터가 Write하고싶은 레지스터의 주소를 송신
TWCR=0×84; ///플래그를 소프트웨어에서 클리어하려면 1을 입력한다
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×28))
{
; ///1.플래그가 셋 되었고 2.상태코드-DATA송신완료 두조건이 만족되면 while()을 빠져나옴
}
TWDR=data; ///송신data를 쓴다
TWCR=0×84; ///플래그를 소프트웨어에서 클리어하려면 1을 입력한다
while(((TWCR&0×80)==0×00) || ((TWSR&0xF8)!=0×28))
{
; ///1.플래그가 셋 되었고 2.상태코드-DATA송신완료 두조건이 만족되면 while()을 빠져나옴
}
TWCR=0×94; ///STOP bit 전송
_delay_us(50);
}
void getRawData()
{
buffer[0] = MPU6050_read(0x3B);
buffer[1] = MPU6050_read(0x3C);
buffer[2] = MPU6050_read(0x3D);
buffer[3] = MPU6050_read(0x3E);
buffer[4] = MPU6050_read(0x3F);
buffer[5] = MPU6050_read(0×40);
buffer[6] = MPU6050_read(0×43);
buffer[7] = MPU6050_read(0×44);
buffer[8] = MPU6050_read(0×45);
buffer[9] = MPU6050_read(0×46);
buffer[10] = MPU6050_read(0×47);
buffer[11] = MPU6050_read(0×48);
ax = (int)buffer[0] << 8 | (int)buffer[1];
ay = (int)buffer[2] << 8 | (int)buffer[3];
az = (int)buffer[4] << 8 | (int)buffer[5];
gx = (int)buffer[6] << 8 | (int)buffer[7];
gy = (int)buffer[8] << 8 | (int)buffer[9];
gz = (int)buffer[10] << 8 | (int)buffer[11];
ax_ang=-atan2((double)ax,sqrt((double)ay*(double)ay+(double)az*(double)az))*180/M_PI; ///가속도센서로 얻은 x축 각도값
ay_ang=atan2((double)ay,(double)az)*180/M_PI;
_delay_ms(500);
}
플렉서블 저항을 이용한 ADC변환 후 명령 지시 실험
//——– Initialize ADC
void ADC_init(void)
{
// 기준전압 설정
ADMUX |= (1 << REFS1) | (1 << REFS0) ;
// ADC 허용
ADCSRA |= (1 << ADEN);
// 프리스케일러 값 64
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
}
//——– Analog to Digital
unsigned int ADC0onversion(int ch)
{
ADMUX=0xC0;
_delay_ms(10);
// AD 변환 시작
ADCSRA |= (1 << ADSC);
// AD 변환 완료 여부 확인, AD 변환 완료될 때까지 대기, 완료 확인되면 다음 진행
while(!(ADCSRA & (1 << ADIF)));
// AD 변환 완료된 데이터 반환
return ADC;
}
unsigned int ADC1onversion(int ch)
{
ADMUX=0xC1;
_delay_ms(10);
// AD 변환 시작
ADCSRA |= (1 << ADSC);
// AD 변환 완료 여부 확인, AD 변환 완료될 때까지 대기, 완료 확인되면 다음 진행
while(!(ADCSRA & (1 << ADIF)));
// AD 변환 완료된 데이터 반환
return ADC;
}
unsigned int ADC2onversion(int ch)
{
ADMUX=0xC2;
_delay_ms(10);
// AD 변환 시작
ADCSRA |= (1 << ADSC);
// AD 변환 완료 여부 확인, AD 변환 완료될 때까지 대기, 완료 확인되면 다음 진행
while(!(ADCSRA & (1 << ADIF)));
// AD 변환 완료된 데이터 반환
return ADC;
}
int ADC_set()
{
unsigned int ch_ADC0,ch_ADC1,ch_ADC2;
int cnt=0;
ch_ADC0 = ADC0onversion(0);
ch_ADC1= ADC1onversion(1);
ch_ADC2=ADC2onversion(2);
if(ch_ADC0>250)
{
cnt++;
}
if(ch_ADC1>700)
{
cnt++;
}
if(ch_ADC2>700)
{
cnt++;
}
_delay_ms(1);
return cnt;
}
void angle_set()
{
int gear=0;
getRawData();
gear=ADC_set();
switch(gear)
{
case 3: //정지
putch_USART0(’7′);
break;
case 2://1단속력
if(ax_ang>60) {//앞
if(ay_ang>50)//오른쪼
putch_USART0(’1′);
else if(ay_ang<-50)//왼쪽
putch_USART0(’2′);
else//전진
putch_USART0(’3′);
}
else if(ax_ang<-60){//뒤
if(ay_ang>50)//오른쪼
putch_USART0(’4′);
else if(ay_ang<-50)//왼쪽
putch_USART0(’5′);
else//전진
putch_USART0(’6′);
}
else //정지
putch_USART0(’7′);
break;
case 1://2단속력
if(ax_ang>60) {//앞
if(ay_ang>50)//오른쪼
putch_USART0(’8′);
else if(ay_ang<-50)//왼쪽
putch_USART0(’9′);
else//전진
putch_USART0(‘a’);
}
else if(ax_ang<-60){//뒤
if(ay_ang>50)//오른쪼
putch_USART0(‘b’);
else if(ay_ang<-50)//왼쪽
putch_USART0(‘c’);
else//전진
putch_USART0(‘d’);
}
else //정지
putch_USART0(’7′);
break;
case 0:/3단속력
if(ax_ang>60) {//앞
if(ay_ang>50)//오른쪼
putch_USART0(‘e’);
else if(ay_ang<-50)//왼쪽
putch_USART0(‘f’);
else//전진
putch_USART0(‘g’);
}
else if(ax_ang<-60){//뒤
if(ay_ang>50)//오른쪼
putch_USART0(‘h’);
else if(ay_ang<-50)//왼쪽
putch_USART0(‘i’);
else//전진
putch_USART0(‘j’);
}
else //정지
putch_USART0(’7′);
break;
}
gear=0;
}
RC카와 통신을 위한 UART 설정 실험
void InitUart(void)
{
UBRR0H=0X00;
UBRR0L=0X67;
UCSR0A = 0X00;
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = 0X06;
}
void Data(unsigned char data)
{
while((UCSR0A & 0X20)==0×00);
UDR0 =data;
}
void putch_USART0(unsigned char data){
while(!(UCSR0A&(1<<UDRE0)));
UDR0=data;
}
void putstr(unsigned char* data){
char i=0;
for(i=0; data[i] != 0; i++){
putch_USART0(data[i]);
}
}
기타
참고 문헌
· AVR ATmega128 프로그래밍과 인터페이싱 (ITC출판,이응혁,장문석,장영건 지음)
· JMDO-BT-1 사용자 매뉴얼
· 24HS5005 datasheet
· SLA7026M datasheet
회로도
수/발광 센서부
차량 Atmega128과 구동부 커넥터