이전글에서 소개한 아두이노 프로젝트 공유
구글의 음성인식 서비스를 이용해서 집안의 전자 제품을 제어함.
Arduino 부품 구성
Arduino 회로도

안드로이드 앱
Github 소스
APK Download
아두이노 소스
#include <SoftwareSerial.h>
SoftwareSerial mySerial(11,12); // RX, TX
const int kDPinActivity = 2;
const int kDPinLight = 13;
const int kAPinBright = 5;
// Commands strings from remote controller
const String kCmdLightOn = "light on";
const String kCmdLightOff = "light off";
const String kCmdSetPrefix = "set:";
// Status string
const String kCmdPrefix = "command:";
const String kStatusActivityDetected = "activity detected";
const char kPacketDelimiter = '#';
// The base brightness to decide day.
int min_brightness_of_day = 10;
int max_brightness_of_night = 5;
void setup() {
pinMode(kDPinLight, OUTPUT);
pinMode(kDPinActivity, INPUT);
pinMode(kAPinBright, INPUT);
digitalWrite(kDPinLight, HIGH); // Trun off
Serial.begin(9600);
Serial.println("Start");
mySerial.begin(9600);
}
bool needLightOn(int activity, int brightness) {
// the lower the value is, the brighter.
if (brightness > max_brightness_of_night) {
// during the day
return false;
}
if (activity) {
return true;
}
return false;
}
bool needLightOff(int brightness) {
if (brightness > min_brightness_of_day) {
return true;
}
return false;
}
// command structure
// [command name]:[value]
void processSettingCmd(String cmd) {
const char* kBrightnessDayValue = "brightness day:";
const char* kBrightnessNightValue = "brightness night:";
if (cmd.startsWith(kBrightnessNightValue)) {
String value = cmd.substring(String(kBrightnessNightValue).length());
max_brightness_of_night = value.toInt();
} else if (cmd.startsWith(kBrightnessDayValue)) {
String value = cmd.substring(String(kBrightnessDayValue).length());
min_brightness_of_day = value.toInt();
}
}
void processCmd(String cmd) {
if (cmd.equals(kCmdLightOn)) {
digitalWrite(kDPinLight, LOW); // Turn on
Serial.println(kCmdLightOn);
} else if (cmd.equals(kCmdLightOff)) {
digitalWrite(kDPinLight, HIGH); // Turn off
Serial.println(kCmdLightOff);
} else if (cmd.startsWith(kCmdSetPrefix)) {
processSettingCmd(cmd.substring(kCmdSetPrefix.length()));
}
}
// Push partial string of command
// and return a command when there is a command completed
String pushCommandFragment(String fragment) {
static String buffer;
buffer += fragment;
int idx = buffer.indexOf(kPacketDelimiter);
if (idx == -1) {
return "";
}
String complete_cmd = buffer.substring(0, idx);
if (buffer.length() > idx + 1) {
buffer = buffer.substring(idx + 1);
} else {
buffer = "";
}
return complete_cmd;
}
// check activity is detected
// and create a response packet if response is needed.
String checkActicityAndCreatePacket(int activity) {
static int last_status = 0;
// prevent creating duplicated packets.
if (last_status == activity) {
return "";
}
last_status = activity;
if (!activity) {
return "";
}
String packet = kStatusActivityDetected;
packet += kPacketDelimiter;
return packet;
}
// The loop function runs over and over again forever
void loop() {
String send_packet = "";
int activity = digitalRead(kDPinActivity);
send_packet += checkActicityAndCreatePacket(activity);
//Serial.print("activity: ");
//Serial.println(activity);
int brightness = analogRead(kAPinBright);
//Serial.print("bright: ");
//Serial.println(brightness);
// Parse command from remote controller
String cmd_fragment = "";
while (mySerial.available()) {
char c = mySerial.read();
cmd_fragment.concat(c);
delay(1);
}
while(1) {
// Combine the fragment with the ones recieved before.
String cmd = pushCommandFragment(cmd_fragment);
if (cmd.length() == 0) {
break;
}
processCmd(cmd);
Serial.print("command in: ");
Serial.println(cmd);
// run more loop with empty fragment
// in case that there are more packets available.
cmd_fragment = "";
}
if (Serial.available())
mySerial.write(Serial.read());
// send packet if there's one to send.
if (send_packet.length() > 0) {
mySerial.print(send_packet);
}
}
간략 설명
- 아두이노 모션 센서에서 인체 동작이 인식이 되면 블루투스를 통해 안드로이드 앱으로 패킷을 보냄.
- 안드로이드 앱에서는 모션이 인식되면 구글 음성 인식서비스를 작동시킴.
- 음성인식 서비스를 항상 활성화시키면 좋겠지만 음성인식 라이브러리 자체가 최대 5초까지만 작동하게 제한되어 있음.
- 5초마다 재시작 시키는 방식도 고려했지만 각 재시작시 생기는 딜레이로 음성인식이 안되는 문제가 있음.
- 따라서 사람의 모션을 인식했을때만 작동하는 방식이 가장 효율적임.
- 음성인식 결과 문자열중 미리 입력해둔 명령어가 있다면 해당 명령어를 아두이노로 전송
- 현재 명령어는 : light on, light off의 두 가지.
- 명령어를 말하기 전에 Signal Speech를 말해야 하는데 현재 입력된 값은 “Lucy”임
- 따라서 “Lucy light on” 이라고 말해야 정상 인식
- 아두이노에서는 해당 명령 처리.
- 가령 light on이 전달되면 릴레이에 신호를 주어 전등을 켬.