【ライブラリ#5】ロボットの意思決定：Behavior Tree

本記事は『[Space ROS (Robot Operating System)](https://qiita.com/advent-calendar/2024/space-ros)』アドベントカレンダーの一部として作成しました。
Space ROS Advent Calendar 2024の概要については、下記の記事をご参照ください。

https://qiita.com/advent-calendar/2024/space-ros


# はじめに：Behavior Treeとは？ロボットの意思決定？
こんにちは、私はロボットの意思決定に興味があり、関わってきたいくつかのプロジェクトで怒られない程度に組み込んでお試ししてきました。この記事では、Space ROSアドベントカレンダー活動にお誘いいただき、そのなかで試したこと、考えたことを皆さんに共有できればと思います。

Space ROSでは、ロボットの意思決定を実現するフレームワークとして[Behavior Tree(BT,行動木)](https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control))を採用しています。
既に12日の[Nav2の記事](https://qiita.com/erina_mori/items/65c137670c6ed3ab8e41)でも少し触れられていますが、本記事ではBehavior Treeについてさらに深堀して、特に宇宙ロボットでの活用方法に焦点を当てて解説します。

宇宙機器の開発において、ソフトウェアの制御ロジック（意思決定機能）には高い信頼性と柔軟性が求められます。打ち上げ後はハードウェア的なメンテナンスが困難な環境で、地上での開発中に考えうる限り多くの状況に対して適切に対応し、ミッションを遂行する必要があるためです。

特に以下のような宇宙機器開発特有の要件に対して、Behavior Treeは解決策になりえます。

<details>
<summary>通信の制約への対応・リソースの制約・フォールトトレランスとの親和性</summary>

## 通信の制約への対応
地上との通信は、ミッションによって数秒から数十分の遅延が発生する可能性があり、また通信機会自体も限られています。そのため、宇宙機器は高い自律性を持つ必要があります。Behavior Treeを用いることで、

* 状況に応じた判断ロジックを階層的に整理
* 通信断絶時の代替行動を明確に定義
* 複雑な条件分岐を見通しよく実装

することが可能になります。
特に、実装の見通しのよさは、要求されるミッションが高度化されるにつれて、複雑な機能を一つの宇宙機に詰め込まないといけない開発フェーズにおいて重要です。

## リソースの制約
宇宙機器では、計算リソースや電力リソースが地上の機器と比べて大きく制限されます。Behavior Treeは、

* 軽量な実行エンジン
* 状態管理のオーバーヘッドが小さい
* 必要なノードのみを実行する効率的な設計

という特徴により、表現力に対して限られたリソースでの動作に適しています。

## フォールトトレランスとの親和性
宇宙機器に重要な特徴であるフォールトトレランス機能と、Behavior Treeは非常に相性が良いと言えます。

* センサー異常時の代替手段への切り替え
* 機器の状態に応じた動作モードの変更
* エラーからの復帰手順の明確な定義

これらの処理を、Behavior Treeの直感的な表現力で実装できます。

</details>

以降の章では、これらの特徴を活かした具体的な実装例と、SpaceROSにおけるBehavior Treeの効果的な活用方法について解説していきます。

## 意思決定フレームワークの比較
ここでいったん立ち止まって、Behavior Treeの周辺を概観します。
上記のような要件を満たすため、宇宙機器開発にとどまらず様々な分野で様々な意思決定フレームワークが提案されてきました。以下にまとめてみた表に示すように、各アプローチにはそれぞれ特徴があり、一長一短があります。

例えばルールベース手法は、その単純さと検証のしやすさから、これまでの宇宙システムでも多く採用されてきました。しかし、ミッションの高度化に伴う状況の複雑化や、並列動作表現の難しさといった課題があります。
一方、機械学習ベースのアプローチは、複雑な状況への適応力は高いものの、動作の予測や検証が困難であり、現状では宇宙システムへの適用にはリスクが大きいと考えられています。（ESAでテスト技術の側面からそうした問題解決を目指した活動を見かけます）

<details>
<summary>意思決定フレームワーク（まだまだありそう）</summary>

| アプローチ | 動作原理・特徴 | メリット・デメリット | 宇宙システムとの相性 |
|-------|-----------------|--------------------|-------------------|
| ルールベース | IF-THEN形式のルールで動作を記述 <br> ・決定プロセスが透明で追跡可能<br>・人間が理解しやすい論理構造<br>・比較的シンプルな実装が可能 | ○直感的で実装が容易<br>○即応性が高い<br>○動作の意図が明確<br>×ルール数増加で管理困難<br>×ルール間の矛盾検出が困難<br>×並列実行の制御が複雑 | 中<br>・単純な制御に適し、実績多い<br>・不具合原因追跡がしやすい<br>・スケーラビリティに課題 |
| 有限状態機械<br>（[SMACC](https://github.com/robosoft-ai/SMACC2)など） | 状態とその遷移で動作を定義 <br> ・状態遷移図で表現<br>・階層化による詳細化<br>・定期的な状態遷移（巡回等） | ○状態と遷移が明確<br>○階層的な構造化が可能<br>○検証が容易<br>×状態数増加で複雑化<br>×並列動作の表現が困難<br>×動的な変更が困難 | 中〜高<br>・状態管理が明確<br>・複雑なタスクには不向き |
| Behavior Tree | 階層的なツリー構造でタスクを表現 <br> ・一方向非循環グラフ(DAG)<br>・ノードの定期的な再実行<br>・並列実行のサポート | ○再利用性が高い<br>○拡張性が良い<br>○バグが少ない<br>○状態の可視化が容易<br>×学習コストが高い<br>×シンプルな動作でも記述量多め | 高<br>・動作検証が容易<br>・異常時対応が明確 |
| プランニング<br>（最適化、PDDL Plannerなど） | 目標状態から行動を自動生成 <br> ・目標と行動生成の2フェーズ<br>・階層的なゴール分解<br>・コスト考慮<br>・部品の再利用 | ○高度な行動生成<br>○目的指向の動作記述<br>○形式的な検証が可能<br>×計算コストが高い<br>×実行時の柔軟性に欠ける<br>×不確実性への対応が困難 | 中<br>・計画性のある動作に適する<br>・リソース制約に注意 |
| 機械学習ベース<br>（ニューラルネットワーク・強化学習等） | データから行動規則を学習 <br> ・行動価値の学習<br>・経験からの方策獲得 | ○複雑な状況への適応<br>○センサー情報の直接活用<br>○経験からの学習が可能<br>×学習データの確保が困難<br>×動作の予測・検証が困難<br>×説明可能性に課題 | 低<br>・予測不可能な動作のリスク<br>・認証プロセスが困難 |
| ベイジアンネットワーク | 確率的な因果関係に基づく推論 <br> ・確率的なグラフモデル<br>・条件付き確率による推論<br>・不確実性の定量化 | ○不確実性の明示的な扱い<br>○事前知識の活用が容易<br>○解釈性が高い<br>×確率モデルの構築が困難<br>×計算コストが高い<br>×動的な状況への対応が困難 | 低〜中<br>・静的な判断には有用<br>・実時間性に課題 |
</details>

# Behavior Treeの概要
Behavior Treeは、階層的なツリー構造でロボットの振る舞いを記述する設計パターンです。
根元のルートノードから評価が開始され、定期的(Tick毎)にツリーを先端に向かって評価することで、状況に応じた適切な行動を選択します。

基本的なノードの種類は以下の通りです：

* ルートノード：毎回の実行評価のスタート地点
* アクションノード：ツリーの先端に位置し実際の動作を実行。Leaf nodeとも（例：「前進する」「アームを動かす」）
* 条件ノード: ツリーの中間にあり、状態を評価（例：「ゴールに到着したか」「バッテリー残量は十分か」）
* 制御ノード: ツリーの中間にあり子ノードの実行順序を制御

この記事で必須の説明としてはこのくらいでしょうか。
より詳細な情報は、BehaviorTree.CPPの公式ドキュメントなどを参照してください。

https://www.behaviortree.dev/

https://www.sciencedirect.com/science/article/pii/S0921889022000513


# Space ROSでのBehavior Tree
Space ROS上では、ROS2環境と同じく任意のBehavior Treeのシステムを展開できます。参考として[公式リポジトリ](https://github.com/space-ros/docker)を見ると、Navigation2のDockerイメージに、[BehaviorTree.CPP](https://www.behaviortree.dev/)のバージョン『3.8.7』が採用されています。(⇔参考までに2024/12時点のBehaviorTree.CPP最新バージョンは4.6です)

## Navigation2での役割

## 環境構築手順

ここでは、環境構築手順について説明します。
個人的な好みとGUIを簡単に使いたかったので、WSL2(+WSLg)+Dockerで構築しました。
WSL2でUbuntu 22.04のイメージを用意し、そちらにDockerをインストールします。
DockerHubで公開されている[osrf/space-rosイメージ](https://hub.docker.com/r/osrf/space-ros)をベースにNavigation2イメージをビルドし、Behavior Treeで試行錯誤できる環境を用意します。

<details>
<summary>具体的な手順</summary>

まずは、Navigation2のイメージをビルドします
```bash
# 起動したWSL内で
$ cd
$ git clone https://github.com/space-ros/docker.git spaceros-docker
$ cd ~/spaceros-docker/navigation2
$ docker build -t osrf/space-ros:latest \
    --build-arg VCS_REF="" \
    --build-arg VERSION="preview" \
    --build-arg SPACE_ROS_IMAGE="osrf/space-ros:latest" \
    .
```

次に、WSLgを使用できるようなコンテナを作成します
```bash
$ docker run -it --name bt_test \
    --mount type=bind,source=/tmp/.X11-unix,target=/tmp/.X11-unix \
    --mount type=bind,source=/mnt/wslg,target=/mnt/wslg \
    --env DISPLAY=${DISPLAY} --env WAYLAND_DISPLAY=${WAYLAND_DISPLAY} \
    --env XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR} \
    osrf/space_nav2
```

Space ROSの実行用に、タブ機能のあるターミナルエミュレータなどを入れると良いかもしれません
```bash
# コンテナのなかで
$ sudo apt install terminator
```

</details>


## 可視化ツールGroot (1 or 2)
BehaviorTreeには、Grootという可視化ツールが公開されています。
こちらは、GUIでノードを繋げながらのTreeの構築や、Behavior Tree実行中の可視化といった機能が提供されています。
現在は、Behavior Tree4シリーズに対応したGroot2が公式のバージョンですが、実行中の可視化などは有料版向け機能となっています。
Space ROSで標準的に使われているBehavior Treeは3系統なのでGroot1でしばらく問題はないと思います。

<details>
<summary>Grootのインストール方法</sumamry>

```shell
$ sudo apt install qtbase5-dev libqt5svg5-dev libzmq3-dev libdw-dev
$ git clone --recurse-submodules https://github.com/BehaviorTree/Groot.git
$ cd Groot
$ cmake -S . -B build
$ cmake --build build
```
</details>

# 宇宙ロボット向け実装例：通信遅延対応
ここでは、宇宙ロボットへのBehavior Treeの適用例として通信遅延がある環境のロボットを題材にして、意思決定機能を作ってみます。

宇宙ロボットが直面する最も大きな課題の一つが通信の問題です。月面では約1.3秒、火星では軌道位置次第で最短でも3分以上の片道遅延が発生します。また、この遅延時間はどの中継衛星、アンテナを使うかなどの通信環境によって大きく変動することがあります。（そのため高度400kmしかない国際宇宙ステーションでも2-3秒程度は遅れるそうです）
さらに、地形による遮蔽や通信機器の故障、周回衛星の位置関係による定期的な通信断など、完全な通信途絶が発生することも珍しくありません。これに加えて通信帯域も限られているため、データの送受信には常に優先順位付けが必要となります。
このような通信環境下では、地上からの直接制御（狭い意味での遠隔操作）は現実的ではなく、ロボット自身がある程度の自律性を持つ必要があります。

## Behavior Treeによる解決アプローチ
Behavior Treeを用いることで、通信状態に応じた柔軟な動作制御を実現できます。

基本的な考え方は、通信状態に応じて実行可能な動作のレベルを変更することです。例えば、通信が正常な場合は地上からの直接指示も実行可能とし、遅延が大きい場合は地上承認が必要な動作は保留、通信が途絶した場合は安全確保動作のみを実行する、といった具合です。
この動作の切り替えは、Behavior Treeの階層構造を活用することで自然に実装できます。通信状態の監視を上位ノードで行い、その結果に応じて適切なサブツリーを選択する形です。これにより、状態変化に応じた動作の切り替えが明確かつ確実に行えます。


## 実装例と動作デモ
実装例をこちらに置かせていただきます。

https://github.com/AkihikoHONDA/spaceros-bt-eg-comdelay

この実装では、通信状態に応じた動作の切り替えと、地上からの応答待ち処理を実現しています。特に重要なポイントは以下の3つです：

* 通信状態の常時監視と状態に応じた適切な動作の選択
* 地上からの応答待ちにタイムアウトを設定し、応答がない場合は安全な状態に移行
* 非同期処理による通信待ちの実装で、システムの応答性を確保

実装されたBehavior Treeは、通信異常時には自動的に安全確保動作を実行し、通信が復旧すれば通常動作に戻ります。これにより、通信状態が変化する環境下でも、ロボットは常に適切な動作を選択できます。
実際の運用では、このベースコードにミッション固有の要件や制約を追加実装することになります。また、様々な通信状態を想定したテストと検証が重要です。特に、通信途絶からの復帰時の動作や、部分的な通信障害への対応など、エッジケースについても十分な考慮が必要となります。

# おわりに（今後について）
最後に、Behavior Treeを使ってみての感想と、今後やってみたいことを書きます。
「やってみたいこと」については、もし先例をご存じでしたらコメントで教えていただけると嬉しいです。一緒にやろう！というのも大歓迎です！！

### 設計・実装のベストプラクティス

Behavior Treeを宇宙ロボットの意思決定システムとして活用する際、これまでのプロジェクト開発経験および今回お試ししてみた経験から得られた設計指針があります。
まず、ツリーの構造化について、上位ノードでは全体の状態管理や安全確保を行い、下位ノードで具体的なタスクを実行するという階層化を意識します。これにより、異常検知と対応がシステム全体で確実に行えます。また、よく使用される動作パターンはサブツリーとして切り出し、再利用可能なコンポーネントとして管理することで、開発効率と信頼性の両方を高められます。
テスト容易性の観点では、各ノードができるだけ単一の責任を持つように設計することが重要です。例えば、「センサーデータの取得」と「判断」と「動作」は別々のノードに分割することで、ユニットテストが書きやすくなり、動作の検証も容易になります。

### 現状の課題と対応アプローチ

現在のBehavior Tree実装における主な課題は、実行時の動的な変更への対応です。宇宙ロボットのミッションでは、予期せぬ状況に応じてタスクの優先順位や実行方法を変更する必要が生じることがあります。この課題に対しては、パラメータのランタイム調整やサブツリーの動的な切り替えなどの機能を活用できますが、そのような変更の安全性を保証する方法については、まだまだ研究の余地がありそうです。
もう一つの課題は、複数のロボットが協調して動作する場合の意思決定の実装です。例えば、月面での建設作業や探査活動では、複数のロボットが協力して作業を行う必要があります。自律分散制御の方もかじっていたことがありますが、Behavior Treeをそのような分散システムでどのように活用するか（できるのか）、特に通信遅延や途絶がある環境での協調動作の実現方法は、今後の重要な研究テーマとなっていくんじゃないかと思います。

### 今後やってみたいこと

Space ROSにおけるBehavior Treeの活用は、まだ始まったばかりです。今後、以下のような方向で貢献できればと考えています。

形式検証（Formal Verification、数学的な手法を用いてソフトウェアやシステムが仕様を満たしていることを厳密に証明する技術）との統合は特に達成させたい展望の一つです。Behavior Treeの構造は、人間の意思と数学的な形式の中間として落とし込んでいて形式的な検証に適しており、特定の条件下で望ましくない状態に陥らないことを数学的に証明できる可能性があると思っています。これは、宇宙機器に求められる高い信頼性要件を満たす上で、大きな価値を持ちます。
Fail Safe, Fault Tolerantといった代表的な信頼性確保の形式への適合はわりとすぐできそうです。

機械学習や最適化手法との組み合わせも興味深い方向性です。例えば、基本的な動作制御はBehavior Treeで記述しつつ、特定のノードの内部で学習型のアルゴリズムを活用するといったアプローチが考えられます。これにより、システムの予測可能性と柔軟性の両立が期待できます。人間でもお買い物の計画は論理的に計画して、商品を引っ張り出すのは感覚的にやっているので、そういった構成は筋が良さそうです。
また、究極的にはツリーの構築は、スタートとゴール、そして取りうる行動を与えられたら自動的に行えるようになるべきだと考えています。[フレーム問題](https://ja.wikipedia.org/wiki/%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E5%95%8F%E9%A1%8C)にもなにか回答を出したいです。


さらに、地上での開発・検証ツールの充実も重要です。現在のGrootのような視覚的な開発ツールに加えて、通信遅延シミュレータとの連携や、動作検証のための自動テスト生成など、開発効率と信頼性を高めるためのツール整備が進むことで、より多くの開発者がSpace ROSとBehavior Treeを活用できる未来を期待しています。

このように、Space ROSにおけるBehavior Treeには、単なる意思決定のフレームワークを超えて、宇宙ロボットの自律性と信頼性を両立させるための重要な基盤技術として、さらなる発展を期待しています。