JetsonTX2のセットアップの記録
JetsonTX2を搭載した移動ロボットを実験で使うので、ROSやOpenCV、ZEDステレオカメラ、rp-LiDARのセットアップの記録を残しておこうと思う。
- ホスト: Ubuntu16.04搭載のノートPC - ターゲット: JetsonTX2
- JetPack
- 1回目のインストール
- 2回目のインストール
- ROSのインストール
- ZEDのSDKのインストール
- OpenCV3(.4)のインストール
- ROSの画像処理関係(ros-perception)のビルド
- ROSの画像処理とOpenCV3+CUDA9.0の連携の確認
- PCLのビルド
- TODO?
JetPack
JetPack-L4T-3.2.1を使った。ZEDのROS用ノードzed-ros-wrapper
をコンパイルする際に、SDK>=2.3を使う必要があるが、CUDA9.0に依存している。よってCUDAのバージョンが9.0以上であるかを確認する。
1回目のインストール
多分1回目ではOSしか入れないと思う。
リカバリーモード
一旦電源を切った後、再度電源を入れると同時に、リカバリーボタンとリセットボタンを同時に押す。2秒後にリセットボタンを外す。すると起動画面は現れないはず。その状態で付属のケーブルでJetsonのmini-USBとPCのUSBを接続し、lsusb
でNVIDIA corpのリストが表示されればOK。
パッケージ選択
ホスト側には何も入れる必要はない。必要最低限にしたいため(そしてROSのOpenCV3との互換性を憂慮して)Jetson側ではFlash OS Image、CUDA(9.0)、cuDNN(7.0)のみ選択した(OpenCV、VisionWorks、TensorRT、Multlmediaはno actionに)。ただし1回目のインストールではOSしか入れないので、他のパッケージはまだ関係なさそう。このまま続行すればインストールは10分ぐらいで終わった。
2回目のインストール
XTerm上のインストーラにfinishedと表示されたらCtr-Cで一旦終了する。Jetsonを起動して、WiFiに繋いで2回目に進む。
パッケージ選択
先ほどと同じ、必要なパッケージだけチェックを入れる。このときFlash OS Imageはno actionにしておく。
IPアドレスの確認
JetsonのIPアドレスを確認。ifconfig
とかip addr show
とか。このときJetson側でapt
を使うコマンドがバックグランドで動いていて面倒なことがあったので、そのような場合は
sudo rm /var/lib/dpkg/lock
しておく。これで勝手に入るのでは。
自分がやった時に起きたエラー
インストールの最中にapt-get update
をやっているようなのだが、デフォルトのサーバーへの接続が遅すぎて、一旦アメリカのサーバーへと変更しようとした。だが何かエラーが起きたようで、インストールの途中でcudaが入っていないと怒られた(指定したはずなのに)。結局一旦中断して、手動(apt-get)でcuda-toolkit-9-0を入れるはめになった。するとスムーズに進んだ。
確認
以下のコマンドが出ればインストールはされていると思う。
which nvcc => /usr/local/cuda-9.0/bin/nvcc
ROSのインストール
ros-kinetic-ros-perception
に含まれるパッケージの多くはOpenCVに依存しており、デフォルトではこれらをインストールしようとするとros-kinetic-opencv3
が依存パッケージと入ってしまう。しかしその実体はOpenCV3のCUDA無しバージョンであるようで、自前でビルドしたOpenCVとの衝突を起こしてしまう。試行錯誤の結果、ros-kinetic-ros-perception
は全て自前でローカル環境でビルドしたほうが良いと思う。なのでROSも必要最低限のパッケージのみ入れる。こちらのスクリプトに従ってインストール。
sudo ./installROS.sh -p ros-kinetic-ros-base
ZEDのSDKのインストール
ここからSDKをダウンロード。自分はバージョン2.4を選んだ。次に以下のレポジトリをクローンしてzed_wrapper
の部分だけcatkin_ws/src
配下に移す。
CUDA>=9.0とSDKがきちんとインストールされていればcatkin_makeできるはず。
OpenCV3(.4)のインストール
現時点で最新のバージョン3.4をビルドする。ここの記事を参考にした。
contrib
opencvのmodules
やinclude
と同じレベルのディレクトリに置いて、-DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules
を上の記事のCMakeコマンドに付け加えた。全体で1時間半程度でビルドできた。
ROSの画像処理関係(ros-perception)のビルド
CUDA有りでビルドしたOpenCV3を使ってimage_view
やcv_bridge
をビルドしてしまう。
$ sudo apt-get install libyaml-cpp libgtk-2.0-dev ros-kinetic-eigen-conversion etc.
で依存関係を満たした後、以下のros-kinetic-image-common
、ros-kinetic-image-pipeline
、ros-kinetic-vision-opencv
をクローンしてビルドする。これでcv_bridge
やimage_view
がローカルのOpenCV3を使ってくれるようになる。もしかしたらPoint Cloud LibraryもCUDA環境でビルドしたほうが速いのかも知れない。
ros-kinetic-opencv3をインストールするべきでない理由
cv_bridge(apt-getでインストールしたもの、ros-kinetic-opencv3を利用する)とcv::cuda::
を両方使用するノードをリンクするときに、${catkin_LIBRARIES}
と${OpenCV_LIBRARIES}
をtarget_link_librariesに指定した。またここの記事を参考にCMakeLists.txtでOpenCVを使い分けさせ、以下のようにきちんと2つのOpenCV両方にリンクされていることを確認した。
$cd ~/catkin_ws/devel/lib/HogeHogePackage/ $ ldd HogeHogeNode => /usr/local/libopencv3.・・・ => /opt/ros/kinetic/lib/libopencv3.・・・
しかしどうやっても実行時にcv::cuda::
へのリンクエラーが出てしまう。ros-kinetic-opencv3はCUDAに対応していないこと、cv_bridge
は(ローカル環境であれros-kinetic-opencv3であれ)OpenCVが使えればそれで良いことを考えて、今回の結論に至った。
ROSの画像処理とOpenCV3+CUDA9.0の連携の確認
以下のようなノードをJetson側に作って
- 動画読み込み
- GPUで処理
- 処理結果を可視化してpublish
ノートPC側でimage_view
で確認するというもの。
PCLのビルド
以下によるとPCLはBoost、Eigen、FLANN、VTK、QHULLに依存するようである。FLANNはまだインストールしていないのでapt-get
しようかと思ったが、FLANNもCUDA有りでビルドできるようである。
Point Cloud Library 1.8.0 has been released – Summary?Blog
FLANNのビルド
以下のレポジトリからクローンしてきて、バージョンを1.9.1にする。
$ git checkout 1.9.1
CUDAを使うため、CMakeLists.txtを以下のように変更する。
option(BUILD_C_BINDINGS "Build C bindings" ON) option(BUILD_PYTHON_BINDINGS "Build Python bindings" ON) option(BUILD_MATLAB_BINDINGS "Build Matlab bindings" OFF) <=== option(BUILD_CUDA_LIB "Build CUDA library" ON) <=== option(BUILD_EXAMPLES "Build examples" ON) option(BUILD_TESTS "Build tests" ON) option(BUILD_DOC "Build documentation" OFF) <=== option(USE_OPENMP "Use OpenMP multi-threading" ON) option(USE_MPI "Use MPI" ON) <===
謎のエラー
自分の環境ではこれでMakefileは生成された。もしかしたらこれは環境依存なのかもしれないが、ビルドの際に以下のようなエラーが出たので、
/home/nvidia/builds/flann/src/cpp/flann/algorithms/kdtree_cuda_3d_index.cu(764): error: namespace "thrust" has no member "gather" 1 error detected in the compilation of "/tmp/tmpxft_0000106b_00000000-6_kdtree_cuda_3d_index.cpp1.ii". CMake Error at flann_cuda_s_generated_kdtree_cuda_3d_index.cu.o.cmake:266 (message): Error generating file /home/nvidia/builds/flann/build/src/cpp/CMakeFiles/flann_cuda_s.dir/flann/algorithms/./flann_cuda_s_generated_kdtree_cuda_3d_index.cu.o src/cpp/CMakeFiles/flann_cuda_s.dir/build.make:63: recipe for target 'src/cpp/CMakeFiles/flann_cuda_s.dir/flann/algorithms/flann_cuda_s_generated_kdtree_cuda_3d_index.cu.o' failed make[2]: *** [src/cpp/CMakeFiles/flann_cuda_s.dir/flann/algorithms/flann_cuda_s_generated_kdtree_cuda_3d_index.cu.o] Error 1 CMakeFiles/Makefile2:240: recipe for target 'src/cpp/CMakeFiles/flann_cuda_s.dir/all' failed make[1]: *** [src/cpp/CMakeFiles/flann_cuda_s.dir/all] Error 2 make[1]: *** Waiting for unfinished jobs.... [ 64%] Linking CXX executable ../bin/flann_example_cpp [ 64%] Built target flann_example_cpp [ 70%] Linking CXX static library ../../lib/libflann_s.a [ 70%] Built target flann_s Makefile:149: recipe for target 'all' failed make: *** [all] Error 2
問題のあったソースファイルsrc/cpp/flann/algorithms/kdtree_cuda_3d_index.cu
に#include <thurst/gather.h>
を追加するとビルドできた。
PCLのビルド
$ sudo apt-get install ros-kinetic-pcl-msgs ros-kinetic-tf ros-kinetic-tf2-eigen etc.
TODO?
Point Cloud LibraryもCUDA有りでビルドして、点群処理パッケージもローカルのものを使わせる。
DCモーターのトルク定数と逆起電力定数は一致する
モーションコントロールで言うところのKtとKeの違いが気になってきたので、復習がてらまとめなおす。
定義
DCモーターではこの2つの値は一致するが、DCモーターによらない定義を始めに示す。
逆起電力定数Ke
逆起電力定数はその名の通りモーターの電気的な特性に由来し、モーターに流れた電流に対して反対向きに発生する電圧で、定義は
である。レンツの法則による発生する誘導起電力は
であるから、とも表せる。
、すなわち機械的な運動に対してどれだけ電圧=電気特性が生まれるかを示す係数であると言える。
トルク定数Kt
モーターが発生するトルクはそれに流れる電流に比例し、発生したトルクに対して
と定義される。これは電流=電気的特性からどれだけトルク=機械的特性が生まれるかを示すと言える。
DCモーター
DCモータの等価回路は、ブラシの電圧降下を無視すると以下のようになる。
電気的な方程式
角速度をとすると逆起電圧はであるから、端子電圧は次のように表される。
機械的な方程式
出力トルクはトルク定数をとしてであるから、
ただし負荷側トルクをとする。
ブロック線図
信号の流れを
- 電圧(入力)
- 電流
- トルク
- 角速度
の順番とするとブロック線図は以下のようになる。
電気的エネルギーと機械的エネルギー
電力に関する方程式は以下のようになる。
それぞれ第一項はモーター内の銅損項、第二項はインダクタに蓄えられるエネルギーの変化、第三項は機械出力を表す。その機械出力は力学的な仕事率としては
と表されるはずであるから、それぞれを比べると が結論される。
電圧制御と電流制御
もしDCモーターに対して電圧制御を行う場合、電機子抵抗とインダクタンスの部分がLPFになっているため、立ち上がりが遅くなってしまう(速い変化、すなわち高周波成分を妨げるため)。一方図のようにオペアンプで駆動すると、(オペアンプが理想的である限り)コイルの周波数特性にかかわらず指定した電流を流せてしまう。理由はオペアンプの出力が電圧源であるためである。
DCモーターのトルク、速度、角度制御システム
先ほどのDCモーターのトルクや速度、角度の制御を行うことを考える。まず始めにトルクから始め、その後制御器を付け加えることで速度、角度の制御系を組む。
トルク制御
トルクの値を指令値に一致させることが目的であるが、残念ながらトルクの値を直接はフィードバックできない。代わりにフィードバックできるセンサ情報としてDCモーターに流れる電流値が挙げられる。そこでトルク定数の式を思い出すと、入力をトルク定数の公称値で割った電流指令を参照値にすれば良い。そしてその参照値とセンサ値の差に対して電圧指令を計算する制御器を設計し、その指令値の電圧を発生する電源をDCモーターに接続すれば良い。というわけでブロック図は以下のようになる。
トルク定数の公称値が実際のモデルと正しければ、このシステムの伝達関数はほぼ1とみなすことができる。
速度制御系
さらにPI制御器を頭に付け、角速度の差からトルクを出力するようにする。
角度制御系
角速度に積分器をつけ、フィードバック誤差に対してPID制御を行う。
差動増幅器のシミュレーション
古典制御について復習するがてら、周波数領域の設計を考えたりするアナログ回路を少し再勉強しようと思った。
オペアンプの基本
1年前講義で聞いた時は全然理解していなかったのだが、以下の3つのルールを使うといいらしい。
ひとつ目はいわゆる仮想接地の原理。2つ目は知識不足なのでよく分からない。
反転増幅回路
1つめのルールから+端子が接地されているため、-端子も電圧が0になる。2つめのルールから-端子には電流が流れないので、電源からの電流はVoutへ向かって流れる。その電流は V1/R0であるから、
であり、入力電圧を反転して出力する。
非反転増幅回路
+端子に電源が直接接続されているので、1つめのルールから-端子にも電源電圧がかかる。したがって2つめルールより電流はVoutからグラウンドへと流れる。その電流値は V1/R1であるから、
となり、増幅率は正である。
差動増幅回路のシミュレーション
図のような差動増幅回路の計算をしてみる。
オペアンプの両端子の電圧は等しいのでとすると、上下について分圧を計算すると
よって分子が等しいので
なので図の回路は
- V3だけオフセットをのせた上で
- V2を基準として(V1 - V2)を増幅する
- 増幅率はR0/R1
ということになる。
ここで次のような回路を設計したいとする。
- 入力 : V
- 出力 : V
- 入力と出力は同相
図の差動増幅回路を使うとすると、V2=0としてV1に信号をのせ、R1=1kΩ、R2=4kΩとすれば入力を増幅できる。またオフセットは5VなのでV3=5Vとすれば良いと思われる。LTSPICEでシミュレーションした結果が以下。
波形をプロットすると以下のようになり、きちんと同位相でオフセットをのせた上で4倍できていることが分かる。
ROS開発のためのEmacs設定
ROSをC++で開発する際に、データタイプや名前空間をいちいち正確に書くのは正直しんどい。特にmsg、srv、actionファイルからどのようなデータ構造体が生成されたのかは確認しづらい(ConstPtr& を付け忘れて醜いコンパイルエラーが出るのはよくある)。また困ったことにflycheckのサーチパスに/opt/ros/kinetic/include
や~/catkin_ws/devel/include
を入れても、どういうわけかそれらを認識してくれない。ネットで探していたところironyを使ってROSパッケージのシンタックスチェックを行う方法を見つけた
Add include paths to flycheck and to company-irony? - Emacs Stack Exchange
のでメモ。これから説明する方法でROSパッケージの補完、コード・リーディングができるようになる。
手順1
自分がこれからビルドしようとしているパッケージに以下を追記
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
そのままcatkin_make
する。すると~/catkin_ws/build
にcompile_commands.json
が生成される。これはrtags
やirony
がソースファイルのパースやコード補完を行うために必要となる。後述のrtags
はCMakeLists.txtのあるディレクトリを自動で探してくれるが、compile_commands.json
は~/catkin_ws/build/
に生成されるので、~/catkin_ws/
にjsonへのシンボリックリンクを貼っておくと自動で解析を行ってくれるようである。
(~/catkin_ws/)$ ln -sf build/compile_commands.json compile_commands.json
これをIronyに読み込ませていく。
手順2
melpaからirony
、yasnippet
、rtags
などをインストール。自分は以下の記事を参照した。
手順3
まずirony, yasnippetでシンタックスチェック(静的解析)やコードの補完を行えるようにする。
$ cd catkin_ws/src $ emacs my_pkg/***/src/node.cpp
Emacsを開いたら環境変数irony-cdb-search-directory-list
を次のように打ち込んで編集
M-x irony-cdb-json-add-compile-commands-path
下のようにProject rootを聞かれるので~/catkin_ws/build/
を指定する。次にCompile commandsを聞かれるので、同ディレクトリのcompile_commands.jsonを読みこませる。
Project root: ~/catkin_ws/build Comiple commands: ~/catkin_ws/build/compile_commands.json
これで完了。さらにC-h v irony-cdb-search-directory-list
で環境変数irony-cdb-search-directory-listにbuild
を付け加えておいた(念の為)。
手順2の設定でEmacs起動時にironyが自動で起動するようになっているはずなので、再度.cppを開く。
$ emacs my_pkg/***/src/node.cpp
うまくいけばirony-serverが起動してシンタックスチェックを開始する。写真のようにros::
の途中まで打ち込むと補完が行われるし、変数の型のチェックもリアルタイムで行われる。
また自分で定義したmsgから自動生成される.h
ファイル(~/catkin_ws/devel/include/mypkg/内に置かれる)についても補完を行ってくれる。特にyasnippet
を使えばテンプレートパラメータや関数の変数のリストも補完してくれるので、かなり便利である。
手順4
次にrtagsでコード・リーディングできるようにする。こうすると/opt/ros/kinetic/include
内のファイルまで型や名前空間を追跡できるので、内部実装も覗けるようになる。手順2にしたがってrtagsとrtags-modeをインストールした後、rdm
、rc
コマンドを使えることを確認する。
$ which rdm /usr/bin/rdm $ rdm --daemon
rtagsのタグを生成する。
$ $ cd ~/catkin_ws/build $ rc -J .
rc
コマンドがjsonの読み込みを開始するので、落ち着くまで待つ。Emacsでcppファイルを開き、タグジャンプしたい関数などにカーソルを合わせてM-.
(Altを押しっぱなしにして-と.を順番に押す)すると定義されている箇所に飛べる。写真ではros::ServiceServer
上にカーソルを合わせてジャンプしたところ/opt/ros/kinetic/include/ros
に飛んだ。
キーバインドは手順2の設定参照。
もちろん自分で作ったパッケージについてもCMAKE_EXPORT_COMPILE_COMMANDS
をONにすれば、補完やタグジャンプを行えるようになる。
ROSのC++はテンプレートメタプログラミングをふんだんに使っているので、irony
やyasnippet
で静的解析や補完を行いながら開発しないとどこでコンパイルエラーがどこで発生しているのか分かりづらい。
その他
.launch
、.urdf
、.xacro
ファイルを開くときにnxml-mode
にするとインデントと閉じタグを勝手に入れてくれる。yaml
ファイルもyaml-mode
でインデントできる。
(add-to-list 'auto-mode-alist '("\\.urdf" . nxml-mode)) (add-to-list 'auto-mode-alist '("\\.xacro" . nxml-mode)) (add-to-list 'auto-mode-alist '("\\.launch" . nxml-mode)) (add-to-list 'auto-mode-alist '("\\.yaml" . yaml-mode))
以上でかなり効率よく開発できる。
追記: clang-format
ROSにも以下のようなC++のスタイルガイドが存在するようである。