ROS2ノードとWebServerの接続ができましたので、今回はカメラ画像をブラウザ表示に挑戦します。色々な方々の様々な方法による対応方式を参考にさせていただきました。
私の方針としては、なるべく独自のモノを作らず、簡単な方法で済ませることにしました。
結果として、カメラ出力TOPICに圧縮画像を追加し、それをWeb Serverで受信して表示するだけの簡単なものとすることにしました。
■Web Video表示構成
下図は今回作成したROS2システムをrqt_graphで表示したものです。
青円部分は、ROS2の外側で管理されているWebServerとなります。
「/v4l2_camera」はカメラ撮影ノードです。そこから四角で囲われたTOPICに画像を送信します。
その画像をWebServerが「/rosbridge_websocket」を介して画像を取得します。
TOPICに/image_rawと/image_raw/compressedの2つが存在していることが分かると思います。
/image_rawは、画像生(RGB)データのTOPICを示します。
/image_raw/comprssedは、圧縮画像データ(JPEG、PNG)を示します。
WebServerで扱うのは、圧縮画像データですので、今回のシステムでは、/image_raw/compressedが必須のTOPICとなります。
■前準備:ROS2パッケージ追加
〇 カメラ関連パッケージの追加
今回は、カメラにCSIカメラを接続します。(osoyoo PI CARキットに含まれているので)
このカメラをUbuntuで使えるようにします。
CSIカメラを使えるようにするには、ちょっと面倒でしたので、raspi-cofigを使って有効化します。
raspi-configの導入方法は、「@penguinprogrammer」さんの記事を参考にさせていただきました。
導入後は、CSIカメラを有効化すれば使用可能になりました。
続いて、ROS2のv4l2(カメラ)関連のパッケージを導入し、カメラが正常動作していることを確認します。
$ sudo apt insntall v4l-utils $ v4l2-ctl --list-devices : : ---> mmal service 16.1 (platform:bcm2835-v4l2-0): # /dev/video0の有効化を確認 /dev/video0 $ sudo apt get install ros-humble-v4l2-camera $ ros2 run v4l2_camera v4l2_camera_node # 撮影開始 $ ros2 run rqt_image_view rqt_image_view # 画像確認(下記参照)
〇 画像転送、圧縮関連パッケージの追加
今回は、WebServer上に画像を表示する都合上、JPEG圧縮された画像を配信することにします。
下記のパッケージを導入します。
最重要なパッケージは、ros-humble-compressed-image-transportです。
正直、知識のない自分は、ROS2 Wikiを探しまくりました。
このパッケージを導入するだけで、v4l2_camra_nodeは圧縮画像の配信を開始します。
今回は、このパッケージのおかげで、自前のノード追加を最小限度に抑えることができました。
$ sudo apt install ros-humble-image-transport $ sudo apt install ros-humble-compressed-image-transport $ sudo apt install ros-humble-image-transport-plugins
■ 動画配信用HTML
動画配信用のHTMLは単純です。
v4l2_cameraが出力する圧縮画像をsubscribe(緑部)して、jpeg画像を表示するだけのものです。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/eventemitter2@6.4.9/lib/eventemitter2.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/roslib@1/build/roslib.min.js"></script>
<script type="text/javascript">
var ros = new ROSLIB.Ros({
url : 'ws://192.168.11.202:9090',
options: {
ros_domain_id: '89'
}
});
// this adds error listener.
ros.on('error', function(error) {
console.log('Error connecting to websocket server: ', error);
});
// this adds close listener.
ros.on('close', function() {
console.log('Connection to websocket server closed.');
});
var image_listener = new ROSLIB.Topic({
ros : ros,
name : '/image_raw/compressed',
messageType : 'sensor_msgs/msg/CompressedImage'
});
image_listener.subscribe(function(message) {
console.log('Recived image:' + message.format);
var imagedata = "data:image/jpeg;base64," + message.data;
document.getElementById('camera_view').setAttribute('src', imagedata);
});
</script>
</head>
<body>
<h1>PiCar Camera</h1>
<p><img id="camera_view" src=""/></p>
</body>
</html>
■ 配信テスト
実際に動作させてみました。
まだ、launchファイルは作っていないので、以下のように起動します。
$ ros2 run v4l2_camera v4l2_camera_node # 別セッションで実行 $ ros2 launch rosbridge_server rosbridge_websocket_launch.xml # 同上
結果は下記のような感じです。
フレームの遅れは多少ありますが、操作できないかな?というレベルです。
PiCarを動かす程度なら、問題ないかと思います。
■ 次回
今回は、いかに簡単に作るかということをテーマに作業を行いました。
調べると、様々な方法があり、ROSのディストリビューションで動作しなかったりするなど、わなも結構ありました。結局、この情報を得るのに結構な時間を費やしてしまいました。
この辺りのノウハウ的な情報が整理されると、もっと色々と楽になるような気がします。
でもまあ、画像までは取れるようになったので一安心です。
また、よろしければ見ていただけるとありがたいです。