みなさん、こんばんは
【watnowテックカレンダーの25日目】
今日はwatnowのおかだが担当します
よろしくお願いします
はじめに
今回は私が卒業研究で触ったSpeech Recognition API(音声認識API)とESP-WROOM-32を用いてLEDを制御してみます.
動作環境及び開発環境
swift5.3.2
Xcode Version 12.4
MacOS Catalina
ios14.4
Speechフレームワークとは
ios10から追加されたフレームワークで音声認識して文字起こししたりとか色々できちゃうやつです!
ESP-WROOM-32とは
通称ESP-32と呼ばれるArduinoとWIFI通信を兼ねたモジュールみたいなのです!
流れ
Arduino側でLEDの制御とWIFI通信の設定を行い,xcode側で認識した音声に応じたURLにアクセスすることで設定したLEDが光ります!!
Arduino側コード
#include <WiFi.h>
constchar*ssid="あなたのSSID";constchar*password="あなたのパス";WiFiServerserver(80);unsignedlongtime_data=0;unsignedlongsecond=0;voidsetup(){Serial.begin(115200);pinMode(4,OUTPUT);//frontpinMode(2,OUTPUT);//backpinMode(15,OUTPUT);//rightpinMode(0,OUTPUT);//left delay(10);// We start by connecting to a WiFi networkSerial.println();Serial.println();Serial.print("Connecting to ");Serial.println(ssid);WiFi.begin(ssid,password);while(WiFi.status()!=WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("");Serial.println("WiFi connected.");Serial.println("IP address: ");Serial.println(WiFi.localIP());server.begin();}voidloop(){WiFiClientclient=server.available();// listen for incoming clientsif(client){// if you get a client,Serial.println("New Client.");// print a message out the serial portStringcurrentLine="";// make a String to hold incoming data from the clientwhile(client.connected()){// loop while the client's connectedif(client.available()){// if there's bytes to read from the client,charc=client.read();// read a byte, thenSerial.write(c);// print it out the serial monitorif(c=='\n'){// if the byte is a newline character// if the current line is blank, you got two newline characters in a row.// that's the end of the client HTTP request, so send a response:if(currentLine.length()==0){// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)// and a content-type so the client knows what's coming, then a blank line:client.println("HTTP/1.1 200 OK");client.println("Content-type:text/html");client.println();// the content of the HTTP response follows the header:client.print("Click <a href=\"/ST\">here</a> to turn the LED on pin All off.<br>");//stopclient.print("Click <a href=\"/FF\">here</a> to turn the LED on pin 4 on.<br>");//frontclient.print("Click <a href=\"/BB\">here</a> to turn the LED on pin 2 on.<br>");//backclient.print("Click <a href=\"/RI\">here</a> to turn the LED on pin 15 on.<br>");//rightclient.print("Click <a href=\"/LE\">here</a> to turn the LED on pin 0 on.<br>");//left// The HTTP response ends with another blank line:client.println();// break out of the while loop:break;}else{// if you got a newline, then clear currentLine:currentLine="";}}elseif(c!='\r'){// if you got anything else but a carriage return character,currentLine+=c;// add it to the end of the currentLine}if(currentLine.endsWith("GET /ST")){stop();}if(currentLine.endsWith("GET /FF")){Serial.printf("前");stop();digitalWrite(4,HIGH);}if(currentLine.endsWith("GET /BB")){Serial.printf("後");stop();digitalWrite(2,HIGH);}if(currentLine.endsWith("GET /RI")){Serial.printf("右");stop();digitalWrite(15,HIGH);}if(currentLine.endsWith("GET /LE")){Serial.printf("左");stop();digitalWrite(0,HIGH);}}}// close the connection:client.stop();Serial.println("Client Disconnected.");}}voidstop(){digitalWrite(4,LOW);digitalWrite(2,LOW);digitalWrite(15,LOW);digitalWrite(0,LOW);}
arduino側の操作
SSIDとPASSWORDを自分のWIFIのものに書き換えてコンパイルしてください.
次にWEBブラウザでIPアドレスにアクセスして設定したボタンを押してLEDが思い通りに点滅するか確認してください.
Xcode側コード
importUIKitimportSpeechclassViewController:UIViewController{//認識する言語privateletspeechRecognizer=SFSpeechRecognizer(locale:Locale(identifier:"ja-JP"))!privatevarrecognitionRequest:SFSpeechAudioBufferRecognitionRequest?privatevarrecognitionTask:SFSpeechRecognitionTask?privatevaraudioEngine=AVAudioEngine()@IBOutletweakvartextView:UITextView!@IBOutletweakvarfromtButton:UIButton!@IBOutletweakvarrightButton:UIButton!@IBOutletweakvarbackButton:UIButton!@IBOutletweakvarleftButton:UIButton!@IBOutletweakvarstopButton:UIButton!overridefuncviewDidLoad(){super.viewDidLoad()SFSpeechRecognizer.requestAuthorization{(status)inOperationQueue.main.addOperation{switchstatus{case.authorized:do{tryself.startSpeech()}catch{print("startError: \(error)")}self.startTimer()default:print("error")}}}}funcstopOnButton(){leturl=URL(string:"http://192.168.10.XX/ST")!varrequest=URLRequest(url:url)request.httpMethod="GET"letconnection=NSURLConnection(request:request,delegate:nil,startImmediately:true)}funcfrontOnButton(){leturl=URL(string:"http://192.168.10.XX/FF")!varrequest=URLRequest(url:url)request.httpMethod="GET"letconnection=NSURLConnection(request:request,delegate:nil,startImmediately:true)}funcbackOnButton(){leturl=URL(string:"http://192.168.10.XX/BB")!varrequest=URLRequest(url:url)request.httpMethod="GET"letconnection=NSURLConnection(request:request,delegate:nil,startImmediately:true)}funcrightOnButton(){leturl=URL(string:"http://192.168.10.XX/RI")!varrequest=URLRequest(url:url)request.httpMethod="GET"letconnection=NSURLConnection(request:request,delegate:nil,startImmediately:true)}funcleftOnButton(){leturl=URL(string:"http://192.168.10.XX/LE")!varrequest=URLRequest(url:url)request.httpMethod="GET"letconnection=NSURLConnection(request:request,delegate:nil,startImmediately:true)}funcstartSpeech()throws{ifletrecognitionTask=recognitionTask{recognitionTask.cancel()self.recognitionTask=nil}letaudioSession=AVAudioSession.sharedInstance()tryaudioSession.setCategory(.record,mode:.measurement,options:[])tryaudioSession.setActive(true,options:.notifyOthersOnDeactivation)letrecognitionRequest=SFSpeechAudioBufferRecognitionRequest()self.recognitionRequest=recognitionRequestrecognitionRequest.shouldReportPartialResults=truerecognitionTask=speechRecognizer.recognitionTask(with:recognitionRequest){[weakself](result,error)inguardlet`self`=selfelse{return}ifletresult=result{self.textView.text=result.bestTranscription.formattedStringprint(result.bestTranscription.formattedString)//特定の文字を発話した際に処理を行うifresult.bestTranscription.formattedString.contains("前のライト"){self.setBackgroundColor(color:.blue)self.frontOnButton()}elseifresult.bestTranscription.formattedString.contains("後のライト"){self.setBackgroundColor(color:.yellow)self.backOnButton()}elseifresult.bestTranscription.formattedString.contains("右のライト"){self.setBackgroundColor(color:.orange)self.rightOnButton()}elseifresult.bestTranscription.formattedString.contains("左のライト"){self.setBackgroundColor(color:.purple)self.leftOnButton()}elseifresult.bestTranscription.formattedString.contains("停止"){self.setBackgroundColor(color:.white)self.stopOnButton()}}}letrecordingFormat=audioEngine.inputNode.outputFormat(forBus:0)audioEngine.inputNode.installTap(onBus:0,bufferSize:1024,format:recordingFormat){(buffer:AVAudioPCMBuffer,when:AVAudioTime)inself.recognitionRequest?.append(buffer)}audioEngine.prepare()try?audioEngine.start()}funcstopSpeech(){guardlettask=self.recognitionTaskelse{fatalError("Error")}task.cancel()task.finish()self.audioEngine.inputNode.removeTap(onBus:0)self.audioEngine.stop()self.recognitionRequest?.endAudio()}privatefuncsetBackgroundColor(color:UIColor){DispatchQueue.main.async{self.view.backgroundColor=color}self.stopSpeech()do{tryself.startSpeech()}catch{print("startError: \(error)")}}//1分でタイムアウトして音声認識されなくなるのでタイマーでループprivatefuncstartTimer(){Timer.scheduledTimer(withTimeInterval:60,repeats:true){_inself.stopSpeech()do{tryself.startSpeech()}catch{print("startError: \(error)")}}}@IBActionfuncstopAction(_sender:Any){self.stopOnButton()}@IBActionfuncfrontAction(_sender:Any){self.frontOnButton()}@IBActionfuncbackAction(_sender:Any){self.backOnButton()}@IBActionfuncrightAction(_sender:Any){self.rightOnButton()}@IBActionfuncleftAction(_sender:Any){self.leftOnButton()}}
xcode側の操作
各Butttonに設定してあるURLを各ボタンのURLに変えてください.
viewController
おわりに
どうでしたでしょうか.今回はiphoneで音声認識させてLEDを制御するということをやってみました.工夫次第で色々なことに応用できると思うのでぜひ色々やってみてください!!
watnowでは、チャレンジ精神旺盛な仲間を募集しています
興味を持たれた方はぜひ@watnowsにDMしてください