# 秋キャンプ2023:レスキュー講習会
[TOC]
## 本日の内容
自分が受けたい方を選択していただく形になります.
- 司令所の活用方法
- 本資料で進めていきます
- 本資料をもとにコンペティションに向けたエージェントを開発していただきます
- RoboCupRescue Simulation (RRS)チュートリアル
- RRSについて知らない方,初めて触る方はこちらを選択することをおすすめします
- [AIT-Rescue]鈴木宏哉,[AIT-Rescue]松永一希の指示に従って,以下の資料を進めてください
- [チュートリアル資料](https://hackmd.io/@wWdqdK0ATVazMbKfXtZHJQ/SkS0xOQQp)
時間が余った場合は,コンペティションへ向けたエージェント開発をおこなってもらう時間としたいと思います.
また,日頃のRRSに関する悩みやエージェント開発の相談など[AIT-Rescue]のメンバーが聞きますので,ありましたら声を掛けてください.
## 導入
RoboCupのRRSでは現在自立分散型の救助活動が主流となっています.
しかし,RRSでは本来司令所による集中制御が可能です.また,分散エージェントに対して司令所は以下のような優位点があります.
- 機能停止することがない
- シナリオによっては受信可能な通信チャネル数が多い
- 救急司令所のみ,避難所の最新情報を常に取得できる
そこで,この講習会では司令所に着目して進めることにしました.
講習会を通して,参加者が司令所を利用したエージェントを開発できるようになってもらいます.
## 司令所による集中制御の流れ
司令所による集中制御の流れは以下になっています.

司令所による集中制御を実装するには以下のモジュールが必要となります.
| モジュール名 | 役割 |
| ---- | ---- |
| TargetAllocator | 司令所が使用するモジュールである.分散エージェントへの司令内容を算出・決定する
| CommandPicker | 司令所が使用するモジュールである.TargetAllocatorが算出した司令内容から,司令(メッセージ)を生成する |
| CommandExecutor | 分散エージェントが使用するモジュールである.自分宛ての司令メッセージを受信した場合,その司令を実行する |
| ChannelSubscriber | 全エージェントが使用するモジュールである.エージェントがメッセージを受信可能とする通信チャネルを選択する |
| MessageCoordinator | 全エージェントが使用するモジュールである.送信予定のメッセージを各通信チャネルに振り分ける|
上の図のようなRRSにおける集中制御の流れは以下のようになります.
1. 分散エージェントは司令所へ自身の情報や,自身が知覚した道路や建物,市民の情報を送信する.この処理はDefaultTacticsから直接参照されるMessageToolに記述されている.
2. 司令所は受信した情報をもとに,エージェントに対するタスクの割当を計算する.この処理はTargetAllocatorに記述されている.
3. 司令所はTargetAllocatorで計算したタスク割当結果をもとに,分散エージェントに対して司令メッセージを送信する.この処理はCommandPickerに記述されている.
4. 分散エージェントは司令所から受信した司令メッセージをもとに,救助活動を実行する.この処理はCommandExecutorに記述されている.
## メッセージと通信
RRSの通信の説明は別のページで説明しますのでこちらの[リンク](https://hackmd.io/@wWdqdK0ATVazMbKfXtZHJQ/B13qOr7Qp)へ遷移してください.
## 各モジュールについての説明
ここでは司令所を使用するときに用いられるモジュールの説明をします.
以下の"○○"には,Fire,Ambulanceのどちらかが入ります.
### ○○TargetAllocator
TargetAllocatorは司令所が使用するモジュールです.司令内容として分散エージェントと割り当てるタスクを算出します.各メソッドの役割を以下に示します.
| メソッド | 役割 |
| ---- | ---- |
| ○○TargetAllocator **updateInfo**(<br>MessageManager) | 新しく受信したメッセージから情報を取得するためのメソッド<br>基本的にこのメソッドで分散エージェントから受信した市民,建物,エージェントの情報を取得する |
| ○○TargetAllocator **calc**() | 分散エージェントへの司令内容を算出するためのメソッド<br>基本的にここで分散エージェントのタスクの割り当てを決定する<br>○○の箇所は消防隊のTargetAllocatorならFire,救急隊のTargetAllocatorならAmbulanceになる |
| Map<EntityID, EntityID> **getResult** | calcメソッドで算出した司令内容を返すためのメソッド<br>返される司令内容はMap<EntityID, EntityID>でなければならない<br>基本的にはkeyが命令対象のエージェントのIDでvalueがやるべきタスク(市民,建物,エリア等)のID |
紹介したメソッドは以下の順で自動に実行されます.
1. updateInfo
2. calc
3. getResult
### CommandPicker○○
CommandPickerは司令所が使用するモジュールです.TargetAllocatorが算出した司令内容から,分散エージェントへの司令メッセージを生成します.
各メソッドの役割を以下に説明します.
| メソッド | 役割 |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| CommandPicker **setAllocatorResult**(Map<EntityID, EntityID>) | TargetAllocatorの計算結果を入力するためのメソッド|
| CommandPicker **calc**() | 司令を生成・リスト化するためのメソッド<br>司令はTargetAllocatorから受け取った司令内容をもとに生成される |
| Collection<CommunicationMessage> **getResult**() | calcメソッドで生成した司令リストを取得するためのメソッド<br>このメソッドは自動で実行され,返した司令リストが送信される |
紹介したメソッドはTargetAllocatorのメソッド実行後に以下の順で自動に実行されます.
1. setAllocatorResult
2. calc
3. getResult
### CommandExecutor○○
CommandExecutorは分散エージェントが使用するモジュールです.自分宛ての司令メッセージを受信した場合,その司令をもとに行動を決定します.
| メソッド名 | 役割 |
| ---- | ---- |
| CommandExecutor **setCommand**(Command○○ command) | 受信した司令を入力するためのメソッド |
| CommandExecutor **calc**() | 受け取った司令を元に行動を決定・実行するためのメソッド |
紹介したメソッドは以下の順で自動に実行されます.
1. setCommand
2. calc
また,CommandExecutorでエージェントの行動が決定できなかった(null)場合,Detectorが実行されます.Detectorで救助対象を決定できなかった(null)場合はSeachで探索対象をを決定します.
## 集中制御の実装例
### エージェントのダウンロード
RRSにおける集中制御の実装例として司令所にハンガリアンアルゴリズムを適用したサンプルエージェントの紹介させていただきます.以下のコマンドを実行して,エージェントをダウンロードしましょう.
```shell
cd WORKING_DIR
curl -LO https://maslab.aitech.ac.jp/~omni0348/autumn_agent_2023.zip
unzip autumn_agent_2023.zip
```
:::info
**NOTE:** Hungarianアルゴリズム: 任意のn対nの行列において,行と列が被らないかつ値の総和が最小となるような1対1の組み合わせを決定することができます.n体のエージェントとn個のタスクで1対1の割り当てを決定できます.
:::
ハンガリアンアルゴリズムを司令所に実装したサンプルエージェントは,以下のように動作します.

消防隊は自分の情報・埋没市民の情報を,救急隊は埋没市民の情報をそれぞれ消防司令所に送信します.
情報を受け取った消防司令所は,受け取った情報からコストの行列を生成しハンガリアンアルゴリズムを実行します.ここでのコストは消防隊と埋没市民の間の距離になります.
そしてハンガリアンアルゴリズムで割当を決定した後,消防隊へ救助司令を各消防隊に出します.司令所から救助司令を受け取った消防隊は司令に沿って市民の救助を開始します.
また,消防隊は市民の掘り起こしが終わった後,消防司令所へ救助完了の報告を送ります.
### プログラムの概要
使用しているモジュールは`autumn_agent_2023/src/main/java/autumn_2023`の中にあります.
#### 情報の送信
サンプルエージェントでは,消防隊と救急隊が情報を送信します.
消防隊は自分の情報と知覚した埋没市民の情報を送信し,救急隊は知覚した埋没市民の情報を送信します.
消防隊と救急隊の埋没市民の情報の送信はそれぞれ`autumn_2023/module/complex/CentralizedControlFBHumanDetector`と`autumn_2023/module/complex/CentralizedControlATHumanDetector`の`updateInfoメソッド`に記述されています.
行数は消防隊が71--84行目で救急隊が65--78行目です.
```java
// 今のステップで知覚した情報を取得
Set<EntityID> changes = this.worldInfo.getChanged().getChangedEntities();
for(EntityID id : changes){
StandardEntity entity = this.worldInfo.getEntity(id);
if(!(entity instanceof Civilian)) continue;// 市民の情報でないなら無視
Civilian civ = (Civilian) entity;
if(!this.isNeedRescueHuman(civ)){// 知覚した市民が救助すべきなら
continue;
}
StandardMessagePriority level = StandardMessagePriority.NORMAL;
// 市民に関するメッセージを生成
MessageCivilian civ_mes = new MessageCivilian(true, level, civ);
messageManager.addMessage(civ_mes,true);// 送信予定メッセージリストに追加
}
```
消防隊の自身の情報の送信はTacticsの方で自動でおこなうので記述していません.
また,消防司令所は消防隊と救急隊からのメッセージを取得します.取得処理は
`autumn_2023/centralized/CentralizedControlFBAllocator.java`の`updateInfo`の
183--204行目にあります.
```java
Set<EntityID> recievetasks = messageManager.getReceivedMessageList(MessageCivilian.class).stream()
.map(e -> {
MessageCivilian mesciv = (MessageCivilian) e;
MessageUtil.reflectMessage(this.worldInfo, mesciv);
return(mesciv);
})
.map(MessageCivilian::getAgentID)
.filter(e -> this.isNeedRescueHuman(this.worldInfo.getEntity(e)))
.filter(e -> !(finishEntityIDs.contains(e)))
.collect(Collectors.toSet());
this.taskSet.addAll(recievetasks);
List<CommunicationMessage> mesfblist = messageManager.getReceivedMessageList(MessageFireBrigade.class);
for(CommunicationMessage mes : mesfblist){
MessageFireBrigade mesfb = (MessageFireBrigade) mes;
MessageUtil.reflectMessage(this.worldInfo, mesfb);
EntityID fbID = mesfb.getAgentID();
FireBrigadeInfo fbi = this.fireBrigadeInfoMap.get(fbID);
fbi.setInfo(mesfb.getTargetID(), mesfb.getPosition(), mesfb.getBuriedness(),
(mesfb.getAction() == MessageFireBrigade.ACTION_RESCUE) ? false : true, this.agentInfo.getTime());
}
```
#### 司令の計算
サンプルエージェントでは,消防司令所がハンガリアンアルゴリズム実行し消防隊に割り当てるタスクを決定します.
ハンガリアンアルゴリズムは`autumn_2023/centralized/CentralizedControlFBAllocator.java`のcalcメソッドで実行されます.
#### 司令の発令
サンプルエージェントでは,`autumn_2023.centralized/CentralizedControlCommandPickerFire.java`で消防司令所が司令を生成します.重要な行は65--68行目になります.
```java
if (target instanceof Human) {// 司令内容のタスクがHumanなら
CommandFire command = new CommandFire(true, agentID, target.getID(), CommandFire.ACTION_AUTONOMY);// 司令を生成
this.messages.add(command);
}
```
#### 司令による行動
サンプルエージェントでは,`autumn_2023.centralized/CentralizedControlCommandExecutorFire.java`で消防隊が司令を実行します.重要な行は200--210行目になります.
```java
switch (this.commandType) {
…
case ACTION_AUTONOMY:
if (this.target == null) {
return this;
}
StandardEntity targetEntity = this.worldInfo.getEntity(this.target);
if (targetEntity instanceof Area) {
this.result = this.actionExtMove.setTarget(this.target).calc().getAction();
} else if (targetEntity instanceof Human) {
this.result = this.actionFireRescue.setTarget(this.target).calc().getAction();
}
}
```
### 集中制御で注意すべき点
集中制御で注意すべき点は主に二つ挙げられます.
- 1stepに送れるメッセージ量の上限
- 計算時間
1stepに送信できるメッセージ量の上限はチャンネルごとに決まっていて,司令所に送るメッセージや司令所が送る司令が多くなりすぎると,1stepに送信できるメッセージ量の上限を超えてしまいます.
それによって,司令所で適切な割当を決定できなくなったり,司令所が送る司令がエージェントに届かなくなったりします.
サンプルエージェントもエージェント数が多いシナリオだとこの問題は発生し,司令所で適切な割り当てを決定できなくなります.
また,1stepにかけられる計算時間にも上限があり,司令所で計算が長引くと司令を出すことができません.
サンプルエージェントでは消防隊やタスクの情報が多すぎると司令所で時間内に割り当てを決めることができない場合があります.
## 実際のシナリオで集中制御をするための工夫
集中制御を実現する上でいくつか工夫できると考えられていることがあるため紹介します.
### 1つのメッセージサイズの削減
RRSでは送信するメッセージを無限に送ることはできません.そのため,1回に送信するメッセージの容量を削減することで多くの種類のメッセージを送信できるようになります.これを実現するには新たにメッセージクラスを作成する必要があります.メッセージクラスの作り方は以下のリンクを参照して下さい.
上記の方法を用いた1つのアプローチとして必要な情報が少ないアルゴリズムを紹介します.
[メッセージクラスの作り方](https://hackmd.io/@wWdqdK0ATVazMbKfXtZHJQ/ByjJtrQmT)
### 必要な情報が少ないアルゴリズム
今回は必要な情報が少ないアルゴリズムの一例としてオークションアルゴリズムを紹介します.このアルゴリズムは名前の通りオークションを基に作られたもので,RRSにおけるオークションアルゴリズムでは司令所が出品者,エージェントが入札者として振る舞います.入札者はタスクに関するコストを送信し,出品者は受信したコストのうち,一番コストが軽いものを選択します.
### 集中制御と分散制御の両立
#### 目的と概要
無線通信の通信量削減を目的とし,司令所と通信する分散エージェントを限定します.そのために分散エージェントには救助グループを形成させます.基本的には救助グループ内で音声通信を用いた協調をおこない,必要な場合にのみ救助グループのリーダと司令所が無線通信を用いて集中制御をおこないます.
#### 処理の流れ
救助グループはタスクを発見した場合,可能ならばグループ内で対処します.グループ内で対処できない場合,グループのリーダが司令所へそのタスクの情報を送信します.司令所は受信したタスクを別の救助グループのリーダへ送信します.タスクを受信したリーダは,自身のグループでそのタスクに対処します.
#### グループの形態
救助グループの形態には同種エージェントのみによるものと異種エージェントを含めるものの2種類が考えられます.前者と比較して後者はより無線通信の通信量削減が期待できると考えられます.これは一連の救助活動をグループ内で完結できるためです.
異種エージェントを含めた形態を考える場合には,グループ内のエージェント数のバランスに注意する必要があります.例えば,消防隊と救急隊によるグループで救出から搬送までさせる場合,消防隊と比較して救急隊は少数で済みます.
#### グループの形成方法
救助グループの形成方法は静的なものと動的なものの2種類が考えられます.前者は事前に形が定義され,シミュレーションを通じて不変です.例えば分散エージェントの初期配置などから形成されます.
後者はシミュレーション実行中に形成や変形,解散します.例えばグループ対象とするタスクの実行にかかるコストの大小によって,グループの大きさを変化させます.
## コンペティション
### 概要
今回の秋キャンプでは司令所に着目したコンペティションをおこないます.使用するシナリオで登場する救助隊は消防隊と救急隊です.また,市民や救助隊の位置,避難所の病床数が異なる複数のシナリオを用意し,有効な司令所の活用方法を模索します.
### ルール
- 救助隊は消防隊と救急隊のみ
- 対象のタスクは倒壊した建物内に存在する埋没した市民
- 各シナリオに消防司令所と救急司令所は1つずつ存在する
- 今回のシナリオでは通信にノイズが発生しないものとする
### 使用するエージェント
講習会で配布したエージェントをもとに開発してもらいます.
<!--
### シナリオについて
今回使用するシナリオは6つあるのですが,似たような特徴を持つマップを2つずつ作成したため,作成したものの一部を作成した意図とともに下図で示します.

病床数は上の避難所から順に100,10,20となっています.
このマップでは病床数が多い避難所が端にあり,中央付近にある避難所は病床数が少なく設定されています.そのため,**司令所が救助した市民をどの避難所へ搬送するか命令することが重要になると考えています.**

このマップでは救急隊エージェントの半数が埋没した状態で始まります.
そのため,**消防隊はエージェントを救出するか,市民を救出するかを選択する必要があります.**

このマップは市民が右下に集中するように配置しました.
その一方救助エージェントは離散的に配置されているため,**エージェント間で情報を共有してタスクをどうおこなうかが重要になると考えています.**
-->
### 最後に
今回のコンペティションでは以下のモジュールを開発することを想定しています.
- 救急隊・消防隊
- TargetAllocator
- CommandPicker
- CommandExecutor
- Detector
- 通信系
- ChannelSubscriberr
- ChannelCordinator
- 新規メッセージクラス
配布されたサンプルや今回の資料を参考にしながらエージェント開発を進めてください.また,RRSの情報をまとめたページがありますのでこちらも参考にしてください.
- [開発するとき知っておきたいRRS仕様など](https://hackmd.io/@wWdqdK0ATVazMbKfXtZHJQ/B13qOr7Qp)
- [エージェントが取得できる情報まとめ](https://hackmd.io/@wWdqdK0ATVazMbKfXtZHJQ/ByZdl_7XT)
- [メッセージクラスの作り方](https://maslab.aitech.ac.jp/codimd/mM_mxWINRTSS4Qlw7RCsxg?view)
エージェントの提出期限:11/11(土)23:59まで
エージェントの提出場所:SlackのDMで[AIT-Rescue]前田か[AIT-Rescue]鈴木涼介まで
### 結果
[Result](https://docs.google.com/spreadsheets/d/1nbICupEOaQxqfIeoQAdMc6SWDCtX7x_tNoSPYEgTvV8/edit#gid=484429253)
今回コンペティションで用いられたシナリオについては以下のリンクから確認してください.
[作成したシナリオとそれぞれのシナリオにおける意図](https://hackmd.io/FhXZSTrLRiWGJSXxkwDU1w)