VoiceVox を ROS2 で使用する

　VoiceVox を ROS2 で使用できるパッケージ <font color='green'>**VOICEVOX_ROS2**</font> を作成しましたので、本パッケージの使用方法を紹介します。
# VOICEVOX_ROS2
　VOICEVOX_ROS2 は ROS2 humble で動作する音声合成パッケージです。ロボットからずんだもんや四国めたんなどの音声合成ボイスを発話できます。ソースコードとドキュメントは以下のリンクから参照してください。

- https://github.com/GAI-313/voicevox_ros2/tree/humble

::: note
**Voicevox_ros2 アップデートのおしらせ**
- API の全体的な修正と **新機能の追加**。
- [**voicevox_core 0.15.3**]() にサポート。新たなキャラクターに対応しました。
- そのた小さなバグを修正しました。
:::

## インストール
　インストール前に ROS ワークスペースを事前に作成してください。
```bash
mkdir colcon_ws/src
```
　`src` ディレクトリに本パッケージをダウンロードします。
 ```bash
cd colcon_ws/src
 git clone https://github.com/GAI-313/voicevox_ros2.git
 ```
 　ダウンロードが完了したら、パッケージをビルドします。
```bash
cd colcon_ws
colcon build --packages-up-to voicevox_ros2
```
::: note info
`--packages-up-to voicevox_ros2` 引数を与えることで、`voicevox_ros2` と、それに依存するパッケージ `voicevox_ros2_interface` のみビルドすることができます。
　Voicevox_ros2 はビルドが開始されると VoiceVox_core や jtalk ライブラリなどの必要なパッケージを自動的にインストールします。**よってビルドには数分程かかります。**
:::

　ビルドが完了したら `~/.bsahrc` とワークスペースを通します。
 ```bash
 source ~/.bashrc
 source colcon_ws/install/setup.bash
 ```
 　これでインストールは完了です。

## voicevox_ros2_core を起動する
　以下のコマンドを実行して、コアノード `voicevox_ros2_core` を起動します。
```bash
ros2 run voicevox_ros2 voicevox_ros2_core
```
　起動時に、以下のメッセージが表示されたら成功です。
```
[INFO] [xxxxxxxx.xxxxxxx] [voicevox_ros2_core]: start voicevox_ros2
```
　このノードが起動すると、以下のトピックが発行されます。
```
/voicevox_ros2/speaker
/voicevox_ros2/status
```
　主に使用するのは `/voicevox_ros2/speaker` です。`/voicevox_ros2/status` は voicevox_ros2_core の動作状況を飛ばしていますので、気にしないでください。

 ## トピックから発話させる
 　voicevox_ros2_core が起動している状態で、新たなターミナルを起動します。
  サンプルとして以下のノードを実行しましょう。
  ```bash
  ros2 run voicevox_ros2 pub
  ```
  　すると
   ```
   こんにちは。VoiceVox_ROS2 です。
   ```
   とずんだもんの声で発話します。
   　次はコマンドからトピックを飛ばして好きなテキストを発話させてみましょう。以下のように `/voicevox_ros2/speaker` トピックに `voicevox_ros2_interface/msg/Speaker` 型で任意のテキスト、発話キャラIDを指定します。加えて **オプション `--once` をつけ忘れないよう気をつけてください。** これを与えないとずっと言葉を喋り続けます…
```bash
ros2 topic pub --once /voicevox_ros2/speaker voicevox_ros2_interface/msg/Speaker "{text: 'hello', id: 1}"
```
　`text` に発話させたいテキストを入力し、`id` に発話するキャラクター ID を指定します。`id` に３を指定するとずんだもんの通常ボイス（ノーマル）で発話します。
 　以下のコマンドは、ずんだもん（ノーマル）で「こんにちは。僕の名前はずんだもんです」と発話させます。
```bash
ros2 topic pub --once /voicevox_ros2/speaker voicevox_ros2_interface/msg/Speaker "{text: 'こんにちは。僕の名前はずんだもんです', id: 3}"
```
　Pythonノードでトピックを経由してテキストを発話させるコードを作成したい場合、こちらを参考にしてください。

 - https://github.com/GAI-313/voicevox_ros2/blob/humble/voicevox_ros2/voicevox_ros2/pub_test.py

 ## サービスから発話させる
 　ROS2 サービス通信で発話させる場合、`/voicevox_ros2/speaker_srv` に `voicevox_ros2_interface/srv/Speaker` 型を使って通信します。以下のサンプルノードを実行すると、サービス通信経由で発話させます。
```bash
ros2 run voicevox_ros2 srv
```
　コマンドからサービス通信で発話させてみましょう。以下のコマンドを実行するとサービス経由で発話できます。
```bash
ros2 service call /voicevox_ros2/speaker_srv voicevox_ros2_interface/srv/Speaker "{text: 'サービス通信で発話させるよ', id: 1}"
```
　データの入力方法はトピックと同じです。Pythonコードでサービス通信をつかって発話させたい場合は、こちらのサンプルコードを参照してください。

- https://github.com/GAI-313/voicevox_ros2/blob/humble/voicevox_ros2/voicevox_ros2/srv_test.py

## API をつかう
　テキストを発話させるだけで導入したい環境に追加のコードを記述するのは大変です。このパッケージには `voicevox_ros2_tts` モジュールが用意されており、このモジュールをつかって１行で発話させることができるようになります。以下のサンプルコードは `voicevox_ros2_tts` の `say` 関数をつかって発話させる最も単純なコードになります。

 ```python
#!/usr/bin/emv python3

## ROS2 ノード関連
from rclpy.node import Node
import rclpy
## tts_speaker メソッドをインポート
from voicevox_ros2.voicevox_ros2_tts import say

# debug
if __name__ == '__main__':
    ## メソッドを使用する前にノードを立ててください。
    rclpy.init()
    node = Node('sample')
    say(node, text='こんにちは！ボイスボックスロスへようこそ')
    say(node, text='キャラクターIDを変更すると、しゃべるキャラクターが変わります', id=2)
```
```python
from voicevox_ros2.voicevox_ros2_tts import say
```
　で発話関数 `say` をインポートします。
 ```python
say(node, text='こんにちは！ボイスボックスロスへようこそ')
```
このように関数`say`の第１引数に`rclpy.Node`オブジェクトを代入し、第２引数`text`に発話させたいテキストを文字列で代入します。<font color='red'>**このとき、引数 `node` に ROS2 ノードの `Node` オブジェクトを代入しないとエラーになります。**</font>
　このとき、発話キャラクターID を指定していないので、デフォルトのキャラクターID 3 番のずんだもんの声が当てられます。
　発話させたいキャラクターを変えたい場合は、以下のように第３引数`id`に発話させたいキャラクターIDを整数で代入します。
```python
say(node, text='キャラクターIDを変更すると、しゃべるキャラクターが変わります', id=2)
```
　`say`関数で発話を行うと、**発話が完了するまでプロセスは待機します。**発話が完了するまで待機するのを無効にしたい場合は、第４引数`wait`に`False`を代入してください。
 ```python
say(node, text='発話が完了するまで待機しません。', wait=False)
```
---
以下が `say` 関数のリファレンスになります。
```python
voicevox_ros2.voicevox_ros2.tts.say(node=rclpy.Node,
                                    text=str:,
                                    id=int:,
                                    wait=bool)
```
- **node**
    (Node)
    Nodeオブジェクトを代入してください。発話のために使用します。
- **text**
    (str)
    VoiceVox に発音させたいテキストを入力してください。

- **id**
    デフォルト値：```3```(int)
    VoiceVox から発音するキャラクターIDを入力してください。デフォルトキャラクターは**ずんだもん（ノーマル）**です。

- **wait**
    デフォルト値：`True` (Bool)
    VoiceVox からの発話が終了するまで待機するかどうかを設定します。True の場合は発話が完了するまでプロセスは待機します。False の場合は発話が完了するまで待機せず次のプロセスへ移行します。

　`say` 関数が実行されているとき、VoiceVox から発話されず、いかのワーニングメッセージが表示された場合、`voicevox_ros2_core` ノードが起動していないことを示しています。
```
[WARN] [1726359383.931152266] [sample]: voicevox_ros2 is not available. wait again
```

## voice_saver を使う
　voice_saver ノードを実行することで任意の場所に作成した音声ファイルを保存することができます。定型文などを作成するときなどにご活用ください。以下のようにオプション `-h` をつけるとかんたんな使用方法を表示してくれます。
```
$ ros2 run voicevox_ros2 voice_saver -h
usage: voice_saver [-h] [-t TEXT] [-i ID] [-p PATH] [-f FILE_NAME] [--speak SPEAK]

options:
  -h, --help            show this help message and exit
  -t TEXT, --text TEXT  必須引数です。発話させたいテキストを入力してください。
  -i ID, --id ID        発話させたいキャラクターIDを選択してください。デフォルトは３です。
  -p PATH, --path PATH  保存先を絶対パスで記述してください。デフォルト値はカレントディレクトリです。
  -f FILE_NAME, --file_name FILE_NAME
                        ファイル名を指定してください。デフォルト名はは output です。拡張子を書く必要はありません。
  --speak SPEAK         保存後その音声ファイルを発話させます。デフォルトは False （無効）です。
```
　カレントディレクトリに任意のテキストを発話させた音声ファイルを保存させたい場合、いかのように `-t` をつけて、その後発話させたいテキストを入力してください。
```
ros2 run voicevox_ros2 voice_saver -t こんにちは！
```
するとカレントディレクトリに `output.wav` という音声ファイルが作成されます。このとき、発話キャラクターIDはデフォルトで３になっています。発話させたいキャラを変更する場合は、`-i` を付与してキャラクター ID を入力してください。
　以下の例ではキャラクターID 2（四国めたん（ノーマル））で発話させた音声ファイルを生成させます。
```
ros2 run voicevox_ros2 voice_saver -t こんにちは！ -i 2
```
　ファイル名を変更したい場合は、`-f` で任意のファイル名に設定できます。このとき拡張子を書く必要はありません。以下の例は `metran_voice` という名前で音声ファイルを生成します。
```
ros2 run voicevox_ros2 voice_saver -t こんにちは！ -i 2 -f metan_voice
```
　`-p`を使って保存先のパスを指定することで別の場所に保存させることもできます。このとき入力するパスは **絶対パス** で書いてください。
```
ros2 run voicevox_ros2 voice_saver -t こんにちは！ -i 2 -f metan_voice -p /path/to/save/directory
```
　音声ファイル生成後、その音声をすぐに発音させたい場合は `--speak true` をつけてください。
```
ros2 run voicevox_ros2 voice_saver -t こんにちは！ --speak true
```
ファイルが生成されると、以下のようなログが表示されるので、正しいテキスト、保存場所化どうか確認してください。
```
$ ros2 run voicevox_ros2 voice_saver -t こんにちは！
[INFO] [1708781094.555798150] [voicevox_ros2_core]: start voicevox_ros2 
[INFO] [1708781094.591227469] [voicevox_ros2_core]: Voice Saver info ...
TEXT: こんにちは！
VOICE ID: 3
SAVE FOR: /colcon_ws/output.wav
            
[INFO] [1708781095.238171811] [voicevox_ros2_core]: GENERATE voice
[INFO] [1708781095.257825423] [voicevox_ros2_core]: done.
```

# キャラクターID一覧
　キャラクター ID は以下の表を参考にしてください。

|キャラクター名|スタイル|ID|
|:----|:----|:----|
|四国めたん|ノーマル|2|
||あまあま|0|
||ツンツン|6|
||セクシー|4|
||ささやき|36|
||ヒソヒソ|37|
|ずんだもん|ノーマル|3|
||あまあま|1|
||ツンツン|7|
||セクシー|5|
||ささやき|22|
||ヒソヒソ|38|
||ヘロヘロ|75|
||なみだめ|76|
|春日部つむぎ|ノーマル|8|
|雨晴はう|ノーマル|10|
|波音リツ|ノーマル|9|
||クイーン|65|
|玄野武宏|ノーマル|11|
||喜び|39|
||ツンギレ|40|
||悲しみ|41|
|白上虎太郎|ふつう|12|
||わーい|32|
||びくびく|33|
||おこ|34|
||びえーん|35|
|青山龍星|ノーマル|13|
||熱血|81|
||不機嫌|82|
||喜び|83|
||しっとり|84|
||かなしみ|85|
||囁き|86|
|冥鳴ひまり|ノーマル|14|
|九州そら|ノーマル|16|
||あまあま|15|
||ツンツン|18|
||セクシー|17|
||ささやき|19|
|もち子さん|ノーマル|20|
||セクシー／あん子|66|
||泣き|77|
||怒り|78|
||喜び|79|
||のんびり|80|
|剣崎雌雄|ノーマル|21|
|WhiteCUL|ノーマル|23|
||たのしい|24|
||かなしい|25|
||びえーん|26|
|後鬼|人間ver.|27|
||ぬいぐるみver.|28|
|No.7|ノーマル|29|
||アナウンス|30|
||読み聞かせ|31|
|ちび式じい|ノーマル|42|
|櫻歌ミコ|ノーマル|43|
||第二形態|44|
||ロリ|45|
|小夜/SAYO|ノーマル|46|
|ナースロボ＿タイプＴ|ノーマル|47|
||楽々|48|
||恐怖|49|
||内緒話|50|
|†聖騎士 紅桜†|ノーマル|51|
|雀松朱司|ノーマル|52|
|麒ヶ島宗麟|ノーマル|53|
|春歌ナナ|ノーマル|54|
|猫使アル|ノーマル|55|
||おちつき|56|
||うきうき|57|
|猫使ビィ|ノーマル|58|
||おちつき|59|
||人見知り|60|
|中国うさぎ|ノーマル|61|
||おどろき|62|
||こわがり|63|
||へろへろ|64|
|栗田まろん|ノーマル|67|
|あいえるたん|ノーマル|68|
|満別花丸|ノーマル|69|
||元気|70|
||ささやき|71|
||ぶりっ子|72|
||ボーイ|73|
|琴詠ニア|ノーマル|74|