EV3で実現した電車と信号を、Unityとマイコンシミュレーションを連携させて動かせるようにしました。
前提とする環境
現時点では、以下の環境を想定しております。
Unity
- Unity Hub
- Unity Hub 3.4.1
- Unity
- Unity 2021.3.7f1
- Blender
- Blender v2.9.3以降
なお、Unityおよび Unity Hub, Blender はインストールされていることを前提として解説します。
Windows 環境
- Windows10 Home, Windows 11
- WSL2/WSLg/Ubuntu20.0.4
- WSL2/Docker Engine
- VSCode
- マイコンの制御プログラムの編集/ビルド用に使います。
事前準備
Windows版では、WSL2を利用しますので、事前にインストールをお願いします。
また、インストール完了後、端末上で以下のコマンドを実行して、ネットワークツール(routeやifconfigコマンド)をインストールしてください。
sudo apt install net-tools
また、事前にUnityおよび Blender のインストールもお願いします!
さらに、Unityプロジェクトを開く際に Windows の Git がインストールされている必要があります。Windows用のGitがインストールされていない方は、こちらの記事を参考にして、インストールおよび環境変数のセットアップをお願いします。
なお、環境変数設定後は、パソコンの再起動が必要となります。
インストール手順
本環境を利用するための最初の一歩は、hakoniwa-unity-ev3modelをクローンすることです。
git clone --recursive https://github.com/toppers/hakoniwa-unity-ev3model.git
※注意:クローンする場所は、WSL2内のディレクトリではなく、/mnt/c
の配下に任意のディレクトリを作成して、クローンしてください
マイコンシミュレーション環境のインストール
マイコンシミュレーション環境はは、docker コンテナ上で実行しますので、以下の手順でイメージを作成します。
- 補足
- Windows版では、
Docker Desktop for Windows
は利用しません。WSL2上のUbuntu環境に Docker Engine をインストールしたものを利用しますので、事前にご準備ください。インストール手順は、こちらです。
- Windows版では、
作業するディレクトリは、hakoniwa-unity-ev3model/hakoniwa-base
直下です。
cd hakoniwa-unity-ev3model/hakoniwa-base
次に、docker イメージを取得します。
最初に docker を起動します。
sudo service docker start
そして、マイコン上で動作するプログラムのビルド用の環境の docker イメージを取得しましょう。
bash docker/template/make_dockerfile.bash dev ev3rt
bash docker/pull-image.bash dev
なお、上記コマンドを実行すると、以下のようなエラーが発生する場合があります。
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/create?fromImage=toppersjp%2Fhakoniwa-ai-runtime&tag=v1.1.0": dial unix /var/run/docker.sock: connect: permission denied
この場合は、/var/run/docker.sock
にアクセス権限を与えてください。
例:
sudo chown tmori /var/run/docker.sock
成功するとこうなります。
v1.0.0: Pulling from toppersjp/hakoniwa-single_robot-dev
:
Digest: sha256:67590dbad91aa5c6829aa4d10d78ace140afe7087b15e333421cff13d4983250
Status: Image is up to date for toppersjp/hakoniwa-single_robot-dev:v1.0.0
docker.io/toppersjp/hakoniwa-single_robot-dev:v1.0.0
次に、マイコンシミュレーション環境の docker イメージを取得しましょう。
bash docker/template/make_dockerfile.bash runtime single_robot
bash docker/pull-image.bash runtime
成功するとこうなります。
v1.0.0: Pulling from toppersjp/hakoniwa-single_robot-runtime
:
Digest: sha256:9d4cc7156174e78b3592d2bdbe59be359ac39d34121063065c9e002ac02e3a5e
Status: Image is up to date for toppersjp/hakoniwa-single_robot-runtime:v1.0.0
docker.io/toppersjp/hakoniwa-single_robot-runtime:v1.0.0
最後に、hakoniwa-unity-ev3model/hakoniwa-base/workspace/runtime/asset_def.txt
を以下のように編集してください。
変更前:
base_practice_1:1
変更後:
block_signal:1:signal.log
train_slow_stop:1:train.log
Unity環境のセットアップ
こちらのインストール方法を参照ください。
電車モデルのシーン表示
Unityエディタ起動後、プロジェクトビューの Scenes/TraninModel/Hakoniwa
をダブルクリックしてください。
このまま、Window/Hakoniwa/Generate
をクリックしましょう。
Unity側のセットアップはこれで終わりです。
マイコンシ制御プログラムの場所とビルド方法
マイコン制御プログラムの場所
プログラムの場所は以下になります。ロボット毎にディレクトリが切られています。
マイコン用のプログラムなので、C言語で書かれており、EV3RTというプラットフォーム上で制御プログラムは動作する前提となります。
- 電車モデルの制御プログラム
- hakoniwa-unity-ev3model/hakoniwa-base/workspace/dev/src/train_slow_stop
- 信号モデルの制御プログラム
- hakoniwa-unity-ev3model/hakoniwa-base/workspace/dev/src/block_signal
マイコン制御プログラムのビルド方法
電車モデルの制御プログラムのビルド方法
bash docker/build.bash train_slow_stop
信号モデルの制御プログラムのビルド方法
bash docker/build.bash block_signal
シミュレーション実行方法
まず、以下のコマンドを起動しましょう。
bash docker/run.bash runtime
成功するとこうなります。
INFO: ACTIVATING HAKO-MASTER
INFO: ACTIVATING ASSET-PROXY
OPEN RECIEVER UDP PORT=172.25.195.216:54001
OPEN SENDER UDP PORT=172.25.195.216:54002
delta_msec = 20
max_delay_msec = 100
INFO: shmget() key=255 size=80768
Server Start: 172.25.195.216:50051
INFO: START block_signal-1
INFO: START train_slow_stop-1
INFO: SIMULATION READY!
次に、Unityのシミュレーション開始ボタンを押下します。
成功すると、こうなります。
さらに、先ほど実行したコマンド側はこうなります。
subscribe_pdu_channel: Got a request: Request { metadata: MetadataMap { headers: {"te": "trailers", "content-type": "application/grpc", "user-agent": "grpc-csharp/2.37.0-dev grpc-c/15.0.0 (windows; chttp2)", "grpc-accept-encoding": "identity,deflate,gzip", "accept-encoding": "identity,gzip"} }, message: SubscribePduChannelRequest { asset_name: "UnityAsset", channel_id: 0, pdu_size: 196, listen_udp_ip_port: "172.25.192.1:54003", method_type: "UDP", robo_name: "EV3TrainModel" }, extensions: Extensions }
create_asset_sub_pdu
create_pdu_channel: Got a request: Request { metadata: MetadataMap { headers: {"te": "trailers", "content-type": "application/grpc", "user-agent": "grpc-csharp/2.37.0-dev grpc-c/15.0.0 (windows; chttp2)", "grpc-accept-encoding": "identity,deflate,gzip", "accept-encoding": "identity,gzip"} }, message: CreatePduChannelRequest { asset_name: "UnityAsset", channel_id: 1, pdu_size: 248, method_type: "UDP", robo_name: "EV3TrainModel" }, extensions: Extensions }
INFO: EV3TrainModel create_lchannel: logical_id=1 real_id=2 size=248
create_asset_pub_pdu: robo_name=EV3TrainModel channel_id=1 real_id=2
create_asset_pub_pdu: channel_ID=1
subscribe_pdu_channel: Got a request: Request { metadata: MetadataMap { headers: {"te": "trailers", "content-type": "application/grpc", "user-agent": "grpc-csharp/2.37.0-dev grpc-c/15.0.0 (windows; chttp2)", "grpc-accept-encoding": "identity,deflate,gzip", "accept-encoding": "identity,gzip"} }, message: SubscribePduChannelRequest { asset_name: "UnityAsset", channel_id: 0, pdu_size: 196, listen_udp_ip_port: "172.25.192.1:54003", method_type: "UDP", robo_name: "EV3SignalModel" }, extensions: Extensions }
create_asset_sub_pdu
create_pdu_channel: Got a request: Request { metadata: MetadataMap { headers: {"te": "trailers", "content-type": "application/grpc", "user-agent": "grpc-csharp/2.37.0-dev grpc-c/15.0.0 (windows; chttp2)", "grpc-accept-encoding": "identity,deflate,gzip", "accept-encoding": "identity,gzip"} }, message: CreatePduChannelRequest { asset_name: "UnityAsset", channel_id: 1, pdu_size: 248, method_type: "UDP", robo_name: "EV3SignalModel" }, extensions: Extensions }
INFO: EV3SignalModel create_lchannel: logical_id=1 real_id=3 size=248
create_asset_pub_pdu: robo_name=EV3SignalModel channel_id=1 real_id=3
create_asset_pub_pdu: channel_ID=1
register: Got a request: Request { metadata: MetadataMap { headers: {"te": "trailers", "content-type": "application/grpc", "user-agent": "grpc-csharp/2.37.0-dev grpc-c/15.0.0 (windows; chttp2)", "grpc-accept-encoding": "identity,deflate,gzip", "accept-encoding": "identity,gzip"} }, message: AssetInfo { name: "UnityAsset" }, extensions: Extensions }
asset_notification_start: Got a request: Request { metadata: MetadataMap { headers: {"te": "trailers", "content-type": "application/grpc", "user-agent": "grpc-csharp/2.37.0-dev grpc-c/15.0.0 (windows; chttp2)", "grpc-accept-encoding": "identity,deflate,gzip", "accept-encoding": "identity,gzip"} }, message: AssetInfo { name: "UnityAsset" }, extensions: Extensions }
この状態で、Unityの START
ボタンをクリックするとシミュレーション開始します。
デモ
マイコン制御プログラムのデモはこちらです。