はじめに
以前「Raspberry Pi に顔を覚えてもらう」を執筆させていただいた者です。続きですよ続き!
前回の記事で、目標として立てた「やりたいこと」がこちら
やりたいこと
- 帰宅したことに反応する
- 誰が帰宅したか判別する
- 2の結果、自分なら「お帰りなさい」他の人なら「どちらさまですか?」と話しかける
奥さんの場合、処理終了(うるさいって言われるから) - 応答に合わせ、粋な返しをする
- 2回くらいの会話ラリーの後、「ゆっくりお休みください」と言って処理終了
今回は3にあたる
「自分なら「お帰りなさい」他の人なら「どちらさまですか?」と話しかける」
こちらを実現するため今回は、Raspberry Piに喋ってもらおうと思います。
今回の実現目標
目的からすると、人感センサーが反応し、それが自分だと判別できたタイミングで動作開始するのが理想です。
ただ、今回は「喋ってもらおう」というのが目標ではあるので、以下の流れになる様に実装します。
- 「ただいま」という音声を受けた(Input)
- 「お帰りなさい」と発声(Output)
- 「おわり」という音声で処理終了(Input)
実現するにあたって
今回は、Google CloudのAI音声サービスを使用して、音声対話システムを構築してみようと思います。
使用するGoogle Cloud サービス
- Cloud Speech-to-Text API(音声認識)
- Cloud Text-to-Speech API(音声合成)
基本構成
- Raspberry Pi 4
- USBマイク
- スピーカー(3.5mm イヤホンジャック端子のもの)
セットアップ
その1 Google Cloud Platform の初期設定
音声認識・音声合成を使うには、Google Cloud Platformのセットアップが必要です。
1. Google Cloud プロジェクトの作成
- Google Cloud Console にアクセス
- 画面上部の「プロジェクトを選択」→「新しいプロジェクト」をクリック
- プロジェクト名を入力(例:
raspberry-pi-voice)して「作成」
2. 必要なAPIの有効化
プロジェクトを作成したら、2つのAPIを有効化します。
Cloud Speech-to-Text API の有効化
- 左メニューから「APIとサービス」→「ライブラリ」を選択
- 検索ボックスに「Speech-to-Text」と入力
- 「Cloud Speech-to-Text API」をクリック
- 「有効にする」ボタンをクリック
Cloud Text-to-Speech API の有効化
- 同じく「APIとサービス」→「ライブラリ」から
- 検索ボックスに「Text-to-Speech」と入力
- 「Cloud Text-to-Speech API」をクリック
- 「有効にする」ボタンをクリック
3. サービスアカウントの作成とキーのダウンロード
APIを使うための認証情報を作成します。
- 左メニューから「IAMと管理」→「サービスアカウント」を選択
- 「サービスアカウントを作成」をクリック
- サービスアカウント名を入力(例:
raspberry-pi-voice-sa) - 「作成して続行」をクリック
- ロールの選択で右を追加:
Cloud Speech Client - 「完了」をクリック
- 作成したサービスアカウントをクリック
- 「キー」タブを選択
- 「鍵を追加」→「新しい鍵を作成」
- キーのタイプは「JSON」を選択して「作成」
- JSONファイルが自動ダウンロードされます(これが
service-account-key.jsonになります)
セキュリティ注意: このJSONファイルは外部に漏らさないよう厳重に管理してください。
コストについて知っておこう
Google Cloud の音声サービスは従量課金制ですが、無料枠がかなり充実しています。
無料枠(2025年12月時点)
Cloud Speech-to-Text API
- 毎月 60分まで無料
- Standard モデルの場合
Cloud Text-to-Speech API
- Standard音声: 毎月 400万文字まで無料
- Neural2音声: 毎月 100万文字まで無料
実際の使用量目安
今回のシステムで「ただいま」→「お帰りなさい」のやり取りを想定すると:
- 音声認識: 1回5秒 × 1日10回 × 30日 = 約25分/月
- 音声合成: 「お帰りなさい」7文字 × 1日10回 × 30日 = 2,100文字/月
→ 完全に無料枠内で運用可能です!
有料になる場合の料金
無料枠を超えた場合でも、比較的リーズナブルです:
- Speech-to-Text: $0.006/15秒(約1円/15秒)
- Text-to-Speech (Neural2): $16.00/100万文字(約2,400円/100万文字)
1日中ずっと使い続けるような用途でない限り、月額数十円〜数百円程度で収まるはずです。
その2 OSインストールとシステム更新
まずは必要なライブラリ等をRaspberry Piにインストールしておきます。既に入ってる場合は、次のステップへ。
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3-pip python3-dev python3-venv
sudo apt install -y portaudio19-dev python3-pyaudio
sudo apt install -y alsa-utils pulseaudio pulseaudio-utils
sudo apt install -y libportaudio2 libportaudiocpp0その3 Python環境構築
仮想環境作成
python3 -m venv voice_env
source voice_env/bin/activate必要なPythonライブラリのインストール
pip install google-cloud-speech google-cloud-texttospeech
pip install pyaudio pygameその4 音声デバイス設定
# 音声デバイス確認
arecord -l # 入力デバイス
aplay -l # 出力デバイス
# USBマイクのテストなので5秒ほど下のコマンド実行後喋ってみてください
arecord -D plughw:[arecordで表示されたカード番号],[arecordで表示されたデバイス番号] -d 5 test.wav
# 上記コマンドで録音したファイルを再生
aplay test.wav
# 音量調整
alsamixerその5 Google Cloud認証設定
サービスアカウントキーを保存したファイルを参照できる位置に配置し、環境変数設定をします。
echo 'export GOOGLE_APPLICATION_CREDENTIALS="/(Raspberry Piでの保存フォルダ)/service-account-key.json"' >> ~/.bashrc
source ~/.bashrcこれで環境が整いました。
いざ実装!!
以下のコードを voice_greeting.py として保存します。
import time
import sys
import os
import tempfile
import pyaudio
from google.cloud import speech
from google.cloud import texttospeech
import pygame
class ContinuousVoiceGreeting:
def __init__(self):
# Google Cloud認証確認
if not os.environ.get('GOOGLE_APPLICATION_CREDENTIALS'):
print("GOOGLE_APPLICATION_CREDENTIALS 環境変数が設定されていません")
raise Exception("Google Cloud認証情報が見つかりません")
# Google Cloud クライアント初期化
self.speech_client = speech.SpeechClient()
self.tts_client = texttospeech.TextToSpeechClient()
# Raspberry Pi最適化設定
self.speech_config = speech.RecognitionConfig(
encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16,
sample_rate_hertz=16000,
language_code="ja-JP",
model="latest_short", # 短時間モデルが安定
use_enhanced=True,
enable_automatic_punctuation=True,
)
# 自然な日本語音声設定
self.tts_voice = texttospeech.VoiceSelectionParams(
language_code="ja-JP",
ssml_gender=texttospeech.SsmlVoiceGender.FEMALE,
name="ja-JP-Neural2-B"
)
self.tts_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3,
speaking_rate=0.9,
pitch=0.0
)
# PyAudio設定(Raspberry Pi最適化)
self.audio_format = pyaudio.paInt16
self.channels = 1
self.rate = 16000
self.chunk = 1024
self.audio = pyaudio.PyAudio()
# システム状態管理
self.is_running = True
self.is_speaking = False
# pygame初期化(3.5mmジャック用最適化)
os.environ['SDL_AUDIODRIVER'] = 'alsa' # ALSA強制使用
pygame.mixer.pre_init(frequency=22050, size=-16, channels=1, buffer=512)
pygame.mixer.init()
print("Raspberry Pi初期化完了!")
def listen_for_voice(self):
"""音声入力を待機・取得する"""
try:
print("音声入力待機中... (5秒間録音)")
# 音声録音
stream = self.audio.open(
format=self.audio_format,
channels=self.channels,
rate=self.rate,
input=True,
frames_per_buffer=self.chunk,
input_device_index=None # デフォルトデバイス使用
)
frames = []
for _ in range(0, int(self.rate / self.chunk * 5)):
try:
data = stream.read(self.chunk, exception_on_overflow=False)
frames.append(data)
except OSError:
print("音声入力でオーバーフローが発生しました")
continue
stream.stop_stream()
stream.close()
audio_data = b''.join(frames)
print("Google Cloudで音声認識中...")
# Google Cloud Speech-to-Text
audio = speech.RecognitionAudio(content=audio_data)
response = self.speech_client.recognize(
config=self.speech_config,
audio=audio
)
if response.results:
text = response.results[0].alternatives[0].transcript
confidence = response.results[0].alternatives[0].confidence
print(f"認識結果: 「{text}」(信頼度: {confidence:.2f})")
return text
else:
print("音声を認識できませんでした")
return None
except Exception as e:
print(f"音声認識エラー: {e}")
return None
def check_tadaima(self, text):
"""「ただいま」検出"""
if text is None:
return False
tadaima_patterns = ["ただいま", "只今", "タダイマ", "tadaima", "ただ今"]
text_lower = text.lower()
for pattern in tadaima_patterns:
if pattern.lower() in text_lower:
print(f"「{pattern}」を検出しました!")
return True
print("「ただいま」は含まれていませんでした")
return False
def speak_okaeri(self):
"""「お帰りなさい」音声出力(3.5mmジャック)"""
if self.is_speaking:
return
self.is_speaking = True
message = "お帰りなさい"
print(f"3.5mmジャックから音声出力: 「{message}」")
try:
# Google Cloud Text-to-Speech
synthesis_input = texttospeech.SynthesisInput(text=message)
response = self.tts_client.synthesize_speech(
input=synthesis_input,
voice=self.tts_voice,
audio_config=self.tts_config
)
# 3.5mmジャック用音声再生(MP3形式)
with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as tmp_file:
tmp_file.write(response.audio_content)
tmp_file_path = tmp_file.name
# pygame音声再生(3.5mmジャック向け最適化)
pygame.mixer.music.load(tmp_file_path)
pygame.mixer.music.set_volume(0.8)
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
time.sleep(0.1)
os.unlink(tmp_file_path)
print("音声出力完了")
except Exception as e:
print(f"音声出力エラー: {e}")
finally:
self.is_speaking = False
def check_exit_command(self, text):
"""終了コマンドチェック"""
if text is None:
return False
exit_patterns = ["終わり", "やめて", "ストップ", "stop", "exit", "quit", "シャットダウン"]
text_lower = text.lower()
for pattern in exit_patterns:
if pattern.lower() in text_lower:
return True
return False
def run(self):
"""メインループ"""
try:
while self.is_running:
recognized_text = self.listen_for_voice()
if recognized_text:
if self.check_exit_command(recognized_text):
print("終了コマンドを検出")
break
if self.check_tadaima(recognized_text):
self.speak_okaeri()
time.sleep(0.5)
print("\n" + "-"*40)
except KeyboardInterrupt:
print("\n Ctrl+Cで終了")
except Exception as e:
print(f"\n システムエラー: {e}")
finally:
self.cleanup()
def cleanup(self):
"""終了処理"""
self.is_running = False
if self.is_speaking:
print("音声出力完了を待機中...")
time.sleep(2)
self.audio.terminate()
pygame.mixer.quit()
def main():
try:
greeting_system = ContinuousVoiceGreeting()
greeting_system.run()
except Exception as e:
print(f"Raspberry Pi初期化エラー: {e}")
print("セットアップガイドを確認してください")
sys.exit(1)
if __name__ == "__main__":
main()
実行してみよう
仮想環境がアクティブになっていることを確認してから実行します。
source voice_env/bin/activate
python voice_greeting.py動かしてみた
実際にRaspberry Pi上で実行してみました。マイクに向かって「ただいま」と話しかけると…
(音が出ます)
音声として「お帰りなさい」と言ってもらえる様になりました!
最後に
今回でRaspberry Piにお話ししてもらえる様になり、少しお友達感が増す様になってきました。
ただ、少し応答に時間がかかる感じがあるため、改善していければなおさらお友達感が増す予感がします。
ここまで話してもらえる様になったなら、次は、Raspberry Piに会話の内容を理解してもらって、粋な返しができるようにするため、次回は、AIをRaspberry Piに搭載して、粋な会話ができるようにするチャレンジにしてみようと思います。
その時、会話の語尾は「にゃ」ってつけてもらうんだ俺!!!








