WSLでORB SLAM3を動かす(完成版)

以前ORB SLAM3を動かしてみたが、それを参考に今回はスクラッチでやってみた。これをすべてやれば動くとこまで行くはず。何かエラーがあればコメントまで。

ORB_SLAM3のビルド

OpenCVはaptでインストールされるものだとバージョンが古いので、ソースからビルドする必要あり。22.04ならいけるかも。

#!/bin/bash -eu
sudo apt update
sudo apt install -y libgl1-mesa-dev libglew-dev cmake pkg-config libegl1-mesa-dev libwayland-dev libxkbcommon-dev wayland-protocols ffmpeg libavcodec-dev libavutil-dev libavformat-dev libswscale-dev libavdevice-dev libjpeg-dev libtiff5-dev libopenexr-dev python3-pip g++ git gcc libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libopencv-dev libssl-dev libopencv-dev libboost-filesystem-dev libboost-serialization-dev cmake ffmpeg python3 python3-dev libeigen3-dev build-essential libssl-dev libboost-filesystem-dev libboost-serialization-dev gedit

mkdir SLAM
export WORKDIR=`pwd`/SLAM
# build opencv
cd $WORKDIR
 
# build Pangolin
cd $WORKDIR
git clone --recursive https://github.com/stevenlovegrove/Pangolin.git
cd Pangolin
mkdir build && cd build
cmake ..
cmake --build .

# build ORB_SLAM3
cd $WORKDIR
git clone https://github.com/UZ-SLAMLab/ORB_SLAM3
cd ORB_SLAM3
sed -i 's/++11/++14/g' CMakeLists.txt
./build.sh

GUIアプリ動作の準備

※11/26更新

echo 'export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '\''{print $2}'\''):0.0' >> ~/.bashrc
source ~/.bashrc

サンプルの実行

※2022/11/06:データセットパス修正しました。

cd $WORKDIR
mkdir -p Datasets/EuRoc/
cd Datasets/EuRoc/
wget -c http://robotics.ethz.ch/~asl-datasets/ijrr_euroc_mav_dataset/machine_hall/MH_01_easy/MH_01_easy.zip
mkdir MH01
unzip MH_01_easy.zip -d MH01/

cd $WORKDIR/ORB_SLAM3
./Examples/Monocular-Inertial/mono_inertial_euroc ./Vocabulary/ORBvoc.txt ./Examples/Monocular-Inertial/EuRoC.yaml ../Datasets/EuRoc/MH01 ./Examples/Monocular/EuRoC_TimeStamps/MH01.txt dataset-MH01_mono

これで以下のような画面が出ればOK。

トラブルシューティング

データセットのパスが違うと、以下のようなログで停止する。(エラーは発生しない)この時はデータセットパスを修正。

$ ./Examples/Monocular-Inertial/mono_inertial_euroc_bak ./Vocabulary/ORBvoc.t
xt ./Examples/Monocular-Inertial/EuRoC.yaml Datasets/EuRoc/MH01 ./Examples/Monocular/EuRoC_TimeStamps/MH01.txt datase
t-MH01_mono
num_seq = 1
file name: dataset-MH01_mono
Loading images for sequence 0...LOADED!

参考

Setting up a virtual machine with ORB SLAM 3 | by Tristan BRAUD | Medium

error: ‘slots_reference’ was not declared in this scope · Issue #387 · UZ-SLAMLab/ORB_SLAM3 · GitHub

WSLでORB SLAM 3をビルド

WSLでSLAMを動かしてみたい、ということでビルドをしてみた。参考にしたサイトではビルドは成功したものの、画面に表示しないサンプルらしく動いているのかわからなかったので、表示されるサンプルを探した。また、画面が表示されない時に設定がおかしいんだかそういうものなんだかわからなかったので、実行時のログも丸々載せておいた。

動かしたのは以下のもの。

github.com

追記

クラッチでインストールしてみたのでどうぞ。

WSLでORB SLAM3を動かす(完成版) - ぼうびろく

手順

ビルドするには以下のサイトが参考になった。なお、何点かコードの修正があるが、それはやっていない。

Setting up a virtual machine with ORB SLAM 3 | by Tristan BRAUD | Medium

  • 修正前

    • Install ROS
$ curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
  • Edit ~/.bashrc (this assumes you use bash) and add
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$WORKDIR/ORB_SLAM3/Examples/ROS/
  • 修正後

    • Install ROS
$ curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add
  • Edit ~/.bashrc (this assumes you use bash) and add
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$WORKDIR/ORB_SLAM3/Examples_old/ROS/

サンプルの実行

サンプルを実行しようとしたものの、上記のサイトにある以下のサンプルはフレームやマップが表示されない。

$ ./Examples/Monocular/mono_euroc ./Vocabulary/ORBvoc.txt ./Examples/Monocular/EuRoC.yaml Datasets/EuRoc/MH01 ./Examples/Monocular/EuRoC_TimeStamps/MH01.txt dataset-MH01_mono

ログは以下の通り

num_seq = 1
file name: dataset-MH01_mono
Loading images for sequence 0...LOADED!

-------

ORB-SLAM3 Copyright (C) 2017-2020 Carlos Campos, Richard Elvira, Juan J. Gómez, José M.M. Montiel and Juan D. Tardós, University of Zaragoza.
ORB-SLAM2 Copyright (C) 2014-2016 Raúl Mur-Artal, José M.M. Montiel and Juan D. Tardós, University of Zaragoza.
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under certain conditions. See LICENSE.txt.

Input sensor was set to: Monocular
Loading settings from ./Examples/Monocular/EuRoC.yaml
Camera1.k3 optional parameter does not exist...
        -Loaded camera 1
        -Loaded image info
        -Loaded ORB settings
Viewer.imageViewScale optional parameter does not exist...
        -Loaded viewer settings
System.LoadAtlasFromFile optional parameter does not exist...
System.SaveAtlasToFile optional parameter does not exist...
        -Loaded Atlas settings
System.thFarPoints optional parameter does not exist...
        -Loaded misc parameters
----------------------------------
SLAM settings:
        -Camera 1 parameters (Pinhole): [ 458.65399169921875 457.29598999023438 367.21499633789062 248.375 ]
        -Camera 1 distortion parameters: [  -0.28340810537338257 0.073959067463874817 0.00019359000725671649 1.7618711353861727e-05 ]
        -Original image size: [ 752 , 480 ]
        -Current image size: [ 600 , 350 ]
        -Camera 1 parameters after resize: [  365.94735717773438 333.44500732421875 292.99069213867188 181.10678100585938 ]
        -Sequence FPS: 20
        -Features per image: 1000
        -ORB scale factor: 1.2000000476837158
        -ORB number of scales: 8
        -Initial FAST threshold: 20
        -Min FAST threshold: 7


Loading ORB Vocabulary. This could take a while...
Vocabulary loaded!

Initialization of Atlas from scratch
Creation of new map with id: 0
Creation of new map with last KF id: 0
Seq. Name:
There are 1 cameras in the atlas
Camera 0 is pinhole
First KF:0; Map init KF:0
New Map created with 271 points
^C

代わりに以下のサンプルを使うと表示される。

$ ./Examples/Monocular-Inertial/mono_inertial_euroc ./Vocabulary/ORBvoc.txt ./Examples/Monocular-Inertial/EuRoC.yaml Datasets/EuRoc/MH01 ./Examples/Monocular/EuRoC_TimeStamps/MH01.txt dataset-MH01_mono

ログは以下の通り。

num_seq = 1
file name: dataset-MH01_mono
Loading images for sequence 0...LOADED!
Loading IMU for sequence 0...LOADED!

ORB-SLAM3 Copyright (C) 2017-2020 Carlos Campos, Richard Elvira, Juan J. Gómez, José M.M. Montiel and Juan D. Tardós, University of Zaragoza.
ORB-SLAM2 Copyright (C) 2014-2016 Raúl Mur-Artal, José M.M. Montiel and Juan D. Tardós, University of Zaragoza.
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under certain conditions. See LICENSE.txt.

Input sensor was set to: Monocular-Inertial
Loading settings from ./Examples/Monocular-Inertial/EuRoC.yaml
Camera1.k3 optional parameter does not exist...
        -Loaded camera 1
        -Loaded image info
IMU.InsertKFsWhenLost optional parameter does not exist...
        -Loaded IMU calibration
        -Loaded ORB settings
Viewer.imageViewScale optional parameter does not exist...
        -Loaded viewer settings
System.LoadAtlasFromFile optional parameter does not exist...
System.SaveAtlasToFile optional parameter does not exist...
        -Loaded Atlas settings
System.thFarPoints optional parameter does not exist...
        -Loaded misc parameters
----------------------------------
SLAM settings:
        -Camera 1 parameters (Pinhole): [ 458.65399169921875 457.29598999023438 367.21499633789062 248.375 ]
        -Camera 1 distortion parameters: [  -0.28340810537338257 0.073959067463874817 0.00019359000725671649 1.7618711353861727e-05 ]
        -Original image size: [ 752 , 480 ]
        -Current image size: [ 600 , 350 ]
        -Camera 1 parameters after resize: [  365.94735717773438 333.44500732421875 292.99069213867188 181.10678100585938 ]
        -Sequence FPS: 20
        -Gyro noise: 0.00016999999934341758
        -Accelerometer noise: 0.0020000000949949026
        -Gyro walk: 1.9392999092815444e-05
        -Accelerometer walk: 0.0030000000260770321
        -IMU frequency: 200
        -Features per image: 1000
        -ORB scale factor: 1.2000000476837158
        -ORB number of scales: 8
        -Initial FAST threshold: 20
        -Min FAST threshold: 7


Loading ORB Vocabulary. This could take a while...
Vocabulary loaded!

Initialization of Atlas from scratch
Creation of new map with id: 0
Creation of new map with last KF id: 0
Seq. Name:
There are 1 cameras in the atlas
Camera 0 is pinhole
Framebuffer with requested attributes not available. Using available framebuffer. You may see visual artifacts.First KF:0; Map init KF:0
New Map created with 271 points
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-hayashi'
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
Starting the Viewer
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 3
mnInitialFrameId = 0
12 Frames set to lost
First KF:4; Map init KF:0
New Map created with 353 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 23
mnInitialFrameId = 14
17 Frames set to lost
First KF:6; Map init KF:4
New Map created with 289 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 29
mnInitialFrameId = 27
21 Frames set to lost
First KF:8; Map init KF:6
New Map created with 358 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 36
mnInitialFrameId = 32
27 Frames set to lost
First KF:11; Map init KF:8
New Map created with 140 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 45
mnInitialFrameId = 41
32 Frames set to lost
First KF:13; Map init KF:11
New Map created with 194 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 51
mnInitialFrameId = 49
34 Frames set to lost
First KF:15; Map init KF:13
New Map created with 257 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 55
mnInitialFrameId = 52
40 Frames set to lost
First KF:18; Map init KF:15
New Map created with 335 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 62
mnInitialFrameId = 60
46 Frames set to lost
First KF:20; Map init KF:18
New Map created with 430 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 70
mnInitialFrameId = 67
52 Frames set to lost
First KF:23; Map init KF:20
New Map created with 293 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 77
mnInitialFrameId = 75
57 Frames set to lost
First KF:25; Map init KF:23
New Map created with 174 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 83
mnInitialFrameId = 81
59 Frames set to lost
First KF:27; Map init KF:25
New Map created with 197 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 86
mnInitialFrameId = 84
62 Frames set to lost
First KF:29; Map init KF:27
New Map created with 194 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 90
mnInitialFrameId = 88
64 Frames set to lost
First KF:31; Map init KF:29
New Map created with 227 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 93
mnInitialFrameId = 91
66 Frames set to lost
First KF:33; Map init KF:31
New Map created with 381 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 96
mnInitialFrameId = 94
71 Frames set to lost
First KF:35; Map init KF:33
New Map created with 365 points
Fail to track local map!
IMU is not or recently initialized. Reseting active map...
SYSTEM-> Reseting active map in monocular case
LM: Active map reset recieved
LM: Active map reset, waiting...
LM: Reseting current map in Local Mapping...
LM: End reseting Local Mapping...
LM: Reset free the mutex
LM: Active map reset, Done!!!
mnFirstFrameId = 104
mnInitialFrameId = 100
103 Frames set to lost
First KF:43; Map init KF:35
New Map created with 365 points
start VIBA 1
end VIBA 1
start VIBA 2
end VIBA 2
Shutdown

Saving trajectory to CameraTrajectory.txt ...
There are 1 maps in the atlas
  Map 0 has 221 KFs

End of saving trajectory to CameraTrajectory.txt ...

Saving keyframe trajectory to KeyFrameTrajectory.txt ...
^C

補足

ORB SLAM2をインストールしようとしたときにg2oをインストールしたのでこれも必要かも。

GitHub - RainerKuemmerle/g2o at 20170730_git

困った場合

よくエラーとして出てくるのは、ライブラリがない、というエラーである。Ubuntuではライブラリはほぼパッケージによってインストールされる。なのでパッケージをインストールしてしまえばいい。

パッケージはapt listコマンドでリストを取得できる。この中から必要なパッケージを見つければいい。ライブラリパッケージには先頭にlibがついている。またビルドするのに必要な、ヘッダーファイルなどを含んだ開発用パッケージは、最後に-devがついている。この2点に着目して探せばいい。

例えばboostというライブラリがない場合は、以下のように検索すればいい。

$ apt list | grep -i boost
libboost-all-dev/bionic,now 1.65.1.0ubuntu1 amd64

WSLにCUDAをインストール Ubuntu 20.04 CUDA 11.7

CUDAのインストールは以下を参考に進めればOK。

CUDA on WSL :: CUDA Toolkit Documentation

ただし、以下のようなエラーが発生する場合がある。

$ sudo apt update
Get:1 file:/var/cuda-repo-wsl-ubuntu-11-7-local  InRelease [1575 B]
Get:1 file:/var/cuda-repo-wsl-ubuntu-11-7-local  InRelease [1575 B]
Err:1 file:/var/cuda-repo-wsl-ubuntu-11-7-local  InRelease
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY BCD50790B81839D3

その時は、以下のコマンドを打てばOK。

$ sudo cp /var/cuda-repo-wsl-ubuntu-11-7-local/*.gpg /usr/share/keyrings/

参考: nvidia - Unable to install CUDA on Ubuntu 22.04 WSL2 - Ask Ubuntu

WSL2でGUIアプリ使う

  1. WSL2をインストール
  2. VcXsrv Windows X Serverをインストール
  3. XLanchを実行して、ディスプレイ番号を0、Additional parameters for VcXsrvに「-ac -nowgl」を指定する。
  4. Windowsファイアウォールによるアプリケーションの許可」から、VcXsrvにプライベート、パブリック両方から許可する。
  5. WSLから以下を実行
$ sudo apt update
$ sudo apt install libgl1-mesa-dev xorg-dev
$ sudo apt install gedit
$ echo 'export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '\''{print $2}'\''):0.0' >> ~/.bashrc
$ source ~/.bashrc
$ gedit

参考

WSL2とWindowsのファイルのやり取りを500MB/sまで高速化した

概要

WSL2でホスト側のディスクへのアクセス速度が遅いので、SSHFSを使用することで読み取りが5MB/s->50MB/sに改善した。

追記: エクスプローラから、WSLに直接アクセスすることで500MB/sまで改善できた。

現状

WSL2ではホスト側のディスク(CドライブとかDドライブとか)をマウントする場合に、仮想ファイルシステムを経由するようで、アクセス速度がめちゃくちゃ遅い。測定結果は以下のようになる。以下は測定したいディスク(/mnt/dなど)で行う。

まず書き込み。ただしエラーとなったため参考まで。

/mnt/d$ dd if=/dev/zero of=tmp bs=1M count=1024
dd: error writing 'tmp': Input/output error
180+0 records in
179+0 records out
188219200 bytes (188 MB, 179 MiB) copied, 0.802771 s, 234 MB/s

次に読み込み。5.2 MB/sと非常に遅いことがわかる。

$ dd of=/dev/zero if=tmp
367615+1 records in
367615+1 records out
188219200 bytes (188 MB, 179 MiB) copied, 36.0973 s, 5.2 MB/s

5MB/sならネットワークのほうが早いじゃないか、ということでSSHFSを使ってみる。

SSHFS の準備

  • WSLでのSSHサーバー起動

wsl2でsshサーバを起動し、外部からそこに接続 - Qiita

  • SSHFSwinのインストール&起動

Windows10にwin-sshfsをインストールする方法

計測結果

上記のようにすると、WSL側のディレクトリがWindows側にマウントされている状態となる。なのでWindows側でアクセス速度を計測する。結果は以下の通り。通常のディスクに比べるとかなり見劣りしてしまうものの、一応高速化することはできた。

WSLに直接アクセス

エクスプローラから「\wsl$」と打つと、現在あるWSLの/にアクセスできる。例えば自分だとUbuntu-18.04というフォルダが作成されており、その下に/dev, /etc ...とフォルダがある。ここにファイルを書き込んでしまえばWSLからも見え、ファイルの読み書きができる状態になる。

ちなみにアクセス速度は以下のような感じ。/ではテストできないので、ホームディレクトリで計測している。ここまで高速化できればOKだろう。

Windows -> WSL間でMMAPをやろうとしたけどうまくいかなかったので、ファイル経由でデータの受け渡しをした

Windows -> WSL間で画像データの受け渡しをしたかったので、MMAPを使ってプロセス間通信をしようとしたが、結局うまくいかなかった。代替策としてファイル経由でデータの受け渡しをした。RAMDISKを使用したのでそれなりに速度は出る、と思う。

やったこと

データ受け渡しのテストとして、Windows側から乱数を書き込み、WSL側で読み取るというテストをした。MMAPを使うソースコードは以下の通り。

  • 送信側
import mmap
import time
import random

with open("hello.txt", "r+b") as f:
    mm = mmap.mmap(f.fileno(), 0)
    while True:
        i = random.randint(50, 100)
        mm[:] = i.to_bytes(2, 'little')
        print(i)        
        time.sleep(1)
  • 受信側
import mmap, time

with open("hello.txt", "r+b") as f:
    mm = mmap.mmap(f.fileno(), 0)
    while True:
        mm.seek(0)
        print(int.from_bytes(mm.read(), 'little')) 
        time.sleep(1)
    mm.close()

それぞれ実行して、Printされる文字列が同じであればいい。

コードの確認もかねて、組み合わせを変えてやった結果は以下の通り。

  • 送信:Windows、受信:Windows
    • 成功
  • 送信:WSL、受信:WSL
    • 成功
  • 送信:Windows、受信:WSL
    • 失敗(WSL側で実行開始した時点のデータからずっと更新されない)
  • 送信:WSL、受信:Windows
    • 失敗(Windows側で実行開始した時点のデータからずっと更新されない)

原因

WSLはOSより下のHyper-vの上で動いていて、そこでメモリ空間も分けられている。MMAPはOS上のリソースをメモリ上にマッピングする関数で、例えば上記ではhello.txtをメモリ上のAという場所にマッピングする。しかしHyper-v経由ではAにアクセスできないので、新たにBという場所にマッピングされる。そのため値が変化しないままなのではないかと思われる。

対処法

MMAPは使えないので、単純にファイル経由での受け渡しにした。これで値が変化するようになった。そのままだとストレージを経由するので、RAMDISKを作ってRAMDISK経由にすれば、速度はより高速になるのではないかと思われる。(そこまで早くならないという情報もあり)

ImDisk Toolkit download | SourceForge.net

  • 送信側
import time
import random

with open("R:\hello.txt", "w+b") as f:
    while True:
        i = random.randint(50, 100)
        f.write(i.to_bytes(2, 'little'))
        f.flush()
        print(i)
        f.seek(0)
        
        time.sleep(1)
  • 受信側
import time

with open("/mnt/r/hello.txt", "r+b") as f:
    while True:
        print(int.from_bytes(f.read(), 'little')) 
        time.sleep(1)

他プロセスから操作可能なUnity物理シミュレーション環境作った

はじめに

ディープラーニングで物体検出など使えるようになってくるとシミュレーション環境で動かしたいと思うのだが、よさそうなSWが見つからなかった。それなら作ればいいじゃないかということで作った。

実際に動いている画面は以下の通り。

youtu.be

制御画面は以下のような感じ。サンプルでは白線を検出して、白線に沿って走行する。とりあえず他プロセスにリアルタイムで映像が取り込めるというところまでで、ディープラーニングは動かしていない(実装はしてある)。

youtu.be

ソースコードは以下。

github.com

個人的に物理エンジンなんかは敷居が高いものと考えていたが、使ってみると案外サクサクできた。Unity触ったことない、なんて人も30分もあれば使えるようになっているのでぜひ使ってみてほしい。「Unity簡単やん!」となって世界が広がる、はず。

アーキテクチャ

ざっくりとしたアーキテクチャは以下の通り。シミュレータから位置や速度情報やカメラの映像を受け取り、コントローラーが、受けとった情報からステアリング角度やアクセルを計算して送信する。シミュレータはそれを受けて操作をし、また情報を送信する。プロトコルはソケット通信とMMAPを使用しており、低遅延でのシミュレーションおよび制御ができる。

追記:ソケット通信で映像を転送するスクリプト追加しました。

構成要素としては以下の通り。

  • Controller:画像処理等を行って操作量を決定する。
  • Sumilator:シミュレーション環境
    • Agent:エージェント。実際に動作を行うもの。車など。
    • Environment:環境。エージェントが動作する空間。街など。

はじめの方は物理シミュレーション(Unity)側にPython環境を組み込むことを考えていたが、2つの環境を分離しソケット通信やMMAPといった一般的なプロセス間通信で接続することで、双方の環境の管理が楽にできるようになった。また、Python側もソケット通信やMMAPが使えればいいので、PythonでなくてもC++Javaなどでも実装可能となっている。

開発記録とか(今後も更新予定)

Unity開発

実験記録

方針

基本的にはエージェントのUnity パッケージとコントローラのサンプルコードのセットで作っていく。

最後に

もし使っていただけて、感想、要望、バグ報告、気軽にいただけると嬉しいです。環境に関しては無数に考えられるので、いろんな環境でテストできるようにするために環境共有してくれると嬉しいです。アセットストアで販売なんかもOK。