이전글에서 소개한 아두이노 프로젝트 공유
구글의 음성인식 서비스를 이용해서 집안의 전자 제품을 제어함.
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이 전달되면 릴레이에 신호를 주어 전등을 켬.