PaPeRo i をScratch3.0で制御する-その3-音声認識、センサーなど

 PaPeRo i をScratch3.0で制御する-その2-LEDと頭の制御の続きです。今回は以下のブロックを追加しました。

  • 音声認識
  • 温度・湿度・人感センサー
  • 照度センサー
  • 顔検出・顔追従
  • 音声の録音・再生
  • 画像の撮影

音声認識

 PaPeRo i 本体の音声認識のためには
(1) 辞書を読込む (「標準」音声認識辞書を読込む)
(2) 音声認識開始
(3) 音声認識停止
(4) 音声認識イベント (「言葉を聞き取った」とき)
(5) 音声認識が成功だったか (「音声認識が成功した」)
(6) 音声認識した言葉 (イベント値「認識した言葉」)
のブロックが必要になります。辞書を読込むには辞書のパス、標準辞書の場合”/opt/papero/lib/Standard.mrg”、を指定する必要があり、複数の辞書を選択可能にできた方が良いので選択メニューを持つ専用のブロックにしましたが、他はブロック数増加を抑えるため、既存ブロックの選択メニューに追加しました。なお(5)ですが、パペロ本体の音声認識では何か聞き取ったけれど何かはわからなかった、という場合にも音声認識イベントが発生するので、それと正常に言葉を聞き取れた場合の判別に使用します。
 使い方の注意点としては、Scratch3.0に限った話ではありませんが、パペロに発話させている間は音声認識を停止しておかないと自分の声を認識する繰り返しが止まらなくなります。また同時に顔検出・顔追従を使ってしまうと音声認識のレスポンスが非常に悪くなるので避ける必要があります。

温度・湿度・人感センサー

 温度・湿度・人感センサーのためには、
(1) センサー値を読むブロック (「温度・湿度・赤外線センサーの値を読み出す」)
(2) センサー値が返されたイベント(「温度・湿度・赤外線センサーの値が返された」)
(3) センサー値 (イベント値「温度」「湿度」「赤外線センサー値」)
が必要で、これらは全て既存ブロックの選択メニュー追加としました。赤外線センサーのセンサー値はオリジナルは
「8704,-3480,-3544,-3524,-3464,Lost」
といった文字列ですが、Scratchは文字列操作が苦手なこともあり、
「赤外線センサー温度」「~上」、「~左」「~下」「~右」「~位置情報」
の選択メニューで6値を個別に取り出せるようにしました。

照度センサー

 照度センサーも同様に、
(1) センサー値を読むブロック (「照度センサーの値を読み出す」)
(2) センサー値が返されたイベント(「照度センサー値が返された」)
(3) センサー値 (イベント値「照度」)
が必要で、これらは全て既存ブロックの選択メニュー追加としました。実際には照度センサーは温度・湿度・人感センサーよりも読み出しシーケンスが複雑なのですが、Scratch上では同じに扱えるよう、ライブラリで吸収しています。

顔検出・顔追従

 顔の検出だけを行う事を「顔検出」、検出した顔へパペロの頭の向きを変える事を「顔追従」としています。顔検出イベントのイベント値から計算してScratchのブロックで顔追従させることも可能ですが、「顔追従開始」「顔追従停止」ブロックだけでできる様に顔追従機能をライブラリ側に実装しました。追加したブロックは
(1) 顔検出開始・停止
(2) 顔追従開始・停止
(3) 顔検出イベント (「顔を見つけた」とき)
(4) 顔を見失ったイベント (「顔を見うしなった」とき)
(5) 顔検出値 (「検出した左目のピクセル座標x」ほか)
で、全て既存ブロックの選択メニュー追加としました。
「顔検出」と計算で顔追従する:

「顔追従」で顔追従する:

音声の録音・再生

 録音開始のAPIは秒数指定がありますが煩雑になるのでブロックでは秒数指定は無くして180秒指定の固定とし、録音停止されるまで録音するという使用方法としました。
(1) 録音開始・停止
(2) wav再生開始・停止
なおファイル名を指定できますが省略可能(省略時は’sound.wav’)としています。

画像の撮影

 画像の撮影で追加したブロックは、
(1) SXGAカメラ撮影
(2) VGAカメラ撮影
(3) 撮影完了(写真をとり終わった)
で、全て既存ブロックの選択メニュー追加としました。

 撮影した画像を見ることができなければ意味がありませんが、ブロックプログラムからコスチュームや背景を作成するのは相当にハードルが高そうなのでひとまず今回はやめ、パペロ本体で/tmp下の.jpgファイルと.wavファイルだけを公開するサーバを動かす仮定とします。これはGolandであれば以下の様なプログラムとなります。

package main

import (
    "fmt"
    "io"
    "math/rand"
    "net/http"
    "os"
    "path/filepath"
    "strings"
    "time"

    "github.com/rs/zerolog"
)

const (
    EXTENSION_DIR = "/Extension"
    LOG_FN        = "/var/log/servejpg.log"
)

var logger zerolog.Logger

func InitPrettyLogger(writer io.Writer, level zerolog.Level) {
    ...省略...
}

func server() {
    addr := ":8864"
    staticDir := "/tmp"
    staticPath := "/"
    jpg := ".jpg"
    wav := ".wav"
    // static file handler
    fileServer := http.StripPrefix(staticPath, http.FileServer(http.Dir(staticDir)))
    fileHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        path := r.URL.Path
        if strings.HasPrefix(path, staticPath) &&
            (strings.HasSuffix(path, jpg) || strings.HasSuffix(path, wav)) {
            logger.Info().Str("Method", r.Method).Str("Host", r.Host).Str("RemoteAddr", r.RemoteAddr).Str("RequestURI", r.RequestURI).Msg("reply.")
            fileServer.ServeHTTP(w, r)
        } else {
            logger.Info().Str("Method", r.Method).Str("Host", r.Host).Str("RemoteAddr", r.RemoteAddr).Str("RequestURI", r.RequestURI).Msg("reject.")
            http.DefaultServeMux.ServeHTTP(w, r)
        }
    })
    logger.Info().Str("addr", addr).Str("staticDir", staticDir).Str("staticPath", staticPath).Msg("start server.")
    http.ListenAndServe(addr, fileHandler)
}

func main() {
    rand.Seed(time.Now().UnixNano())
    server()
}

※zerologの初期化については省略しています
これでたとえば192.168.1.1:8864/picture.jpgをブラウザで開くと/tmp/picture.jpgを見ることができます。単なるWebサーバであるため、撮影後にその画像を見るにはリロードが必要になります。

動作確認

 IBM Cloudのアプリを更新しましたのでお試しください。順次機能追加を行う予定なので、もし記事内容と異なる場合にはご容赦ください。


0