[57호]지팡이
2019 ICT 융합 프로젝트 공모전 참가상
지팡이
1. 심사평
칩센 재미있는 작품이라는 생각이 먼저 들었습니다. 시각장애인들에게 도움이 될 듯 하다는 생각이 들기도 했습니다만, 시제품만을 보아서는 휴대성등에서 약간 문제가 되지 않을까 합니다. 주변 장애물이나, 물웅덩이등에 대하여 빠르게 반응하는 모습은 매우 좋았습니다만, 지팡이를 찾기 위해 앱을 동작하고 사용해야 하는 내용의 전제조건인 시각장애인들에게는 쉽지 않아 보입니다. 하지만 추가적인 제품화를 고려한다면 재미있고 유용한 제품이 될 가능성도 보입니다.
뉴티씨 시각장애인들이 사용할 수 있는 지팡이에 대한 여러가지 제안이 있었지만, 물을 감지하고 장애물을 감지하는 것은 매우 좋은 생각으로 보입니다. 현실적으로 구현하여 판매할 수 있을 것이라고 생각되며, 구현할 때에 배터리를 적게 사용하도록 디자인한다거나 충전타입으로 만들어서 충전할 수 있도록 하면 더 좋겠습니다. 또한, 시각장애인들이 스마트폰을 보기가 어려우므로, 간단한 버튼 등으로 지팡이를 찾는 것이 더 좋지 않을까 생각해 보았습니다. 실제로 상품화 되면 좋겠습니다. 이에 높은 점수를 드립니다.
위드로봇 장애인용 지팡이는 많이 연구가 된 분야인 만큼 사전 연구에 대한 조사를 먼저 한 뒤 개선점에 대한 부분의 연구가 있으면 좋을 것 같습니다.
펌테크 지팡이를 사용할 대상이 시각장애인 인점을 감안하자면 스마트폰에서 지팡이 찾기 기능을 수행시 터치 방식보다는 음성인식을 통해 찾는 방식을 사용했다면 더욱 효율적이지 않았을까 하는 생각이 들었고 장애물 감지를 위해 사용된 초음파센서는 벽과 같은 큰 장애물의 경우는 신속하게 감지후 대응이 가능하나 장애인에게 실제 위협이 될 수도 있는 비교적 작은 장애물의 경우는 탐색 능력이 저하될 수 있으므로 지팡이 하우징 설계 과정에서 초음파센서를 고정할 위치를 신중히 결정할 필요성이 있고, 적합한 센서로의 변경을 고려해볼 필요가 있다고 생각됩니다. 출품된 작품은 전체적으로 창의성 및 아이디어가 돋보이는 작품이라고 생각합니다.
2. 목표
시각장애를 가진 사람들을 위한 지팡이를 만들어 1. 비록 근거리이긴 하나 앞에 사물을 미리 감지하고 거리감을 느낄 수 있도록 한다. 2. 비오고 난 후 길거리에 고여 있는 물을 감지해 돌아갈 수 있도록 한다. 3. 지팡이를 가까운 곳에서 잃어 버렸을 때 소리를 내어 찾을 수 있게 하고자 한다.
3. 지팡이 구성도
1. 부저 및 이어폰 : 초음파 센서로 감지한 거리나 수분감지 센서로 감지한 물웅덩이를 알려주는 기능
2. 초음파 센서 : 거리측정
3. 블루투스모듈 : 스마트폰과 블루투스 통신으로 찾기 기능
4. 수분감지센서 : 비오고 난 후 길에 고여있는 물웅덩이를 감지하는 기능
3.1. 지팡이의 주요기능
3.1.1. 방향 및 거리 측정 기능
초음파센서 2개로 사물과의 거리를 측정 후 거리에 따라 소리의 주기에 변화를 주어 방향과 거리감을 알 수 있도록 한다.
3.1.2. 물 감지 기능
지팡이 끝의 수분감지 회로의 신호를 받아 비오고 난 후 길에 고여 있는 물을 감지해 알려준다.
3.1.3. 찾기 기능
블루투스 통신으로 소리를 출력해 지팡이를 찾도록 도와준다.
3.2. 회로설계
OrCAD로 회로도 작성
3.3. 회로구현
만능기판에 납땜으로 완성
3.4. 개발환경
컴파일러 : AtmelStudio7.0
마이크로 컨트롤러 : Atmega8
주요부품 : HC-SR04 초음파센서 모듈, HC-06 블루투스 통신모듈, 부저, 지팡이, 충전배터리
4. 주요 동작 및 특징
4.1. 방향 및 거리 측정 기능
HC-SR04는 Trig핀에 펄스신호를 주면 잠시 후 Echo핀에서 신호가 나온다. Echo신호는 사물과의 거리에 따라 길이가 달라 지는데 High인 구간의 시간을 측정하면 사물과의 거리를 알 수 있다.
거리측정
Atmega8의 Timer2으로 시간을 카운트하고 INT0핀과 INT1핀으로 HC-SR04 Echo신호 상승엣지와 하강엣지를 감지해 거리를 계산한다.
위에서 측정한 거리를 바탕으로 사용자버튼으로 이어폰, 부저의 출력을 설정 할 수 있도록 한다.
이어폰 출력
Atmega8의 Timer1의 OCR1A핀과 OCR1B핀을 Compare Output Mode로 설정해서 부저음 생성한다. 두개의 HC-SR04 초음파 센서로 측정한 거리에 따라 이어폰 양쪽 음의 간격을 달리해 방향 및 거리감을 알 수 있도록 한다.
원거리 : 긴 간격의 부저음
중거리 : 빠른 부저음
단거리 : 연속된 부저음
이어폰 출력의 예)
초음파센서에서 감지한 거리가 좌측은 멀고 우측은 가까운 경우는 좌측은 긴 간격의 부저음이 나고 우측은 빠른 부저음이 난다.
스피커 출력
두개의 HC-SR04로 측정한 거리를 비교해 가까운 거리에 대한 이어폰 출력을 하나의 스피커에서 그대로 출력한다.
스피커 출력의 예)
4.2. 물 감지 기능
Atmega8의 ADC로 저항과 물의 전압분배로 물을 감지하면 이어폰과 스피커로 출력한다.
이어폰 출력 : 지팡이 끝의 수분 감지센서에서 물을 감지하면 이어폰 양쪽으로 번갈아가며 부저음을 출력한다.
부저출력 : 수분감지시 부저음을 출력한다.
4.3. 찾기 기능
원래 하고 싶었던 기능은 스마트폰에서 음성인식으로 앱 실행, 블루투스 연결, 지팡이 찾기 실행 등을 하고 싶었으나 기술 부족으로 할 수 가 없어서 테스트용으로 앱인벤터에서 버튼으로 조작하도록 만든다. 앱인벤터로 블루투스앱을 만들고 지팡이 보드에 블루투스 모듈을 달아 블루투스통신으로 스마트폰과 통신함 ‘지팡이 찾기’ 버튼을 누르면 부저음을 울려 지팡이 위치를 알 수 있게 한다. ‘부저 끄기’ 버튼을 누르거나 보드에 있는 사용자 버튼을 누르면 부저음을 멈춘다.
5. 지팡이 제작과정
5.1. 지팡이APP 코드
5.2. Atmega8 AtmelStudio7.0 코드
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile uint32_t m_t;
uint32_t c_t;
uint32_t s_t[10];
uint32_t u_t;
uint32_t u_t_save[2];
uint32_t u_d[2];
uint16_t b_t[2];
uint16_t b_c[2];
uint8_t b_m,b_m_prev;
uint8_t u_s[2];
uint8_t u_f[2];
uint8_t u_n;
uint16_t w_s;
uint8_t btn,btn_prev;
ISR(TIMER0_OVF_vect)
{
TCNT0 = 130;
m_t++;
}
ISR(TIMER1_COMPA_vect)
{
if(b_m == 0)
{
OCR1A = TCNT1 + 100;
}
else if(b_m == 1)
{
OCR1A = TCNT1 + 100;
if(b_t[0] < b_t[1])
{
if(TCCR1A & 0×10)
{
PORTB ^= 0×08;
}
}
else
{
if(TCCR1A & 0×40)
{
PORTB ^= 0×08;
}
}
}
else if(b_m == 10)
{
OCR1A = TCNT1 + 30;
if((TCCR1A & 0×10) && b_m_prev == 1)
{
PORTB ^= 0×08;
}
}
else if(b_m == 20)
{
OCR1A = TCNT1 + 30;
if((TCCR1A & 0×10))
{
PORTB ^= 0×08;
}
}
}
ISR(TIMER1_COMPB_vect)
{
if(b_m == 0)
{
OCR1B = TCNT1 + 100;
}
else if(b_m == 1)
{
OCR1B = TCNT1 + 100;
}
else if(b_m == 10)
{
OCR1B = TCNT1 + 30;
}
else if(b_m == 20)
{
OCR1B = TCNT1 + 30;
}
}
uint16_t ADCRead(uint8_t ch)
{
uint16_t temp;
ADMUX &= ~0x1F;
ADMUX |= ch & 0x1F;
ADCSRA |= 0×40;
while((ADCSRA & 0×40));
ADCSRA |= 0×10;
temp = (uint16_t)ADCL + ((uint16_t)ADCH<<8);
return temp;
}
ISR(INT0_vect)
{
if(u_s[0] == 0)
{
u_t = 0;
u_s[0] = 1;
MCUCR = 0×02;
}
else if(u_s[0] == 1)
{
u_s[0] = 2;
u_t_save[0] = u_t;
GICR = 0;
}
}
ISR(INT1_vect)
{
if(u_s[1] == 0)
{
u_t = 0;
u_s[1] = 1;
MCUCR = 0×08;
}
else if(u_s[1] == 1)
{
u_s[1] = 2;
u_t_save[1] = u_t;
GICR = 0;
}
}
int main(void)
{
DDRD |= 0xC0; //LED
DDRD |= 0×30; //Trig
PORTD|= 0x0C; //Echo
DDRB |= 0×06; //Ear Phone
DDRB |= 0×08; //Buzzer
PORTB |= 0×11; //Button
TCCR0 |= 0×03;
TIMSK |= 0×01;
TCNT0 = 130;
TCCR2 = 0x0A;
OCR2 = 10; //8MHz / 8 /10 = 10us (340m/s -> 3.4mm/10us)
TIMSK |= 0xC0;
TCCR1B = 0×04;
OCR1A = 100;
OCR1B = 100;
TIMSK |= 0×18;
ADCSRA |= 0×87;
ADMUX |= 0xC0;
SREG |= 0×80;
while (1)
{
w_s = ADCRead(0);
btn = ~(((PINB>>0)&0×01) | ((PINB>>3)&0×02));
if(w_s <= 500 && (b_m == 0 || b_m == 1))
{
b_m_prev = b_m;
b_m = 10;
}
else if(w_s > 500 && b_m == 10)
{
b_m = b_m_prev;
}
if(b_m == 0)
{
if((btn&0×01) && !(btn_prev&0×01))
{
b_m_prev = b_m;
b_m = 1;
}
}
else if(b_m == 1)
{
if((btn&0×01) && !(btn_prev&0×01))
{
b_m_prev = b_m;
b_m = 0;
}
}
else if(b_m == 10)
{
if((btn&0×01) && !(btn_prev&0×01))
{
if(b_m_prev == 0)
{
b_m_prev = 1;
}
else if(b_m_prev == 1)
{
b_m_prev = 0;
}
}
}
else if(b_m == 20)
{
if((btn&0×01) && !(btn_prev&0×01))
{
b_m = b_m_prev;
}
}
SREG &= ~0×80;
c_t = m_t;
SREG |= 0×80;
if(c_t – s_t[0] >= 500)
{
s_t[0] = c_t;
PORTD ^= 0×80;
}
if(c_t – s_t[1] >= 50)
{
s_t[1] = c_t;
if(u_n == 0)
{
u_n = 1;
PORTD |= 0×10;
_delay_us(10);
PORTD &= ~0×10;
u_s[0] = 0;
MCUCR = 0×03;
GICR = 0×40;
}
else if(u_n == 1)
{
u_n = 2;
PORTD |= 0×20;
_delay_us(10);
PORTD &= ~0×20;
u_s[1] = 0;
MCUCR = 0x0C;
GICR = 0×80;
}
else if(u_n == 2)
{
u_n = 0;
u_d[0] = 1.7 * u_t_save[0];
u_d[1] = 1.7 * u_t_save[1];
b_t[0] = u_d[0];
b_t[1] = u_d[1];
if(b_t[0] > 2000)
{
b_t[0] = 2000;
}
if(b_t[1] > 2000)
{
b_t[1] = 2000;
}
if(u_s[0] == 2 && u_s[1] == 2)
{
u_f[0] = 1;
u_f[1] = 1;
}
else if(u_s[0] != 2 && u_s[1] == 2)
{
u_f[0] = 0;
u_f[1] = 1;
}
else if(u_s[0] == 2 && u_s[1] != 2)
{
u_f[0] = 1;
u_f[1] = 0;
}
else
{
u_f[0] = 0;
u_f[1] = 0;
}
if(b_m == 0)
{
b_c[0]++;
if(b_c[0]*150 > b_t[0])
{
b_c[0] = 0;
}
if(u_f[0])
{
if(!b_c[0])
{
TCCR1A |= 0×10;
}
}}
}else
}{
}TCCR1A &= ~0×10;
}}
}if(b_c[0])
}{
}TCCR1A &= ~0×10;
}}
b_c[1]++;
if(b_c[1]*150 > b_t[1])
{
b_c[1] = 0;
}
if(u_f[1])
{
if(!b_c[1])
{
TCCR1A |= 0×40;
}
}
else
{
TCCR1A &= ~0×40;
}
if(b_c[1])
{
TCCR1A &= ~0×40;
}
}
else if(b_m == 1)
{
b_c[0]++;
if(b_c[0]*150 > b_t[0])
{
b_c[0] = 0;
}
if(u_f[0])
{
if(!b_c[0])
{
TCCR1A |= 0×10;
}
}
else
{
TCCR1A &= ~0×10;
}
if(b_c[0])
{
TCCR1A &= ~0×10;
}
b_c[1]++;
if(b_c[1]*150 > b_t[1])
{
b_c[1] = 0;
}
if(u_f[1])
{
if(!b_c[1])
{
TCCR1A |= 0×40;
}
}
else
{
TCCR1A &= ~0×40;
}
if(b_c[1])
{
TCCR1A &= ~0×40;
}
}
else if(b_m == 10)
{
if(TCCR1A & 0×10)
{
TCCR1A &= ~0×10;
TCCR1A |= 0×40;
}
else
{
TCCR1A |= 0×10;
TCCR1A &= ~0×40;
}
}
else if(b_m == 20)
{
if(TCCR1A & 0×10)
{
TCCR1A &= ~0×10;
TCCR1A |= 0×40;
}
else
{
TCCR1A |= 0×10;
TCCR1A &= ~0×40;
}
}
}
}
btn_prev = btn;
if(c_t – s_t[2] >= 10)
{
s_t[2] = c_t;
}
}
return 0;
}