[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과 구동부 커넥터
[43호]Smart Pad
2017
ICT 융합 프로젝트 공모전 최우수상
Smart Pad
글 | 단국대학교 정의동, 양지현, 최진우
심사평
칩센 유사한 작품이 있었으나, 시제품의 완성도와 시연의 구성이 매우 좋았습니다. 작품과 같은 제품을 기획할 때 운동량 측정 등 여러 부가 기능에 대한 고려를 많이 하느라 메인 기능의 부각을 저하시키는 경우가 많이 있는데, 보고서 및 시연 영상에서 핵심 기능을 강조함으로서 제품의 기획의도를 더 잘 이해하게 만들었습니다. 추가적으로 연동하는 스마트장치의 네비게이터에서 이미 인지한 정보를 다른이에게 공유한다는 내용 또한 흥미를 끌게 하는 작품입니다. 신발 깔창에 제품을 설치하는 방식인데, 좀 더 심플한 액세서리 개념으로 적용하는 방법은 없을지 고민을 해보는 것도 좋아 보입니다.
뉴티씨 당장 제품으로 만들어도 될 만큼 좋은 작품입니다. 그대로 출시해도 될 것 같지만, 이 기술을 따로 VR이나 AR에 적용하면 더 많은 가시적인 효과를 볼 가능성이 있겠습니다.
위드로봇 동영상 데모가 훌륭합니다. GPS 위치 오차가 심한 지역에서는 동영상처럼 적절한 서비스를 제공하기가 어려울 수 있습니다. 이 부분에 대한 대비책이 있다면 매우 훌륭한 서비스를 제공하는 제품이 될 것 같습니다.
작품 개요
최근 웨어러블 디바이스들이 많이 출시가 되고 있고 있습니다. 웨어러블 디바이스는 신체에 부착하여 컴퓨팅 행위를 할 수 있는 모든 것들을 뜻하고, 일부 컴퓨팅 기능 수행이 이용 가능한 애플리케이션까지 포함된 기기를 의미합니다. 인간과 사물 그리고 기기 등 연결대상과 그 범위가 빠른 속도로 확대되고, 사용자를 네트워크와 연결시키는 웨어러블 디바이스의 중요성이 부각되고 있는 시점에서 생각해 낸 웨어러블 디바이스는 SMART PAD입니다.
일반 사람들 ver.
많은 웨어러블 디바이스들이 나오고 있지만 깔창으로 나오고 있는 것들은 대부분 칼로리 측정기, 만보계 기능을 하는 것인데 이것에 착안하였고 길치, 방향치인 사람들도 올바른 방향으로 길을 찾아갈 수 있게 알려주면 좋겠다는 생각과 요새 납치, 유괴에 관해 이슈가 되는 점에 대해 보호자에게 현재위치를 알리는 것이 필요하다는 생각에 더해 Smart PAD란 것을 생각하게 되었습니다.
또한 내 하루 일과를 알 수 있고 여행일기를 쓰면 좋겠다는 생각 또한 발자취 메뉴와 여행일기 메뉴를 생각 하게 되었습니다. 이 스마트 패드로 사람들이 지도에 시간을 할애하는 것이 아닌 주변을 돌아보며 다닐 수 있고 안전한 귀가길, 여행자에게는 여행일기에 더불어 하루종일 나의 발자취 또한 매일 저장할 수 있게 하는 것이 목적입니다.
시각장애인 ver.
깔창에 진동모터를 부착하여 앞, 뒤, 좌, 우를 진동으로 길을 알려주는 웨어러블 디바이스입니다. 그뿐만 아니라 일반 사람들이 걷다가 신호등이 고장난 곳, 공사 중인 곳 등을 3초 이상 멈추게 되면 사용자의 위치를 서버에 보내 지도에 표시합니다. 많은 사용자가 표시한 지역을 활용하여 시각장애인분들이 그 지역을 피할 수 있도록 합니다.
작품 설명
주요 동작 및 특징
하드웨어
· 양쪽 발에 아두이노 미니 프로, 진동모터, 가속도/지자기/자이로 센서, 블루투스, 압력센서 등을 부착한다.
· 안드로이드에 tmap api를 사용하여 MAP을 보여준다.
· 안드로이드 어플리케이션 내에 두 가지 방법 중(촉각적-진동/청각적방법) 하나를 선택한다.
· 어플리케이션에 현재 방향과 다음 방향을 알려줄 알고리즘을 적용한다.
· 깔창에 달린 가속도, 자이로, 지자기 센서를 사용해 절대적인 현재 위치를 파악한다.
· 길을 가다가 멈출 경우 압력센서로 멈춰있는지 걷고 있는지 판단하여 블루투스 1:N 통신으로 현재 위치를 안드로이드에게 전달한다.
· 안드로이드 어플리케이션에서 위에서 말한 알고리즘으로 다음 방향을 구한다.
· 블루투스 통신으로 다음 방향을 전달한다.
· 깔창에 부착된 진동모터 또는 청각적인 알림으로 방향을 알 수 있다.
· 촉각적 방법일 경우 – 앞이면 양발의 ‘앞’에 달린 진동 모터를 뒤면 양발의 ‘뒤’에 달린 진동모터를 왼쪽 방향이면 ‘왼발’을 오른쪽 방향이면 ‘오른발’ 진동모터를 울리게 한다.
· 청각적 방법일 경우 음성으로 어느 방향으로 가야 하는지 알려준다.
· 음성인식으로 목적지를 정할 수 있다.
· 안드로이드 어플리케이션 메뉴는 아래와 같다.
1. 현재위치부터 목적지까지의 길을 보여주는 메뉴,
2. 길을 상세히 설명한 메뉴,
3. 최근 검색 메뉴,
4. 사용자가 하루 종일 다닌 발자취를 보여주고, 여행 메모(사진,동영상)를 할 수 있는 여행 다이어리 메뉴
5. 하루 종일 얼마나 걸었는지를 알려주는 메뉴
6. 보호자에게 사용자 위치를 알림 메뉴
앞서 말한 4번 메뉴를 통해 사용자의 그 날 하루 발자취와 여행일기를 쓸 수 있다.
현재 있는 곳에서 사진을 찍은 경우, 나중에 그 장소에서 무얼 했는지, 얼마나 그 장소에 있었는지를 알 수 있다.
소프트웨어
길찾기 알고리즘
1. 현재 위치와 그 다음 가야할 곳 (1m 앞)의 위치를 알아냅니다.
2. getAngle이라는 함수를 만들어서 현재위치와 다음 위치까지의 각도를 알아냅니다. bearingTo(destination)을 사용하여 알아낼 수 있습니다.
3.이를 이용하여 방향벡터를 구할 수 있으므로 어느 방향인지 판단을 할 수 있습니다.
4. 그 전에 현재 사용자가 바라보는 방향의 정보를 깔창으로부터 받아와 절대 방향을 생성합니다.
5. 절대 방향을 토대로 진행방향과 비교를 하여 다음 방향을 구합니다.
6. 다음 방향을 깔창에 진동으로 알려줍니다.
7. 현재위치를 계속해서 갱신해야만 사용자가 움직이면서 계속해서 다음 방향을 새로 구할 수 있습니다.
어플리케이션 모습
용도 및 사용방법
음성인식 또는 text 방법으로 목적지를 설정합니다. 어플리케이션의 방향설정 알고리즘을 통해 다음 위치를 구하면 위의 그림처럼 발에 진동이 울려 방향을 알 수 있다. 여행일기 메뉴에서는 오늘 하루의 발자취와 일기(사진, 메모)등을 쓸 수 있다.
어플에 나온 화살표 방향이 진동방향을 알려준다. 왼쪽은 사람이 느낀 방향을 손가락으로 나타낸 사진이다.
주요 사용자 및 수혜자
처음 가는 길에 대한 방향정보를 알려주어 목적지에 도달할 수 있게 하기 때문에 여행자 또는 길치, 방향치에게 편의를 줄 수 있다. 또한 청각적인 도움 또는 촉각적 도움을 주기 때문에 시각장애인에게 또한 편의를 줄 수 있다.
특장점 및 활용계획
지도가 아닌 주변에 시각을 씀으로써 안전하게 목적지에 도달할 수 있을 뿐만 아니라 보호자에게 사용자의 위치를 알릴 수 있고 여행일기 또는 하루 일지를 씀으로써 오늘 하루에 대해 돌아 볼 수 있다.
서버와 빅데이터 활용부문
일반 사용자가 신호등이 고장난 곳, 공사중인 곳에서 3-5초 정도 서있으면 사용자의 위치를 모바일에서 GPS 데이터를 받아서 서버로 전송합니다. 그리고나서 서버는 데이터베이스에 위치정보를 저장합니다. 위치 정보가 많이 쌓여서 지도상으로 정보를 조회하고 싶을 때는, 데이터 베이스에서 모아놓은 정보를 조회하여 서버단에서 지도를 조회할 수 있도록 합니다. 위 그림은 서버에서 지도 정보를 조회했을 때 나타나는 대략적인 화면입니다. 사용자가 정지한 지점 여러 군데가 데이터베이스에 저장되어 있는데, 서버는 데이터베이스에서 정보를 조회하여 밀집되어 기록되어 있는 위치가 있는지 확인하게 됩니다. 이때 KNN 알고리즘을 사용하여 밀집되어 있는 위치를 찾고, 밀집도에 따라서 구분을 달리하여 해당 지점을 표시하여 한눈에 개선할 지점을 조회할 수 있습니다.
또한 어플리케이션에서 구현한 알고리즘을 통해 개선되어야할 위치를 피하여 사용자(시각장애인)에게 길을 알려줍니다.
전체 시스템 구성
· T map API를 이용해 MAP 구현
· 방향 Algorithm을 구축하여 사용자가 가야 할 방향 구하기
· 길 찾기 중 보호자에게 SMS로 알람
· 아두이노와 Bluetooth 통신을 통한 데이터 송신 및 수신
1) 지자기센서 사용해 절대방향 수신
2) 자이로,가속도 센서를 사용해 운동량, 만보계량 수신
3) 알고리즘에서 구한 방향 송신
· 작품규격
사이즈 : 220 x 90 x 40(mm)
개발 환경(개발언어, Tool, 사용시스템 등)
· 개발언어 – C언어 / java : 개발 Tool에서 쓰이는 언어가 C언어이기 때문에 자연스레 C언어를 이용하여 코딩 및 소스구현을 하게 되었습니다. 이클립스에서 쓰는 언어는 java이기 때문에 java를 공부하고 소스를 구현하였습니다.
· 개발 Tool – 아두이노 IDE tool : 아두이노 프로미니를 사용하여 아두이노 전용 tool인 IDE tool을 사용하였습니다.
· 개발 Tool – 이클립스 : 안드로이드 스튜디오가 나오기전 이클립스를 사용했었는데 이클립스로 java 공부할 때 사용하여 구현하다보니 이클립스가 더 편해져서 이클립스를 사용하여 app 개발을 했습니다.
· 사용 시스템 – 아두이노 프로미니 : 깔창에 들어가려면 작은 mcu를 사용해야되고 센서와 모터가 많이 들어가기 때문에 핀이 많이 필요하여 타이니두이노 보단 아두이노 프로미니가 적합하다고 생각했습니다. 깔창에 있는 아두이노에선 연산을 많이 요구하지 않기 때문에 속도면에서 빠르지 않아도 된다고 생각하여 아두이노 프로미니를 선택하였습니다.
단계별 제작 과정
기타(회로도, 소스코드, 참고문헌 등)
회로도
public synchronized float getAngle(){
TMapPoint point1 = point_st ;
//TMapPoint pOINT2 = Point();
Location here = new Location(“Start”);
here.setLatitude(point1.getLatitude());
here.setLongitude(point1.getLongitude());
Location destination = new Location(“End”);
//destination.setLatitude(point2.getLatitude());
///destination.setLongitude(point2.getLongitude());
destination.setLongitude(Destlatitude);
destination.setLongitude(Destlongitude);
if(point1==null || destination == null
|| (point1.getLatitude() == 0 && point1.getLognitude() == 0)
|| (Destlatitude == 0 && Destlongitude == 0)) {
return -1;
; else {
mAngle = here.bearingTo(destination); //Angles: -180 ~ 180
}
/* if(point1 == null || point2 == null
|| (point2.getLatitude() == 0 && point2.getLongitude() == 0)
|| (Destlatitude == 0 && Destlongitude == 0)) {
return -1;
; else {
mAngle = here.bearingTo(destination); //Angles: -180 ~ 180
} * //도착지점
if(mAngle < 0) {
mAngle += 360; //convert to 0~360 range
}
//mangle.setText(Float.toString(mAngle));
return mAngle;
}
private void Battery…Check(float battery)
if(gpsLocation ! = null) {
updateCooridiate(gpsLocation);
} else if (networkLocation !=null) {
updateCooridiate(networkLocation);
}else{
updateCooridiate(passiveLocation);
}
}
@override
prodected void onResume() {
// TODO Auto-generated method stub
super.onResume();
setup();
}
/////////
@override
public void onStart() {
// TODO Auto-generated method stub
super.onstart();
Location location = mLocationManager/getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
Location gpsLocation = null;
Location networkLocation = null;
Location passiveLocation = null;
// gps가 항상 정확하지 않음으로, 프로바이더 두개를 사용하는 것이 가장 정확도가 높다.
gpsLocation = requestUpdatesFromProvider(LocationManager.GPS_PROVIDER);
networkLocation = requestUpdatesFromProvider(LocationManager.NETWORK_PROVIDER);
passiveLocation = requestUpdatesFromProvider(LocationManager.PASSIVE_PROVIDER);
if (gpsLocation ! = null) {
updateCooridiate(gpsLocation);
} else if(networkLocation ! = null) {
updateCooridiate(networkLocation);
} elsle {
updateCoorkdiate(passiveLocation);
방향 알고리즘 부분
public void checkAngle1()
{
if((rpAngle >= 270) && (rpAngle <= 360))
{
compass(‘F’);
}
else if((rpAngle >= 0) && (rpAngle <= 89))
{
compass(‘R’);
}
else if((rpAngle >= 90) && (rpAngle <= 180))
{
compass(‘B’);
}
else
{
compass(‘L’);
}
}
public class httprequest extends Thread
{
double v1 = 0;
double v2 = 0;
public httprequest(double v1, double v2)
{
this.v1 = v1;
this.v2 = v2;
}
public void run() {
// TODO Auto-generated method stub
String url = “http://ec2-54-148-213-31.us-west-2.compute.amazonaws.com:5000/”;
String str1 = Double.toString(v1);
String str2 = Double.toString(v2);
uri += str1;
uri += ‘/’;
uri += str2;
RequestBundle rb = new RequestBundle();
rb.setUrl(uri);
rb.setHttpMethod(HttpMethod.GET);
Mat<String, Object > mmap = new HashMap<String, Object>();
APIRequest api = new APIRequest();
try {
api.request(rb);
} catch (malformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
아두이노 소스
왼쪽 발
#include <SoftwareSerial.h>
SoftwareSerial blue(2,3);//rx tx
#include <Wire.h> //I2C Arduino Library
#include <String.h>
int Stream_control =8; //20
int Stream_status =7;
#define address 0x1E //0011110b, I2C 7bit address of HMC5883
float thetan=0;
float m[10]={0,};
float sum_theta=0;
float sum_thetan=0;
char dir;
char dir2=0;
int dir_sum=0;
int FSR_Pin = A0;
int FSRReading;
float Rfsr;
int Vibrate_pins[4] = {5,0,4,6}; // LED 연결 핀
boolean Vibrate_state[4];
int Battery_Pin = A1;
int Battery_Check;
float Battery;
int step = 0;
void setup(){
//Initialize Serial and I2C communications
Serial.begin(9600);
blue.begin(9600);
Wire.begin();
//Put the HMC5883 IC into the correct operating mode
Wire.beginTransmission(address); //open communication with HMC5883
Wire.write(0×02); //select mode register
Wire.write(0×00); //continuous measurement mode
Wire.endTransmission();
for(int i = 0; i < 3; i++){
pinMode(Vibrate_pins[i], OUTPUT);
Vibrate_state[i] = false;
digitalWrite(Vibrate_pins[i], Vibrate_state[i]);}
pinMode(Stream_control,OUTPUT); //40
pinMode(Stream_status,INPUT);
}
void loop(){
int x,y,z;
Wire.beginTransmission(address);
Wire.write(0×03);
Wire.endTransmission();
Wire.requestFrom(address, 6);
if(6<=Wire.available()){
x = Wire.read()<<8; //X msb
x |= Wire.read(); //X lsb
z = Wire.read()<<8; //Z msb
z |= Wire.read(); //Z lsb
y = Wire.read()<<8; //Y msb
y |= Wire.read(); //Y lsb
}
FSRReading = analogRead(FSR_Pin);
Rfsr = ((9.78 * FSRReading)/(1-(FSRReading/1023.0)));
delay(250);
Battery_Check = analogRead(Battery_Pin);
Battery = Battery_Check/4.2;
if (blue.available()){
byte data = blue.read();
digitalWrite(Stream_control,HIGH);
blue.write(65);
blue.write(84);
blue.write(79);
blue.write(50);
blue.write(13);
int a=digitalRead(Stream_status);
// Serial.println(a);
if(a==0)
{
digitalWrite(Stream_control,LOW);
// delay(800);
Serial.println(data);
blue.write(data);
blue.write(13);
//Serial.print(“ATO1:”);
// Serial.println(data);
delay(800);
}/*
if(data >= ’1′ && data <= ’5′)
{
if((data==’4′)||(data==’1′)||(data==’2′))
{
digitalWrite(Stream_control,HIGH);
blue.write(65);
blue.write(84);
blue.write(79);
blue.write(49);
blue.write(13);
int a=digitalRead(Stream_status);
// Serial.println(a);
if(a==0)
{
digitalWrite(Stream_control,LOW);
// delay(800);
Serial.println(data);
blue.write(data);
blue.write(13);
//Serial.print(“ATO1:”);
// Serial.println(data);
delay(800);
}
}*/
if(data==’5′)
{
step = 1;
}
if((Rfsr>1000)&&(step==1))
{
step=0;
theta(x,y);
}
Serial.println((char)data);
int index = data – ’0′ – 1;
Vibrate_state[index] = !Vibrate_state[index];
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);
delay(2000);
Vibrate_state[index] = !Vibrate_state[index];
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);
}
//}
theta(x,y);
}
void theta(int mx, int my)
{
thetan = atan2(my,mx)*(180/3.14159265) +180;
compass(thetan);
// Serial.println(dir);
}
void compass(float sum_theta)
{
if ((sum_theta>=53) && (sum_theta <=160))
{
dir = ‘E’;
}
else if ((sum_theta>=6) && (sum_theta <=52))
{
dir = ‘F’;
}
else if (((sum_theta>=322) && (sum_theta <=360))||((sum_theta>=0) && (sum_theta <=5)))
{
dir = ‘G’;
}
else if ((sum_theta>=161) && (sum_theta <=320))
{
dir = ‘H’;
}
compass_print(dir);
}
void compass_print(char dir)
{
//Serial.println(dir);
//if(Rfsr>1000)
// {
//blue.println(sum_theta);
if(dir != dir2)
{
digitalWrite(Stream_control,HIGH);
delay(800);
// BTSerial.println(“AT”);
blue.write(65);
blue.write(84);
blue.write(79);
blue.write(50);
blue.write(13);
// BTSerial.write((char)’T');
//Serial.print(“okay”);
delay(10);
int a=digitalRead(Stream_status);
// Serial.println(a);
// if(a==0)
// {
digitalWrite(Stream_control,LOW);
delay(800);
blue.write(dir);
blue.write(13);
//Serial.println(BTSerial.println());
// }
}
dir2 = dir;
// }
}
오른쪽 발
#include <SoftwareSerial.h>
SoftwareSerial blue(2,3);//rx tx
// 데이터(문자열)을 받을 버퍼의 크기.
#define BUFF_SIZE 20
// 데이터 버퍼
uint8_t buffer[BUFF_SIZE];
uint8_t index = 0;
uint8_t data;
int Vibrate_pins[4] = {8,7,0,4};
int Vibrate_state[4];// LED 연결 핀
int FSR_Pin = A0;
int FSRReading;
float Rfsr;
int cnt;
int i;
void setup(){
//Initialize Serial and I2C communications
Serial.begin(9600);
blue.begin(9600);
//digitalWrite(8, HIGH);
// digitalWrite(4, HIGH);
for(int i = 0; i < 3; i++){
pinMode(Vibrate_pins[i], OUTPUT);
Vibrate_state[i] = false;
digitalWrite(Vibrate_pins[i], Vibrate_state[i]);}
}
void loop(){
if (blue.available()){
//byte data = blue.read();
data = blue.read();
// if(data == 13)
// {
// Serial.println(data);
if(data >= ’1′ && data <= ’4′)
{
Serial.print(“buffer:”);
Serial.println(data);
int index = buffer[0] – ’0′ – 1;
Vibrate_state[index] = !Vibrate_state[index];
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);
delay(2000);
Vibrate_state[index] = !Vibrate_state[index];
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);
// for(i=0;i<index;i++)
// buffer[i]=0;
// index=0;
}
/*buffer[index++] = data;
// 버퍼가 꽉 찼거나 문자열이 끝났을 때,
// 루프에서 나간다.
Serial.print((char)data);
if(index == BUFF_SIZE || data == 13)
{Serial.println(data);
Serial.print(“buffer:”);
Serial.println(buffer[0]);
if(buffer[0] >= ’1′ && buffer[0] <= ’4′)
//if(data >= ’1′ && data <= ’4′)
{
int index = buffer[0] – ’0′ – 1;
Vibrate_state[index] = !Vibrate_state[index];
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);
delay(2000);
Vibrate_state[index] = !Vibrate_state[index];
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);
for(i=0;i<index;i++)
buffer[i]=0;
index=0;
}
// 9600bps 기준으로 delay 를 1ms 을 줘야 한다.
delay(1);
//}
FSRReading = analogRead(FSR_Pin);
Rfsr = ((9.78 * FSRReading)/(1-(FSRReading/1023.0)));
delay(250);
if(Rfsr>1000)
{
cnt++;
if(cnt>1000){
blue.println(“5″);
cnt=0;
}
}
}
}
참고문헌
· 카페 [임베디드 공작소]
· 200개의 단계별 예제로 배우는 안드로이드드 4.0 [한동호 저자]
· 그 외 네이버 지식인, 네이버 카페 “당근이의 AVR 갖구 놀기”
[43호]빠른 전송을 자랑하는 USB 3.0 인터페이스 [oCamS-1 CGN-U] 스테레오 카메라 출시
위드로봇(주)
빠른 전송을 자랑하는 USB 3.0 인터페이스
[oCamS-1 CGN-U] 스테레오 카메라 출시
계측기, 스마트센서, 자동 제어 시스템 등의 분야에서 사업을 진행하고 있는 위드로봇에서는 그동안 볼 수 없었던 경쟁력 있는 스테레오 카메라 ‘oCamS-1 CGN-U’를 출시하였다. 스테레오 카메라란 입체사진을 찍기 위한 카메라로써 카메라 몸통 좌우에 간격을 띄워놓고 같은 물체를 촬영하고, 스테레오 뷰어를 이용해서 보면 상이 입체적으로 보이게 되는 카메라이다.
‘oCamS-1 CGN-U’는 ROS와 호환되므로 쉽게 로봇 운영 시스템의 풍부하고 강력한 기능을 활용할 수 있으며, 교환이 가능한 M12 렌즈를 제공함으로써 다양한 응용분야에 유연하게 적용하여 더욱 편리하게 이용할 수 있다. 또한 초고속 USB 3.0 인터페이스를 지원하여 고속 전송이 가능해, 빠른 스피드를 자랑한다. ‘oCamS-1 CGN-U’는 Window7/8/9, Linux, Plug-and Play by UVC(USB Video Class) Protocol 등 다양한 운영체제를 지원하며, 기존 스테레오 카메라와 위드로봇에서 앞서 출시된 스테레오 카메라보다 가격대가 저렴해 경제성 또한 높게 평가되고 있다. 다른 제품보다 저렴하지만 제품의 품질, 스펙 모두 뒤처지지 않아 충분히 경쟁력있는 제품으로 자리 잡고 있다.
위드로봇은 계속하여 ‘oCamS-1 CGN-U’제품의 관련 동영상 및 기타 자료들을 지속적으로 업데이트하여 제품을 널리 알리겠다고 말했다.
더 자세한 사항은 디바이스마트 홈페이지에서 확인해 볼 수 있다.
특징
- ROS 호환성: ROS(Robot Operating System)와 호환되므로 적은 노력으로 ROS의 풍부하고 강력한 기능을 활용할 수 있습니다.
- 풍부한 데이터: 스테레오 영상 이미지와 IMU 관성센서 데이터가 같이 제공되므로 별도의 처리 없이 카메라 자세 등을 알 수 있습니다.
- 유연성: 교환 가능한 표준 M12 렌즈를 제공하므로 다양한 응용분야에 적용할 수 있습니다.
- 고속 전송: USB 3.0 SuperSpeed 인터페이스를 지원합니다.
- 경제성: 동급 제품에 대비하여 매우 합리적인 가격으로 스테레오 영상을 제공합니다.
Board Detail
사양
Type | Description |
---|---|
센서 | OnSemi AR0134 CMOS 이미지 센서(1/3인치) |
인터페이스 | USB 3.0 Super-Speed |
렌즈 | 교환 가능한 표준 M12 렌즈 |
지원 OS | Windows 7/8/10, Linux, Plug-and Play by UVC(USB Video Class) protocol |
전원 공급 | USB Bus Power |
동작 온도 | 0°C ~ + 70°C |
소모 전력 | DC 5V/240mA |
셔터 | 글로벌 셔터(Electric Global Shutter) |
Field Of View(FOV) | - 65 degrees at full resolution of 1280(H) x 960(V) - FOV for the following resolutions are reduced from the full resolution image due to cropping: 1280(H) x 720(V) - FOV for the following resolutions is maintained due to binning: 640(H) x 480(V) |
제어 기능 | Brightness, Exposure, Color Gain(Red, Blue) |
이미지 전송률 | 2560×960 @45fps, 2560×720 @60fps, 1280×480 @45fps |
무게 | 약 30 g(렌즈 포함) |
크기 | 146mm x 26mm (PCB) |
베이스 라인 | 120 mm |
Softwares
[oCamS-1CGN-U] USB 3.0 스테레오 카메라 제품 구매하러 가기
[43호]Guardian Angel (Babycare)
2017
ICT 융합 프로젝트 공모전우수상
: Guardian Angel (Babycare)
글 | 단국대학교 양지현, 우경은, 박건주
심사평
칩센 육아와 관련된 IT 기술은 언제나 hot item입니다. 특히 ‘만에 하나 라도’ 라는 것에 불안해 하는 영유아를 둔 부모에게 잘 와닿을 수 있는, 즉 상품적인 가치가 있을법해 보인다는 느낌을 받았고, 작품 제작에 있어서도 전반적으로 시스템 구성이 잘 되어 있고, 각 파트별 구성 요소에 대한 이해도도 높아 여러가지 면에서 기획이 잘 되어 있는 작품이라는 생각이 듭니다. 세부적으로 각 파트에 적절한 하드웨어 선정을 고민한 흔적과 함께 신호 및 시그널 처리 부분에 대한 명확성이 눈에 띄었습니다. 밴드 부분에 있어서 무선 전파의 감쇄를 저하시키지 않는 재질을 고려하는 부분은 필요할 것으로 보이네요. 개인적으로는 실제 완성품의 가격부분 등이 문제가 아니라면, 하나쯤 구비해 놓을 수도 있겠다는 생각이 듭니다.
뉴티씨 이 작품은 완성도가 뛰어나서 당장 상품으로 만들수도 있을 것 같습니다. 매우 좋은 아이디어입니다. 다만, 디자인과 경량화 관련 고민을 해야할 것입니다.
위드로봇 유사한 상용 제품과의 차별성 부분을 추가로 설명할 수 있으면 훌륭한 작품이 될 것 같습니다.
작품 개요
한 아기의 아빠가 아기와 함께 있다가 화장실이 급해 아기를 앉혀 놓고 잠시 자리를 비운 동안 아기가 심장마비로 사망했다는 뉴스를 본 적이 있습니다. 또한 아기는 돌연사하는 경우도 많고, 부모가 제 때 알아 차리지 못해 조치를 취하지 못한 경우도 많습니다. 이를 보고 아기의 상태를 실시간으로 알려주고 확인할 수 있다면 이런 상황을 피할 수 있지 않을까? 라는 생각을 하였습니다. 그래서 아기 모니터링 밴드를 만들게 되었습니다. 이 작품을 만들 때 고려 한 점은 다음과 같습니다.
1. 아기의 사망 원인 중 가장 큰 비중을 차지하는 부분은 아기의 갑작스러운 심정지와 무호흡 상태인 돌연사입니다. 심장박동수를 통해 숨을 쉬는지 안 쉬는지를 판단할 수 있으므로 심장박동 센서를 제작하여 측정해야 합니다.
2. 아기의 저체온방지를 위해 온도 센서를 달아 체온을 측정해야 합니다.
3. 아이의 모습을 실시간으로 볼 수 있도록 아기 옆에 인형을 두고 아기를 촬영하며 서버에 넘겨주는 방식으로 부모의 스마트폰 애플리케이션으로 볼 수 있게 합니다.
4. 아기가 뒤집었을 경우 그 상태로 오래 있게 되면 폐에 무리가 가서 숨을 못 쉬게 됩니다. 이를 방지하기 위해 아기가 뒤집힌 상태인지 파악해야 합니다.
5. 아기가 울 경우, 부모가 알게 된다면 적절한 조치를 취할 수 있으므로 아기의 울음소리를 파악하여 알려줍니다.
이 5가지의 사항을 중점으로 아기 상태를 측정할 수 있는 발찌와 부모의 팔찌, 스마트폰 어플리케이션을 만들었습니다.
작품 설명
주요 동작 및 특징
이 작품은 아기의 심박수, 체온, 울음, 상태를 모니터링 할 수 있는 웨어러블 디바이스입니다. 이 작품은 밴드형 하드웨어, 아기 인형 하드웨어, 안드로이드 어플리케이션, 서버로 나누어 살펴 볼 수 있습니다.
구성
① Band (bracelet)
· CPU
· 센서부(심박동 센서, 적외선 온도 센서, 가속도 센서)
· 통신부(bluetooth)
· 배터리
· 프레임
② 아기 인형
· CPU
· 센서부(마이크센서)
· 통신부(bluetooth)
· 배터리
③ 안드로이드 어플리케이션
④ 서버
하드웨어-소프트웨어
① 밴드 – 심박동센서
심장박동 센서의 기본원리는 PPG 측정과 같습니다. 아래 사진과 같이 LED를 사용하여 빛을 발산하면 손가락에 흐르는 혈류량에 따라 반사되는 양이 다릅니다. 적혈구가 많을수록 빛이 흡수되므로 반사되는 빛의 양이 감소합니다. Photo diode가 반사되는 빛을 전기신호로 바꾸어 줍니다. Photo diode로부터 출력되는 전기신호의 세기를 증폭시켜 ADC를 이용해서 디지털 값으로 변화시킵니다. 이를 심장박동수로 계산하면 됩니다. OPAMP와 2.34Hz를 cuf off 주파수로 가지는 low pass filter를 2개 구현하여 직렬로 연결하였습니다. 2.34Hz를 cuf off 주파수로 결정한 것은 최대 심장박동수를 150bpm(beat per minute)를 고려한 것입니다. 2.5Hz= 150beat/60sec이기 때문입니다.
다음은 소스 부분 설명입니다. 위 그림에서 보듯이, 60초에서 x를 나누면 심장박동수입니다. 따라서 이를 구하는 소스로는 pulse의 상승 부를 파악하기 위해 pulse의 부분을 나눕니다. pulse 값이 30 ~ 1000 사이의 값일 경우, 상승 시점으로 간주합니다. 그때의 시간을 알아 nowtime이라는 변수에 저장합니다. 정확도를 위해 sampling을 하는데 상승 시점일 때 총 아홉 번으로 나누어 샘플링을 합니다. 샘플링 할 때의 시간을 lasttime 변수에 저장합니다. 아홉 번 샘플링 한 값들의 평균을 구하고 60초로 이를 나누면 심박 수를 구하게 됩니다.
② 아기 인형 – 마이크 센서
인터럽트를 써서 센서 ADC 값을 받아들이고, FIR 필터를 사용하여 주변 소리를 제거하여 아기 울음소리만 추출합니다. Filtering은 신호처리의 핵심적인 과정으로 어떤 신호에 대한 스펙트럼을 원하는 주파수 대역만큼 제한시키는 주파수 선택 회로입니다. 여기서 원하는 주파수 대역은 통과 대역(passband)이 되고 원치 않는 대역은 차단 대역(stopband)이 됩니다. FIR 필터 소스는 ‘디지털 신호 처리 공학’이라는 수업에서 배운 이론을 바탕으로 짰습니다. FIR 필터는 입력신호의 유한한(Finite) 값들만을 가지고 필터를 하는 디지털 필터입니다.
먼저 Matlab을 이용하여 소스를 구현했습니다. 몇 개의 아기 울음소리파일을 Matlab으로 분석해 본 결과, 잡음을 제거하기 위해서는 저주파 영역을 통과시키고 고주파를 차단하는 Low Pass Filter를 설계해야 한다는 것을 알 수 있었습니다. 주파수 spectrum을 확대해 본 결과, 0.12π까지 거의 90%의 음성신호가 분포되어 있다는 것을 알 수 있었습니다. 따라서 Pass band = 0.12π 로 설계했습니다. 마찬가지로 0.54π~0.6π 사이에 진폭이 큰 잡음이 시작되는 것을 보아 stop band는 0.54π로 설계했습니다. 필터의 차수를 결정하여 주파수 대역폭을 설정해 주어야 하는데, pass band(0.12π)에서 통과되는 음성신호 90% 제외한 나머지 10%가 주파수 대역폭 안으로 포함될 수 있도록 설계합니다. 따라서 약 0.3π로 주파수 대역폭을 설정했습니다. FIR 필터 중 창 함수 법을 사용했습니다. Non-causal infinite impulse response의 특성을 가진 적당한 이상적 주파수 선택적 필터를 고르고 선형 위상 인과적 FIR 필터를 얻기 위해, 임펄스 응답을 잘라내는 방식입니다. 이 방식을 이용하여 잡신호를 제거하고 원래 음성신호를 복원해 아기 울음소리를 구분하였습니다.
전체적인 신호처리 과정은 다음과 같습니다. MIC 센서를 사용하여 아날로그 값을 받습니다. 그다음, ADC 변환 소자를 사용하여 디지털 값으로 변환시킵니다. 변환된 값을 FIR 필터 처리를 하여 주변 잡음을 잡아내어 아기 울음소리인지 판단합니다. 아기 울음소리라면 부모에게 알리게 됩니다.
아직 모든 상황에서의 완벽한 잡음처리는 되지 않지만, 제가 여태 테스트해 본 음성들은 아기 울음소리만 파악할 수 있었습니다. 그래서 현재, 여러 상황에서 테스트하고 있습니다.
소프트웨어
안드로이드 APP
BPM , Temperature, Camera/album 총 세부분으로 나눌 수 있습니다.
■ BPM : 먼저 서버에서 심박 수를 받아와야 하기 때문에 JSON parsing을 합니다. 파싱이란, 컴퓨터에서 컴파일러 또는 번역기가 원시 부호를 기계어로 번역하는 과정의 한 단계로, 즉 원시 프로그램에서 나타난 토큰(token)의 열을 받아들여 이를 그 언어의 문법에 맞게 구문 분석 트리(parse tree)로 구성해 내는 일입니다. 그 중 저는 JSON이라는 파싱을 사용하였습니다. 전달받은 데이터가 없다면, 정보조회를 진행할 필요가 없으므로 doinBackground 함수를 사용하여 정보조회를 진행할 데이터가 넘어왔는지 검증했습니다. JSON 형태로 받은 데이터를 보관할 String을 선언해주고, JSON Format의 정보를 받아서 모바일 앱에서 필요한 정보만 꺼내옵니다. 생성자가 JSON String을 받아들여서 우리가 처리하기 쉽게 Object hierarchy에 넣어 주어 설정해 놓은 변수에서 불러오면 됩니다.
시각적으로 표현하기 위하여 progress bar를 구현하여 최대 150bpm에서 몇을 차지하였는지 보여 주었습니다. 또한, 막대 그래프와 꺾은선 그래프를 이용하여 현재까지 측정했던 데이터들과 평균을 보여줬습니다.
현재까지의 측정 기록을 볼 수 있도록 DB를 구축했습니다.
SQL을 사용하여 table을 생성하고 날짜, bpm를 저장하여 보여줍니다. 이 db를 사용하여 list array로 보여주며, graph를 보여줄 때도 사용됩니다.
■ Temperature : 체온을 온도계 그림으로 애니메이션 효과를 주기 위하여 Canvas 함수를 이용하여 온도계를 그려주었습니다. 체온도 bpm과 마찬가지로 서버에서 JSON parsing을 해와서 정보를 보여줬습니다.
위의 소스는 tem(Json 파싱해온 값)의 값을 온도계의 전체 범위로부터 빼서 온도가 올라가는 애니메이션 부분 알고리즘입니다.
서버
라즈베리파이를 이용하여 서버 구축을 하였습니다. mysql을 이용하여 db를 구축하였고 php언어를 사용해 html 홈서버를 구축하였습니다.
안드로이드에서 json 파싱을 해주어야 하기 때문에 json 언어로 바꾸어 주었습니다. 아기가 울 때, 뒤집었을 때 부모의 핸드폰에 카카오톡 같은 알림 메시지가 보내지게 하기 위하여 FCM을 구축하여 사용했습니다.
카메라 (라즈베리파이)
라즈베리파이 카메라를 사용하여 스트리밍을 통해 어플에서 보여줍니다. mjpg-streamer를 이용하여 url을 통하여 어플에서 불러와서 보여줍니다.
전체 시스템 구성
개발 환경(개발언어, Tool, 사용시스템 등)
개발언어 – C언어 /java
개발 Tool에서 쓰이는 언어가 C언어이기 때문에 자연스레 C언어를 이용하여 코딩 및 소스구현을 하게 되었습니다.
안드로이드 스튜디오에서 쓰이는 언어는 java이기 때문에 java 공부를 하고 이용했습니다.
개발 Tool – 아두이노 개발툴(IDE), 안드로이드 스튜디오, 라즈베리파이 Linux
아두이노 프로미니를 사용하였기 때문에 아두이노 개발툴을 사용했고, 안드로이드 어플을 만들기위해 안드로이드 스튜디오를 사용했습니다. 또한 서버와 인형 하드웨어에 라즈베리파이를 사용하여 Linux 개발 tool을 사용했습니다.
사용 시스템 – Arduino pro mini
아두이노 프로 미니를 선정하게 된 이유는 첫째, 가능한 작은 mcu를 찾고 있었기 때문입니다. 또한 처리속도에 고속이 필요하지 않기 때문입니다. 아두이노는 알고리즘 코딩만 하면 쉽게 사용할 수 있으므로 여러 mcu 중 가장 적합하다고 생각하여 메인 mcu로 사용하였습니다.
사용 시스템 – 라즈베리파이3
라즈베리파이를 선정하게 된 이유는 서버를 구축하기 위해서입니다. 리눅스 환경의 OS를 가지고 있고 MYSQL 등 db 구축도 쉽기 때문에 선택하게 되었습니다. 또한, 인형 하드웨어에서 쓰인 라즈베리파이를 선택한 이유는 900MHz의 빠른 속도와 1GB의 넉넉한 램 용량, 저렴한 가격 및 많은 GPIO 핀을 보유하고 있어서입니다. ADC 핀이 따로 존재하지 않다는 불편한 점이 있지만, 신호처리도 유용하고 아두이노와 블루투스 통신을 통해 데이터를 주고받아야 했기 때문에 라즈베리파이를 선택했습니다.
단계별 제작 과정
계획 세우기 및 사전조사(2017.01.02 ~ 2017.01.09)
프로젝트 주제를 정하고 그에 대한 사전조사를 인터넷 및 관련 사람들을 대상으로 조사하여 문제점, 주요특징, 앞으로의 전망 등을 충분히 조사를 하였습니다.
해당 작품 공부 및 제작 준비(2017.01.10 ~ 2017.01.30)
안드로이드 어플을 만들기 위해 사용한 언어는 java였습니다. 이를 위해 java 공부를 하였고, 리눅스 용어 공부도 하였습니다.
심장박동 센서 회로설계 공부를 하고 mic 센서를 통한 fir 필터 처리를 위해 matlab 문법 공부와 fir 필터에 대해 다시 공부했습니다.
하드웨어 제작(2017.01.31. ~ 2017.02.06)
심장박동센서 회로를 토대로 하드웨어를 제작하였고, 3D프린터와 아크릴 제작등을 이용하여 팔찌의 형태를 갖췄습니다. 또한 인형부분 마이크 센서와 카메라 부분도 제작하였습니다.
마이크센서와 라즈베리파이의 신호처리(2017.02.07. ~ 2017.02.15)
소리의 값을 받아와 라즈베리파이의 adc핀(adc변환소자 이용)에 연결 및 디지털 데이터를 뽑아내어 FIR 필터 알고리즘을 거친 변환 데이터를 걸러낸 후 안드로이드 FCM을 구축하여 안드로이드에 알림메시지를 띄웠습니다.
안드로이드 제작 , 서버제작 (2017.02.15. ~ 2017.03.25)
라즈베리파이를 이용하여 서버를 구축하고, db table을 만들어 아두이노와 라즈베리파이로부터 센서 값을 받아와 저장합니다. 안드로이드의 UI와 서버로부터 Json parsing을 통해 값을 받아와 보여줍니다. FCM 테스트를 통해서 안드로이드에 값이 전달되는 것을 확인할 수 있었습니다.
전체적인 연동 및 테스트 (2017.03.25. ~ 2017.04.30)
아두이노 + 라즈베리파이 + 서버(라즈베리파이) + 안드로이드를 연동시켜서 테스트를 하고 있습니다. 아직 아기에게 직접 착용하여 테스트는 하지 못하였지만, 많은 사람들에게 테스트를 해본 결과, 잘 작동하고 있습니다. 앞으로 아기들에게도 테스트하여 계속해서 디버깅하고 좋은 착용감을 위해 하드웨어 부분도 다시 고려하려 합니다.
기타(회로도, 소스코드, 참고문헌 등)
회로도
소스코드
심장박동센서 코드
#include “Heartrate.h”
int num[sample_num] = { 0 };
int getnum(int pin)
{
numcnt++;
if (numcnt >= sample_num){
numcnt = 0
}
num[numcnt] = analogRead(pin);
return(num[numcnt]);
}
int getCnt(void)
{
return(numcnt);
}
int GetRate(void)
{
static int flag
static unsigned long sampleTime[10];
unsigned long numTime_
int cnt
if (numcnt){
cnt = numcnt – 1
}
else{
cnt = sample_num – 1
}
if ((num[numcnt]>1000) && (num[cnt]<70)){
nowTim = millis();
int time = nowTim – lastTim
lastTim = nowTim
if (time>300 && time<2000){
sampleTime[flag++] = time
if (flag > 9)flag = 0
}
int array[10] = { 0 };
for (int i = 0 i<10 i++){
array[i] = sampleTime[i];
}
int array_ = 0
for (int i = 9 i>0 i–){
for (int j = 0 j<i j++){
if (array[j] > array[j + 1]){
array_ = array[j];
array[j] = array[j + 1];
array[j + 1] = array_
}
}
}
array_ = 0
for (int i =3 i <= 7 i++){
array_ += array[i];
}
numTime_ = 300000 / array_///<60*1000*
return((int)numTime_);
}
return(0);
}
int getRate(void)
{
return(GetRate());
}
안드로이드 코드
FIR필터 소스
voice_noise1(rectangular)
% 음성 파일 불러오기
[y,Fs]=wavread(‘C:\Users\jihyunyang\Desktop\voice\voice_noise1′);
% t 설정
t=(0:length(y)-1)/Fs;
figure(1)
subplot(5,1,1),plot(t,y);
xlabel(‘t’),ylabel(‘x’),title(‘Voice’);
% 음성파일의 fft
f=Fs*t;
y2= fft(y);
S_n=fft(y2,512);
w=(0:255)/256*(Fs/2);
subplot(5,1,2),plot(w,abs([S_n(1:256)'])),xlabel(‘Voice fft’);
% Rectangular filter의 특성결정
fp=100;
fs=500;
wp=2*fp/Fs;
ws=2*fs/Fs;
o_pass=2*pi*fp/Fs;
o_stop=2*pi*fs/Fs;
o_total=o_stop-o_pass;
n=8*pi/o_total
n=256;
n1=257;
% Rectangular filter 사용
y1=rectwin(n1);
wn=[wp ws];
[b,a]=fir1(n,wn,y1);
[H,w]= freqz(b,a,512);
% Rectangular Filter 그래프 출력
subplot(5,1,3),plot(w,abs(H)),xlabel(‘Lowpass Filter’);
grid
% 필터링 후 신호출력
sf = filter(b,a,y);
sound(sf,Fs)
subplot(5,1,4)
plot(f,abs(sf)),xlabel(‘FILTERLING 후 신호’);
title(‘Soundfile(Freq)’);
grid
% 필터링 후 wave 파일 저장
wavwrite(sf,Fs,’C:\Users\son ju young\Desktop\FIR\voice_noise1_LPF(rectangular).wav’);
% 필터링 후 신호 fft 변환 후 출력
y3 = fft(sf);
subplot(5,1,5)
plot(f,abs(y3));
xlabel(‘FILTERLING WAVE fft 변환’);
grid
% 필터링 후 fft변환 wave 파일 저장
bits=16;
wavwrite(sf,Fs,bits,’C:\Users\jihyunyang\Desktop\FIR\voice_noise1_fft(rectangular).wav’);
voice_noise1(blackman window)
% 음성 파일 불러오기
[y,Fs]=wavread(‘C:\Users\jihyunyang\Desktop\voice\voice_noise1′);
% t 설정
t=(0:length(y)-1)/Fs;
figure(1)
subplot(5,1,1),plot(t,y);
xlabel(‘t’),ylabel(‘x’),title(‘Voice’);
% 음성파일의 fft
f=Fs*t;
y2= fft(y);
S_n=fft(y2,512);
w=(0:255)/256*(Fs/2);
subplot(5,1,2),plot(w,abs([S_n(1:256)'])),xlabel(‘Voice fft’);
% blackman filter의 특성결정
fp=100;
fs=500;
wp=2*fp/Fs;
ws=2*fs/Fs;
o_pass=2*pi*fp/Fs;
o_stop=2*pi*fs/Fs;
o_total=o_stop-o_pass;
n=8*pi/o_total
n=256;
n1=257;
% blackman filter 사용
y1=blackman(n1);
wn=[wp ws];
[b,a]=fir1(n,wn,y1);
[H,w]= freqz(b,a,512);
% blackman Filter 그래프 출력
subplot(5,1,3),plot(w,abs(H)),xlabel(‘Lowpass Filter’);
grid
% 필터링 후 신호출력
sf = filter(b,a,y);
sound(sf,Fs)
subplot(5,1,4)
plot(f,abs(sf)),xlabel(‘FILTERLING 후 신호’);
title(‘Soundfile(Freq)’);
grid
% 필터링 후 wave 파일 저장
wavwrite(sf,Fs,’C:\Users\jihyunyang\Desktop\FIR\voice_noise1_LPF(blackman).wav’);
% 필터링 후 신호 fft 변환 후 출력
y3 = fft(sf);
subplot(5,1,5)
plot(f,abs(y3));
xlabel(‘FILTERLING WAVE fft 변환’);
grid
% 필터링 후 fft변환 wave 파일 저장
bits=16;
wavwrite(sf,Fs,bits,’C:\Users\jihyunyang\Desktop\FIR\voice_noise1_fft(blackman).wav’);
참고문헌 등
· 프로젝트로 배우는 라즈베리파이, 도날드 노리스 지음, 한빛미디어
· 200개의 단계별 예제로 배우는 안드로이드, 한동호, 제이펍
· 안드로이드 UI & GUI 디자인, 박수레, 에이콘 출판
· http://paulbourke.net/miscellaneous//dft/, written by paul bourke
· 네이버 지식인, 네이버 카페 “당근이의 AVR 갖구 놀기”, “전자공작소”, “임베디드공작소”
[43호]SMART TECH SHOW 2017
SMART TECH SHOW 2017
매일경제·MBN 주최 및 미래창조과학부 후원으로 2017 스마트테크쇼가
6월 21일부터 6월 23일까지 사흘간 서울 코엑스에서 개최되었다.
글 | 심혜린 기자 linda@ntrex.co.kr
이번 전시회는 ‘4차 산업혁명&호모사피엔스 2.0’ 주제로 생활을 윤택하게 해줄 드론, 가상현실(VR), 사물인터넷(IoT), 웨어러블, 자율주행차 등 첨단 스마트 기술을 다뤘다. 전시관은 모바일테크, 리테일테크, 에듀테크, 스마트모빌리티/로보테크 등 4가지의 중점 테마로, 약 150여 개 업체가 부스를 구성하였으며 대기업보다는 스타트업, 벤처기업 전시관이 주를 이루었다. 부대행사로는 스타트업이 참여하는 데모데이, 파미나(파티+세미나) 등이 함께 개최되어 비즈니스 기회도 주어졌다. 더불어 4차 산업혁명 시대 기업문화 혁신과 직업능력개발’을 주제로 한 컨퍼런스도 열렸다.
전시회 입구에 들어서자마자 MBC VR 체험관이 눈에 띄었다. 학생 참관객들은 주로 가상현실(VR)에 관심을 보이며 체험하느라 분주한 모습이었다. 유명 놀이기구를 VR와 플라잉체어로 간접적으로 체험할 수 있었다. 한 참관객은 예상보다도 더 현실적이라고 말했다. 실제 놀이동산을 방불케할 만큼 기다리는 학생들의 줄이 꽤 길었다. MBC는 MBC 무한도전과 VR 드라마 사월애 등 360도 VR 기술을 적용한 예능·드라마 콘텐츠를 다수 제작했으며 VR 콘텐츠 대중화에 힘쓰고 있다.
기자의 눈에 확 들어온 것은 (주)아이로(대표이사 오용주, www.airo.kr)에서 전시한 로봇 물고기 ‘마이로(MIRO)’ 였다. 최근 언론에 노출되었던 것만큼 헤엄치는 움직임이 실제 물고기와 똑같아서 놀라웠다. 50cm 가량의 마이로는 몸 사이로 LED 불빛이 나와 화려함을 자랑했다. 그저 헤엄치는 게 전부로 보일 수 있지만, 센서가 내장되어 있어 스스로 장애물을 피해 가며 유영할 수 있고, 블루투스로 연결해 사용자가 직접 조작할 수도 있다. 또한 배터리 완충 후 최대 20시간까지 유영한다. 물고기의 각양각색의 화려한 문양은 3D 디자인으로 맞춤 제작도 가능하다. 전세계적으로 로봇 물고기를 판매하는 기업은 (주)아이로가 유일하다. (주)아이로는 내년까지 가정에서 키울 수 있는 애완 로봇 물고기 출시를 목표로 하고 있다고 밝혔다.
(주)누리봄은 많은 관람객들로 붐볐다. (주)누리봄(대표 이준섭,www.nuribom.com)의 전면 투사 전자칠판 ‘T3k CANVAS’는 다년간 터치센서 공급을 통해 누리봄만의 입증된 기술을 기반으로 하였다. 터치 방식으로 멀티 터치 제스처를 지원하고, 별도 소프트웨어가 필요 없어 사용자의 편의성을 높이기 위해 노력한 점이 돋보였다. 또한 세라믹보드를 적용하여 선명한 글씨체를 구현하고, 잔상없이 쓰고 지울 수 있게 설계되었다. 광학터치를 통해 미세하게 작은 점까지 표현할 수 있을 정도로 정교하며, 마카용 일반 칠판과 터치용 전자칠판, 두 가지 기능을 동시에 사용 가능하다고 관계자는 설명했다. 뛰어난 제품 사양에도 합리적인 가격대를 책정해 학교 교실, 어학실, 멀티미디어실, 군부대 세미나실, 대학교 강의실 등에서 활용할 수 있는 제품이다.
(주)한국과학’(대표 조원득, www.chocopi.org)에서 선보인 ‘초코파이보드’는 어려운 코딩을 쉽게 가르치기 위해 개발한 보드이다. 초코파이키트로 직접 만든 초코파이 뽑기 기계를 선보여 체험할 수 있게 해 관람에 재미를 더했다. 그래서인지 코딩에 관심이 많은 학생들로 부스가 붐볐다. 초코파이보드는 스크래치를 사용하여 아두이노에 이해도가 없어도 아두이노로 만든 결과물과 동일한 결과물을 얻을 수 있는 제품이다. 광범위한 확장성을 갖추고 있어 로봇부터 시간 맞춰 물을 주는 스마트 화분까지 다양한 제품을 제작할 수 있다. 특히 초코파이보드가 다른 유사 제품과 차별화되는 점은 전력 공급이 자유로워 5-12V의 아무 전압에서나 작동이 잘 되며, 회로 설계로 256개의 LED도 연결이 가능하다. 복잡한 선 연결도 최소화하여 간단하다. 코딩이 처음이어도 제품을 구매하면 책자가 포함되어 있어 책자를 따라서 하다보면 쉽게 사용할 수 있다.
아날로그적인 공작의 로망을 실현해주는 기계 맥스트레이딩(유니맷 공작기계 한국 총판, 대표 김우민, www.maxtrading.co.kr)의 ‘유니맷(UNIMAT)’도 이번 전시회에서 많은 관람객의 손재주가 없더라도 성인, 어린이 등 누구나 안전하게 사용할 수 있는 공작기계로 나무, 플라스틱, 금속 등 다양한 재료를 가공할 수 있다. 보통의 공작기계는 너무 커서 집에 보관하기 힘들지만 A4 사이즈의 크기의 단 1대의 공작기계로 나무선반, 샌딩머신, 스카시톱, 금속 선반 등으로 만들어지니 DIY 메이커들에게 탐나는 제품이 아닐 수 없었다. 모듈로 구성되어 있어 기능, 사이즈, 파워 등을 업그레이드 할 수 있으며 소음과 진동이 적어 실내사용에도 적합하다. DIY 취미활동을 즐기는 사람들이 늘어나는만큼 높은 수요가 기대되는 제품이다.
이번 전시회에서는 가상현실(VR)을 융합한 혁신 콘텐츠가 돋보였다. 스타트업 (주)일리오(대표 오태근)는 가상현실(VR)을 활용해 가상 관광 플랫폼 ‘VRIEF’ 솔루션을 선보였다. 이 솔루션을 통해서 로보틱스 SLAM 내비게이션 기술과 VR 제작 기술을 결합하여 VR 실내 스트릿 뷰를 제공한다. 특히 빠른 스캔 속도를 자랑해 코엑스 A홀을 1시간만에 스캔이 가능하다. 사물과 건물을 구별해 동적 물체 제거가 가능하고 GPS가 없는 공간에서도 생성이 된다. URL을 통한 쉬운 배포로 누구나 언제든지 접근이 용이하다. Deep Linking으로 사용자 행동 패턴 분석을 통해 마케팅 및 맞춤형 정보도 제공한다. 이 플랫폼은 전시회, 박람회에 참가하지 못한 기업들이 정보를 획득하고 상담을 쉽게할 수 있으며, 홍보의 장으로도 활용될 수 있다. 기업에서 매번 박람회를 참가해 바이어 상담을 하더라도 원하는 바이어와 전부 상담을 하지 못한다는 아쉬움이 있지만, 이제 이 ‘VRIEF’ 솔루션을 통해서 해결할 수 있다.
국산 드론 제조사 드로젠(대표 이흥신, www.drogen.co.kr)은 ‘드론 교육 체험장’을 꾸리고 여러 종류의 드론을 선보여 인기가 대단했다. 드론에 처음 입문하는 참관객들도 직접 드론의 조작법을 교육받으며 장애물을 통과하는 시연까지 체험했다. 또한 입문자용부터 상급자용까지 다양한 드론을 전시하였다. 오전에만 수백명의 참관객들이 다녀가 드론의 대중화에 기여했다고 평가된다. 인천 송도에 드론을 체험하며 커피를 즐길 수 있는 1석 2조의 ‘카페 드로젠’ 을 운영하는등 드론 문화 확산에도 적극적으로 앞장서고 있는 기업이다.
이외에 드론 관련 부대행사로는 드론워즈 쇼케이스가 펼쳐졌다. 국내에서는 처음으로 시도되는 방식의 대회여서 특히 더 주목을 받았다. 국내외 드론레이싱 대회에서 활동 중인 프로레이서들이 총출동해 이종격투기와 비슷한 룰로 진행되었다. 드론 파일럿들이 화려한 조종 기술을 선보였으며 긴장감이 넘쳤다. 드론이 점점 단순한 취미생활이 아닌 스포츠 종목의 한 부분으로 진화하고 있다는 점을 실감하는 순간이었다.
기존 비슷한 주제의 전시회에서 중점적으로 다루지 않았던 코딩 교육, 강의 플랫폼 등도 함께 다뤄 점점 미래의 교육과 일자리가 변화되고 있다는 점을 실감했다. 대기업은 거의 참가하지 않아 큰 규모의 부스는 없었지만 곳곳에 새로운 시도가 돋보이는 전시회였다. 올해 스마트테크쇼는 더이상 ICT 업계 종사자만의 비즈니스 현장이 아닌 일반 대중들이 즐기는 축제의 장이였다. 모든 체험 요소와 볼거리에 일반인, 학생 등의 관람객이 붐볐으며 폭넓은 연령대를 대상으로 쉽고 재미있게 둘러볼 수 있도록 많은 준비를 한 느낌이었다. 내년에도 새로운 기술을 만날 수 있기를 기대하며 이번 관람기를 마친다.