[61호]우울증 치료로봇 IWMYS (I will make you smile)
2020 ICT 융합 프로젝트 공모전 우수상
우울증 치료로봇 IWMYS (I will make you smile)
글 | 성균관대학교 김승년, 임혁수, 최윤수
1. 심사평
칩센 과연 우울증이 치료될지는 모르겠지만, 우선 보고서에 포함된 작품과 시연 동영상 기준으로는 흥미롭고 자연스레 웃음이 나는 작품입니다. 여러 면에서 함께 공동 개발자간에 재미있게 작품 개발이 진행되지 않았나하는 막연한 생각도 듭니다. 개발의 난이도나 기능을 따져보자면 아주 복잡도가 높지는 않지만, 반드시 좋은 작품이나 제품은 복잡해야한다라는 것을 보기좋게 뒤집을수 있다는 것을 보여주는 좋은 작품입니다.
펌테크 작품의 아이디어와 창의성, 실용성이 돋보이는 작품으로 생각됩니다. 군더더기 없이 꼭 필요한 기능으로 목적에 맞는 최적의 시스템으로 잘 구성하였고 추후 작품의 완성도를 높일경우 상업적으로 충분한 가치를 가질 수 있는 제품이 될수 있을것이라 생각됩니다. 전체적으로 작품의 기획의도, 기술 구현도, 완성도 등에서 높을 평가를 주고 싶은 작품입니다.
위드로봇 관련 문헌 조사에서부터 구현까지 완성도가 매우 높은 작품입니다. 얼굴 인식에 대한 결과 분석이 빠진 것이 아쉽습니다.
2. 작품개요
이 작품을 만들 때, 크게 2가지를 고려했다. 첫째로, ‘사회적으로 도움이 되는 제품’ 을 만들고 싶었다. 요즘 심각한 사회적 문제가 무엇이고, 이를 어떻게 하면 획기적으로 해결할 수 있을지 팀원들과 이야기를 나누었다. 그 결과 심각한 사회문제인 우울증을 해결해 보는 게 어떨까? 하는 목표를 가졌다. SNS 서비스의 발달로 서로가 늘 연결되어 있는 것처럼 이 사회에도 우울증은 증가하고 있다. 건강보험심사평가원에서 제공한 그래프를 보면 우울증이 계속해 늘어나고 있는 경향을 알 수 있다.
우리는 웃음치료법을 통해 우울증을 치료하고자 했다. 우리 몸은 웃을 때 ‘엔도르핀’이라는 호르몬이 나와서 고통이나 아픔을 잊게 해주는데, 이를 유도하기 위해서 스피커로 격려가 되는 말과, 어이가 없는 개그와, 랜덤으로 재생되는 경쾌한 음악을 재생시킴으로써 최종적으로 우울하거나 슬픈 일이 있을 때 당사자로 하여금 웃음을 짓게 하여 마치 사람과 소통하듯이 듣는 이로 하여 따뜻함을 느낄 수 있게 만들었다. 우리의 로봇이 행복한 사람들이 더 많아지는데 많이 쓰였으면 한다.
2번째로 ‘로봇의 작동방식’을 고민했다. 작동방식이 복잡하면 어르신이나, 아이들이 로봇의 작동에 어려움을 느낄 수가 있다. 단순하면서 우울함을 해소해줄 수 있는 작동방식이 필요했다.
“웃으면 복이 온다” 라는 격언이 있다. 행복해지는 가장 첫 단계는 웃는 것이라고 생각했다. 그래서 우리 로봇은 ‘억지 미소’에 작동하도록 설계되었다. 우울한 사용자가 로봇에 억지 미소를 지어주면, 음성(우리의 녹음된 목소리, 아재개그), 텍스트 메시지(힘내세요, 웃어주세요)가 출력되어 그 ‘억지 미소’를 ‘진짜 웃음’으로 바꾸어준다. 우리의 로봇은 미소 짓는 자에게 진정한 웃음을 선사한다.
3. 작품 설명
3.1. 주요 동작 및 특징
3.1.1. 주요 동작
3.1.2. 특징
OpecvCV의 Haar Cascade 알고리즘을 사용해 웃음을 검출합니다. Haar Cascade는 머신러닝 기반의 인식 방법이므로, 학습된 모델이 필요합니다. OpenCV의 github repository에서 haarcascade_frontalface_default.xml와 haarcascade_smile.xml를 다운받아 얼굴과 표정 검출에 사용했습니다.
라즈베리파이에서 웃음을 인식하면, 6가지의 아재개그와 7가지의 위로의 말을 랜덤으로 재생합니다.
아두이노는 라즈베리파이와 시리얼 통신으로 연결되어 있습니다. 라즈베리파이는 웃지 않을 때는 숫자 ‘0’을, 웃고 있을 때는 숫자 ‘1’을 전송합니다.
아두이노에서 ‘1’의 신호를 받으면, 스피커 모듈을 통해 음악을 연주하고, LCD 디스플레이에 6가지의 위로의 말을 랜덤으로 보여줍니다.
3.2. 전체 시스템 구성
3.2.1. 시스템 개요도
1단계: 카메라 수신부
2단계: 라즈베리파이
3단계: 아두이노
4단계: LCD 디스플레이 + 스피커 재생
3.2.2. 1단계-카메라 수신부
카메라 종류: Logitech WebCam C170
1.카메라 영상을 실시간으로
라즈베리파이로 전송
3.2.3. 2단계-라즈베리파이
-라즈베리파이4
1. 전송받은 영상을 실시간으로 검출
2. 얼굴을 파란색 테두리로 검출
3. 얼굴 내에서 미소를 노란색 테두리로 검출
4. 미소가 발견되면 아두이노로 시리얼신호 전송
-웃음 인식 모습
3.2.4. 3단계-아두이노
-아두이노 UNO
1.시리얼신호를 입력 받으면 스피커와 LCD를 작동시킴
3.2.5. 4단계-스피커, LCD
라즈베리파이 스피커
-웃으면 아래 중 한 개 랜덤 출력
1오늘 하루 힘들었지? 고생했어~
2.내일도 좋은 일만 있을거야
3.행복한 하루 되세요~
4.이리와~ 안아줄게
5.넌 정말 소중한 사람이야
6.지금 이대로도 괜찮아
7.내가 필요할 때, 항상 옆에 있을게!
(이하 기계음)
1.사슴이 눈이 좋으면? 굿아이디어
2.맥주가 죽기전에 남긴 말은? 유언비어
3.나무를 톱으로 캐면? 트리케라톱스
4.반성문을 영어로 하면? 글로벌
5.가장 안전한 감옥은? 안전제일
6.석유가 도착하는데 걸리는 시간은? 오일
아두이노 LCD 모니터
웃으면 아래 중 한 개 랜덤 출력
1. There will be only good thing
2. Have a happy day
3. You are so precious
4. You did a Great job!!
5. Come here, I’ll give you a hug
6. It is OK as it
-웃지 않으면
Smile ^-^ 출력
아두이노 스피커
웃으면 다음 노래 중 한 개 랜덤 재생
1.비행기
2.학교종
3.3. 개발환경(개발 언어, Tool, 사용 시스템 등)
3.3.1. 모델링 Tool
제품의 틀을 만들기 위해, 오토데스크의 ‘Inventor’와 ‘Thinkercad’를 이용했다. 치수와 자석을 넣는 세밀한 작업의 경우 원통 및 사각형은 Inverntor로, 면 단위의 전반적 3D작업에는 Thinkercad로 개체합치기 및 개체 나누기로 작업을 진행했다. 3D 프린터로 출력 시 Cubicreator는 ‘큐비콘 듀오’로 위의 뚜껑부분을 출력할 때 사용했다. 아래 부분은 2 부분으로 나누어 Cura로 작업한 후 엔더3 pro를 이용해 출력하였다.
3.3.2. software
3.3.3. 부품
4. 단계별 제작 과정
제작과정은 크게 3개로 나눠져 있다. 1) 라즈베리파이를 통한 비전인식과 녹음된 음성파일 재생, 2) 아두이노를 통한 LCD디스플레이의 텍스트 출력 및 스피커의 음악출력, 3) 마지막으로 이러한 모듈을 수용할 로봇의 디자인과 모듈의 고정
4.1. 표정인식 VISION 시스템의 구축
1. 윈도우 PC에서 웃음검출기 작동 확인
1. 아나콘다 가상환경을 생성
2. OpenCV, numpy 설치
3. 웃음검출기 구현
2. 라즈베리파이로 옮기기
1. 코드를 라즈베리파이로 옮김
2. OpenCV, numpy 설치
3. 작동 확인
3. 아두이노와 시리얼 통신 확인
1. sudo pip3 install pyserial
2. ls /dev/tty* 명령어로 ttyACM0 포트에 연결됨을 확인
3. blink 예제를 변형해, 시리얼 통신이 제대로 되는지 확인
4. pygame으로 목소리 재생 구현
1. 위로의 말, 아재개그 문구 선정
2. 녹음
3. pygame을 이용해 재생할 수 있도록 구현
4.2. 아두이노
배경음악 2종류 함수 생성 ▶ LCD 화면 출력 6종 함수 생성 ▶ 라즈베리파이로부터 serial통신 값 수신 ▶ 랜덤 변수에 따라 화면, 음악 동시출력. 라즈베리 파이에서 받은 Serial신호가 -1(신호없음) 일 때, 아무 반응도 하지 않는다. 0(무표정) 일 때, 웃음을 유도하는 문구 출력 ‘^-^’. 1(웃는표정) 일 때, random변수를 받아 여러 종류의 위로, 응원의 말과 함께 귀여운 배경음을 출력한다.
1) talkie라이브러리를 활용한 스피커제어 시도
특정 음이 아닌 녹음된 자연어를 출력하기 위해 음성데이터를 직접 만들었다. 텍스트를 음성파일로, mp3파일을 wav파일로 convert하고, normalize과정까지 거쳐 다듬은 후 비트맵으로 변환시켰다. 무료 제공된 talkie라이브러리를 사용해 코드에 적용시켰지만 음질이 매우 떨어졌다. 이 후 앰프모듈 추가, 스피커 스펙 변경, 음성데이터 수정 등의 방법을 통해 이를 극복하려 했지만 끝내 비트맵으로 변환하는 과정에서 발생하는 라이브러리 자체의 한계점이라 판단하고, 라즈베리 파이 내에서 mp3파일을 직접 적용하는 방법을 선택했다.
2) LCD 한글 출력을 위한 시도
가장 많이 쓰이는 저렴한 16×02 LCD에서는 한글출력을 지원하지 않는다. 직접 좌표를 설정해 한글을 임의로 표시할 수 있지만, CGRAM에 8개의 바이트 배열만을 저장할 수 있기 때문에 짧은 문장도 표현하기 쉽지 않고 깨져서 표현된다. 개인 라이브러리를 사용하거나, 한 글자씩 출력하는 방법을 시도해보았지만 가독성이 떨어지면 위로의 말을 전달하는 목적과 맞지 않아 쉬운 영어문장과 귀여운 이모티콘으로 대체했다.
4.3. 3단계 디자인
이 작품을 모델링 하는 과정에는 우울증을 치료해야 하기 때문에 각이 있는 모델 보다는 최대한 둥근 면적을 많이 포함하는 모델을 고려했고, 더 나아가 나무와 숲을 연상시키는 색을 입히면 어떨까? 라는 색채적인 측면도 고려했다. 머리 부분에는 구멍을 파서 꽃을 장식하고자 했다. Inventor로 대략적인 형상의 모델링을 진행했다. Inventor로는 면 단위의 볼륨감을 디자인하는 데 부족함을 느껴, Tinkercad를 이용해 기본 형상을 붙이고 자르는 방식으로 모델링을 했다.
이는 로봇 하체의 뒷모습이며 엉덩이 부근에 구멍을 뚫어 외부 전압을 공급할 수 있도록 설계하였다. 이때 Inverntor로 원통형 3개를 작업한 뒤 큰 원통형에 모깍기로 기울기를 준 다음 원뿔형을 만들었다. 이후 2개의 원기둥을 다리로 붙인 다음 원기둥의 반만큼만 기울기를 주어 원뿔 형태로 깎았다. 많은 장치들이 들어가야 하는 만큼 큰 수용 능력이 필요했고, 로봇이 사람처럼 두 팔과 두 다리를 가지길 원했다. 이에 다리의 크기를 최대한 줄여서 몸통부분이 크도록 조절하였다.
아래는 로봇 하체의 앞모습이다. 앞을 디자인 할 때에는 우울증 치료의 목적과 맞게 상대방이 사랑 받고 있다는 느낌을 주기 위해 하트 모양을 선택했으며, 손 모양은 Inverntor로는 작업하기가 어려워서 팔과 하트는 Thinkercad에서 작업을 했다. 격언을 띄워 주기 위한 아두이노 LCD 디스플레이를 배치하기 위해 하트 앞부분에 구멍을 냈으며, 손 모양은 몸체와 하트를 연결하는 역할을 한다.
이 사진은 로봇 상체 사진이며 눈 쪽에는 카메라를 설치하기 위해 구멍을 뚫었고 머리 부분에는 하트모양의 구멍과 눈 위쪽 부근에도 하트모양을 달았다. 머리 윗부분에 구멍을 파서 꽃을 심어, 사용자가 편안하게 느끼도록 디자인했으며, 인테리어 용품으로도 손색없도록 아름답게 디자인하기 위해 노력했다.
결합할 때에는 나사나 볼트를 사용하는 것 보다 (재질이 PLA라서 깨질 경우 다칠 우려가 있음) 자석을 이용해서 결합을 한다면, 쉽게 분리 및 조립이 가능하고 내부 기기의 문제가 생겼을 시 쉽게 대처가 가능해서 3D프린트 출력 시 레이어 스톱 기능을 넣어서 자석을 순간접착제로 부착시킨 뒤 말리고 출력을 진행시켰다. 아랫부분 자석4개 윗부분 자석4개 총 8개를 사용했다.
4.4. 도색 및 조립
도색할 때에는 스프레이를 이용했다. 화분과 같은 인상을 주고자 밤색과 녹색 2가지색을 채용했으며, 피부는 녹색으로 그 외에는 전부 밤색으로 도색했다. 도색을 할 때에는 원치 않는 부분까지 침범할 우려가 있어서 칠하고자 하는 부분을 제외하고는 전부 테이프로 감아서 스프레이로 작업했으며, 그 외 흘러내린 부분은 붓으로 작업을 했다.
로봇의 머리 부분에는 좌측 사진과 같이 꽃으로 장식을 하였다. 스펀지의 중앙에 구멍을 내고 글루건을 이용해서 꽃을 고정시켰다.
꽃을 통해 사용자가 편안하고 자연적인 분위기를 느꼈으면 했다.
5. 기타
5.1. 전체 회로도
5.2. 웃음 검출을 위한 Raspberry pi 코드
import numpy as np
import cv2
import serial
import pygame
import random
print(“import clear”)
faceCascade = cv2.CascadeClassifier(‘haarcascades/haarcascade_frontalface_default.xml’)
smileCascade = cv2.CascadeClassifier(‘haarcascades/haarcascade_smile.xml’)
print(“recall model”)
cap = cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)
ser = serial.Serial(‘/dev/ttyACM0′, 9600)
print(“camera & serial connected”)
music_file1 = “sound/didgreat.mp3″
music_file2 = “sound/goodTomorrow.mp3″
music_file3 = “sound/happyDay.mp3″
music_file4 = “sound/hugYou.mp3″
music_file5 = “sound/okayAsItIs.mp3″
music_file6 = “sound/myPrecious.mp3″
music_file7 = “sound/standByYourSide.mp3″
music_file8 = “sound/joke1.mp3″
music_file9 = “sound/joke2.mp3″
music_file10 = “sound/joke3.mp3″
music_file11 = “sound/joke4.mp3″
music_file12 = “sound/joke5.mp3″
music_file13 = “sound/joke6.mp3″
music = [music_file1, music_file2, music_file3, music_file4, music_file5, music_file6, music_file7, music_file8, music_file9, music_file10, music_file11, music_file12, music_file13]
while True:
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(20, 20)
)
for (x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w, y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
smile = smileCascade.detectMultiScale(
roi_gray,
scaleFactor = 1.5,
minNeighbors=15,
minSize=(25, 25),
)
if len(smile)==0:
print(ser.write(“0″.encode()))
else:
for (x2, y2, w2, h2) in smile:
cv2.rectangle(roi_color, (x2, y2), (x2 + w2, y2 + h2), (0, 255, 255), 2)
print(ser.write(“1″.encode()))
music_number = random.randint(0, 12)
print(music_number)
pygame.mixer.init()
pygame.mixer.music.load(music[music_number])
pygame.mixer.music.play()
clock = pygame.time.Clock()
while pygame.mixer.music.get_busy():
clock.tick(30)
pygame.mixer.quit()
cv2.imshow(‘faceWithSmile’, img)
k= cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
5.3. 1602LCD화면 출력과 스피커제어를 위한 Arduino 코드
#include <LiquidCrystal_I2C.h>
#include<Wire.h>
long randNumber;
int speaker=3;
LiquidCrystal_I2C lcd(0×27,16,2);
void airpl(){ //비행기
tone(speaker,659);
delay(350);
tone(speaker,587);
delay(150);
tone(speaker,523);
delay(200);
noTone(speaker);
delay(50);
tone(speaker,587);
delay(200);
noTone(speaker);
delay(50);
tone(speaker,659);
delay(200);
noTone(speaker);
delay(80);
tone(speaker,659);
delay(200);
noTone(speaker);
delay(80);
tone(speaker,659);
delay(200);
}
void schbell(){ //학교종
tone(speaker,784);
delay(200);
noTone(speaker);
delay(80);
tone(speaker,784);
delay(200);
noTone(speaker);
delay(80);
tone(speaker,880);
delay(200);
noTone(speaker);
delay(80);
tone(speaker,784);
delay(200);
noTone(speaker);
delay(80);
tone(speaker,784);
delay(200);
noTone(speaker);
delay(80);
tone(speaker,784);
delay(200);
noTone(speaker);
delay(80);
tone(speaker,659);
delay(300);
}
void Hg1(){
lcd.setCursor(1,0);
lcd.print(“There will be”);
lcd.setCursor(0,1);
lcd.print(“only good thing”);
lcd.init();
}
void Hg2(){
lcd.setCursor(0,0);
lcd.print(“Have a happy day”);
lcd.init();
}
void Hg3(){
lcd.setCursor(3,0);
lcd.print(“You are so”);
lcd.setCursor(5,1);
lcd.print(“precious”);
lcd.init();
}
void Hg4(){
lcd.setCursor(0,0);
lcd.print(“You did a”);
lcd.setCursor(1,1);
lcd.print(“Great job!!”);
lcd.init();
}
void Hg5(){
lcd.setCursor(0,0);
lcd.print(“Come here, I’ll”);
lcd.setCursor(1,1);
lcd.print(“give you a hug”);
lcd.init();
}
void Hg6(){
lcd.setCursor(0,0);
lcd.print(“It is OK as it”);
lcd.init();
}
void setup(){
Serial.begin(9600);
lcd.init();
lcd.backlight();
randomSeed(analogRead(5)); //랜덤seed생성
}
void loop() {
if(Serial.available()){
int swt=(int)Serial.read(); //기분값입력
if(swt==48){ //ASCII(48)=0 (무표정)
lcd.setCursor(3,0);
lcd.print(“Smile ^-^”);
}
else if(swt==49){ //ASCII(49)=1 (웃는표정happy)
randNumber=random(1,7);
Serial.println(randNumber);
if(randNumber==1){ //1) 내일도 좋은일만 있을거야
Hg1();
schbell();
}
else if(randNumber==2){//2) 행복한하루되세요
Hg2();
airpl();
}
else if(randNumber==3){//3) 넌정말소중한사람
Hg3();
schbell();
}
else if(randNumber==4){//4) 오늘하루힘들었지고생했어
Hg4();
airpl();
}
else if(randNumber==5){//5) 이리와안아줄게
Hg5();
schbell();
}
else{ //6)지금이대로도괜찮아
Hg6();
airpl();}
}}
}
5.4. 참고문헌
1. OpenCV github repository:
2. 10, 20대 우울증 환자 현황; 2019년11월29일;건강보험심사평가원
5.5. 작품 작동 시연 동영상
[1] https://www.youtube.com/watch?v=Ulte1ao_2Tc[2] https://www.youtube.com/watch?v=qkcn13aGhbk
[3] https://www.youtube.com/watch?v=Ot1GmvqJPso
동영상에서 VNC viewer로 라즈베리파이에 원격접속해 웃음을 인식하는 모습을 촬영하였습니다. 이때, VNC viewer 자체의 딜레이와 라즈베리파이의 느린 연산으로 인한 딜레이가 겹쳐, 모니터 화면에 버퍼링이 있습니다. 하지만 스피커를 통해 정상작동하고 있음을 확인할 수 있습니다.