[56호]맥돼지
2019 ICT 융합 프로젝트 공모전 입선
맥돼지
1. 심사평
칩센 다양한 기능의 집합이 돋보이는 작품입니다. 그 중 음성 인식 엔진 API를 적용한 것이 가장 눈에 띄는 기능이지만, java script engine을 사용하기보다는 Phython을 이용하여 새로운 방식의 자신만의 솔루션을 찾는 건 어땠을까 하는 아쉬움이 듭니다. 많은 기능을 포함하였으나, 여러 기능에 대하여 위에 말했듯이 음성 인식을 통한 기능 구현이었다면 훨씬 개발 작품의 가치를 올릴 수 있었을 듯 합니다.
뉴티씨 독거노인 등을 위한 실버 시대를 대비한 맥돼지. 좋은 작품이네요. 여러가지 아이디어를 접목해서, 편리하게 쓸 수 있도록 노력한 점이 돋보입니다. 음성인식을 사용하여 작품의 편리성을 높인 점도 최근의 추세를 반영한 작품이라고 하겠습니다.
위드로봇 구현이 잘 된 완성도가 높은 작품입니다. 추후 추가 작업이 기대됩니다.
펌테크 작품의 아이디어와 실용성 창의성이 돋보이는 작품으로 생각됩니다. 음성인식기술을 접목하여 편의성을 높이는 등 군더더기 없이 꼭 필요한 기능으로 목적에 맞는 최적의 시스템으로 잘 구성하였고 작품의 완성도 역시 상당이 높았다고 생각합니다. 전체적으로 작품의 기획의도, 기술 구현도, 완성도 등에서 높은 평가를 주고 싶은 작품입니다.
2. 작품 개요
2.1. AI 스피커란?
인공지능 스피커(artificial intelligence speaker, AI Speaker)란, 음성인식을 통해 음악 감상, 정보 검색 등의 기능을 수행하는 스피커이다. 인공지능 서비스의 시장 전망은 매우 밝은데, 미국의 정보 기술 연구 및 자문 회사인 가트너는 AI 스피커 시장 규모가 2015년 약 4050억 원에서 매년 40% 이상 성장을 예상, 2020년에는 약 2조 3600억 원이 될 것으로 전망했다. 또한, 시장조사기관 오범(Ovum)은 가상 비서와 음성 AI를 지원하는 스마트 홈 제품, TV, 웨어러블 기기의 수는 2021 년에 16억 3,000만 대에 육박할 것으로 예상하고 있다. 우리 일상에서도 애플의 시리(Siri), 구글의 구글 어시스턴트(Google Assistant), KT의 기가지니(GiGA Genie) 등과 같은 AI 스피커들을 쉽게 볼 수 있다. AI 스피커의 주 사용층은 20~30대이며 주 사용 목적은 음성을 통한 시간 확인, 알람 설정, 일정 등록 및 메모, 문자, 전화 등이다.
2.2. 독거노인 비율 증가 및 그에 따른 고독사의 증가
우리는 기존의 젊은 층을 겨냥한 AI 스피커와 달리, 정보 소외 계층을 위한 AI 스피커를 제작하고 싶었다. 제작 방향에 관한 회의 초기에는 정보 소외 계층에게 어떻게 하면 정보를 쉽게 전달할 수 있을 지를 중점으로 토의를 진행했다. 그러나 곧 정보 소외 계층은 대부분이 노인층이므로 단순히 정보 전달만이 목적이 아닌, 그들의 편의 및 안전을 보장해줄 수 있는 AI 스피커를 만들어보자는 것으로 의견을 합쳤다.
노인층에 가장 필요한 것은 무엇인지 토의해보고 조사해보는 과정에서 독거노인의 고독사에 관한 자료를 보았다. 보건복지부의 통계에 따르면 독거노인 무연고 사망자 수는 2011년 693명부터 시작하여 2016년에는 1232명으로 시간이 지남에 따라 계속 증가하는 추세를 보이고 있다. 홀로 사시는 분들은 쓰러지시더라도 집에 방문하는 사람이 없어 빠르게 응급처치를 취하지 못하고, 오랜 시간이 흘러 사망하신 후에야 발견되는 것이다. 우리는 바로 이 점에 주목하여 고독사 방지를 위한 기능을 탑재한 AI 스피커를 만들기로 했다.
2.3. 작명 및 외관에 관하여
외관은 어르신들께서 친근함을 느낄 수 있도록 제작하고자 했다. 아이, 강아지, 돼지 형상 등의 의견이 나왔고 이 중 가장 의미를 둘 만한 것으로 결정하기로 했다. 또한, 간단히 모델링할 수 있는 쉬운 모양인지의 여부도 검토했다. 돼지는 약 4800여년 전부터 긴 세월을 인간과 함께한 동반자와 같은 동물이며, 머리부분과 귀 부분, 코 정도의 특징을 살리면 쉽게 모델링 가능하다는 점에 착안하여 최종적으로 외관은 돼지 모양으로 하기로 했다. 그리고 작품명은 우리가 속한 소모임 이름이 MAC이며 작품의 외관이 돼지 모양이므로 ‘맥돼지’로 정했다.
2.4. 주차별 프로젝트 일정
3. 작품 설명
3.1. 전체 시스템 구성
1) 라즈베리파이 인공지능 스피커 구현과 기능추가
· 인공지능 스피커 구현
· 날씨정보 구현
· LCD 구현
2) 아두이노 기능추가
· 초음파센서를 통한 고독사 방지 알람
· 무드등, LED기능 구현
3) 하드웨어 3D 모델링
· 디자인 설계
· 3D 모델링 파일 제작 및 출력
위와 같이 총 3분야로 나누어 기능을 구현하였다. 첫 번째 분야는 라즈베리파이를 이용한 인공지능 스피커의 핵심기능 구현이다. 인공지능 스피커의 특성상 전체적인 시스템의 구현을 위해서는 끊임없이 인터넷 서버와 통신하여야 하기에 인터넷 통신에 적합한 프로그래밍 언어를 사용하는 것이 좋다. 그렇기 때문에 이 부분은 인터넷의 서버에서 정보를 송수신하기 쉽도록 제작된 프로그래밍언어인 자바 스크립트로 진행하였고, 날씨정보 불러오기와 유튜브 동영상 재생과 같이 인터넷을 사용하는 기능들을 자바 스크립트로 프로그래밍 하였다. 이외에 인공지능 스피커의 전체적인 시스템을 라즈베리파이가 담당하기에 LCD 구현도 라즈베리파이로 진행하였다.
두 번째 분야는 아두이노 IDE를 사용한 코딩이다. 초음파센서를 통한 응급상황 정보 확인, 무드등 기능은 라즈베리파이로도 구현이 가능하긴 하지만, 이와 같은 추가기능을 위해서는 많은 포트가 필요하며, 인터넷 통신이 필요없기에 복잡한 자바스크립트로 전체 시스템을 구성하는 것은 낭비였다. 따라서 자바 스크립트보다 간편하고 포트가 겹칠 수 있는 문제점도 해결할 수 있는 아두이노를 대안으로 활용하기로 하였다.
세 번째 분야는 3D 모델링이다. 3D 프린터를 이용하여 작품을 제작하는 단계는 크게 모델링(modeling), 프린팅(printing), 피니싱(finishing)의 3단계로 나뉜다.
첫 번째로 모델링은 3D 도면을 제작하는 단계인데, 이번 작품에서는 ‘오토데스크 인벤터(Autodesk Inventor)’를 이용하였다. 다음으로 프린팅은 인벤터로 설계한 도면을 ‘stl’파일로 저장하고 ‘gcode’로 전환한 후 3D 프린터를 이용하여 뽑아내는 단계이다. 3D 프린터는 신도리코의 ‘3D WOX’를 사용하였고, 제작물의 재료는 PLA이다. 마지막 단계인 피니싱은 3D 프린터로 뽑아낸 제작물에 보완 작업을 하는 단계로 이번 작품에서는 사포질과 도색으로 피니싱 작업을 하였다. 우선 뽑아낸 모든 제작물을 사포질하여 잘 붙여질 수 있도록 표면을 연마시키고, 스프레이로 도색을 하였다. 돼지 머리와 몸통은 분홍색, 리본은 빨간색, 그리고 돼지의 귀는 LED 불빛이 잘 보일 수 있도록 하얀색으로 도색하였다.
3.1.1. 돼지 귀 모델링
귀는 XZ평면 위로 서로 수직인 직선을 그은 후 직선의 끝점을 호로 연결하여 평면을 만들었다. 회전을 이용하여 입체도형을 완성하였다.
귀는 머리에 부착하여야 하기 때문에 머리와 똑같은 반원모형을 XY평면에 만든 후 회전시켜 귀와 겹치는 부분을 돌출을 이용하여 차집합하여 제거해주었다 그 후 무드등으로 활용하기 위해 셀을 이용하여 두께를 1mm만 남도록 설정하고 3D 프린터로 뽑을 때 밀도를 낮추어 LED 불빛이 잘 비추게 만들어 주었다 .
3.1.2. 박스 모델링
라즈베리파이와 아두이노, 약배급기가 들어갈수 있도록 각 변의 길이가 180mm인 직사각형을 만들어 주었다. 그 후 돌출을 이용하여 두께가 150mm인 육면체를 만들어주었다. 직사각형의 평면에 양변이 170mm인 직사각형을 만들어 양변에 5mm의 여유공간이 남도록 하였다. 이를 또 돌출시켜 깊이가 145mm인 육면체를 만든 후 이를 차집합 시켜 박스 모양만 남도록 하였다. 아두이노와 라즈베리파이가 부착 될 직육면체를 박스 가운데 세운 후 앞면에 디스플레이를 설치하기 위해 직사각형으로 된 구멍과 마이크가 잘 작동할수 있게 작은 구멍 또한 뚫어주었다.
3.1.3. 돼지 몸통 모델링(1)
돼지의 몸통은 XY평면에 높이가 60mm, 윗변이 50mm, 아랫변이 75mm인 사다리꼴을 스케치한 후, 회전을 이용하여 대략적인 입체도형을 완성하였다. 그 후 쉘을 이용하여 윗면은 두께가 5mm, 아랫면은 두께가 30mm가 되도록 몸통의 내부를 비워주었다. 그리하여 최종적으로 돼지 몸통 위에 돼지 머리가 안정적으로 장착될 수 있도록 설계하였다.
3.1.4. 돼지 몸통 모델링(2)
돼지 몸통의 윗부분을 더 파이게 하면 돼지 머리가 더 안정적으로 안착될 수 있지 않을까 하는 생각으로 ‘돼지 몸통 모델링(1)’에서 조금 수정을 해보았다. 돼지 몸통 윗 부분의 XY평면에 반지름 60mm인 원을 스케치한 후 양쪽으로 100mm만큼 돌출시킨 후 차집합을 이용하여 잘라내었다. 하지만 ‘돼지 몸통 모델링(1), (2)’를 모두 3D 프린터로 뽑아내어 돼지 머리와 붙여본 결과 처음에 만들었던 (1)번 모델링이 머리를 더 잘 받쳐주어 최종적으로 원래 도안이었던 (1)번 모델링을 선택하여 결과물을 완성하였다.
3.1.5. 돼지 코 모델링
정면 가운데에 알림센서가 있어야 잘 작동하기때문에 돼지 코의 두 부분 중 한 곳을 뚫어 주어 그 안에 센서를 넣어주었다. 돼지 코 안의 센서는 독거노인들의 고독사를 방지하기 위한 알림 센서이다.
3.1.6. 돼지 리본 모델링
돼지 리본을 한꺼번에 출력하지 않고 두 부분으로 나누어서 설계한 이유는 센서를 리본의 뚫린 부분에 넣고 조립을 더 손쉽게 하기 위해서이다. 돼지 리본 안에 넣은 센서는 돼지 귀 내부에 있는 LED를 ON/OFF하고 색을 바꾸는 센서이다.
3.1.7. 약 배급기 모델링
독거노인을 위한 인공지능 스피커이기도하고 요즘 많은 사람들이 영양제, 약등 챙겨먹을 일이 많은데 간단히 인공지능 스피커에서 약을 먹을 시간을 체크해주고 인공지능 스피커에서 바로 약을 먹을수 있게 약통을 만들어 알람이 울리면 그 자리에서 까먹지 않고 먹을수 있게 설계하였다.
3.1.8. 본체 부품 모델링
3.2. 주요 동작 및 특징
1) 초음파센서를 통한 고독사 방지용 알람 기능
2) 유튜브 노래재생
3) 알람 설정 및 일정 등록
4) 무드등
5) 약 보관 및 배급 기능, 무선충전 기능
3.3. 개발환경
4. 단계별 제작과정
4.1. 라즈베리파이
4.1.1. 음성인식 API 선정
인공지능 스피커의 핵심은 음성인식 API라고 할 수 있다. 음성인식 API 시스템에 대하여탐색해 보았고 그 결과 네이버 음성인식 API, KT 음성인식 API, 구글 어시스턴트 등 크게 음성인식 API가 지원되는 3가지 시스템을 찾을 수 있었다. 이후 어느 음성인식 API를 사용할 것인지 회의를 하였다. 회의결과 네이버 음성인식 API는 정보량이 부족하였으며, 구글 어시스턴트는 한글 인식능력이 떨어진다는 결론을 내었다. 그래서 한국어 인식능력도 좋으며 비교적 정보량도 많은 편인 KT 음성인식 API를 사용하기로 결정하였고, 시스템구현을 시작하였다.
4.1.2. 코딩
라즈베리파이에서 인공지능 스피커 기능을 구현하기 위해서 자바스크립트 엔진 위에서 동작하는 이벤트 처리 I/0 프레임워크 NODE.JS을 이용하였다. 파이썬을 통한 기능구현도 검토해 보았으나, 관련 자료가 부족하고 자바스크립트를 활용하는게 더 효율적이라 판단하여 자바스크립트를 활용하였다.
4.1.3. 디스플레이추가
처음에는 인공지능 스피커 전면에 3.5인치 TFT LCD를 부착하여 간단한 조작 및 날씨정보를 제공하려 했었다. 그러나 라즈베리파이에서 마이크 보드가 사용하는 핀과 TFT LCD가 사용하는 핀 사이에서 충돌이 일어나 작동 오류가 일어났다. 그래서 라즈베리파이의 GPIO 포트를 사용하지 않고 DSI케이블을 연결해 사용하는 라즈베리파이용 7인치 디스플레이를 사용하여 간단한 터치 조작 및 날씨 정보 제공을 하였다.
4.2.아두이노
4.2.1. 고독사 방지용 알림 기능
1) 알고리즘
2) 회로 연결
#define MESSAGE_BUZ 6 //MESSAGE BUZZER 6번 핀에 할당
#define SENSOR 10 //IR센서 10번 핀에 할당
#define BUZZER_TIMER 10000 //손 대지 않았을 시 BUZZER 울릴 시간 설정
#define MESSAGE_TIMER 15000 //손 대지 않았을 시 MESSAGE BUZZER 울릴 시간 설정
unsigned long start_millis; //센서 인식 시의 시간 값 저장할 변수 정의
int mode = 0 ; // mode : 0 = stop , 1 구동
void setup() {
Serial.begin(9600); //Board rate 지정
mode = 0;
pinMode(BUZZER, OUTPUT); //BUZZER 출력 할당
pinMode(MESSAGE_BUZ, OUTPUT); //MESSAGE BUZZER 출력 할당
pinMode(SENSOR, INPUT); //IR 센서 입력 할당
}
void loop() {
int sensor_Value = digitalRead(SENSOR); //IR 센서 인식 확인 변수 정의
if ( sensor_Value == 0 ) { //센서 인식
Serial.println(“Hand Clap”); //Serial Monitor에 ‘Hand Clap’ 출력
if ( mode == 0 ) { //센서 인식했으며 mode가 1일 때
mode = 1; //mode를 0에서 1로 바꿔줌
start_millis = millis(); //스탑워치 시작, Start_millis에 현재 시간값 저장
Serial.println(“STARTED”); //Serial Monitor에 ‘STARTED’ 출력
noTone(BUZZER); //BUZZER 끔
noTone(MESSAGE_BUZ); //MESSAGE BUZZER 끔
sensor_Value = 2 ; //Sensor_Value를 2로 바꿔줌
}
if ( mode == 1 ) { //mode가 1일 때
if (sensor_Value == 0) { //센서 인식되면
start_millis = millis(); //start_millis에 현재 시간값 저장
Serial.println(“TIMER INIT.”); //스탑워치 리셋, Serial Monitor에 ‘TIMER INIT.’ 출력
noTone(BUZZER); //BUZZER 끔
noTone(MESSAGE_BUZ); //MESSAGE BUZZER 끔
} } }
if ( mode == 1 ) { //mode가 1일 때
if ( ( millis() – start_millis ) > BUZZER_TIMER ) { //현재시간값-이전에 저장한 시간값이
BUZZER_TIMER보다 크면
Serial.println(“BUZZER”); //Serial Monitor에 ‘BUZZER’ 출력
tone(BUZZER,440); //BUZZER 울림
noTone(MESSAGE_BUZ); //MESSAGE BUZZER 끔
}
if ( ( millis() – start_millis ) > MESSAGE_TIMER ) { //현재시간값-이전에 저장한 시간값이
MESSAGE_TIMER보다 크면
Serial.println(“SEND MESSAGE”); //Serial Monitor에 ‘SEND MESSAGE’ 출력
noTone(BUZZER); //BUZZER 끔
tone(MESSAGE_BUZ,494); //MESSAGE BUZZER 울림
}
Serial.print(“MILLIS = “); //Serial Monitor에 ‘MILLIS = ‘ 출력
Serial.print(millis()); //Serial Monitor에 처음 센서 인식부터
현재까지의 전체 시간값 출력
Serial.print(“,”); //Serial Monitor에 ‘,’ 출력
Serial.print(“TIMER = “); //Serial Monitor에 ‘TIMER = ‘ 출력
Serial.println(millis() – start_millis); //Serial Monitor에 스탑워치 시간 출력
}
delay(500);
}
1) 알고리즘
2) 회로 연결
3) 코딩
#define ledr 11 //red led 11번 핀에 할당
#define ledg 10 //green led 10번 핀에 할당
#define ledb 9 //blue led 9번 핀에 할당
#define ledr2 7 //두 번째 red led 7번 핀에 할당
#define ledg2 6 //두 번째 green led 6번 핀에 할당
#define ledb2 5 //두 번째 blue led 5번 핀에 할당
#define Sensor 3 //적외선 센서 3번 핀에 할당
float RGB[3]; //3가지 값을 한 번에 처리할 수 있는 변수 RGB
float x; //소수값까지 표현할 수 있는 변수 x
int flag1 = 0; //현재 센서 값을 받을 변수
int flag2 = 0; //이전의 센서 값 저장할 변수
int state = 5; //switch case 역할을 할 변수
void setup() {
pinMode(ledr,OUTPUT); //red led 출력 설정
pinMode(ledg,OUTPUT); //green led 출력 설정
pinMode(ledb,OUTPUT); //blue led 출력 설정
pinMode(ledr2,OUTPUT); //두 번째 red led 출력 설정
pinMode(ledg2,OUTPUT); //두 번째 green led 출력 설정
pinMode(ledb2,OUTPUT); //두 번째 blue led 출력 설정
pinMode(Sensor, INPUT); //적외선 센서 입력 설정
Serial.begin(9600); //board rate 9600
}
void loop() {
flag1 = digitalRead(Sensor); //적외선 센서 값을 받음
if((flag1==0)&&(flag2==0)) { //센서 인식 된 상태 & 직전에 센서 인식 안됨
state = state-1 ; //state값 1만큼 내려줌
}
flag2 = 1-flag1; //이후의 센서 인식값과 비교할 현재의 센서 값 저장
if(state == 5){ //state가 5일 때
delay(100); //chattering 현상 방지 위한 delay
analogWrite(ledr, 255); //red led 끔
analogWrite(ledg, 255); //green led 끔
analogWrite(ledb, 255); //blue led 끔
analogWrite(ledr2, 255); //두 번째 red led 끔
analogWrite(ledg2, 255); //두 번째 green led 끔
analogWrite(ledb2, 255); //두 번째 blue led 끔
}
if(state == 4){ //state가 4일 때
analogWrite(ledr, 0); //red led 최대 밝기
analogWrite(ledg, 123); //green led 중간 밝기
analogWrite(ledb, 255); //blue led 끔
analogWrite(ledr2, 0); //두 번째 red led 최대 밝기
analogWrite(ledg2, 123); //두 번째 green led 중간 밝기
analogWrite(ledb2, 255); //두 번째 blue led 끔
delay(100); //chattering 현상 방지 위한 delay
}
if(state == 3){ //state가 3일 때
analogWrite(ledr, 255); //red led 끔
analogWrite(ledg, 0); //green led 최대 밝기
analogWrite(ledb, 255); //blue led 끔
analogWrite(ledr2, 255); //두 번째 red led 끔
analogWrite(ledg2, 0); //두 번째 green led 최대 밝기
analogWrite(ledb2, 255); //두 번째 blue led 끔
delay(100); //chattering 현상 방지 위한 delay
}
if(state == 2) { //state가 2일 때
analogWrite(ledr, 255); //red led 끔
analogWrite(ledg, 255); //green led 끔
analogWrite(ledb, 0); //blue led 켬
analogWrite(ledr2, 255); //두 번째 red led 끔
analogWrite(ledg2, 255); //두 번째 green led 끔
analogWrite(ledb2, 0); //두 번째 blue led 켬
delay(100); //chattering 현상 방지 위한 delay
}
if(state == 1 ){ //state가 1일 때
delay(300); //chattering 현상 방지 위한 delay
for (float x=0;x<PI;x=x+0.000003){ //led들에 입력할 변수를 할당하기 위해 변수 x를 만듦
RGB[0]=255*abs(sin(x*(180/PI))); //red led에 입력할 변수 할당
RGB[1]=255*abs(sin((x+PI/3)*(180/PI))); //green led에 입력할 변수 할당
RGB[2]=255*abs(sin((x+(2*PI)/3)*(180/PI))); //blue led에 입력할 변수 할당
analogWrite(ledr,RGB[0]); //red led에 변수 입력
analogWrite(ledg,RGB[1]); //green led에 변수 입력
analogWrite(ledb,RGB[2]); //blue led에 변수 입력
analogWrite(ledr2,RGB[0]); //두 번째 red led에 변수 입력
analogWrite(ledg2,RGB[1]); //두 번째 green led에 변수 입력
analogWrite(ledb2,RGB[2]); //두 번째 blue led에 변수 입력
if(digitalRead(Sensor)==0) { //센서 인식된 상태이면
state=5; //state를 5로 바꾸고
break; //for문을 break함, 위의 if(state==5)로 돌아감
} } }
Serial.println(state); //serial monitor로 state값 확인
}
6. 참고자료
· 스마트스피커(AI 스피커) : https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A7%88%ED%8A%B8_%EC%8A%A4%ED%94%BC%EC%BB%A4
· [단독]’고독한 대한민국’…무연고 사망자, 5년 새 2배 폭증 (아시아경제 19.02.14) : http://view.asiae.co.kr/news/view.htm?idxno=2019 021411080903737
· Jeremy Blum, 『익스플로링 아두이노』, 한빛아카데미, 14.05.19
· 데릭 몰로이, 『익스플로링 아두이노』, 위키북스, 18.04.03
· 송형주,고현준, 『인사이드 자바스크립트』, 한빛미디어, 14.01.02