えいあーるれいの技術日記

ROS2やM5 Stack、Ubuntuについて書いています

RaspberryPi Camera Module 3 をROSで触る

新しいカメラ「RaspberryPi Camera Module」(ラズパイカメラ3)が来ました。

新しいカメラは撮像素子にSONY IMX708を採用しており、以前のバージョンよりも高解像度になっています。主な機能を以下に示します。


特にHDR機能は大きな機能でしょう。

ソニー製のHDR機能搭載カメラでは、Quad Bayer配列を4画素ごとに採用しており、この中の画素は露光時間をピクセルごとに変更することができます。

隣接した撮像素子ごとに露光時間を変更することで二つの明るさの画像を取得し、これをカメラ側で適切に調整することで画像を取得することができます。

この画像合成によってHDR画像の解像度はHDR機能なしの1/4になってしまいますが、増加した画素数でそのデメリットがカバーされています。


左がHDRなしの画像、右がHDRありの画像です。

右の方がより人が見た景色に近い自然な明るさになっていて、懐中電灯のLEDの形もなんとなく見えると思います。


オートフォーカス

このラズパイカメラ3では、オートフォーカスも搭載されています。

オートフォーカスは、自動焦点機能のことで、対象であろうと思った物体に対してピントを合わせにいきます。

以前からありましたが、このラズパイカメラ3では標準で搭載されています。

以下の映像では、10cm付近まで接近してもリアルタイムでピントを合わせてくれます。すごい。


以上が、ラズパイカメラ3の主な機能でした。

これが5000円未満で買えてしまいます…!(恐ろしい)


ROS2で動くようにしてみた

私は、ラズパイカメラ3が発売される以前にrpi-bullseye-ros2(RaspbianでROS2が動くやつ)向けにpicameraをROS2でラップするプログラムを作成していました。

ros2_v4l2_cameraほどの互換ではないですが、似たような感覚で扱えるパッケージです。

github.com

これのオプションがまだHDRに対応していなかったので、対応させることにしました。


libcamera-appsでは対応が終わっていたので、既に開発が終わっていたのか?…と思っていたのですが、まさかのv4l2コントロールAPIを叩いていたみたいです。

github.com

やっていることは非常に単純で、カメラをオープンにする前に /dev/v4l-subdev にアクセスして V4L2_CID_WIDE_DYNAMIC_RANGE というIDに対して1を書き込みます。


RaspbianにおけるYOLOX-ROSの環境構築方法に従ってYOLOX-ROSの環境構築を行っていざ実践!

ちゃんと動きました。

ただし、固定焦点モードになっているようでした。(確かに固定焦点の方が都合はいいのだが…)


まとめ

今回は、ラズパイカメラ3(RaspberryPi Camera Module 3)を触ってみました。5000円でハードウェアなHDRを触れるというのは非常に面白い体験でした。

オートフォーカスは対象が限られていればとても有効に働くと思うので、工作の幅が広がる面白い機能だと思います。


参考

www.raspberrypi.com

Raspberry Pi カメラモジュール V3www.switch-science.com

RaspberryPi OSでVLP-16をROS2で動かす(RaspberryPi4)

執筆中の記事「RaspberryPi OSで始めるROS2(仮)」に追加される内容を先にブログに投稿しています。

最近TLでVelodyne Lidarの購入報告がたくさん上がっていますね。

最近はMID-360などの小型で広範囲スキャンしてくれるセンサも増えています。

低価格化に伴い、ご家庭の測定機器として一家に一台の時代が到来しているということでしょうか?


しかしながら、中古でも10万近くするLidarを買ってしまうと、それを処理するためのコンピュータ不足に悩まされてしまいますよね(!?)

ここでは、研究室に落ちていたVelodyne(VLP-16)をRaspberryPi OS + Raspbianで動かす方法について説明したいと思います。

Raspbianは、RaspberryPi向けに作成された軽量Linuxで、Rvizも軽快に動きます。


ここでは、VLP-16のソフトウェア側の構築方法を説明します。配線などは、説明書や他の記事を参考にしてください。

ほとんどの場合は、Jetson XavierやOrinやゲーミングPC上で環境構築をして動かした方が幸せになれます。


必要なもの

  • VLP-16
  • 変換コネクタ
  • RaspberryPi4 Model Bとその周辺機器
  • RaspberryPi OS (64bit) が書き込まれたSDカード


RaspberryPiの環境構築

ROS2のインストール

RaspberryPiではない場合、ROS2 Documentationを見ながら環境構築すれば大体解決します。

ここからのコマンドは、RaspberryPi OSの初期設定が終わった直後の状態を想定しています。

sudo apt update && sudo apt upgrade
sudo apt install -y libpcl-dev libyaml-cpp-dev libpcap-dev

wget https://s3.ap-northeast-1.wasabisys.com/download-raw/dpkg/ros2-desktop/debian/bullseye/ros-humble-desktop-0.3.1_arm64.deb
sudo apt install -y ./ros-humble-desktop-0.3.1_arm64.deb


ソースコードの取得

ros2_wsワークスペースとします。

依存関係を自力で解決しなければならないので、package.xmlを見ながらソースコードを追加していきます。

velodyne.gitを含む3つのパッケージで動くと思います。

mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src

git clone https://github.com/ros-drivers/velodyne.git -b ros2
git clone https://github.com/ros/angles.git -b ros2
git clone https://github.com/ros/diagnostics.git -b humble


ビルドします。

source /opt/ros/humble/setup.bash
cd ~/ros2_ws/
colcon build


IPアドレスの探索

Velodyneはデフォルトで10.0.0.201に設定されていますが、変更される場合もあります。その場合、外部からは見つからないため、wiresharkで探す必要があります。

sudo apt install -y wireshark
# 青画面が出た場合はyesを選択
sudo wireshark


Velodyneイーサネットに直接続している場合はeth0を選択する必要があります。

ここでは、192.168.0.200が見つかったので、dhcpcd.confを編集する必要があります。

sudo nano /etc/dhcpcd.conf
# 末尾に追記
interface eth0
static ip_address=192.168.0.100/24
static routers=192.168.0.1


編集したらCtrl+oで保存→Ctrl+xで終了して再起動します

ifconfigを実行してeth0欄で192.168.0.100となっていればOKです。

再起動しない場合は、sudo systemctl restart networking.service && sudo service dhcpcd reloadで読み込めると思います。

WebブラウザでVLP16のIPアドレス(ここでは192.168.0.200)にアクセスして設定が可能です。


VLP16の起動

ターミナル1

Velodyneのドライバです。デバイスIPアドレスとモデル名は適宜変更してください。

source ~/ros2_ws/install/setup.bash
ros2 run velodyne_driver velodyne_driver_node --ros-args -p device_ip:="192.168.0.200" -p model:="VLP16"


ターミナル2

ROS2のPCL2形式に変換するノードのようです。

source ~/ros2_ws/install/setup.bash
ros2 launch velodyne_pointcloud velodyne_convert_node-VLP16-launch.py


ターミナル3

最後に、可視化ツールRvizで開きます。

source ~/ros2_ws/install/setup.bash
rviz2
# frameをvelodyneに設定
# pointclound2を選択して/velodyne_pointsを開く


レンダリングしなければ、UDPでデータが流れてくるだけなので、それほど重くはなりません。

しかし、点群処理を行うには性能がかなり厳しいかもしれないので、工夫が必要です。


参考資料

https://velodynelidar.com/wp-content/uploads/2019/12/63-9243-Rev-E-VLP-16-User-Manual.pdf

https://qiita.com/akira-sasaki/items/dff6f7c4196884d6746f


Wasabi Cloudに課金しました。

みなさんはクラウドストレージといったら何を思い浮かべますか?

Google DriveAWS S3?

昨年の中旬、私はWasabiクラウドを契約して実際に少しずつデータを移行しています。

主にdpkgやラズパイのOSイメージを配布する際に使用しようと考えています。


そもそもクラウドストレージが必要か

私はしばしば他のプラットフォームに対してクロスコンパイルを行うことがあり、これまでもいくつか成果物があります。rpi-bullseye-ros2はその中でも大きな成果です。


rpi-bullseye-ros2 : RaspberryPi OS向けのROS2-Desktopパッケージ

github.com


このようなパッケージは一般家庭用i9などのリソースであってもコンパイルに数時間かかるため、パッケージ化して配布できることは非常に大きな意味を持ちますが、一方でバージョン管理や対応プラットフォームの拡張を考えると際限なくストレージを食い尽くしていきます。

私はこのようなパッケージについては、元々GitHubのリリースページで配布していましたが、GitHubのリリースページでは対応に限界があることや1つのファイルにつき2GBまでの制限があることが少し煩わしく感じていました。


ちょうどその頃、AIの動物園(PINTO_model_zoo)や変換ツールで有名なPINTOさんWasabiクラウドに移行するとのことで、その手のクラウドも使ってみようと思いました。

PINTO_model_zooでは、毎日のように大量のダウンロードがあるそうで、現在のGoogleDriveではアクセス落ちが頻発していたそうです。すごい…


Wasabi cloudとは

詳しくは以下URLより

About Us | Wasabi - Wasabi

Wasabi cloudは、「クラウドデータストレージのコストを削減してより高速でシンプルなサービスを提供する」ことを目的に David Friend と Jeff Flowers の 2 人によって設立されました。


Wasabiクラウドのメリット・デメリット

メリット

1. 高コスパ

Wasabiクラウドの料金には2種類あり、「Pay As You Go」(従量課金)と「Reserved Capacity Storage」(年契約)があります。

後者は100TB単位での契約となるため、個人は「Pay As You Go」の方で契約となります。


「Pay As You Go」は1TB毎に5.99ドルの課金が発生します。

6ドルは1ドル=130円であれば780円/月です。

…と言ってもよく分からないかもしれませんが、計算ツールで他のクラウドと比較すると、圧倒的に安いことがわかります。

Cloud Storage Pricing: Wasabi vs Azure, Google & AWS S3 Pricing

比較サイト(wasbiクラウド)では1TB〜1PBまでの料金シミュレーションです。1TBからはほとんど比例して金額が上昇しますが、Wasabiクラウドは他のクラウドサービスよりも1/5以下でストレージを実現します。

他のストレージとしてはGoogle Oneもありますが、こちらは2TBで1300円かつ他のサービスも利用できるので、Wasabiクラウドよりも安くなります。

しかし、APIリクエスト制限がGoogle Driveにあるため、使いにくさがあります。


2. 下り料金ゼロ

サーバの送受信にはその通信量に応じて料金がかかるのが基本となりますが、Wasabiクラウドはそれがゼロです。

大きなデータを保存する際は、受信時に料金がかかるのは大きな負担になるのでありがたいところです。

また、妨害目的の意図的な大量リクエストに対して対策になります。


3. AWS S3互換

S3とは「Simple Storage Service」の略で、クラウドストレージのことです。

S3にはバケットごとに対してAPI経由のアップロード・ダウンロード・同期などの操作を行ったり、URLを公開してアクセス可能にしたりできます。

Wasabiクラウドでは、AWS S3と互換性があり、GUIでの操作感こそ異なりますが、CLI操作はURLを除いてほとんど同じ(というかaws-cliを使える!)なので、AWSの公式チュートリアルを読んでも操作できます。

また、Amazon S3が謳っている「11 nines availability」(99.999999999%の可用性)も同様に実現させています。

11 nines availability (99.999999999% availability) とは、複数リージョンに対して冗長に保存することで耐久性・可用性を確保することを保証します。1 つのオブジェクトで損失が起きる予測平均発生率は、10,000 年に 1 度とされています。

Amazon S3 Glacier ストレージクラス | AWS


デメリット

ほとんどないと言ってもいいかもしれませんが、次が挙げられるかもしれません。

1. 1TBまではコスパが悪くなる

Wasabiクラウドは最低料金が1TB基準になります。

そのため、一切使わなくても1TB分の料金がかかります。これは、使用分だけ課金されるAWSや課金の必要がないGoogle Driveと比べると良くないでしょう。

公開するデータが非常に大きくなることを見据える場合に検討すると良いでしょう。


2. 他のAPIとの結びつきが弱い

AWS S3互換ですが、結局はAWSのサービスではないため、AWSの豊富な資力と比べると物足りないかもしれません。


Wasabiクラウド資源の使い道

Wasabiクラウドは私が主催している講習会(NITKK-ROS-Team)や独自に作成したプロジェクトの環境構築コストの短縮に大いに役立つため、こちらに使用しています。


Ar-Ray-code/Installer

サポートが不十分なOSSライブラリのインストール用バイナリをdpkg形式で提供します。

現時点では OpenVINO(Raspbian)とTFLite(C++, amd64)向けに提供していますが、要望があればDiscussionsに記入してください。

できる限り対応します。

github.com


Ar-Ray-code/rpi-bullseye-ros2

このパッケージはRaspberryPi OS Bullseye向けにROS-Desktopを構築するためのパッケージです。

RaspbianでRviz2が動きます。

こちらは、dpkgでインストーラを配布したり、RaspiOSのイメージを配布する予定です。

最初はgpgキーを登録してupdateさせることでインストール可能にしていたのですが、apt-updateを行うメリットが薄いため直接ダウンロードさせることにしました。

また機会があればaptlyを使って登録したいですね…

github.com


現時点でのインストール方法です。

最新のURLは各リポジトリを確認してください。それらを集めたgithub.ioを作成予定です。

wget https://s3.ap-northeast-1.wasabisys.com/download-raw/dpkg/ros2-desktop/debian/bullseye/ros-humble-desktop-0.3.1_arm64.deb
sudo apt install ./ros-humble-desktop-0.3.1_arm64.deb


学生向けROS交流コミュニティを作りました(Discord)

あけましておめでとうございます。今年もよろしくお願いします。

2023年は、私はいよいよ新社会人ということで間違いなく大変な年になりそうな予感です…


みなさん多忙なはずなのにかなりの進捗を生んでるので、私は生き残れるのでしょうか…

そんな感じですが、今年も変わらず更新を頑張ろうと思います。


学生コミュニティ!?

実はあまり言っていなかったのですが、実は私は以前から「NITK.K ROS-Team」という講習会兼コミュニティを運営していまして、今年度からさらにオープンにする活動を行っています。

「運営」と言っても資金ゼロ、アクティブメンバーで研究室を超えて講習を行っているだけの小規模なものなんです…


今回は、そんな「ROS-Team」のオープンコミュニティ枠を紹介します。


NITK.K ROS-Teamとは

NITK.K ROS-Teamは、Microsoft Teams上で活動している高専内の研究室内でのグループです。

主にROS2の初学者に対して講習を行うことが目的です。今年度は4月〜6月で全6回程度行いました。


正式には高専名を取って「NITK.K ROS-Team」と言いますが、特定の高専にとどまらなくなっているため、「ROS-Team」と呼んでいます。


ROS-Teamでは、これまでドキュメントの積み重ねと連携が難しかった研究室をまたがるような研究に対してROS2などのエコシステムを駆使して連携を取ろうとしています。

実際には昨年度から講習自体は行っており、他学科を跨いだ研究連携を実現させています。

ROSであれば、入出力がドキュメントがなくても推測が容易で、他のプログラムとの連携も行いやすいため、ドキュメントを残す手段として非常に有用だと考えています。


高専を超えて…

今年度は他の学校との連携を模索するためにSlackの使用を検討していました。Teamsは高専のメールアドレスが基本必要ですが、Slackであれば招待も送りやすいです。

しかし、ちょうど悪いタイミングでSlackの規約が変わってしまい、使い勝手が非常に悪いものになってしまいました。

90日でデータが消えるのは少し勿体無い。


そんな時、Twitterの流れを受けて(?)闇のエンジニア兼ブロガーのからあげ先生がDiscordサーバを建てたそうで、そちらがそこそこ使いやすそうでした。

karaage.hatenadiary.jp


Discordはチャットや音声チャットを行えるクローズドSNSです。ゲームユーザやプログラマに人気です。

無料でもかなり余裕持ってサービスを利用できるので、こちらでサーバを作成しました。

誰でも参加可能です。詳しくは以下のURLから確認してみてください。

nitkk-ros-team.github.io


初心者向けだったはずなのに…?

私が募集したせいか、結構私のTLの人が入ってくれました。一応Teams側でも募集はしたのですが…

私のTLは明らかに時間に対する進捗が1桁異なるレベルのつよつよばかりで、初心者向けのはずのオープンコミュニティはあっという間に「猛者の集い」と化してしまいました。


なんと、からあげ帝国の主も現れました!?

からあげ先生!?(掲載許可をいただきました。ありがとうございます)

かなりカオスな状況になっていますが、心強いですね。


これからの運用

オープンな講習資料作成に興味を持っていただいている方も多いので、こちらではオープンな資料の共同作成を進めていこうと考えています。

ROS-Teamの「学生視点での講習の提案」を実現するために、講習手順などのシステム化を進めていきたいと考えています。

最終的には、ドキュメント化されたつよつよをこのコミュニティから輩出して世界征服します社会に貢献していければと考えています。


1月中旬?にはイベントの発表も予定しています。

ROSを触ったことない人や別分野だけど講習の方法に悩まれている方はぜひ私たちの活動を見てください↓

NITK.K ROS-Team Homepage

YAMLでComposableNodeを起動する(ROS2・launch_yaml)②

この記事はROS2アドベントカレンダー2022、12/18 の記事です。


同じアドベントカレンダーでcomposable nodeを含むlaunchをPythonからxmlに置き換える記事が出ています。

qiita.com

記事中の 冗長なPythonのlaunchを書く必要があったのですが、HumbleからはXMLで記述できるようになりました。 を見て、

これは、yamlについて書かなくては…! と思ったので私もまた言及しようと思いました。


(ちなみに、composable_nodeをyamlで呼び出すこと自体は半年前の記事にあります。)

YAMLでComposableNodeを起動する(ROS2・launch_yaml) - えいあーるれいの技術日記


バージョンを重ねるたびに機能が追加されており、composable_nodeはROS-Humbleからの機能です。


LaunchのYAMLXML(仕様)

launch_rosでは、Pythonからのlaunch操作は直接呼び出して、それ以外はParserを介して解釈させます。

解釈されたタグをもとに @expose_action(node_container) などのデコレータ関数に飛ばします。

github.com

仕組みがコレなので、XMLYAMLの仕様は同一というわけです。

XMLで使えるものはYAMLでも使える(はず)です。

解釈部分については launch 内の launch_yaml と launch_xml に記載されています。

github.com

LaunchのYAMLXML(記法)

でも、XMLYAMLはぱっと見る感じ全然違う雰囲気があるのですぐ乗り換えるのはな〜…と思いがちですが、

いくつかポイントを押さえれば簡単です。

(元記事の「XMLでの記述方法」を参考に説明します。)

qiita.com


ハッシュ

ハッシュとは、YAMLキーワード: 値 の組み合わせのことです。

素数は一つだけでなく、複数にすることもできます。

# ハッシュの例
a: b
b:
  c: d
  d: e
  f: g


XMLの属性(abc="def"のように記述するやつ)はすべてハッシュで記述されます。

例えば、以下のように書かれているxmlがあるとします。

<node_container pkg="rclcpp_components" exec="component_container" name="my_container" namespace="" args="test_args"/>

これをYAMLに直すと次のようになります。

node_container:
    pkg: "rclcpp_components"
    exec: "component_container"
    name: "my_container"
    namespace: ""
    args: "test_args"


配列

配列は - で接続された主に複数の要素を記述するものです。

こちらは、XML名前空間入れ子にする際に使用します。

例えば、以下のように書かれているxmlがあるとします。

<load_composable_node target="my_container">
  <composable_node pkg="demo_nodes_cpp" plugin="demo_nodes_cpp::ParameterBlackboard" name="board2" namespace="test_namespace">
    <param name="test" value="aaa" />
    <extra_arg name="use_intra_process_comms" value="true" />
  </composable_node>
</load_composable_node>

これをYAMLに直すと次のようになります。

- load_composable_node:
     target: "my_container"
     composable_node:
        -
          pkg: demo_nodes_cpp
          plugin: "demo_nodes_cpp::ParameterBlackboard"
          name: "board2"
          param:
             -
               name: "test"
               value: "aaa"
          extra_arg:
             -
               name: "use_intra_process_comms"
               value: "true"

値が紐づけられない名前空間の接続は全て配列になっています。


以上を踏まえて、先の記事のXMLからYAMLに変換したコードを以下に示します。

launch:
    - node_container:
        pkg: "rclcpp_components"
        exec: "component_container"
        name: "my_container"
        namespace: ""
        args: "test_args"
        composable_node:
           -
             pkg: demo_nodes_cpp
             plugin: "demo_nodes_cpp::ParameterBlackboard"
             name: "board1"
             namespace: "test_namespace"
             param:
             -
               name: "test"
               value: "aaa"
             extra_arg:
             -
               name: "use_intra_process_comms"
               value: "true"
    - load_composable_node:
             target: "my_container"
             composable_node:
               -
                 pkg: demo_nodes_cpp
                 plugin: "demo_nodes_cpp::ParameterBlackboard"
                 name: "board2"
                 namespace: "test_namespace"
                 param:
                 -
                   name: "test"
                   value: "aaa"
                 extra_arg:
                 -
                   name: "use_intra_process_comms"
                   value: "true"


demo_nodes_cpp の talker_listener.launch.py も次のように書けます。

launch:
  - node_container:
      pkg: "rclcpp_components"
      exec: "component_container"
      name: "my_container"
      namespace: ""
      composable_node:
        -
          pkg: "demo_nodes_cpp"
          plugin: "demo_nodes_cpp::Talker"
          name: "node_talker"
          remap:
          -
            from: /chatter
            to: /talker_listener
        -
          pkg: "demo_nodes_cpp"
          plugin: "demo_nodes_cpp::Listener"
          name: "node_listener"
          remap:
          -
            from: /chatter
            to: /talker_listener


まだまだある!?オプション

launch/test_executable.py at galactic · ros2/launch · GitHubより

launch:
    - executable:
        cmd: ls -l -a -s
        cwd: '/'
        name: my_ls
        shell: true
        output: log
        'launch-prefix': $(env LAUNCH_PREFIX '')
        env:
            - name: var
              value: '1'

ls コマンドをルートディレクトリに対して行うlaunch.yamlです。executableキーを使用して実行するみたいです。


launch/test_include.py at humble · ros2/launch · GitHubxml)より

launch:
    - let: { name: launch_path, value: "/opt/ros/humble/share/demo_nodes_cpp/launch/topics/" }
    - include:
        file: "$(var launch_path)talker_listener.launch.py"

他のlaunchファイルもyamlで実行できます。

includeもとを辿る方法は見つけられませんでした…

ROS1で見られた $(find <pkg>) は使えませんでした。


サンプルが少ないので流行りにくさは感じますが、かなりスッキリとかけると思います。