ROS2 Foxy + YOLO v4 の実装（darknet_ros）

　ROS2 + darknet_ros の組み合わせは[過去のQiita記事](https://qiita.com/Ar-Ray/items/93baac6cc716dc1862fe)で解説しましたが、それはYOLO v3までのサポートでした。

　私はよくYOLO v4-tinyのモデルを使用するので、ROS2でもYOLO v4をサポートしていないかなーーと思い探して見たものの見当たらなかったので、実装しました。

　ここでは従来のdarknet_rosとの違いと使い方について簡単に説明します。コレがあればYOLO v4による物体検出のROS2移行も心配ないですね！(?)

　今回使用するリポジトリのリンクを貼っておきます。気づいた点やバグがあればぜひコメント・issueを送ってもらえるとありがたいです。

https://github.com/Ar-Ray-code/darknet_ros_yolov4

## 従来のdarknet_rosとの違い（修正点）
　将来のROSやOpenCVに対応させたいと思う人が出てくると思うので、どんな感じにdarknet_rosを修正したのかを簡単ではありますが示します。
### Submoduleについて
　darknet_rosの[Foxy実装](https://github.com/leggedrobotics/darknet_ros/tree/foxy)で使用しているdarknetは[pjreddie氏](https://github.com/pjreddie/darknet/tree/508381b37fe75e0e1a01bcb2941cb0b31eb0e4c9)実装のもので、YOLO v3までのサポートです。一方で、YOLO v4の対応は[AlexeyAB氏](https://github.com/AlexeyAB/darknet/tree/e2a128737bcee224088a0076629983e2a4beca01)の実装が必要です。そのため、submoduleへのリンク先を変えました。

### Darknet APIについて
　Darknet APIという言葉自体は無いですが、ROSに対応させるためにいくつか関数やメソッドを用意してあるため、APIと表記します。

　pjreddie/darknet_rosとAlexeyAB/darknetのYOLOのサポートが異なるということは前述したとおりですが、AlexeyAB/darknetの方はOpenCV4に対応しています。OpenCV3からOpenCV4への移行過程でIPLという型が廃止されてしまいます。そして、pjreddie/darknetにおいてはIPLを使っています。
　Darknetの環境構築において「OpenCVは3.??以下を使ってください」という注意書きがあるサイトを見たことがあると思いますが、おそらくIPL依存のライブラリであることが原因です。そのため、AlexeyAB/darknetのAPIではIPLをcv::Mat型に変更する必要があります。ROS-FoxyではOpenCV4.2がデフォルトのバージョンなので、そちらのほうを使ったほうが環境構築も楽です。

※ [leggedrobotics/darknet_ros:foxy](https://github.com/leggedrobotics/darknet_ros/tree/foxy)でもOpenCV4は使えますが、それは__pjreddie/darknetの方__をMat対応させているからです。foxyのサブモジュールである[kunaltyagi/darknet](https://github.com/kunaltyagi/darknet/commit/cb82c21fbbaf06177e49ea20660487b1fbe08d54)のdiffを確認してみてください。個人的には、サブモジュールはやむを得ない場合を除いて本家のものをそのまま引っ張ってくるほうがいいと思っているので、darknet_rosの方を変更する方針にしました。

　結果、submoduleのリンク先とAPIに修正を加えた形になりました。

![Screenshot from 2021-05-12 12-31-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1022754/ae68cfc2-3c13-ac0c-830b-3686a4f5fb2e.png)

　変更箇所については、先日開いたプルリクのdiffを参考にしてください。

https://github.com/leggedrobotics/darknet_ros/pull/319/files

### AlexeyAB/darknetのCMakeLists.txtの削除
　AlexeyAB/darknetにはCMakeLists.txtが含まれています。コレを放置していると、`$ colcon build`などでビルドしたときにエラーになります。しかも、darknet_rosよりも先にビルドされてしまうため、darknet_ros側で対処することができませんでした。そのため、darknetのCMakeLists.txtを消すスクリプトを作成しました。CMakeLists.txtが含まれるdarknetを使うときは必ずCMakeLists.txtを消しておきましょう。

```sh:rm_darknet_CMakeLists.sh
#!/bin/sh
SCRIPT_DIR=$(cd $(dirname $0); pwd)
rm $SCRIPT_DIR/darknet/CMakeLists.txt
```
### CUDA11での注意点（CMakeLists.txt）
　CUDA10とCUDA11では破壊的な変更はあまりなかったようでそのままプログラムが動作しますが、CUDA11では動作するアーキテクチャが異なるので注意が必要です。CUDA11ではKeplerのGPUがサポートされていません。

```cmake:CMakeLists.txt(一部)
  set(
    CUDA_NVCC_FLAGS
    ${CUDA_NVCC_FLAGS};
    -O3
    # -gencode arch=compute_30,code=sm_30
    # -gencode arch=compute_35,code=sm_35
    -gencode arch=compute_50,code=[sm_50,compute_50]
    -gencode arch=compute_52,code=[sm_52,compute_52]
    -gencode arch=compute_61,code=sm_61
    -gencode arch=compute_62,code=sm_62
  )
```

## インストール

　環境構築は過去にQiitaに上げた記事と同じです。CUDA11.2+OpenCV4+ROS-Foxyのセットアップを終わらせたところからスタートです。

https://qiita.com/Ar-Ray/items/93baac6cc716dc1862fe

　ワークスペースの構築とビルドの手順を示します。

```sh
$ sudo apt install ros-foxy-v4l2-camera
$ source /opt/ros/foxy/setup.bash
$ mkdir -p ~/ros2_ws/src
$ cd ~/ros2_ws/src
$ git clone --recursive https://github.com/Ar-Ray-code/darknet_ros_yolov4.git
$ darknet_ros_yolov4/darknet_ros/rm_darknet_CMakeLists.sh
$ cd ~/ros2_ws
$ colcon build --symlink-install
```
## 実行方法
　ターミナル1の実行前にWebカメラを接続して`/dev/video0`を使えるようにしてください。
### ターミナル1

```bash
$ source /opt/ros/foxy/setup.bash
$ source ~/ros2_ws/install/local_setup.bash
$ ros2 run v4l2_camera v4l2_camera_node --ros-args -r __ns:=/camera/rgb
```

### ターミナル2

```bash
$ source /opt/ros/foxy/setup.bash
$ source ~/ros2_ws/install/local_setup.bash
$ ros2 launch darknet_ros yolov4.launch.py
```

![](https://user-images.githubusercontent.com/67567093/117596596-a2c8db00-b17e-11eb-90f9-146212e64567.png)

## 実行環境とパフォーマンス

　yolov4.weightsは非常に重たいモデルなので、十分なスペックのGPUを用意するかyolov4-tinyを使用することをおすすめします。

### 動作環境（ハードウェア）

| 項目 | スペック                                    |
| ------ | --------------------------------------- |
| CPU    | Ryzen7 2700X (@3.7GHz x 16)             |
| RAM    | 16GB DDR4                               |
| GPU    | NVIDIA GeForce RTX 2080 Ti (GDDR6 11GB) |

### 動作環境（ドライバ）

| 項目 | バージョン                                 |
| ------ | --------------------------------------- |
| Driver | 460.32.03                               |
| CUDA   | 11.2                                    |
| OpenCV | 4.2                                     |
| CUDA   | 11.2                                    |
| ROS version   | Foxy (Ubuntu 20.04 LTS)          |

### パフォーマンス

| 項目 | スピード                                 | メモリ使用量            |
| ------ | --------------------------------------- | ------ | 
| YOLO v3 | 67 fps (72 ~ 62 fps) | 1781MB |
| YOLO v4 | 29 fps (27 ~ 30.5 fps) | 3963MB |

## リンク

　このdarknet_rosの実装にあたってとても参考になったリポジトリです。

https://github.com/AlexeyAB/darknet

https://github.com/leggedrobotics/darknet_ros

https://github.com/Tossy0423/yolov4-for-darknet_ros/