マルチECUシミュレーション環境・箱庭がCANデータをROS2で可視化する！

# 概要
結論から言いますと，こういう環境が出来ました．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244147/f933acf7-aace-fc9d-6c56-619cc98f7396.png)

おそらくですが，上記のようなシミュレーション環境はオープンソースベースでは初めてではないのか？と思ったりしています．

## 理由
* オープンソースベースの AUTOSAR 実装はないと思われる
* オープンソースベースの RH850 のマイコンシミュレータはないと思われる(QEMUもやってない)
* オープンのソースベースで時間同期を含んだマルチECUシミュレーション環境はないと思われる
* さらに ROS2 でのCAN通信データのビジュアライズまでやっているのはあんまり聞かない．

## なぜこういう環境を作れたのか？
[TOPPERS](https://www.toppers.jp/index.html) と[箱庭WG](https://toppers.github.io/hakoniwa/)がこれらの要素技術をすべてそろえてくれていた．

* AUTOSAR STACK
  * [OS](https://www.toppers.jp/atk2.html#:~:text=TOPPERS%2FATK2%E3%81%A8%E3%81%AF&text=ATK2%EF%BC%88Automotive%20Kernel%20Version%202,%E3%81%97%E3%80%81%E7%84%A1%E5%84%9F%E5%85%AC%E9%96%8B%E8%87%B4%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)
  * [RTE](https://www.toppers.jp/a-rtegen.html)
  * [COMSTACK](https://www.toppers.jp/a-comstack.html)
* MCU simulator
  * [Athrill](https://www.toppers.jp/athrill.html)
* CAN Device
  * [RH850f1k/CAN Device Simulator](https://github.com/toppers/athrill-target-rh850f1x)
* Hakoniwa Core
  * [C++版箱庭コア機能](https://github.com/toppers/hakoniwa-core-cpp)
* CAN Monitor
  * [ROS2ベース箱庭CANモニタ](https://github.com/toppers/hakoniwa-ros2pdu)

# 前提環境
本環境は，Docker 上で環境構築しています．
なので，OSの要件は以下の通りです．

* OS
  * Docker が動作する OS(WSL2, Linux, Mac)


なお，本環境のベースとなる情報は以下を良記事を参照ください！

* [GitHub Codespaces でできる！ 仮想シミュレーション環境での車載アプリ](https://qiita.com/mitsu48/items/f7ca8d7d026754bb4eee)

# 利用手順

## リポジトリ取得

```
git clone -b hako --recursive https://github.com/toppers/hakoniwa-ecu-multiplay.git
```

## docker イメージを作成する

```
cd hakoniwa-ecu-multiplay/hako
```

```
bash docker/create-image.bash 
```

## 端末を 5 個起動する
マルチECU環境なので，端末をたくさん立ち上げないといけないです．．．

* 端末A：箱庭マスタ機能の起動用
* 端末B：AUTOSARベースのCAN通信サンプルアプリ起動用
* 端末C：CANデータをROS2変換するROS2ノード起動用
* 端末D：ROS2トピック観測用
* 端末E：箱庭コマンド実行用

上記端末を立ち上げたら，以下の要領で docker コンテナを起動します．

### 端末A：箱庭マスタ機能の起動用
```
bash docker/run.bash
```

### 端末B：AUTOSARベースのCAN通信サンプルアプリ起動用
```
bash docker/attach.bash
```
```
cd $HAKO_WS_CAN
```

成功すると，CANプログラムが存在するディレクトリに移動しています．

```
# pwd
/root/workspace/a-comstack/can/target/hsbrh850f1k_gcc/sample
```


### 端末C：CANデータをROS2変換するROS2ノード起動用
```
bash docker/attach.bash
```

### 端末D：ROS2トピック観測用
```
bash docker/attach.bash
```

### 端末E：箱庭コマンド実行用
```
bash docker/attach.bash
```

## マルチECUシミュレーション実行準備

## 端末A：箱庭マスタの起動

```
hako-master 1000 10000
```

成功した時のメッセージ：
```
START
INFO: shmget() key=255 size=7040 
```

## 端末B：CAN通信プログラムの起動

```
hako-proxy ./proxy_config.json
```

成功した時のメッセージ：
```
add_option:/root/athrill-target-rh850f1x/athrill/bin/linux/athrill2
add_option:-c1
add_option:-i
add_option:-d
add_option:device_config_with_can_hako.txt
add_option:-m
add_option:memory_with_hako.txt
add_option:atk2-sc1.exe
INFO: PROXY start
```

## 端末C：CANデータをROS2変換するROS2ノードを起動

```
bash run.bash can_proxy rx
```

成功した時のメッセージ：
```
START:can_proxy_rx_node
```


## 端末E：箱庭コマンド実行する
ここまでで事前準備終了です．

まずは，箱庭コマンドで，箱庭アセットが登録されているか確認しましょう．

```
# hako-cmd ls
athrill_test_node
can_proxy_rx_node
```

上記のように２個のアセットが登録されていることがわかります．

次に，箱庭のシミュレーション状態をみてみましょう．

```
# hako-cmd status
status=stopped
```

シミュレーション停止状態ですね．

ということで，シミュレーション開始しましょう．

```
# hako-cmd start
start
# hako-cmd status
status=running
```

こうすると，これまでの端末上でログが出てきますが，まだ動きません．
なぜかというと，CAN通信プログラムを実行するマイコンシミュレータAthrillがデバッグモードになっているためです．

端末Bを見てみましょう．

```
pid:127
monitring:
exec_args_count=8
the_args[0]=/root/athrill-target-rh850f1x/athrill/bin/linux/athrill2
the_args[1]=-c1
the_args[2]=-i
the_args[3]=-d
the_args[4]=device_config_with_can_hako.txt
the_args[5]=-m
the_args[6]=memory_with_hako.txt
the_args[7]=atk2-sc1.exe
core id num=1
ROM : START=0x0 SIZE=1024
RAM : START=0xfede8000 SIZE=512
DEV : START=0xffff0000 SIZE=1024
ELF SET CACHE RIGION:addr=0x0 size=57 [KB]
Elf loading was succeeded:0x0 - 0xe680 : 57.640 KB
Elf loading was succeeded:0xe680 - 0x128c4 : 0.160 KB
ELF SYMBOL SECTION LOADED:index=16
ELF SYMBOL SECTION LOADED:sym_num=602
ELF STRING TABLE SECTION LOADED:index=17
DEBUG_FUNC_HAKO_ASSET_NAME = athrill_test_node
DEBUG_FUNC_HAKO_ASSET_NAME = athrill_test_node
DEBUG_FUNC_HAKO_PUB_0 = channel0/CAN_IDE0_RTR0_DLC8_0x001/0
create_channel: id=0 size=28
DEBUG_FUNC_HAKO_SUB_0 = channel0/CAN_IDE0_RTR0_DLC8_0x123/1
DEBUG_FUNC_HAKO_SUB_1 = channel0/CAN_IDE0_RTR0_DLC8_0x122/2
DEBUG_FUNC_HAKO_SUB_2 = channel0/CAN_IDE0_RTR0_DLC8_0x003/3
DEBUG_FUNC_HAKO_SUB_3 = channel0/CAN_IDE0_RTR0_DLC8_0x004/4
DEBUG_FUNC_HAKO_ASSET_NAME = athrill_test_node
DEBUG_FUNC_FT_LOG_SIZE=1024
[DBG>
HIT break:0x0
[NEXT> pc=0x0 prc_support.S 256
```

こんな感じで，0x0番地でブレーク状態になっています．

さっそく，`c`コマンドで，Athrillのシミュレーションを開始すると，以下のように動き出します．

```
c
[CPU>
TOPPERS/ATK2-SC1 Release 1.4.2 for HSBRH850F1K (Aug 12 2022, 21:12:59)

== finished StartupHook ==
== Can_Init ==
== CanIf_ControllerModeIndication(0, 2) ==
LOADED: PDU DATA
```

CANデータ送信するログ(例)：

```
== CanIf_TxConfirmation(3) ==

[FCN0] Can_Write(3) CAN-ID:0x1
DATA[0]:0x5
DATA[1]:0x6
DATA[2]:0x7
DATA[3]:0x8
DATA[4]:0x9
DATA[5]:0xa
DATA[6]:0xb
DATA[7]:0xc

== finished SendTask ==
== CanIf_TxConfirmation(3) ==
```


## 端末D：ROS2トピック観測する

端末Dで，ROS2トピック観測する準備をします．

```
source install/setup.bash
```

この状態で，トピック一覧を見てみましょう．

```
ros2 topic list
/channel0/CAN_IDE0_RTR0_DLC8_0x1
/parameter_events
/rosout
```

`/channel0/CAN_IDE0_RTR0_DLC8_0x1` というのが，送信されているCANデータのROS2トピックになります．

では，これを見てみましょう．

```
ros2 topic echo /channel0/CAN_IDE0_RTR0_DLC8_0x1
```

こんな感じで，CAN通信データのヘッダ情報と中身のデータが見えますね！
```
head:
  channel: 0
  ide: 0
  rtr: 0
  dlc: 8
  canid: 1
body:
  data:
  - 39
  - 40
  - 41
  - 42
  - 43
  - 44
  - 45
  - 46
```

# デモ

操作イメージのデモはこんな感じです．

![multi-ecu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244147/e73db6b9-9391-8fd4-4762-b668e7aa750b.gif)


## その他
今回はCAN通信モジュールのシミュレーションしかお見せしていませんが，RTEを含めたシミュレーションも可能です．

また，本シミュレーション環境は，`GitHub Codespaces`でも体験できるようにしたいと考えておりますので，乞うご期待ください．


# お知らせ：箱庭もくもく会

TOPPERS箱庭WGでは，もくもく会を不定期に開催しています．
本記事の内容を実際に試してみたい方や試してみたけど詰まっている方は，ぜひご参加ください．画面共有しながら参加者同士でサポートしたり，一緒に新しい機能を実装したりと”もくもく”しましょう．

https://hakoniwa.connpass.com/