UMEHOSHI ITA TOP PAGE

作成中

[Raspberry Pi 3 Model A+]と[UMEHOSHI ITA]を乗せたモータ付き台車の利用例: 音声入力での操作

このページで示したロボットのハードを使っています。
なお、EEPROMの内容は、この
ページで作成した内容と同じです。
(別途のRAMにSPI受信処理を埋め込む方式で検討しています)

RaspberryPi3で動かす音声認識の検討

現時点(2026年4月)で、無料枠が多い音声認識サービスのIBM Watson Speech to Textが魅力的であるが、クレカ登録あったのでチョット足踏みしてしまった。
その必要が無くローカル実行が可能なOpenAI Whisperがあったが使用予定のRaspberryPi3では重いらしい。(Pi 4/5推奨)
そこでVosk(ヴォスク)というモジュールを利用して試すことにした。

まずは、OSを最新の状態にし、マイク入力に必要なライブラリをインストールします。
sudo apt update
sudo apt upgrade
sudo apt install portaudio19-dev
現在はPython 3.9.2 (default, Mar 12 2021, 04:06:34)で動作しています。(Raspberry Pi OS :Bullseye の標準環境)
このシステムへ、次の操作でVoskをインストールしました。
依存関係で、(C言語のインターフェースなど)を先にインストールしています。
sudo apt install python3-pip python3-cffi libportaudio2
pip3 install vosk
pip install pyaudio
以上で、srt-3.5.3 tqdm-4.67.3 vosk-0.3.45 websockets-15.0.1、pyaudio-0.2.14がインストールされました。

pip3 install vosk を実行しただけでは、モデル(学習済みデータ)はインストールされません。
あくまで Vosk を動かすための 「エンジン(プログラム本体)」 だけです。
言葉を理解するための「辞書(モデル)」は、別途手動でダウンロードして配置する必要があります。
「辞書(モデル)」は言語(日本語、英語、中国語など)やサイズ(軽量版、高精度版)によって多種多様です。
ラズパイ3では、メモリ消費が少ない「small」モデルを使用します。
Vosk Models へアクセスして、vosk-model-small-ja-0.22.zip(49,704,573byte)をダウンロードし、
次のように/usr/local/appsで、modelの名前のディレクトリへ展開しました。
wget https://alphacephei.com/vosk/models/vosk-model-small-ja-0.22.zip
unzip vosk-model-small-ja-0.22.zip
mv vosk-model-small-ja-0.22 model

以上で環境の出来上りです。 voskの実験に使うテスト用ファイル(vosk_wav_test.py)を次の様に用意しました。
import wave
import json
from vosk import Model, KaldiRecognizer

# 1. モデルのパスを指定(前回ダウンロードしたフォルダ名)
model_path = "model" 
# 2. 読み込むWAVファイル
wav_file = "morter_ctrl.wav"

if not wave.open(wav_file):
    print("WAVファイルが開けません")
    exit(1)

wf = wave.open(wav_file, "rb")

# フォーマットチェック
if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
    print("WAVファイルは '16-bit PCM mono' である必要があります。")
    exit(1)

model = Model(model_path)
# サンプリングレートをファイルに合わせる
rec = KaldiRecognizer(model, wf.getframerate())

print("認識中...")

while True:
    data = wf.readframes(4000)
    if len(data) == 0:
        break
    if rec.AcceptWaveform(data):
        # 認識確定時の結果
        result = json.loads(rec.Result())
        print("確定結果:", result.get("text", ""))

# 最終的な認識結果
final_result = json.loads(rec.FinalResult())
print("最終結果:", final_result.get("text", ""))
このファイル(vosk_wav_test.py)と、認識させるテスト用の音声ファイル(morter_ctrl.wav)を次のように配置させて、 実行させます。
/usr/local/apps
├── vosk_wav_test.py  (実行するプログラム)
├── morter_ctrl.wav   (音声ファイル)
└── model/           
        ├── am/
        ├── conf/
        ├── graph/
        ├── ivector/
        └── rescore/
この実行結果は、次のようになりました。
suzuki@raspberrypi:/usr/local/apps $ python vosk_wav_test.py
LOG (VoskAPI:ReadDataFiles():model.cc:213) Decoding params beam=13 max-active=7000 lattice-beam=4
LOG (VoskAPI:ReadDataFiles():model.cc:216) Silence phones 1:2:3:4:5:6:7:8:9:10
LOG (VoskAPI:RemoveOrphanNodes():nnet-nnet.cc:948) Removed 0 orphan nodes.
LOG (VoskAPI:RemoveOrphanComponents():nnet-nnet.cc:847) Removing 0 orphan components.
LOG (VoskAPI:ReadDataFiles():model.cc:248) Loading i-vector extractor from model/ivector/final.ie
LOG (VoskAPI:ComputeDerivedVars():ivector-extractor.cc:183) Computing derived variables for iVector extractor
LOG (VoskAPI:ComputeDerivedVars():ivector-extractor.cc:204) Done.
LOG (VoskAPI:ReadDataFiles():model.cc:282) Loading HCL and G from model/graph/HCLr.fst model/graph/Gr.fst
LOG (VoskAPI:ReadDataFiles():model.cc:308) Loading winfo model/graph/phones/word_boundary.int
認識中...
確定結果: 全身 更新 左 回転 右 回転 同率
最終結果:
suzuki@raspberrypi:/usr/local/apps $
上記実行で使った、morter_ctrl.wav は、705Kbps モノラル 44.1KHz 16ビットサンプル で、 「前進 後進 左回転 右回転 倒立」と発音したの10秒の音声ファイルです。
確定結果は、認識中が出てから、約23秒後に表示されました。

Smallの辞書モデルの場合、高度な文脈判断でなく、直前の1?2単語とのつながりから判断なので、前進を全身と判断されるなど、希望の認識にならない。
そこでKaldiRecognizerの第3引数に、'["前進", "後進", "左回転", "右回転", "倒立", "[unk]"]'と 指定し、ワード 以外の判定をさせないようにした。
それは、上記 rec = KaldiRecognizer(model, wf.getframerate()) のコードを、次のように変更して実現しました。
# 認識させたい言葉のリストをJSON形式の文字列で作成
words = '["前進", "後進", "左", "右","回転", "倒立", "[unk]"]'
rec = KaldiRecognizer(model, wf.getframerate(), words)
10秒程度のファイルでは長すぎるので、1秒程度ファイルで判定することにした。
Voskで使う認識用も音声ファイルは、16bit LPCM (Little Endian)、1ch (モノラル)、16,000Hz (16kHz)のサンプリングレート限定に決定した。
(なお、Vosk内部でも結局 16kHzに間引く計算を行っているらしい。)

PIC32MX側で得たサウンド情報でRaspberryPi3を動かす検討

PIC32MX側のAN0のADコンバーター側を利用する。
メモリが少ないので、バッファは使わずにすぐSPIを介して送信する方法で進める。
伝達は「#二輪倒立制御を考える」で使ったようにラズパイがSPIマスターであるが、伝達方向が逆でPIC32MXからラズパイへ送信する。
(Raspberry Piシリーズ(RP2040のPICO以外)は、基本的に「SPIスレーブ非対応」ということで、ラズパイがSPIマスターにする)
Raspberry PiをSPIマスターにして16ビットサウンドデータを受信処理を続ける処理を行い、 1秒程度分の有効データがバッファに蓄えられたらrec1.wavファイルを生成して、音声認識を行う目標で検討しました。 spirectowav.pyで この受信処理は、スレッドで
import spidev
import time

def spi_send(spi: spidev.SpiDev, datas: list):
    # spiで、listのbyte列を送る。 (送信成功で、Trueを返す)
    mas_req_idx:int=0 # 要求されたデータの添え字
    last_idx = len(datas)-1
    fail_count=0
    while True:
        send_data = datas[mas_req_idx]
        rec_data = spi.xfer2([send_data])[0] # 1byte送受信
        print(f"send[{mas_req_idx}]:{send_data},receive: {rec_data}")
        if rec_data > last_idx: return False # スレーブから想定外の受信
        if rec_data == mas_req_idx: # 受信エラーと判断し、先頭から送り直す。
            mas_req_idx = 0
            fail_count+=1 # 失敗数カウント
            if fail_count > 5: return False # 送信失敗
            time.sleep(0.001) # チョット待つ
            continue
        if mas_req_idx == last_idx: return True # 送信成功終了
        mas_req_idx = rec_data # 次のデータの添え字に更新
    #
#

spi = spidev.SpiDev() # SPI操作オブジェクト生成
spi.open(0, 0)        # bus=0 device=0 (CE0) でSPIオープン

spi.max_speed_hz = 7812500 # 7.8 MHzSPIクロック
spi.mode = 0 # クロック信号(SCLK)はLow待機、LowからHighに立ち上がる瞬間でデータを読み取り









apt-listchanges: News
---------------------

cups (2.3.3op2-3+deb11u4) bullseye; urgency=medium

  This release addresses a security issue (CVE-2023-32360) which allows
  unauthorized users to fetch documents over local or remote networks.
  Since this is a configuration fix, it might be that it does not reach you if you
  are updating 'cups-daemon' (rather than doing a fresh installation).
  Please double check your /etc/cups/cupsd.conf file, whether it limits the access
  to CUPS-Get-Document with something like the following
  >  
  >    AuthType Default
  >    Require user @OWNER @SYSTEM
  >    Order deny,allow
  >   
  (The important line is the 'AuthType Default' in this section)

 -- Thorsten Alteholz   Tue, 19 Sep 2023 21:20:27 +0200
suzuki@raspberrypi:~ $ sudo apt install python3-pip python3-cffi libportaudio2
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
python3-pip is already the newest version (20.3.4-4+rpt1+deb11u1).
The following package was automatically installed and is no longer required:
  libfuse2
Use 'sudo apt autoremove' to remove it.
The following additional packages will be installed:
  python3-ply python3-pycparser
Suggested packages:
  python-ply-doc
The following NEW packages will be installed:
  libportaudio2 python3-cffi python3-ply python3-pycparser
0 upgraded, 4 newly installed, 0 to remove and 337 not upgraded.
Need to get 285 kB of archives.
After this operation, 1,457 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:2 http://ftp.udx.icscoe.jp/Linux/raspbian/raspbian bullseye/main armhf python3-ply all 3.11-4 [65.5 kB]
Get:3 http://ftp.udx.icscoe.jp/Linux/raspbian/raspbian bullseye/main armhf python3-pycparser all 2.20-3 [74.5 kB]
Get:4 http://ftp.udx.icscoe.jp/Linux/raspbian/raspbian bullseye/main armhf python3-cffi all 1.14.5-1 [87.9 kB]
Get:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian bullseye/main armhf libportaudio2 armhf 19.6.0-1.1 [57.5 kB]
Fetched 285 kB in 32s (8,824 B/s)
Selecting previously unselected package libportaudio2:armhf.
(Reading database ... 106593 files and directories currently installed.)
Preparing to unpack .../libportaudio2_19.6.0-1.1_armhf.deb ...
Unpacking libportaudio2:armhf (19.6.0-1.1) ...
Selecting previously unselected package python3-ply.
Preparing to unpack .../python3-ply_3.11-4_all.deb ...
Unpacking python3-ply (3.11-4) ...
Selecting previously unselected package python3-pycparser.
Preparing to unpack .../python3-pycparser_2.20-3_all.deb ...
Unpacking python3-pycparser (2.20-3) ...
Selecting previously unselected package python3-cffi.
Preparing to unpack .../python3-cffi_1.14.5-1_all.deb ...
Unpacking python3-cffi (1.14.5-1) ...
Setting up libportaudio2:armhf (19.6.0-1.1) ...
Setting up python3-ply (3.11-4) ...
Setting up python3-pycparser (2.20-3) ...
Setting up python3-cffi (1.14.5-1) ...
Processing triggers for libc-bin (2.31-13+rpt2+rpi1+deb11u5) ...
Processing triggers for man-db (2.9.4-2) ...
suzuki@raspberrypi:~ $
suzuki@raspberrypi:~ $ sudo apt install portaudio19-dev
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following package was automatically installed and is no longer required:
  libfuse2
Use 'sudo apt autoremove' to remove it.
The following additional packages will be installed:
  libasound2-dev libjack-dev libjack0 libportaudiocpp0 uuid-dev
Suggested packages:
  libasound2-doc jackd1 portaudio19-doc
The following packages will be REMOVED:
  libjack-jackd2-0
The following NEW packages will be installed:
  libasound2-dev libjack-dev libjack0 libportaudiocpp0 portaudio19-dev uuid-dev
0 upgraded, 6 newly installed, 1 to remove and 0 not upgraded.
Need to get 643 kB of archives.
After this operation, 2,822 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:2 http://archive.raspberrypi.org/debian bullseye/main armhf libasound2-dev armhf 1.2.4-1.1+rpt2 [126 kB]
Get:1 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf libjack0 armhf 1:0.125.0-3+b1 [91.2 kB]
Get:4 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf libjack-dev armhf 1:0.125.0-3+b1 [212 kB]
Get:5 http://ftp.udx.icscoe.jp/Linux/raspbian/raspbian bullseye/main armhf libportaudiocpp0 armhf 19.6.0-1.1 [17.0 kB]
Get:6 http://ftp.udx.icscoe.jp/Linux/raspbian/raspbian bullseye/main armhf portaudio19-dev armhf 19.6.0-1.1 [99.1 kB]
Get:3 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf uuid-dev armhf 2.36.1-8+deb11u2 [97.8 kB]
Fetched 643 kB in 22s (29.7 kB/s)
dpkg: libjack-jackd2-0:armhf: dependency problems, but removing anyway as you requested:
 libportaudio2:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 libfluidsynth2:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 libavdevice58:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 libasound2-plugins:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 gstreamer1.0-plugins-good:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 libportaudio2:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 libfluidsynth2:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 libavdevice58:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 libasound2-plugins:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.
 gstreamer1.0-plugins-good:armhf depends on libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125; however:
  Package libjack-jackd2-0:armhf is to be removed.
  Package libjack-0.125 is not installed.
  Package libjack-jackd2-0:armhf which provides libjack-0.125 is to be removed.

(Reading database ... 106996 files and directories currently installed.)
Removing libjack-jackd2-0:armhf (1.9.17~dfsg-1) ...
Selecting previously unselected package libjack0:armhf.
(Reading database ... 106985 files and directories currently installed.)
Preparing to unpack .../0-libjack0_1%3a0.125.0-3+b1_armhf.deb ...
Unpacking libjack0:armhf (1:0.125.0-3+b1) ...
Selecting previously unselected package libasound2-dev:armhf.
Preparing to unpack .../1-libasound2-dev_1.2.4-1.1+rpt2_armhf.deb ...
Unpacking libasound2-dev:armhf (1.2.4-1.1+rpt2) ...
Selecting previously unselected package uuid-dev:armhf.
Preparing to unpack .../2-uuid-dev_2.36.1-8+deb11u2_armhf.deb ...
Unpacking uuid-dev:armhf (2.36.1-8+deb11u2) ...
Selecting previously unselected package libjack-dev.
Preparing to unpack .../3-libjack-dev_1%3a0.125.0-3+b1_armhf.deb ...
Unpacking libjack-dev (1:0.125.0-3+b1) ...
Selecting previously unselected package libportaudiocpp0:armhf.
Preparing to unpack .../4-libportaudiocpp0_19.6.0-1.1_armhf.deb ...
Unpacking libportaudiocpp0:armhf (19.6.0-1.1) ...
Selecting previously unselected package portaudio19-dev:armhf.
Preparing to unpack .../5-portaudio19-dev_19.6.0-1.1_armhf.deb ...
Unpacking portaudio19-dev:armhf (19.6.0-1.1) ...
Setting up libportaudiocpp0:armhf (19.6.0-1.1) ...
Setting up libjack0:armhf (1:0.125.0-3+b1) ...
Setting up uuid-dev:armhf (2.36.1-8+deb11u2) ...
Setting up libjack-dev (1:0.125.0-3+b1) ...
Setting up libasound2-dev:armhf (1.2.4-1.1+rpt2) ...
Setting up portaudio19-dev:armhf (19.6.0-1.1) ...
Processing triggers for man-db (2.9.4-2) ...
Processing triggers for libc-bin (2.31-13+rpt2+rpi1+deb11u13) ...
suzuki@raspberrypi:~ $
suzuki@raspberrypi:~ $ pip3 install vosk
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting vosk
  Downloading vosk-0.3.45-py3-none-linux_armv7l.whl.metadata (1.8 kB)
Requirement already satisfied: cffi>=1.0 in /usr/lib/python3/dist-packages (from vosk) (1.14.5)
Requirement already satisfied: requests in /usr/lib/python3/dist-packages (from vosk) (2.25.1)
Collecting srt (from vosk)
  Downloading https://www.piwheels.org/simple/srt/srt-3.5.3-py3-none-any.whl (22 kB)
Collecting tqdm (from vosk)
  Downloading https://www.piwheels.org/simple/tqdm/tqdm-4.67.3-py3-none-any.whl (78 kB)
Collecting websockets (from vosk)
  Downloading https://www.piwheels.org/simple/websockets/websockets-15.0.1-cp39-cp39-linux_armv7l.whl (179 kB)
Downloading vosk-0.3.45-py3-none-linux_armv7l.whl (2.4 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.4/2.4 MB 3.3 MB/s  0:00:00
Installing collected packages: websockets, tqdm, srt, vosk
Successfully installed srt-3.5.3 tqdm-4.67.3 vosk-0.3.45 websockets-15.0.1

[notice] A new release of pip is available: 25.3 -> 26.0.1
[notice] To update, run: python3 -m pip install --upgrade pip
suzuki@raspberrypi:~ $
suzuki@raspberrypi:~ $ python3 -m pip install --upgrade pip
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Requirement already satisfied: pip in ./.local/lib/python3.9/site-packages (25.3)
Collecting pip
  Downloading https://www.piwheels.org/simple/pip/pip-26.0.1-py3-none-any.whl (1.8 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 232.4 kB/s  0:00:07
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 25.3
    Uninstalling pip-25.3:
      Successfully uninstalled pip-25.3
Successfully installed pip-26.0.1
suzuki@raspberrypi:~ $
suzuki@raspberrypi:~ $ pip install pyaudio
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting pyaudio
  Downloading https://www.piwheels.org/simple/pyaudio/PyAudio-0.2.14-cp39-cp39-linux_armv7l.whl (56 kB)
Installing collected packages: pyaudio
Successfully installed pyaudio-0.2.14
suzuki@raspberrypi:~ $