えいあーるれいの技術日記

ROS2やM5 Stack、Ubuntuについて書いています

ROS2-Foxyでdarknet-ros(Ubuntu20.04+OpenCV4.2+CUDA11.2)

※Qiitaの記事もチェックしてみてください。

qiita.com

Ubuntu20.04の環境構築をしました。そして、Ubuntu18プログラムの移行のためにとりあえずDarknetの環境構築を行いました。Darknetの環境構築を行う記事は多くありますが、将来環境構築を複数回行うことを見越して備忘録として書きます。

この記事では、Ubuntu20.04+CUDA11.2+OpenCV4.2(すべて最新)の組み合わせを前提にしています。また、NVIDIAドライバのバージョンは460.32.03です。

Ubuntu20.04LTSの環境構築

1.Ubuntu20.04LTSのインストール:minimal installationでいいです。言語は英語推奨。

2.パッケージの更新とインストール

$ sudo apt update
$ sudo apt upgrade
$ sudo apt install git gcc cmake

3.NVIDIA Driverのインストール: 公式ドライバー | NVIDIAGPUの種類を選択してダウンロードします。

 私が使用したドライバは以下のリンクから直接とべます。(Linux Driver)

www.nvidia.com

4.nouveauを無効化する

echo `blacklist nouveau` >> /etc/modprobe.d/blacklist-nouveau.conf
echo `options nouveau modeset=0` >> /etc/modprobe.d/blacklist-nouveau.conf
sudo reboot

5.NVIDIA Driverをインストールする

  • Ctrl+Alt+F2を押して、CUIログインをする。
$ cd ~/Downloads/
$ chmod +x NVIDIA-Linux-x86_64-460.67.run
$ ./NVIDIA-Linux-x86_64-460.67.run

###基本的には質問に対してOKでいい

$ sudo reboot

6.再度ログインしてターミナルを開き、$nvidia-smiでドライバがインストールされているか確認

成功例

| NVIDIA-SMI 460.32.03    Driver Version: 460.32.03    CUDA Version: 11.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  GeForce RTX 208...  On   | 00000000:06:00.0  On |                  N/A |
| 24%   32C    P8    22W / 260W |    654MiB / 11016MiB |      3%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A       983      G   /usr/lib/xorg/Xorg                102MiB |
|    0   N/A  N/A      1491      G   /usr/lib/xorg/Xorg                336MiB |
|    0   N/A  N/A      1623      G   /usr/bin/gnome-shell               70MiB |
|    0   N/A  N/A      2349      G   ...AAAAAAAAA= --shared-files       72MiB |
|    0   N/A  N/A     18194      G   ...AAAAAAAA== --shared-files       22MiB |
|    0   N/A  N/A    113055      G   ...AAAAAAAAA= --shared-files       35MiB |
+-----------------------------------------------------------------------------+

7.CUDA 11.2のインストール

  • CUDA Toolkit 11.7 Downloads | NVIDIA Developerに従ってインストール。

  • nanoなどで~/.bashrcを開いて追記する。cudaのままでもいいし、cuda-11.2などのバージョン指定でもよい。(バージョンを切り替えがちな人はbashrcに記載しないほうがいいかも)

export PATH="/usr/local/cuda/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH"

8.cuDNNのインストール

ROS2のインストール

ROS2用ワークスペースの作成

 4つめのコマンドで--recusiveオプションを追加しないように!

$ source /opt/ros/foxy/setup.bash

$ cd ~/
$ mkdir -p ros2_ws/src
$ cd ros2_ws/src
$ git clone https://github.com/ajaypaul2008/darknet_ros.git
$ cd darknet_ros
$ git checkout foxy

$ git clone https://github.com/kunaltyagi/darknet.git
$ cd darknet
$ git checkout opencv4

$ cd ~/ros2_ws/
$ colcon build
  • webカメラ用ROS2パッケージもインストールしておきましょう。
$ sudo apt install ros-foxy-v4l2-camera

実行

 あらかじめROS2とワークスペースの環境はロードしておきましょう。

  • 1つめのターミナル:$ ros2 run v4l2_camera v4l2_camera_node __ns:=/color

  • 2つめのターミナル:ros2 launch darknet_ros darknet_ros.launch.py

AlexeyAB氏実装のdarknetについて

 Ubuntu20.04LTS+CUDA11.2の場合、そのまま動きました。

動作確認

トラブルシューティング

  • cannot find -lcudaというエラーについて:以下のリンクを参照して、バージョンを書き換えてシンボリックリンクを貼り付ける。

github.com

  • Could not load library libcudnn_cnn_train.so.8などロードできないという趣旨のエラー:リンクを正しく貼り直す。

  • error "OpenCV 4.x+ requires enabled C++11 support"というエラーが出る:リポジトリが違います。あるいは、OpenCV3.2を導入することでも解決します。

参考資料

github.com

github.com

github.com

ROS2におけるjoy→Twist変換の簡単解説(joy2twist)

PS5なロボット!? DualSenseをROS2で使う - えいあーる・れいの技術日記の続きです。(そういえば、全くAI要素ないなー)

 ROS2ではアクチュエータの回転や移動にはTwistメッセージをよく使うと思いますが、実際にコントローラからドライバを介して発せられるメッセージはJoyメッセージです。

 おそらく、ほとんどのモータ制御ノード(プログラム)はJoyメッセージを受信してその要素を使用してモータ制御に使うと思います。しかし、私は、マイコンボードを別途ROS2ノードにしてしまっているので、そうはいきません。

 そこで、Joy→Twistに変換できるプログラムを作成したので簡単に解説します。JoyメッセージをTwistに変換するプログラム自体はパッケージが公開されている(?)と思いますが、DualSenseには対応していないみたいなので個人的に作成したプログラムを用いて作り方を簡単に解説します。

なぜJoyそのままはダメなのか?

  1. キーボード入力や他のシミュレーションの入力がTwistだから
    • TurtlesimなどほとんどのシミュレーションがTwistを採用しています。
  2. Twistのほうがサイズが小さいから
    • Joyメッセージはint32型x16の配列とfloat32型x6の配列とHeader(4つのint32)の組み合わせとなりモノにもよりますが、マイコンには大きすぎます。Twistなら、Vector3(float32)x2=実質float32x6の配列だけになり、単純計算でも1受信あたり80byteの節約ができます。実際にはROSのメッセージは動的メモリの確保を行います。
    • 経験上、ESP32でJoyメッセージの送受信はできませんでした。(解決策があれば、ご意見頂けると幸いです)
  3. バージョン依存があるから
    • コントローラを変更するたびにマイコンのプログラムを変えるのは面倒です。当然ながら、長い間同じ仕様のほうが使いやすいです。

簡単な解説

 以下にプログラムを示します。ソースコードGitHubにupしています。

github.com

#include "joy/ps_base.hpp"
#define JOY_VERSION PS5

#include <geometry_msgs/msg/twist.hpp>

#if JOY_VERSION == PS5
    #include "joy/ps5.hpp"
    using namespace ps5;
#elif JOY_VERSION == PS4
    #include "joy/ps4.hpp"
    using namespace ps4;
#elif JOY_VERSION == PS3
    #include "joy/ps3.hpp"
    using namespace ps3;
#endif

class example_joy:public rclcpp::Node, public ps
{
    public:
        rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr twist;
        geometry_msgs::msg::Twist send_data;

        void sub_joy_thread(const sensor_msgs::msg::Joy::SharedPtr msg)
        {
            get_data(msg);
            send_data.linear.x = -1*joy_left_x*127;
            send_data.linear.y = joy_left_y*127;
            send_data.angular.z = -1*joy_right_x*127;
            
            twist->publish(send_data);
        } 

        example_joy(const std::string name, const rclcpp::NodeOptions & options):Node(name, options)
        {
            using namespace std::chrono_literals;
            sub_joy = this->create_subscription<sensor_msgs::msg::Joy>("joy", 1, std::bind(&ps::sub_joy_thread, this, std::placeholders::_1));
            twist = this->create_publisher<geometry_msgs::msg::Twist>("cmd_vel",1);
        }
};

int main(int argc, char** argv)
{
    rclcpp::init(argc, argv);
    rclcpp::NodeOptions options;
    auto node = std::make_shared<example_joy>("joy_test",options);
    
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

パーツに分けて解説します。

1. ファイルのインクルード

 joy/ps_base.hppは、自作のライブラリです。https://github.com/Ar-Ray-code/ps_ros2_commonで使用したものを流用しています。PS5を宣言していればps5.hppがインクルードされます。また、Twistのライブラリを導入しています。(rclcppはps_base.hppで宣言されています。)

#include "joy/ps_base.hpp"
#define JOY_VERSION PS5

#include <geometry_msgs/msg/twist.hpp>

#if JOY_VERSION == PS5
    #include "joy/ps5.hpp"
    using namespace ps5;
#elif JOY_VERSION == PS4
    #include "joy/ps4.hpp"
    using namespace ps4;
#elif JOY_VERSION == PS3
    #include "joy/ps3.hpp"
    using namespace ps3;
#endif

2. Classの宣言

 example_joyクラスを作成します。(名前は任意)

自作クラスには2つのクラス(rclcpp::Nodeとps)を継承します。

class example_joy:public rclcpp::Node, public ps
{
    public:
    
    ...
}

3. メンバ変数の宣言

 パブリッシャの送信用変数とパブリッシュ用スマートポインタを宣言します。(2つ)

// (class内のはなし)
        geometry_msgs::msg::Twist send_data;   // sub_joy_thread関数で宣言してもよい
        rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr twist;

4. Joyメッセージのコールバック関数

 受け取ったメッセージをTwistに変換します。

        void sub_joy_thread(const sensor_msgs::msg::Joy::SharedPtr msg)
        {
            get_data(msg);
            send_data.linear.x = -1*joy_left_x*127;
            send_data.linear.y = joy_left_y*127;
            send_data.angular.z = -1*joy_right_x*127;
            
            twist->publish(send_data);
        } 

 JoyメッセージからTwistへの変換は写真の通りになっています左ジョイスティックは平行移動で、右ジョイスティックは旋回を表します。

f:id:Ray_ar:20210318231934p:plain

5. クラスの初期化(コンストラクタ)

 サブスクリプションとパブリッシャを宣言し、スマートポインタへの代入を行います。sub_joyps_baseライブラリで宣言されています。

        example_joy(const std::string name, const rclcpp::NodeOptions & options):Node(name, options)
        {
            using namespace std::chrono_literals;
            sub_joy = this->create_subscription<sensor_msgs::msg::Joy>("joy", 1, std::bind(&ps::sub_joy_thread, this, std::placeholders::_1));
            twist = this->create_publisher<geometry_msgs::msg::Twist>("cmd_vel",1);
        }

6. main関数

 慣れると、テンプレートのコピペで済むようになります。auto node = make_shard<...>("..",options)は適宜変更してください。

int main(int argc, char** argv)
{
    rclcpp::init(argc, argv);
    rclcpp::NodeOptions options;
    auto node = std::make_shared<example_joy>("joy_test",options);
    
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

動作確認

  • joy2twistと同じようなcmakelist.txtを作成してコンパイルします。joy_nodeをインストールして動かします。うまく動けば、rqt_graphでつながります。引数は必要ありません。

f:id:Ray_ar:20210318231950p:plain

もはやVSCode!?最新のArduinoを試してみた(Arduino IDE 2.0.0-beta3)

 皆さんはArduinoで開発されるときはどの環境を使っているのでしょうか?おそらくArduino IDEVSCodeの2択になると思います。私はこれまでそれほどArduinoのコードを書いていなかったので、純正IDEを使っていました。VSCodeでの環境構築を行ったこともありましたが、パスを探すのが大変だった記憶があります…

 Arduino IDEの最新版の説明に"autocompletion"(自動補完)とあったので、興味を持ちインストールしてみました。意外と使いやすそうなので、従来の1.8.13と比較して簡単に紹介します。

Arduino IDE 2.0.0-beta3のインストール方法

 現在のArduino IDE 2はベータ版のリリースがあります。

Arduinoのダウンロードページへのリンク:https://www.arduino.cc/en/software

f:id:Ray_ar:20210316185259p:plain

ダウンロードされたexeファイルをクリックしてインストールを進めます。インストールは特殊な環境でない限りはデフォルトの設定で問題ないと思います。1.8以前のバージョンと共存させる場合はzipインストールをお勧めします。

起動後

 起動すると次のような画面が出ます。

f:id:Ray_ar:20210316185638p:plain
起動後

デザインは4種類から選ぶことができます。VSCodeではダークテーマを使用しているので試しにダークテーマを選択すると…

f:id:Ray_ar:20210316185804p:plain
ダークテーマのArduino

もはやVSCode!!

新機能

 Arduino2.0以降だとツールバーがあるみたいです。

f:id:Ray_ar:20210316185920p:plain

新しくデバッグツールが実装されています。ボードマネージャーやライブラリマネージャーは埋め込み式になったみたいです。

 その他にも、VSCodeでお世話になる「Ctrl+P」による機能検索や便利な文字検索、文字補完機能も継承されています。

f:id:Ray_ar:20210316190630p:plain

f:id:Ray_ar:20210316190840p:plain
文字検索

(個人的に)惜しいところ

 明らかに便利になるであろうArduino2.0.0ですが、少し個人的に物足りないところもあります。これは、今後の改善で修正されうるので期待しています。

その1. どうしても表記上のエラーが出る場合がある。

 M5Stackのような対象のターゲットを対象にするライブラリの場合、#if defined(ESP32)で条件分岐をすることがありますが、現時点ではこの条件を自動補完してくれません。そのため、実際にはエラーではないが、エラーになる場合があります。現時点ではM5Stackのライブラリに行って#define ESP32を補完することが必要です。

その2. Git機能はついていない

 VSCodeと機能比較をするなら、これはどうしても劣ってしまいます。そもそもArduinoは、「もっとシンプルに、もっと安価に、技術者でない学生でもデジタルなものを作ることができるようにする」(https://ja.wikipedia.org/wiki/Arduino より)というコンセプトに立ち上がったプロジェクトなので、仕方のないことなのかもしれませんが…

その3: メモリ消費量が多い

 VSCodeを引き継いでいるので、仕方のないことかもしれませんが、かなりメモリを消費します。その量は環境にもよりますが、私の場合はGoogle Chrome以上でした。

 Arduino IDEは小学生・中学生もターゲットにしている開発環境なので、低スペックなPCにやさしくない仕様といえます。ただし、コンパイル速度は従来のArduinoと同じくらいです。(実際に10回ほど測ったところ、2.0.0のほうが少し速かったです)

f:id:Ray_ar:20210316192651p:plain
メモリ消費量の比較

その4: 進捗の確認が少し微妙

 Arduinoコンパイラの特色だった進捗バーが実装されておらず、コンパイル結果の色表示もないため、コンパイルされても少し分かりにくいです。慣れればいいだけの話かもしれませんが。

f:id:Ray_ar:20210316192132p:plain

おわりに

 現在、M5 Stackやros2arduino関連でArduinoを使用しており、そのコードに関しては問題なくコンパイルが通りました。面倒な環境構築をすることなくVSCodeのような操作感をArduinoで実現できることを考えれば、かなり便利なエディタに進化したと思います。

 まだ使っていない人は、ぜひこの機会に2.0.0-betaをインストールしてみてはいかがでしょうか?

rqt_graphはWindowsで映せたというはなし

 現在、自宅には4kのディスプレイ1台があります。しかし、UbuntuWindowsどちらを映すかでいつも悩みます…。

 開発においてUbuntuは便利ですし、オフィス系や多くのソフトを扱えるWindowsも使いたいところです。再起動したり、モニタ切り替えとかをするのも面倒なもので、だらしない自分としては1台のコンピュータですべてのタスクをこなしたいところではあります。

 そこで現在、Windows10ですべて開発を進めたいと思い、環境構築にチャレンジしています。確か、プログラム開発はリモートでもVSCodeで扱えたと思うので、sshでのプログラムはそんなに問題にならないし、ファイル転送についても、scpで何とかなるので解決(?)。あとは、リモート操作の最大の障壁といえるGUIです。

 私は、VNCを使ってデスクトップを映すという手が真っ先に浮かびましたが、いらないところまで映したくないなーと気になったり、ウィンドウサイズが小さいと映せる範囲も狭いので何かと不便です。そこで、コマンド実行後に対象ウィンドウのみを映す方法を模索することにしました。

とりあえず実行したこと

qiita.com

↑この手順に従ってX11 Forwardingを行ってみました。大まかな手順としては、

  1. Windows側にvcxsrv-64.1.20.9.0.installerをダウンロードする。
  2. インストーラーのデフォルトの設定でインストールを完了する。(設定はXLaunchで変更可能)
  3. TeraTermを開いて、設定->SSHポート転送 をクリックして「リモートのXアプリケーションをローカルのXサーバに表示する」にチェックを入れて、閉じる。
  4. 設定の保存をする。
  5. 再度Tera Termでログインする。

 私はJetson AGX Xavierと接続しました。

現時点での動作報告

 一応動作したみたいですが、SSH接続後に

Xlib:  extension "NV-GLX" missing on display "localhost:10.0".
Xlib:  extension "NV-GLX" missing on display "localhost:10.0".
Xlib:  extension "NV-GLX" missing on display "localhost:10.0".

というエラー表記が出て、GUIアプリの立ち上がり時に

libGL error: MESA-LOADER: failed to open swrast (search paths /usr/lib/aarch64-linux-gnu/dri:\$${ORIGIN}/dri:/usr/lib/dri)
libGL error: failed to load driver: swrast

というエラーが出たことを確認しました。エラーの解消法は今のところ分かっていませんが…

 rviz2,rqt_graph,rqt_image_viewについて動作確認を行いました。

f:id:Ray_ar:20210314173047p:plain
実行結果

  • rviz2 : コアダンプ

  • rqt_graph : 正常に動作

  • rqt_image_view : 正常に動作せず(バッファが足りないというエラーがPublisher側で確認できた)

 結果、rqt_graphの動作は確認できました。OpenGLのエラーが解消すれば、もしかしたらRvizも動くかもしれませんが、今のところは動作を確認できませんでした。

 ちなみに、Chromium-browserも動かしてみました。これは、少し動作に遅れはありますが、動きました。アプリによって動作するものと動作しないものがあるのでしょうか…?


 Ubuntu用に記述しているGUIプログラムをWindowsでもリモート操作できるようになったので、とりあえず現時点ではOKということで。しかし、現在位置の確認とかをするのにRviz2は必要になってくるので、何か解決策が欲しいところです。


追記:Jetson特有の問題みたいです。Raspiやx86+Geforce環境では動作したみたいです。改善方法が欲しいー

PS5なロボット!? DualSenseをROS2で使う

 最新のPlaystationコントローラのDualSense(PS5純正コントローラ)を購入しました。Ubuntuに接続できたので、メカナムロボットに使用してみました。

 この記事はJetson搭載メカナムロボットとりあえず動いた(Jetson TX2+ESP32+Realsense) - えいあーるれいの技術日記の続きです。この時点ではROS1実装ですが、この機会にROS2に実装しました。

f:id:Ray_ar:20210312230529p:plain
DualSenseでロボット制御

 システムは以下のような構成になっています。

  • DualSense(Dualshock4などでも可)

  • Jetson AGX Xavier

  • ESP32

  • メカナムホイールキット

 通信の流れは以下の通りになっています。

f:id:Ray_ar:20210312232356p:plain
ハードウェアブロック図

プログラムについて

 Joyスティックとの接続とJoy_nodeについては、Qiitaに方法をUPしています。(GitHubへの直接のリンクはこちら→https://github.com/Ar-Ray-code/ps_ros2_common

qiita.com

 上の記事(自分の記事)を参考にしてJoystickのメッセージをTwist型に変換します。GitHubのリンクを以下に示します。(GitHubでの実装はROS Dashing上で行っています。)

github.com

 そして、ESP32にjoy2twistから出力される`cmd_vel'トピックをESP32に送信して、それをもとにメカナムホイールを動かします。Arduinoプログラムを以下のGitHubのリンクを以下に示します。あらかじめMicro-XRCE-DDS-Agentが動くコンピュータを用意してください。

github.com

 回路については説明しません。

動作

 動作の様子です。最新型コントローラな操作感でロボット操作も快適になるかも!?

ROSについて

 ROSとはRobot Operating Systemの略称で、ロボット制御に必要なパッケージや環境が揃っているオープンソースプロジェクトです。企業での産業用ロボット開発から個人のホビーロボット開発まで多くの活用例があります。

 ROS関連の書籍も充実しているのでぜひチェックしてみてください。

(画像をクリックすると詳細ページに移動します)