ubuntu16.04 YOLOv3 darknet_rosのインストール 

#目的
ROS上でYOLOを動かしたい。
> Robot Operating System (ROS) とは、ロボット用のソフトウェアプラットフォーム（by wiki）

なのですが、SLAM系のプログラムは結構ROS上で動かしているものが多いので、
将来的に他のROS上で動くSLAMと連携させるときとかに使うかなということで、darknet_rosをインストールしました。

ついでにRICHOのTHETAを使ってリアルタイムでの物体認識もやってみたので、その方法についても記していきます。

#環境
ubunu16.04
ROS kinetic
Geforce 1080ti
Nvidia driver 384.
logicoolのwebカメラ


# ROSのインストール
ROSのチュートリアル通りにやればできます。私でも出来たので親切に書かれていると思います。
ROSはubuntuのバージョンでインストールするものが変わります。

ubuntu14.04  -->  indigo
http://wiki.ros.org/ja/indigo/Installation/Ubuntu
ubuntu16.04  -->  kinetic
http://wiki.ros.org/ja/kinetic/Installation/Ubuntu
ubutnu18.04  -->  melodic（英語）
http://wiki.ros.org/Installation/Ubuntu

いずれの場合も無事にインストールできました。
因みにいつもfullバージョンをインストールしています。

```
sudo apt-get install ros-indigo-desktop-full
```

インストールが済んだら**ROS環境のインストールとセットアップ**もしておきましょう。
http://wiki.ros.org/ja/ROS/Tutorials/InstallingandConfiguringROSEnvironment

これでROSのワークスペースが作成できます。


# カメラドライバノードのセットアップ

参考にさせていただきました。:bow_tone2:
https://qiita.com/k65c1/items/b80fd2af67a9880a0fd5
https://qiita.com/dcm_kitade/items/6ff790fbb0a97913265b

まずuvc_cameraをインストールしておきます。

```
sudo apt-get install ros-kinetic-uvc-camera
```
melodicの場合は

```
sudo apt install ros-melodic-libuvc-camera
```
libuvcに変更されているみたいです。

そしてカメラドライバをインストール＆コンパイル

```
sudo apt-get install ros-kinetic-camera-info-manager ros-kinetic-image-view libv4l-dev
cd catkin_workspace/src
git clone https://github.com/ros-drivers/camera_umd.git
cd …/
catkin_make -DCMAKE_BUILD_TYPE=Release
```

インストールが完了したらuvc_cameraのlaunchファイルを編集して、自分のカメラの解像度に変えておきます。

```
catkin_ws/src/camera_umd/uvc_camera/launch$ nano camera_node.launch
```

```
<launch>
  <node pkg="uvc_camera" type="uvc_camera_node" name="uvc_camera" output="screen">
    <param name="width" type="int" value=“640” />
    <param name="height" type="int" value=“480” />
    <param name="fps" type="int" value="30" />
```


# darknet_rosのインストール

```
sudo apt install ros-kinetic-opencv3 ros-kinetic-darknet-ros-msgs ros-kinetic-video-stream-opencv ros-kinetic-cvbridge
```
ros-kinetic-cvbridgeだけないと言われましたがスルーしました。
そして、ROSの環境構築したときに作成したワークスペースに移動しdarknet_rosをgit cloneします。

```
cd ~/catkin_ws/src 
git clone --recursive https://github.com/leggedrobotics/darknet_ros.git 
```

CMakeListsを編集します。

```
atom workspace/catkin_ws/src/darknet_ros/darknet_ros/CMakeLists.txt
```

+のところを追記します。

```
@@ -61,6 +61,10 @@
 # Enable OPENCV in darknet
 add_definitions(-DOPENCV)
 add_definitions(-O4 -g)
+add_definitions(-DCUDNN)
+include_directories(/usr/lib/aarch64-linux-gnu)

 catkin_package(
   INCLUDE_DIRS
@@ -145,6 +149,7 @@
     cudart
     cublas
     curand
+    cudnn
     ${Boost_LIBRARIES}
     ${OpenCV_LIBRARIES}
     ${catkin_LIBRARIES}
```

そしてコンパイル

```
cd ../
catkin_make -DCMAKE_BUILD_TYPE=Release
```


# uvc_cameraノードからカメラのトピック（映像）を受信して動かしてみる

ros.yamlを編集します。uvc_cameraから配信されるトピック名が/image_rawなのでそれに変更します。

```	
atom catkin_ws/src/darknet_ros/darknet_ros/config/ros.yaml
```

```
subscribers:

  camera_reading:
    topic: /image_raw   
    queue_size: 1
```

そして実行。カメラノードを配信するコマンド

```
roslaunch workspace/catkin_ws/src/camera_umd/uvc_camera/launch/camera_node.launch
```

続いて、darknet_rosで受け取り推論するコマンド。

```
roslaunch workspace/catkin_ws/src/darknet_ros/darknet_ros/launch/darknet_ros.launch
```

実はここで以下のようなエラーがでました。
※めちゃめちゃここでハマりました。。。

```
	... logging to /home/okubo/.ros/log/ee47e9a0-341b-11e9-b0d8-37b170e048bf/roslaunch-okubo-	TakemuraLab-16357.log
	Checking log directory for disk usage. This may take awhile.
	Press Ctrl-C to interrupt
	Done checking log file disk usage. Usage is <1GB.
	
	Invalid <arg> tag: darknet_ros
	ROS path [0]=/opt/ros/kinetic/share/ros
	ROS path [1]=/home/okubo/workspace/catkin_ws/src/video_stream_opencv
	ROS path [2]=/opt/ros/kinetic/share. 

	Arg xml is <arg default="$(find darknet_ros)/yolo_network_config/weights" name="yolo_weights_path"/>
	The traceback for the exception was written to the log file
```
# 解決策

ROS_PACKAGEのpathを確認すると、

```
echo $ROS_PACKAGE_PATH
/home/okubo/workspace/catkin_ws/src/video_stream_opencv:/opt/ros/kinetic/share
```
探しているdarknet_rosのpathがないことが発覚。

ROS path[1]の中でvideo_stream_opencvの中を見ているので、darknet_rosの中を探すため、１つ上のdir /home/okubo/workspace/catkin_ws/src もパスに追加します。

```
export ROS_PACKAGE_PATH="/home/okubo/workspace/catkin_ws/src/video_stream_opencv:/opt/ros/kinetic/share:/home/okubo/workspace/catkin_ws/src"
```	
catkin_wsの中でpathを通します。

```
cd workspace/catkin_ws
source devel/setup.bash
```

これで先ほどのコマンドをもう一度打ったら無事成功。
ROS上でYOLOを動かしてみることができました。



# THETAを使ってみる

THETAのSを今回は使いました。
まず、THETAをwifiで接続させます。

ubuntuPCにwifi接続させる方法はコチラ。

次にtheta_image.py ファイルを作ります。（どこでもよいです。今回はworkspace直下に）

```

import io
import json
import inspect
import time
import cv2
import numpy as np
import requests
import signal
import sys

import roslib
import rospy
from std_msgs.msg import String
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError

_DEBUGMODE = True
cam = 'http://192.168.1.1:80'
url = cam+'/osc/'
exe = url+'commands/execute'

# ROS publisher
image_pub = rospy.Publisher("image_raw", Image, queue_size=1)
bridge = CvBridge()

def handler(signal, frame):
        print("Shutting down...")
        sys.exit(0)

# API ver2.0

def startSession():
    j = {'name': 'camera.{}'.format(inspect.currentframe().f_code.co_name), 'parameters': {}}

    r = requests.post(exe, data=json.dumps(j))
    if _DEBUGMODE:
        print("---startSession---")
        print(r.json())
    return r.json()


def closeSession(id):
    j = {'name': 'camera.{}'.format(inspect.currentframe().f_code.co_name), 'parameters': {'sessionId': '{}'.format(id)}}

    r = requests.post(exe, data=json.dumps(j))
    if _DEBUGMODE:
        print("---closeSession---")
        print(r.json())
    return r.json()


def _getLivePreview(id):
    global image_pub
    global bridge
    j={'name':'camera.{}'.format(inspect.currentframe().f_code.co_name),
    'parameters': {'sessionId': id}}
    print(j)
    r=requests.post(exe, data=json.dumps(j), stream=True)
    bytes = b''
    for byteData in r.iter_content(chunk_size=1024):
        bytes += byteData
        a = bytes.find(b'\xff\xd8')
        b = bytes.find(b'\xff\xd9')
        if a != -1 and b != -1:
            jpg = bytes[a:b+2]
            bytes = bytes[b+2:]
            try:
                i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
                image_pub.publish(bridge.cv2_to_imgmsg(i, "bgr8"))
            except:
                print("OpenCV Error")
            '''
            cv2.imshow('live preview', i)
            if cv2.waitKey(1) == 27:
                cv2.destroyAllWindows()
                return
            '''
            #rospy.spin()
    return r.json()

def main():
    signal.signal(signal.SIGINT, handler)
    # ROS settings
    rospy.init_node('theta_livePreview_publisher', anonymous=True)

    # session
    d = startSession()
    if d['state'] == 'error':
        return closeSession('SID_001')

    # api and options
    id = d['results']['sessionId']
    img = _getLivePreview(id)

    # session
    closeSession(id)


if __name__ == '__main__':
    main()

```

thetaのモードをカメラモードにして実行
（※liveモードではできないので注意）

```
roslaunch workspace/catkin_ws/src/darknet_ros/darknet_ros/launch/darknet_ros.launch
python theta_image.py
```



# 実行コマンドまとめ

ターミナルが新しくなると初期化されるので、毎回以下のコマンドを打って始めます。

```
source workspace/catkin_ws/devel/setup.bash
```
- WEBカメラの場合

```
roslaunch workspace/catkin_ws/src/camera_umd/uvc_camera/launch/camera_node.launch
roslaunch workspace/catkin_ws/src/darknet_ros/darknet_ros/launch/darknet_ros.launch
```
- thetaの場合

```
roslaunch workspace/catkin_ws/src/darknet_ros/darknet_ros/launch/darknet_ros.launch
python theta_image.py
```




#　おわり

特に最初THETAを有線接続で動かそうとしてハマりました。結局wifiルータを購入してGALLERIAのPCにさしてwifi接続で何とか成功しました。