반응형

80년대 90년대에 PC를 다뤄본 분들은 게임이나 특정 프로그램에서 가끔 사람의 목소리가 흘러나오는 것을 들은 기억이 있을 것입니다. 조금은 조악한 음질로 나왔던 것으로 기억이 납니다. 로봇 목소리 같기도 하고 발음도 그다지 좋지 못했지만 알아듣기는 했었죠. 당시엔 신기한 기술이었지만 지금은 게임에에서도 전문 성우의 목소리가 나오니... 격세지감 이죠. 이런 옛날 PC에서 나오던 사람의 목소리를 아두이노에서도 'Talkie' 라는 라이브러리를 이용하면 들을 수 있습니다. 말하는 아두이노를 만들 수 있는 것이죠. Talkie Library는 70~80년대에 텍사스 인스트루먼트사에서 개발한 Speech Synthesis Architecture (Linear Predictive Coding) 라는 음성을 합성하는 기술을 이용한 라이브러리 입니다. 현재는 영어로만 말 할 수 있고 직접 단어의 발음 데이터를 만들 수 있는 기술이 있는 분이라면 한국어도 가능하다고 생각이 됩니다. 사실 Talkie의 영어단어 데이터도 제작자의 GitHub 에 등록된 것이 1100여개 정도 밖에 안되거든요.


유명한 스티브잡스의 1984년 매킨토시 프레젠테이션 영상 입니다. 동영상을 보면 컴퓨터가 말을 합니다. 바로 이런게 음성합성(Speech Synthesis Architecture) 기술을 이용해서 사람의 목소리를 흉내내는 것입니다. 컴퓨터가 말을 하니 엄청난 환호와 박수가 나오는 걸로 보아 당시엔 굉장히 신기한 기술 이었던 것 같습니다. ^^


아두이노 이외에 필요한 것이 있습니다. 음성을 들을 조그만 스피커와 음성을 증폭 시켜주는 앰프 입니다. 저의 경우엔 예전에 한 번 다뤘었던 PAM8403 을 이용한 미니 앰프가 있어서 이것을 이용해 주었습니다. 스피커를 직접 연결해도 되는데 소리가 들리긴 들리는데 출력이 작아서 소리가 너무 작게 들리네요. 스피커는 피에조 부저 같은걸 연결하면 안됩니다. 미니 라디오 같은데 들어가는 작은 스피커를 연결하면 됩니다. 만약 앰프도 없고 스피커도 없다면 아두이노 음성출력 부분을 PC 스피커에 연결해도 됩니다.


■ PAM8403 앰프에 대해서 궁금한 분들은 아래 링크를 참고 하세요.

[취미&DIY] - 초미니앰프 PAM8403 으로 만드는 미니 스피커 (PAM8403 Mini Amplifier)

 


■ Talkie Library 설치와 이용


https://github.com/going-digital/Talkie 사이트에서 위의 그림처럼 Download ZIP 을 눌러서 라이브러리 파일을 다운로드 합니다. 압축을 풀면 Talkie Master 폴더가 있는데 그 하위의 Talkie 폴더만 아두이노IDE 의 Libraries 폴더에 복사해 넣습니다. 

Talkie-master.zip


그런데 이 라이브러리에 문제가 있습니다. 바로 최신버전(V1.6.5)의 아두이노 IDE로 예제파일을 열면 아래와 같이 컴파일 에러가 발생 합니다.

 

variable 'spDANGER' must be const in order to be put into read-only section by means of '__attribute__((progmem))'


대략 위와 같은 에러인데 이것은 버전 1.0.x 버전의 아두이노 IDE 구버전을 사용하면 해결 됩니다. 저의 경우는 V1.0.5 를 다운로드 받아서 사용 했습니다. 이미 최신버전의 IDE 가 설치되어 있으므로 Install 버전 보다는 ZIP 파일을 풀면 바로 사용할 수 있는 버전을 추천 합니다.


아두이노IDE 구버전은 아래의 사이트에서 다운로드 받을 수 있습니다.

https://www.arduino.cc/en/Main/OldSoftwareReleases#previous


위에 표시한 버전을 다운로드 받으면 됩니다. 그냥 압축풀고 적당한 위치에 복사한 후 arduino.exe 파일을 실행하면 됩니다. 물론 위에서 복사했던 Talkie Library 폴더도 여기에 있는 Libraries 폴더에 복사해 넣어야 합니다.

 

■ 


위와 같이 연결이 됩니다. PAM8403 앰프는 5V 전원을 사용하므로 아두이노 5V 단자의 전원을 사용하면 됩니다. 


 PAM8403

 Arduino Uno

 Left Channel Input

 D3

 Common Input

 GND

 Power Input 5V (+)

 5V

 Power Input GND (-)

 GND


 Speaker

 PAM8403

Input (+)

 Left Out +

Input (-)

 Left Out -

 

PAM8403 앰프는 이렇게 연결이 쉽도록 케이블을 꼽을 수 있게 커넥터를 납땜해서 달아 주었습니다. 앰프는 전원입력부, 음원입력 과 출력(Stereo)로 이루어져 있습니다. 입력과 출력은 어차피 Mono 이므로 Left 채널만 이용해 주었습니다.


■ 소스1 (예제 데이터 Play)

소스는 Talkie Library 예제를 이용해 보았습니다. 파일->예제->Talkie 로 들어가시면 됩니다. 맨 위에 있는 Getting Started 소스를 한 번 보겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Talkie library
// Copyright 2011 Peter Knight
// This code is released under GPLv2 license.
//
// Welcome to the Talkie library examples.
//
// Talkie is a speech synthesiser that works from a fixed vocabulary.
//
// There are hundreds of words in the 'Vocabulary' examples.
//
// Sound is output on digital pin 3. It can drive headphones directly, or add a simple audio amplifier to drive a loudspeaker.
// 
 
#include "talkie.h"
 
Talkie voice;
 
uint8_t spDANGER[] PROGMEM = {0x2D0xBF0x210x920x590xB40x9F0xA20x870x100x8E0xDC0x720xAB0x5B0x9D0x620xA60x420x9E0x9C0xB80xB30x950x0D0xAF0x140x150xA50x470xDE0x1D0x7A0x780x3A0x490x650x550xD00x5E0xAE0x3A0xB50x530x930x880x650xE20x000xEC0x9A0xEA0x800x650x820xC70xD80x630x0A0x9A0x650x5D0x530xC90x490x5C0xE10x7D0x2F0x730x2F0x470x590xC20xDE0x9A0x270x5F0xF10x8B0xDF0xFF0x03};
uint8_t spMOTOR[]  PROGMEM = {0x660xAA0x8C0x690x530x920xC40x2D0x2F0x6B0x2A0x740xDA0x9D0xB20xDD0xF60x360xAB0xCE0x780xDA0x9D0xB20xD50x9A0x010xDB0x770x450xA00x750xC50xB80x710x590xDA0x310xE50x6A0x220x630xDE0xDA0x9A0xBB0xA30x750x680xAF0x7B0x3E0xC30x9D0x970x600x870xE60x8B0x4F0x780x4B0x760xB20x090xAF0xFE0xFD0x7F};
uint8_t spFIRE[]   PROGMEM = {0x040x180xCE0x4D0x020x1A0xD00x800x040x460x910x550x570x070x6D0xD90xCD0xAE0x4F0x550x5D0x590x870xAE0xB90xD50x6D0x5B0xDB0x7D0x930xB60xED0xEE0xE30x5A0x6B0x6A0xF40x910xD50x730x6B0x670xF50x470xBC0xD40xA70x9C0xA50x340xE40xD00xA60xF00xE40xAA0xB80x2D0xAB0xC30x9B0x620xC20xAC0x740xF60x9F0xFB0x720x0B0xEC0x920xCD0xEE0xCF0x430x690x4C0x5B0xFF0x3F};
uint8_t spON[]     PROGMEM = {0x650x4A0xEA0x3A0x5C0xB20xCE0x6E0x570xA70x480xE60xD20x5D0xBB0xEC0x620x170xBB0xDE0x7D0x9F0xDA0x5C0x5C0x7A0xAA0xB50x6E0xCB0xD00x0E0xAD0x6E0xAF0xEE0xF90x880x670xBC0xDC0x3D0xAC0x600xB80x450xF30xB70xBF0xC30xDD0xA20xBB0xAB0xCD0x890x8F0x7F0xFE0x1F};
uint8_t spRED[]    PROGMEM = {0x6A0xB50xD90x250x4A0xE50xDB0xC50x4F0x6D0x880x950x2D0xD20xB40x8F0x2E0x370x0E0x330xCF0x7E0xAA0x9A0x5C0xC30xB40xCB0xA90x860x690x760xD30x370xB70xBE0xCD0xED0xEF0xB40xB70xB00x350x690x940x220x6D0x100x280x420xB90x8B0xC80x060x000x500xCF0x0E0xEE0x620xEA0xA60xBC0xC30x140xBB0x4A0x9F0xFA0xA50xAF0x250x130x170xDF0x9C0xBF0xFF0x07};
uint8_t spIS[]     PROGMEM = {0xAD0xED0xD50x580xA40x9E0xCE0x760xF50xDD0xAB0x290xF50xD20xDD0xEF0x7E0x0C0xC30xA90x060xFA0xD30x320x0F0x6E0x940x220x8F0xF30x920xF60x050x430xCC0x740x770x3E0xC30xF50x950x980xA90xBA0x8B0x8F0x000x7E0x730xE50x000x050x280xF00xFF};
uint8_t spALERT[]  PROGMEM = {0xA50xCF0xC60xAB0x550x5B0xAF0x390xDA0xC90x540xDD0xBC0xC60xC20x3C0x270x200xCF0x1C0xD70x300xB00x450x160x690x1D0xC30x110xE40x590x8A0x7C0xB50x9B0x8B0xD90x300xB70xD30x760x190x9A0x250x590x570x590xEC0x110xAF0xE80xD90xF90x2A0x8A0x1D0xF00x750x3F0x730xAC0x870x3B0xA20x0B0xAA0x2B0xCF0xE40x100xA10xDC0x450x640x030x000x800x010x660x360x330xC00xAB0xD50x0A0x680x250x850x020xFF0x0F};
 
void setup() {
  voice.say(spDANGER);
  voice.say(spDANGER);
  voice.say(spRED);
  voice.say(spALERT);
  voice.say(spMOTOR);
  voice.say(spIS);
  voice.say(spON);
  voice.say(spFIRE);
}
void loop() {
}
cs


위의 소스를 보시면 음성데이터를 변수에 저장하고 voice.say(변수명); 하면 음성이 나오는 방식 입니다. DANGER(변수명: spDANGER) 라는 단어 하나의 데이터가 어마 어마 합니다.


플레이하면 다음과 같이 스피커로 음성이 나옵니다. 잡음이 많은데 아두이노의 노이즈를 앰프가 그대로 반영해서 저렇게 나오는 듯 합니다. 잡음 제거회로 같은걸 연결하면 나아지려나요?

 

남성의 목소리로 경고 메시지를 말하는 예제(Getting Started) 입니다.


여성의 목소리로 시간을 알려주는 예제(Vocab_US_Clock)를 실행해 보았습니다. 


노래도 합니다. 수잔 베가의 Tom's Diner 라는 노래라고 합니다.


위의 소스에도 보이듯이 이런 다양한 목소리는 단어 하나 하나 지정된 음성 합성 데이터를 이두이노가 읽어들이면서 스피커로 내보내는 것입니다. 여러 예제에 쓰인 단어 데이터들을 한 데 모아 봤습니다. 이렇게 한 군데 모아 놓으면 나중에 활용할 단어들을 쉽게 찾을 수 있을 것 같습니다. 데이터는 너무 방대해서 텍스트 파일로 만들었습니다. voice_data.txt 를 다운로드 받아서 사용하시면 됩니다. 뭐 대충 보니 일상에서 많이 사용하는 영어 단어 들은 대부분 있는것 같습니다. 변수명을 보시면 spWORK[] 이런 식으로 되어 있는데 이 데이터의 경우 발음은 WORK 입니다.


voice_data.txt



여기서 그냥 끝내기엔 좀 아쉬움이 있어서 초음파 센서를 이용해서 일정 거리에 물체가 감지되면 Hello I am Computer 라고 말하는 소스를 한 번 만들어 보았습니다.


■ 소스2


위와 같이 기존의 회로에 초음파 센서를 추가해 주었습니다. 초음파 센서의 사용에 대해서 궁금하신 분들은 [여기] 를 클릭하면 저의 예전 글을 볼 수 있습니다.


 초음파 센서

 아두이노

 VCC

 5V

 GND

 GND

 Trig

 D9

 Echo

 D8


20cm 이내에 물체가 감지되면 'Hello I am Computer' 라는 말이 나오게 해 보려고 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "talkie.h"
 
Talkie voice;
 
//Hello I am Computer 음성 데이터
uint8_t spHELLO[] PROGMEM ={0x00,0xC0,0x80,0x60,0x59,0x08,0x10,0x3D,0xB7,0x00,0x62,0x64,0x3D,0x55,0x4A,0x9E,0x66,0xDA,0xF6,0x56,0xB7,0x3A,0x55,0x76,0xDA,0xED,0x92,0x75,0x57,0xA3,0x88,0xA8,0xAB,0x02,0xB2,0xF4,0xAC,0x67,0x23,0x73,0xC6,0x2F,0x0C,0xF3,0xED,0x62,0xD7,0xAD,0x13,0xA5,0x46,0x8C,0x57,0xD7,0x21,0x0C,0x22,0x4F,0x93,0x4B,0x27,0x37,0xF0,0x51,0x69,0x98,0x9D,0xD4,0xC8,0xFB,0xB8,0x98,0xB9,0x56,0x23,0x2F,0x93,0xAA,0xE2,0x46,0x8C,0x52,0x57,0x66,0x2B,0x8C,0x07};
uint8_t spI[]     PROGMEM = {0x2B,0x2B,0xA5,0x3A,0xCD,0x9B,0x9C,0xB4,0x9A,0x8B,0x08,0x5B,0xB4,0x92,0xE2,0xDF,0x3D,0xBD,0xE6,0x89,0x4B,0x7C,0xB7,0x88,0x98,0x27,0x2D,0xFE,0xC3,0x22,0x6A,0x9E,0xB4,0xF8,0x0F,0xF7,0x68,0x78,0xB2,0x6A,0x3E,0x23,0x6C,0xE5,0xA9,0x9B,0xBA,0x8C,0xD4,0xD6,0xA7,0x6E,0xFA,0x32,0x4A,0x57,0x9F,0xB1,0xF9,0x89,0x48,0x5B,0x73,0xA6,0x16,0xCB,0x33,0x6C,0xF1,0x5A,0x7B,0x0E,0x8F,0xB0,0xDA,0x63,0x6D,0x51,0x3C,0xB2,0x16,0xB7,0xAD,0x79,0xD5,0xEC,0x9A,0x53,0xB6,0x9E,0x44,0x62,0xBB,0x4E,0xDA,0xBA,0x63,0xCD,0x99,0xCA,0x69,0xED,0x8E,0x2C,0x27,0xE5,0xFC,0x19,0x41,0x71,0x51,0x19,0x19,0x49};
uint8_t spAM[]    PROGMEM ={0xA3,0x28,0x4D,0xDD,0x64,0x15,0x9D,0xA2,0x34,0x0B,0xD5,0x4A,0x74,0xAA,0x3C,0x2D,0x44,0x2A,0xD5,0xAD,0x6E,0x75,0xAA,0xD4,0xB5,0x59,0x33,0xCE,0xAD,0x4F,0x1D,0x6B,0x94,0x9A,0x57,0xD9,0xED,0x68,0x6D,0xA9,0x56,0xC9,0xD8,0xAD,0x35,0x8E,0x4B,0xC5,0x54,0xFB,0xCE,0x77,0xA6,0xD3,0x8E,0x4A,0xC3,0xDD,0x98,0x4E,0x7A,0x49,0xE5,0x76,0xEA,0x3B,0xDD,0x3F,0x00,0x00};
uint8_t spCOMPUTER[]   PROGMEM ={0x0A,0x08,0x79,0xC4,0x02,0xA7,0x8A,0xCE,0xD3,0x03,0xDA,0xEE,0xAA,0xD7,0xA5,0xB6,0x59,0x4A,0x85,0xD2,0xD8,0x16,0x8F,0x02,0x60,0x21,0x32,0x00,0x29,0x2B,0x5A,0xE0,0x24,0x25,0x85,0x82,0x5B,0x9F,0x9D,0xAC,0x34,0x38,0x4B,0xB1,0xC8,0x33,0x33,0x07,0x74,0x1D,0x91,0x2A,0xDF,0x34,0xA9,0xAD,0xED,0xAC,0x66,0x3B,0xFB,0xD6,0xBB,0xA6,0xAA,0x1B,0xE9,0xC3,0x60,0x3B,0xFB,0x14,0xA5,0x76,0x83,0xAD,0xE4,0xE9,0xE6,0xDA,0x0C,0x21,0x5A,0x92,0x7A,0xAA,0x07};
 
//출력핀(trig)과 입력핀(echo) 연결 설정, 다른 핀을 연결해도 됨.
int trigPin = 9;
int echoPin = 8;
 
//초음파 센서 관련 변수
float duration, distance, previous;
 
//시리얼 속도설정, trigPin을 출력, echoPin을 입력으로 설정
void setup(){
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}
 
//초음파를 보낸다. 다 보내면 echo가 HIGH(신호받기) 상태로 대기
void loop(){
  digitalWrite(trigPin, HIGH);
  delay(10);
  digitalWrite(trigPin, LOW);
 
  // echoPin 이 HIGH를 유지한 시간을 저장 한다.
  duration = pulseIn(echoPin, HIGH);
  // HIGH 였을 때 시간(초음파가 보냈다가 다시 들어온 시간)을 가지고 거리를 계산 한다.
  // 340은 초당 초음파(소리)의 속도, 10000은 밀리세컨드를 세컨드로, 왕복거리이므로 2로 나눠준다.
  distance = ((float)(340 * duration) / 10000/ 2;
 
  //시리얼모니터에 Echo가 HIGH인 시간 및 거리를 표시해준다.
  Serial.print("Duration:");
  Serial.print(duration);
  Serial.print("\nDIstance:");
  Serial.print(distance);
  Serial.println("cm\n");
 
  // 20cm 이내에 물체가 감지되고 이전 거리측정값이 20cm 보다 크다면
  // Hello 나옴 (Hello 를 물체 감지 시 한 번만 나오게 하기 위함)
  if(distance < 20 && previous > 20) {
    voice.say(spHELLO);
    voice.say(spI);
    voice.say(spAM);
    voice.say(spCOMPUTER);
  }
 
  previous = distance;
  
  delay(100);
}
cs


소스를 보면 Hello I Am Computer 라는 4개의 단어가 있는데 모두 제가 만든 데이터 사전?인 voice_data.txt 파일에서 가져온 데이터들 입니다.


노이즈가 너무 심하지만 Hello I Am Computer 라는 목소리가 뚜렷하게 들립니다. 노이즈는 위에서 말했듯이 앰프가 아두이노 등의 고주파 노이즈 등을 그대로 증폭해서 생기는 것 같습니다. 원래 소스에서 생기는 노이즈는 아닙니다. 차폐를 한다면 노이즈가 줄어든 음성을 들을 수 있을 것입니다.



이상으로 Talkie Library 를 이용해서 아두이노에게 말을 시켜 보았습니다. 해 보면서 어린시절 PC에서 나오던 게임음성을 듣던 추억도 떠오르고 초창기 TTS(Text To Speech) 소프트웨어들도 생각나고 그렇네요.


아두이노로 로봇 만드시는 분들은 이 라이브러리 이용해서 말하는 로봇을 구현해 보는 것도 재미있는 프로젝트가 될 것 같습니다.




■ 추가사항 (2016.11.05) : 위에서 라이브러리의 구동을 위해 아두이노 IDE 구버전을 사용하면 된다 라고 했었는데 그 방법 말고도 변수 선언 시 앞에 const 를 붙여주면 아두이노 IDE 구버전을 사용할 필요가 없다고 '뎐상' 님이 알려주셨습니다. 감사합니다. 댓글 참조하시길 바랍니다. 

uint8_t spDANGER[] PROGMEM = {0x2D,

▼▼▼

const uint8_t spDANGER[] PROGMEM = {0x2D,

반응형

+ Recent posts