ROS Kineticで複数カメラノードの起動

# 動機・目的
個人的には、複数のUSBカメラを同時につないで、やりたいことがあるのだけれども、以前のようなyamlファイルの置き方だと、設定ファイルを複数置くことができなくなってしまう。それぞれのカメラに対して、calibration URLを指定して、各カメラノードを適宜していするようにしたい。


# 環境
- Ubuntu 16.04 LTS
- ROS Kinetic Kame
- USBカメラ（Logicool C270　UVC対応）1台
- USBカメラ (Logicool C525 ) 1台

本当は、同じカメラで揃えたかったが、とりあえず今回は起動テストということで、別の型のを使用。



#複数カメラの指定と呼び出し

[ROSでARマーカーの認識（その１）](https://blog.goo.ne.jp/yggdrasill033/e/ee203f88f424c25fabac0d67b6502bbd)
を参考にすると、camera_nodeの実行時に、

```
$ rosrun uvc_camera uvc_camera_node _device:=/dev/video0 _camera_info_url:=file:///home/{user_name}/.../camera.yaml
```
とURLを指定してやることで、個別にノードを実行できるようだ。
各パラメータ前の”_”のつけ忘れに注意。
launchファイルにこの設定を書き込めば、複数のカメラが立ち上がった時に、それぞれにファイルを指定して読み込ませることができそう。


キャリブレーションファイルは、こんな感じ

```python:camera_red.yaml
image_width: 640
image_height: 480
camera_name: camera
camera_matrix:
  rows: 3
  cols: 3
  data: [731.92302, 0, 284.494982, 0, 734.366434, 215.848372, 0, 0, 1]
distortion_model: plumb_bob
distortion_coefficients:
  rows: 1
  cols: 5
  data: [0.069866, -0.208815, -0.014744, -0.010224, 0]
rectification_matrix:
  rows: 3
  cols: 3
  data: [1, 0, 0, 0, 1, 0, 0, 0, 1]
projection_matrix:
  rows: 3
  cols: 4
  data: [737.895264, 0, 279.179763, 0, 0, 741.738281, 211.069042, 0, 0, 0, 1, 0]
```
camera_nameをcameraにしていないと、warningが出る。
（他との対応関係の理解がまだまだ...）



# カメラノードをlaunchファイルからの呼び出し

ということで、launchファイルの書き方を復習がてら、改造してみる。

カメラ一台のノードを立ち上げて、ビューワーノードを立ち上げるには、

```python:camera_single.launch
<launch>
  <node pkg="uvc_camera" name="camera1" type="uvc_camera_node" output="screen">
    <param name="device" type="string" value="/dev/video0"/>
    <param name="width" type="int" value="640"/>
    <param name="height" type="int" value="480"/>
    <param name="pixel_format" value="mjpeg"/>
    <param name="camera_frame_id" value="usb_cam"/>
    <param name="io_method" value="mmap"/>
    <param name="frame_id" value="camera"/>
    <param name="camera_info_url" type="string" value="file:///home/{user_name}/.../camera.yaml"/>
  </node>

  <node name="image_view" pkg="image_view" type="image_view" output="screen">
    <remap from="image" to="image_raw">
    </remap>
  </node>
</launch>
```
のように書けばよさそう。各パラメータをノードに付随して指定していける。
また、カメラの設定ファイルは、camera_info_urlで絶対パスで指定することができる。
/{user_name}/.../は、それぞれ好きなディレクトリを、ファイルを保存した場所に。

1つ目のノードの名前（name）や、device paramのvalueなどは、それぞれの環境や好みでつける。

ビューワー側のノードの指定パラメータはまだ勉強中（remapあたりがまだ完全に理解していないなぁ）。

とりあえずは絶対パスの表現になっているので、今後、パスの指定方法を変更したい。事前に登録した環境変数、相対パスなども使用可能だろうか。


複数のUSBカメラを1台のPCにつなぐときは、ポートの帯域が足りなくなることが原因で思ったとおりの動作をしない情報も目にしているので、複数台のカメラを使うときは気をつけなければならないようだ。


# 2台以上のカメラ接続

1台の設定が終わったので、2台の場合を考えていく。
追加したいカメラ1台を、前回の方法でキャリブレーションを実行して、設定ファイルを作っておく。（カメラとファイルの紐付けが対応つくように、カメラにシールや名前をつけて、ファイルとの対応が間違わないようにする。）

前回の方法で、nodeの起動確認をしたりすれば、やはり最後はlaunchファイルにまとめてしまいたい。


2台以上のノードを立ち上げるときは、トピック名がかぶっていると混線するので、groupタグを使って分離。groupでnamespace(ns)を分けていれば、ノード名やトピック名がかぶっていても大丈夫。

[ROS launchファイルの使い方](https://kazuyamashi.github.io/ros_lecture/ros_launch.html)

```python:camera_multi.launch
<launch>
  <group ns="camera_blue">
    <node pkg="uvc_camera" name="camera0" type="uvc_camera_node" output="screen">
      <param name="device" type="string" value="/dev/video0"/>
      <param name="width" type="int" value="640"/>
      <param name="height" type="int" value="480"/>
      <param name="pixel_format" value="mjpeg"/>
      <param name="camera_frame_id" value="usb_cam"/>
      <param name="io_method" value="mmap"/>
      <param name="frame_id" value="camera_blue"/>
      <param name="camera_info_url" type="string" value="file:///home/{user_name}/.../camera_blue.yaml"/>
    </node>

    <node name="image_view_blue" pkg="image_view" type="image_view" output="screen">
      <remap from="image" to="image_raw">

      </remap>
    </node>
  </group>

  <group ns="camera_red">
    <node pkg="uvc_camera" name="camera1" type="uvc_camera_node" output="screen">
      <param name="device" type="string" value="/dev/video1"/>
      <param name="width" type="int" value="640"/>
      <param name="height" type="int" value="480"/>
      <param name="pixel_format" value="mjpeg"/>
      <param name="camera_frame_id" value="usb_cam"/>
      <param name="io_method" value="mmap"/>
      <param name="frame_id" value="camera_red"/>
      <param name="camera_info_url" type="string" value="file:///home/{user_name}/.../camera_red.yaml"/>
    </node>
  
    <node name="image_view_red" pkg="image_view" type="image_view" output="screen">
      <remap from="image" to="image_raw">
      </remap>
    </node>
  </group>
</launch>

```
今回は、対応確認とカメラを見分けるために、redとかblueとか名前を付け替えたりしているが、適宜それぞれ好きにできそう。


別に端末を立ち上げて、

```
$ rqt_graph
```
とすると、今回作ったノードとトピックの関係が可視化できる。

![rosgraph.png](https://qiita-image-store.s3.amazonaws.com/0/233094/7d1cd31f-d53c-84b8-058e-05d1f9acde49.png)


launchファイルの書き方は、こちらも参考になった。
[極楽とんぼのロボット製作記　【ROS】一斉にnodeを起動するLaunchの書き方](http://www.g104robo.com/entry/ros-launch)


# おわりに

つぎは、ROSのパッケージにある、ARを利用して、マーカーの（もしくはマーカーに対するカメラの）姿勢を取得することを調べる。