ROS2 galacticでMIPIカメラから画像を取る
まえがき
ROS2 galacticで独立差動二輪ロボットを自作しています。今回は自作ロボットに搭載しているラズパイ4にMIPIカメラを取り付け、ROS2のノードで画像を取ってみました。
環境
- ラズパイ4(Ubuntu 20.04LTS) & ROS2 galactic(インストール済みの前提です)
- MIPIカメラ(ArduCamのOV5647を使ったものを使いましたがラズパイ4でサポートしていれば何でもいいんじゃないでしょうか)
手順
MIPIカメラの取り付け
FFCケーブルの表裏を注意して取り付けます。
Ubuntu20.04にMIPIカメラを有効にする設定を追加
kernelがカメラを認識しているかを確認する
v4l-ctlコマンドを使います。v4l-ctlはv4l-utilsパッケージに入っているようですのでインストールします。
$ sudo apt install v4l-utils
コマンドを実行します。
$ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
/dev/video10
/dev/video11
/dev/video12
/dev/media1
bcm2835-isp (platform:bcm2835-isp):
/dev/video13
/dev/video14
/dev/video15
/dev/video16
/dev/media0
Cannot open device /dev/video0, exiting.
/dev/video0
が有効になっていれば認識されているらしいです。Cannot open ...
となっており認識されていないようです。
/boot/firmware/config.txt
に以下を追加します。
start_x=1
gpu_mem=128
以下の行より上に記載したほうが良いらしいです。
include syscfg.txt
include usercfg.txt
OSを再起動します。
もう一度v4l2-ctl --list-devices
で確認します。
$ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
/dev/video10
/dev/video11
/dev/video12
/dev/media1
bcm2835-isp (platform:bcm2835-isp):
/dev/video13
/dev/video14
/dev/video15
/dev/video16
/dev/media0
mmal service 16.1 (platform:bcm2835-v4l2):
/dev/video0
今度はCannot open ...
ではなくmmal service ...
のようになっており、認識されていることがわかります。
v4l2-cameraパッケージの追加
以下を実行してv4l2-cameraパッケージをインストールします。
$ sudo apt install ros-galactic-v4l2-camera
v4l2-cameraノードの実行
以下を実行してv4l2-cameraノードを実行します。
$ ros2 run v4l2_camera v4l2_camera_node
カメラのキャリブレーションファイルが無いのでワーニング・エラーがたくさん出ますが、とりあえず立ち上がります。
ノード名・トピック名の確認
どんなノード・トピックがあるか見てみます。
$ ros2 node list
/v4l2_camera
$ ros2 node info /v4l2_camera
/v4l2_camera
Subscribers:
/parameter_events: rcl_interfaces/msg/ParameterEvent
Publishers:
/camera_info: sensor_msgs/msg/CameraInfo
/image_raw: sensor_msgs/msg/Image
/parameter_events: rcl_interfaces/msg/ParameterEvent
/rosout: rcl_interfaces/msg/Log
Service Servers:
/set_camera_info: sensor_msgs/srv/SetCameraInfo
/v4l2_camera/describe_parameters: rcl_interfaces/srv/DescribeParameters
/v4l2_camera/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
/v4l2_camera/get_parameters: rcl_interfaces/srv/GetParameters
/v4l2_camera/list_parameters: rcl_interfaces/srv/ListParameters
/v4l2_camera/set_parameters: rcl_interfaces/srv/SetParameters
/v4l2_camera/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
Service Clients:
Action Servers:
Action Clients:
$ ros2 topic list
/camera_info
/image_raw
/parameter_events
/rosout
ノード名はv4l2_camera、トピック名は/camera_infoと/image_rawがあるようです。
画像が送られていることを確認
$ ros2 run rqt_image_view rqt_image_view
圧縮した画像データをpublishできる?
生(raw)のデータはトピックとしてpublishしていますが、圧縮したデータはpublishできるのでしょうか?
ROSのドキュメントで確認したところ、image_transportという別のノードを使うようです。
image-transportパッケージの追加
以下を実行してimage-transportパッケージをインストールします。
$ sudo apt install ros-galactic-image-transport
image-transportノードの実行
以下を実行してimage-transportノードを実行します。
$ ros2 run image_transport republish raw
ノード名・トピック名の確認
どんなノード・トピックがあるか見てみます。
$ ros2 node list
/image_republisher
/v4l2_camera
$ ros2 node info /image_republisher
/image_republisher
Subscribers:
/in: sensor_msgs/msg/Image
/parameter_events: rcl_interfaces/msg/ParameterEvent
Publishers:
/out: sensor_msgs/msg/Image
/parameter_events: rcl_interfaces/msg/ParameterEvent
/rosout: rcl_interfaces/msg/Log
Service Servers:
/image_republisher/describe_parameters: rcl_interfaces/srv/DescribeParameters
/image_republisher/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
/image_republisher/get_parameters: rcl_interfaces/srv/GetParameters
/image_republisher/list_parameters: rcl_interfaces/srv/ListParameters
/image_republisher/set_parameters: rcl_interfaces/srv/SetParameters
/image_republisher/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
Service Clients:
Action Servers:
Action Clients:
/image_republisherノードは、/inをsubscribeして/outをpublishしているようです。
トピック/inをv4l2_cameraに合わせてremapします。ついでに/outもremapします。
$ ros2 run image_transport republish raw --ros-args --remap in:=/image_raw --remap out:=/image_raw/compressed
画像が送られていることを確認
$ ros2 run rqt_image_view rqt_image_view
ということで、image-transportを使うことで圧縮画像をpublishすることができました。
launchファイルにまとめる
今回やったことを一つのlaunchファイルにまとめました。
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
v4l2_node = Node(
package='v4l2_camera',
executable='v4l2_camera_node',
output='screen'
)
image_transport = Node(
package='image_transport',
executable='republish',
arguments=["raw"],
remappings=[('in', '/image_raw'),
('out', '/image_raw/compressed')
]
)
return LaunchDescription([
v4l2_node,
image_transport
])
最後に
カメラのキャリブレーションをしたらv4l2のメッセージが消えるかは今後試してみます。
Discussion