WSL (Windows Subsystem for Linux) 的 VSLAM (Visual Simultaneous Localization and Mapping) 道路

Optics_css發表於2021-02-11

WSL 的 VSLAM 道路


Windows Subsystem for Linux 闖入 Visual Simultaneous Localization and Mapping 世界的艱難道路... 這裡包含各種各樣的 WSL 中可能用到的包,美化方案,以及相關軟體的一些使用小技巧,用於自己踩坑記錄的同時,希望能夠幫到同為使用 Windows 踩坑的 CVer 們... ...

安裝好 Windows Subsystem for Linux 後要做的

解除安裝原裝 Vim

一波強硬操作把好刪的地方先咔嚓掉(讓輸密碼就老實輸,讓確認就直接'Y'):

sudo apt-get remove vim
sudo apt-get remove vim-runtime
sudo apt-get remove vim -tiny
sudo apt-get remove vim-common
sudo apt-get remove vim-doc
sudo apt-get remove vim-scripts

然後檢查還剩什麼帶 "vim" 字眼的還活著,輸入:

dpkg -l | grep vim

得到下面這三個東西:

rc  vim-common	2:8.1.2269-1ubuntu5	all	Vi IMproved - Common files
rc  vim-runtime	2:8.1.2269-1ubuntu5	all	Vi IMproved - Runtime files
rc  vim-tiny	2:8.1.2269-1ubuntu5	amd64	Vi IMproved - enhanced vi editor - compact version

扯掉它最後的救命稻草,用:

sudo dpkg -P vim-tiny vim-common vim-run

安裝 Nano

這樣就成功 remove 了原裝的 vim,下面用 apt-get 命令安裝 nano,也是一種編輯器:

sudo apt-get install nano

Linux換源

進入阿里雲 Ubuntu 映象,選擇 ubuntu 20.04 (focal) 配置所對應的源:

deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

在 source.list 檔案中新增這些源並儲存(按,Ctrl+K):

sudo nano /etc/apt/source.list # Use nano to edit the .list file

一些小型的 Tips

  • “右鍵”在 WSL 中意味著 “Paste”;

  • 訪問源列表中每個網址並讀取軟體列表,最後把這個更新後的列表儲存在本地電腦,用的命令為:

    sudo apt-get update
    

    要想把本地已安裝的軟體與軟體列表中對應軟體進行對比,發現需要更新的檔案,用下面這個:

    sudo apt-get upgrade
    
  • 回到 home 目錄是用:

    cd ~
    
  • WSL 似乎不支援這東西

    # sudo apt-get install yum
    
  • 要想鑑定一個網站是否正常連線,使用如下的命令:

    ping XXX.com # "Packet Internet Groper", as an example, use 'ping github.com'
    

    這是工作在 TCP/IP 網路體系結構中應用層的一個服務命令, 主要是向特定的目的主機傳送 ICMP(Internet Control Message Protocol 因特網報文控制協議)Echo 請求報文,測試目的站是否可達及瞭解其有關狀態。

    等待一段時間後(你認為差不多到了統計的總時長了),使用以下命令停止:

    ctrl+C
    

    最終輸出基本上是下面這個樣子(github 有一定的丟包 a... ...):

    PING github.com (140.82.113.3) 56(84) bytes of data.
    64 bytes from github.com (140.82.113.3): icmp_seq=1 ttl=47 time=565 ms
    64 bytes from github.com (140.82.113.3): icmp_seq=2 ttl=47 time=1062 ms
    64 bytes from github.com (140.82.113.3): icmp_seq=3 ttl=47 time=389 ms
    64 bytes from github.com (140.82.113.3): icmp_seq=4 ttl=47 time=513 ms
    64 bytes from github.com (140.82.113.3): icmp_seq=5 ttl=47 time=434 ms
    64 bytes from github.com (140.82.113.3): icmp_seq=6 ttl=47 time=607 ms
    64 bytes from github.com (140.82.113.3): icmp_seq=7 ttl=47 time=373 ms
    64 bytes from github.com (140.82.113.3): icmp_seq=8 ttl=47 time=401 ms
    ^C
    --- github.com ping statistics ---
    9 packets transmitted, 8 received, 11.1111% packet loss, time 8026ms
    rtt min/avg/max/mdev = 372.733/542.963/1062.033/212.073 ms, pipe 2
    
  • 只有 g++ 不足以在 Linux 上面開心地做開發,最好在一切的開始先裝一下 build-essential 這個包,裡面有很多依賴,能夠使預設的 Ubuntu 具備 C/C++ 的編譯環境,執行:

    sudo apt-get install build-essential
    
  • Node Package Manager(npm)能夠加快下載軟體包的速度(?):

    sudo apt install npm
    
  • 想要看看可以升級的軟體以及它們的版本資訊,使用:

    apt list --upgradable -a
    
  • 直接 Kill 當前程式:

    ctrl+C
    
  • 一種臨時給予許可權的方法:

    sudo chmod 777 /dev/ttyUSB*
    

    相應的,如果想要給串列埠一個永久許可權,使用:

    sudo usermod -a -G dialout user_name
    
  • 尋找包的位置,mlocate 可以用來定位軟體包,使用 locate 命令:

    sudo apt-get mlocate
    sudo apt-get install mlocate
    sudo updatedb
    locate eigen3
    

    就可以輸出 eigen3 的位置。

  • doxygen 編譯文件的方法,下載並 make doc 就可以編譯出一個 doxygen 文件:

    sudo apt-get install doxygen
    make doc
    

配置一個比較漂亮的Shell

可以通過 cat 來檢視當前的 Linux 系統是否有可用的 shell:

cat /etc/shells
sudo apt-get install zsh

安裝完後,shells 中將出現 zsh

# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/usr/bin/screen
/bin/zsh
/usr/bin/zsh

emmmm... ... 要安裝的就是叫做 zsh 的東西,可以把命令列弄得好看一些,對於提高工作效率有很好的促進作用,安裝步驟很簡單,直接執行:

sudo apt-get install zsh

然後切換當前 shell 至 zsh 就成功了:

chsh -s /bin/zsh

更新後會輸出一個:

# Updated process:[oh-my-zsh] Would you like to update? [Y/n] Y
Updating Oh My Zsh ...

remote: Enumerating objects: 154, done.
remote: Counting objects: 100% (154/154), done.
remote: Compressing objects: 100% (78/78), done.
remote: Total 116 (delta 69), reused 84 (delta 38), pack-reused 0
Receiving objects: 100% (116/116), 27.17 KiB | 11.00 KiB/s, done.
Resolving deltas: 100% (69/69), completed with 24 local objects.
From https://github.com/ohmyzsh/ohmyzsh
 * branch            master     -> FETCH_HEAD
   93c837f..c549387  master     -> origin/master
 README.md                                      |  61 +++---
 lib/functions.zsh                              |   4 +-
 lib/termsupport.zsh                            |  12 +-
 plugins/aws/aws.plugin.zsh                     |   1 -
 plugins/bgnotify/bgnotify.plugin.zsh           |   2 +-
 plugins/brew/README.md                         |   7 +-
 plugins/brew/brew.plugin.zsh                   |   1 +
 plugins/bundler/README.md                      |  79 +++++---
 plugins/bundler/bundler.plugin.zsh             | 116 ++++++-----
 plugins/compleat/compleat.plugin.zsh           |   7 +-
 plugins/composer/composer.plugin.zsh           |   2 +
 plugins/drush/drush.plugin.zsh                 |   2 -
 plugins/git/git.plugin.zsh                     |  14 +-
 plugins/ipfs/LICENSE                           |  22 ++
 plugins/ipfs/README.md                         |  17 ++
 plugins/ipfs/_ipfs                             | 717 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 plugins/laravel5/laravel5.plugin.zsh           |  19 +-
 plugins/minikube/minikube.plugin.zsh           |  10 +-
 plugins/pip/pip.plugin.zsh                     |   6 +-
 plugins/stack/stack.plugin.zsh                 |   1 -
 plugins/sublime-merge/README.md                |  17 ++
 plugins/sublime-merge/sublime-merge.plugin.zsh |  55 +++++
 plugins/terraform/README.md                    |   3 +-
 plugins/terraform/terraform.plugin.zsh         |   2 +
 plugins/wp-cli/wp-cli.plugin.zsh               |   1 -
 themes/agnoster.zsh-theme                      |   2 +-
 themes/avit.zsh-theme                          |   4 +-
 27 files changed, 1017 insertions(+), 167 deletions(-)
 create mode 100644 plugins/ipfs/LICENSE
 create mode 100644 plugins/ipfs/README.md
 create mode 100644 plugins/ipfs/_ipfs
 create mode 100644 plugins/sublime-merge/README.md
 create mode 100644 plugins/sublime-merge/sublime-merge.plugin.zsh
First, rewinding head to replay your work on top of it...
Fast-forwarded master to c549387745205d7fa8e91c1e6dcdae6901d9dd1d.
         __                                     __
  ____  / /_     ____ ___  __  __   ____  _____/ /_
 / __ \/ __ \   / __ `__ \/ / / /  /_  / / ___/ __ \
/ /_/ / / / /  / / / / / / /_/ /    / /_(__  ) / / /
\____/_/ /_/  /_/ /_/ /_/\__, /    /___/____/_/ /_/
                        /____/
Hooray! Oh My Zsh has been updated and/or is at the current version.
To keep up on the latest news and updates, follow us on Twitter: https://twitter.com/ohmyzsh
Want to get involved in the community? Join our Discord: https://discord.gg/ohmyzsh
Get your Oh My Zsh swag at: https://shop.planetargon.com/collections/oh-my-zsh

開啟檔案 .zshrc,更改 ZSH_THEME=ZSH_THEME="agnoster",開啟的方法如下(用 Nano 編輯):

sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
nano ~/.zshrc

實際上,此時 reboot 後看到的是奇怪的樣式,需要調整字型才能讓它正常起來,進入官網下載相應的字型,直接雙擊安裝後,在 WSL 命令列視窗直接 右鍵->屬性->字型 並更改字型的樣式即可。

輸出檔案樹檢視到.txt(Windows 版本)

開啟"執行"對話方塊(Win+R),輸入 cmd,開啟控制檯命令視窗...

C:\Users\a1020>g:
G:\>cd \__BiBliOthèQuE__
G:\__BiBliOthèQuE__>tree /f > saved_names.txt

Linux 中做這件事似乎需要下面這個東西:

sudo apt-get install tree

這個弄出來也蠻好看的,在路徑中輸入:

tree

得到了下面一棵很 happy 的樹圖:

藉助 WSL 走進 VSLAM的世界

WSL 掛載 Windows檔案

WSL 是可以訪問 Windows 中的檔案的,除了軟體要安裝在根目錄(?),其它的檔案例如各種程式碼、資料檔案什麼的都希望可以放在別的地方,由此,可以切換路徑到自己喜歡的目錄裡面:

cd /mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo

下載 SLAMdemo 檔案、安裝 cmake、Hello SLAM

從 Gitee 中把目標檔案 clone 下來:

git clone https://gitee.com/wenyawei/slambook.git

安裝 cmake 的過程還是像以往一樣:

sudo apt-get install cmake

完事之後隨便來一下 cmake 命令,可以輸出一些奇奇怪怪的東西:

Usage

  cmake [options] <path-to-source>
  cmake [options] <path-to-existing-build>
  cmake [options] -S <path-to-source> -B <path-to-build>

Specify a source directory to (re-)generate a build system for it in the
current working directory.  Specify an existing build directory to
re-generate its build system.

Run 'cmake --help' for more information.

接下來把路徑切到 slambook/ch2,用g++編譯一下 helloSLAM.cpp,並執行生成的可執行檔案 a.out

cd slambook/ch2
g++ helloSLAM.cpp
./a.out

得到如下所示 Hello SLAM! 的輸出:

安裝 Eigen、檢測是否成功

直接採用 apt-get 安裝:

sudo apt-get install libeigen3-dev

從前面的路徑回退一位,並切換到 ch3/useEigen 的路徑:

cd ..
cd ch3/useEigen

使用 cmake 進行編譯,並執行:

cmake .
make
./eigenMatrix

輸出為(...):

1 2 3
4 5 6
1       2       3
4       5       6
10
28
32
77
 0.680375   0.59688 -0.329554
-0.211234  0.823295  0.536459
 0.566198 -0.604897 -0.444451

 0.680375 -0.211234  0.566198
  0.59688  0.823295 -0.604897
-0.329554  0.536459 -0.444451
1.61307
1.05922
 6.80375   5.9688 -3.29554
-2.11234  8.23295  5.36459
 5.66198 -6.04897 -4.44451
-0.198521   2.22739    2.8357
  1.00605 -0.555135  -1.41603
 -1.62213   3.59308   3.28973
0.208598
Eigen values =
0.0242899
 0.992154
  1.80558
Eigen vectors =
-0.549013 -0.735943  0.396198
 0.253452 -0.598296 -0.760134
-0.796459  0.316906 -0.514998
time use in normal inverse is 0ms
time use in Qr decomposition is 0ms

安裝 Pangolin、檢測是否成功

詳細安裝步驟以及檢測見我的 Pangolin Installation & Examination 教程。

安裝 Sophus、檢測是否成功

和之前一樣,直接切入軟體包的目錄進行編譯,指令如下:

cd /mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/Sophus
mkdir build
cd build
cmake ..
make

然後開心地發現竟然有編譯錯誤!!具體錯誤為:

/mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/sophus/sophus/so2.cpp: In constructor ‘Sophus::SO2::SO2()’:
/mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/sophus/sophus/so2.cpp:32:26: error: lvalue required as left operand of assignment
   32 |   unit_complex_.real() = 1.;
      |                          ^~
/mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/sophus/sophus/so2.cpp:33:26: error: lvalue required as left operand of assignment
   33 |   unit_complex_.imag() = 0.;
      |                          ^~
make[2]: *** [CMakeFiles/Sophus.dir/build.make:66: CMakeFiles/Sophus.dir/sophus/so2.cpp.o] Error 1
make[2]: Leaving directory '/mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/sophus/build'
make[1]: *** [CMakeFiles/Makefile2:91: CMakeFiles/Sophus.dir/all] Error 2
make[1]: Leaving directory '/mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/sophus/build'
make: *** [Makefile:144: all] Error 2

於是去尋找路徑下名為 so2.cpp 的原始檔,找到如下程式碼:

SO2::SO2()
{
unit_complex_.real() = 1.;
unit_complex_.imag() = 0.;
}

顯然這種賦值方式是 XXX 的,應該用實參的形式賦值,也就是說,改成下面的形式:

SO2::SO2()
{
//unit_complex_.real() = 1.;
//unit_complex_.imag() = 0.;
unit_complex_.real(1.);
unit_complex_.imag(0.);
}

然後重新編譯一下,就通過了:

/usr/bin/cmake -E cmake_progress_start /mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/sophus/build/CMakeFiles 0

接著的使用中會遇到的麻煩事是找不到 Sophus 庫,需要把 CMakeLists.txt 裡面寫上你安裝的 Sophus 庫的標頭檔案路徑以及共享庫的路徑:

# Use the set(·) command to input the directories of Sophus
set(Sophus_INCLUDE_DIRS "/mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/Sophus/sophus")
set(Sophus_LIBS "/mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/Sophus/build/libSophus.so")
find_package(Sophus REQUIRED)
include_directories(
${Sophus_INCLUDE_DIRS}
)
target_link_libraries(useSophus ${Sophus_LIBRARIES})

咳咳,上面是非模板 Sophus 的安裝和使用,,下面才是模板庫的,命令列如下(記得不要回滾):

git clone https://github.com/strasdat/Sophus.git
cd /mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/SophusTemplate
mkdir build
cd build
cmake ..
make
sudo make install

並沒有任何編譯錯誤,這樣一下子安裝下來就是隻有標頭檔案的 Sophus,就像 eigen3 一樣的,它和非模板庫的區別在於,這個裡面的型別定義都是基於模板的,也就是說,有更強的泛化效能。

安裝 Ceres、g2o、檢測是否成功

同前,首先應當安裝依賴:

sudo apt-get install qt5-qmake qt5-default libqglviewer-dev-qt5	libsuitesparse-dev libcxsparse3 libcholmod3
sudo apt-get install liblapack-dev libsuitesparse-dev libcxsparse3 libgflags-dev libgoogle-glog-dev libgtest-dev

然後進入編譯:

git clone https://github.com/RainerKuemmerle/g2o.git
sudo apt-get install libsuitesparse-dev qtdeclarative5-dev qt5-qmake libqglviewer-dev-qt5
sudo su
cd g2o
mkdir build
cd build
cmake ../
make -j8
sudo make install

遇到了編譯錯誤:

/usr/lib/qt5/bin/uic: error while loading shared libraries: libQt5Core.so.5: cannot open shared object file: No such file or directory
make[2]: *** [g2o/apps/g2o_viewer/CMakeFiles/viewer_library.dir/build.make:62: g2o/apps/g2o_viewer/ui_base_main_window.h] Error 127
make[1]: *** [CMakeFiles/Makefile2:1580: g2o/apps/g2o_viewer/CMakeFiles/viewer_library.dir/all] Error 2

查了一下,這個錯誤名為 error while loading shared libraries: libQt5Core.so.5: cannot open shared object file: No such file or directory,還好還好,有個解決思路幫助我成功解決了這個問題,似乎為 WSL 特有的,執行如下語句後再進行編譯就可以了:

sudo strip --remove-section=.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5

開了7個執行緒,花了得有接近 3~4 min 叭才弄完,但是完了就好完了就好,最後別忘了 sudo make install 一下。

g2o_viewer run 一下 sphere.g2o 來證明一下已經下載完成:

./g2o/bin/g2o_viewer /mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/3rdparty/ch10/sphere.g2o

一個需要注意的點是,最好別在別的位置編譯 g2o 庫,可能會報錯告訴你路徑裡有中文。

安裝 OpenCV4.4、檢測是否成功

詳細安裝步驟以及檢測見我的 OpenCV4.4.0 Installation & Examination 教程。

Cmake、g++

在 WSL 中使用 g++ 列印虛表的操作如下,會自動寫到一個檔案裡:

g++ -fdump-class-hierarchy XXX.cpp

使用 g++ 匯出繼承結構的指令如下:

g++ -fdump-class-hierarchy -c XXX.cpp

Cmake 的簡單用法

構建 CMakeList.txt 如下,注意一定要把儲存的編碼格式改成 UTF8

# The lowest version required
cmake_minimum_required( VERSION 2.8 )
# Project name
project( HelloSLAM )
# The executable file addition
add_executable( helloSLAM helloSLAM.cpp )

在終端輸入:

# Path to slambook/ch2
cd /mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/Demolist/slamdemo/slambook/ch2
# CMake, the current path
cmake .
make
# Run the executable file
./helloSLAM

可以通過新建並切換到 build 資料夾,並對於上一個資料夾進行編譯,就可以將 cmake 編譯時產生的檔案生成在 build 裡面,這樣有利於原始碼的釋出:

mkdir build
cd build
cmake ..
make

注意每次編譯時都記得把以前的 Makefile 刪除。

Python 的簡單用例

學會用命令列呼叫 Python 標準庫的 doctest,從而生成程式碼的分析檔案,首先自然是切換到相應的路徑:

cd /mnt/c/Users/a1020/Desktop/Reinforcement_ELyou/#Pythonic/Fluent-Python/01-data-model

執行下面的指令,呼叫 doctest,可以獲得一個名為 frenchdeck.doctest 的檔案:

python3 -m doctest frenchdeck.py

檔案內容為程式碼的分析:

>>> from frenchdeck import FrenchDeck, Card
>>> beer_card = Card('7', 'diamonds')
>>> beer_card
Card(rank='7', suit='diamonds')
>>> deck = FrenchDeck()
>>> len(deck)
52
>>> deck[:3]
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
>>> deck[12::13]
[Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
>>> Card('Q', 'hearts') in deck
True
>>> Card('Z', 'clubs') in deck
False
>>> for card in deck:  # doctest: +ELLIPSIS
...   print(card)
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
...
>>> for card in reversed(deck):  # doctest: +ELLIPSIS
...   print(card)
Card(rank='A', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='Q', suit='hearts')
...
>>> for n, card in enumerate(deck, 1):  # doctest: +ELLIPSIS
...   print(n, card)
1 Card(rank='2', suit='spades')
2 Card(rank='3', suit='spades')
3 Card(rank='4', suit='spades')
...
>>> suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
>>> def spades_high(card):
...     rank_value = FrenchDeck.ranks.index(card.rank)
...     return rank_value * len(suit_values) + suit_values[card.suit]

Rank test:

>>> spades_high(Card('2', 'clubs'))
0
>>> spades_high(Card('A', 'spades'))
51

>>> for card in sorted(deck, key=spades_high):  # doctest: +ELLIPSIS
...      print(card)
Card(rank='2', suit='clubs')
Card(rank='2', suit='diamonds')
Card(rank='2', suit='hearts')
...
Card(rank='A', suit='diamonds')
Card(rank='A', suit='hearts')
Card(rank='A', suit='spades')

相關文章