音声強化版PaPeRo i のTinker Board S にソニー製カードリーダーライターPaSoRi RC-S380を接続してNFCのNDEFデータを読むことができたので、カードがタッチされてNDEFデータを読み取れたらそれをパペロが発話するデモを作成しました。
構成
- NDEFテキストレコードが読み取れたらそのテキストをそのまま発話する
- 同時に音声認識を行いpapebot.do_chatbot_operation()による雑談返答を行う
- paperotserver(こちら末尾のリンクからダウンロードしてください)経由で音声認識機能を利用する(PCでデバッグできる)
- stpypaperoを使用した状態遷移プログラム
ソースコード
ndefspeechdemo.py
import threading
from logging import (getLogger, Formatter, debug, info, warn, error, critical,
DEBUG, INFO, WARN, ERROR, CRITICAL, basicConfig)
import tornado.ioloop
import papebotclient
from stpypapero import StPyPaperoThread
import ndefcardreader
from papebotcom import (
MID_RECOGNIZED,
MID_DO_CHATBOT_OPERATION_RES,
KEY_SENTENCE,
)
MID_READY = 'Ready'
MID_TIMER = '_timer'
MID_END_OF_SPEECH = '_endOfSpeech'
MID_NDEF_DATA = '@ndefData'
KEY_STATUS = 'Status'
KEY_TEXT = 'text'
logger = getLogger(__name__)
class App(StPyPaperoThread):
def initialize(self, *args, **kwargs):
self.handler = self.in_init
self.papebot = None
self.ndef_text = None
def set_papebot(self, papebot):
self.papebot = papebot
def unmute(self):
if self.papebot is not None:
self.papebot.voice_unmute()
def mute(self):
if self.papebot is not None:
self.papebot.voice_mute()
def speech(self, text):
self.mute()
super().speech(text=text)
def nfc_touch_speech(self, txt='タッチありがとう'):
self.speech(txt)
self.ndef_text = None
def do_chat(self, text):
if self.papebot is not None:
self.papebot.do_chatbot_operation(sentence=text, talk=False)
self.trans_state(self.in_chat_wait)
def in_init(self, name, msg):
# 初期状態イベント処理
if name == MID_READY:
self.start_face_tracking()
self.speech('こんにちは')
self.trans_state(self.in_speech)
def in_speech(self, name, msg):
# 発話中状態イベント処理
if name == MID_END_OF_SPEECH:
if self.ndef_text is not None:
self.nfc_touch_speech(self.ndef_text)
else:
self.unmute()
self.trans_state(self.in_idle)
elif name == MID_NDEF_DATA:
self.ndef_text = msg.get(KEY_TEXT)
def in_idle(self, name, msg):
# アイドル状態イベント処理
if name == MID_RECOGNIZED:
txt = msg.get(KEY_SENTENCE)
logger.info('event: {} txt: {}'.format(name, txt))
if txt is not None and 0 < len(txt):
self.do_chat(txt)
elif name == MID_NDEF_DATA:
self.nfc_touch_speech(msg.get(KEY_TEXT))
self.trans_state(self.in_speech)
else:
logger.info('event: {}'.format(name))
def in_chat_wait(self, name, msg):
# 雑談返答問い合わせ中イベント処理
if name == MID_DO_CHATBOT_OPERATION_RES:
logger.info(msg)
txt = msg.get(KEY_TEXT)
if txt is not None and 0 < len(txt):
self.speech(txt)
self.trans_state(self.in_speech)
else:
if self.ndef_text is not None:
self.nfc_touch_speech(self.ndef_text)
self.trans_state(self.in_speech)
else:
self.unmute()
self.trans_state(self.in_idle)
elif name == MID_NDEF_DATA:
self.ndef_text = msg.get(KEY_TEXT)
def main():
logger.info('start.')
simid = ''
ipnet = '192.168.5'
papeurl = 'ws://{}.1:8088/papero'.format(ipnet)
boturl = 'ws://{}.100:8867/papebot'.format(ipnet)
if 0 < len(simid):
papeurl = '' # 空文字でシミュレータに接続
stpapero = App(simid=simid, simname='', url=papeurl)
def on_ndef_data(ndef_data):
# NFCタッチ時のコールバック:
# NDEF_DATAイベントを送る。最初に見つかったtextレコードのtextを送る
if isinstance(ndef_data, list):
for rec in ndef_data:
logger.info(rec)
if rec.type == 'urn:nfc:wkt:T':
txt = rec.text
stpapero.put_ex_event(MID_NDEF_DATA, {KEY_TEXT: txt})
break
# カードエミュレータクラスインスタンス
cardreader = ndefcardreader.NdefCardReader(on_ndef_data=on_ndef_data)
def eventcb(rpapebot, msg):
# papebotイベントコールバック
if msg is None:
logger.error('None.')
return False
name = msg.get('Name')
if name is not None:
# イベントをそのままパペロ側にputする
stpapero.put_ex_event(name, msg)
try:
# tw = True # 「パペロ」必要
tw = False # 「パペロ」不要
module_list = ['weather', 'wikipedia']
rmt = papebotclient.PapebotClient(boturl, event_callback=eventcb,s
triggerword_onoff=tw, chat_talk=False,
module_list=module_list)
stpapero.start()
stpapero.set_papebot(rmt)
rmt.start()
threading.Thread(target=tornado.ioloop.IOLoop.current().start).start()
cardreader.run()
except KeyboardInterrupt:
logger.info('KeyboardInterrupt!')
except Exception as e:
logger.error(e)
logger.info('end.')
if __name__ == '__main__':
loglevel = INFO
LOG_FMT = '%(asctime)s %(levelname)s %(thread)d.%(name)s.%(funcName)s %(message)s'
basicConfig(level=loglevel, format=LOG_FMT)
main()
動作確認
(1) Tinker Board S でpapebotserverを起動してください
python3 papebotserver.py
(2) Androidでカードエミュレーションでパペロに発話させたい文字列をNDEFテキストレコードで返すアプリを動かしてください
変更例:
NdefRecord record = NdefRecord.createTextRecord("ja", "エヌデフ通信テストです");
(3) パペロのIPアドレスが直書きになっているので修正した上でPCまたはTinker Board S でndefspeechdemo.pyを実行してください
sudo python3 ndefspeechdemo.py
0