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

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

UnityのRenderTextureをROS2で可視化する(Unity・ROS2・初学者)

初めてUnityを触る機会がありました。

なぜUnityを触りだしたかというと、私が現在開発しているYOLOX-ROSをバーチャル環境上でシミュレーションしたらデモとして最高なんじゃね?と思ったからです。

これまで私は画像認識系のプログラムの動作デモの画像を作るときは、Webカメラからのキャプチャ画像をスクショしていました。

しかしながら、画像だけだと移植元の物体検出プログラムとあんまり変わらないREADMEになっちゃうし、いまいちインパクトに欠けるなと感じていました。

そこで、これからはメタバースの時代ということで最新のプログラムを仮想世界に持っていくことにしました。バーチャル上の映像でもお試しできるなんて新時代ですよね!?


こうしてAr-Rayは個人的未開の地であるシミュレーションの道へと突き進むのであった…

ROSのシミュレーションといえば…?

ROSのシミュレーション環境といったらGazeboだと思っていたのですが、最近だとUnityのほうが人気みたいです。

ということでUnityの環境構築をしてレッツプログラミング!C#?なにそれ…


ここから先は実装までの過程を書くので、プログラムだけ気になる方は以下のGitHubリポジトリをご確認ください。使い方などもそのリポジトリのREADMEに載っています。わからないことがあればTwitterやissue欄で教えてください。

github.com

ググりまくる

あいにく私の手元にはUnityの本がなかったので、「ROS2 Unity」とかのキーワードを使って検索しまくりました。

すると最初にROS関連でよくお世話になっている片岡さんの記事を見つけました。どうやらros2-for-unityというプログラムが速くていいらしいです。

zenn.dev

シミュレーションつよつよな方のオススメを無視するわけには行かなかったので、私はros2-for-unityのコードを参考に実装していくことにしました。

当然かもしれませんが、都合よくros2-for-unity + 画像処理を使ったプログラムが見つかるわけもなく、この後自分のC#力の低さやUnityのComponentの考え方が全く理解できないことが壁となり苦戦しまくることとなりました…

実装したい内容

ここで、当初私が作りたかった手法を以下の画像に示します。

言葉にしたらとってもシンプル。Unity上のカメラ映像をROS2用の画像データにして公開するだけです。

f:id:Ray_ar:20220131210243p:plain

しかしながら、Unity歴1日の私にはとても苦しいことがありました。それは次の2点です。

  • カメラからの画像の取得方法が分からない。(RenderTextureが分かっていないため)
  • これまでcv_bridgeを使ってきたためか、どのようにしてカメラ画像をsensor_msgs/Imageに値を埋め込めばいいのか分からなかった。

他にもデバッグログが出せないとか入出力先の指定方法がわからないなどの実装以前の悩みを抱えながら実装を始めました。

かなり参考になった情報

カメラから画像を取得するときはRenderTextureオブジェクトを使えば良いということが分かってきた頃、「Unity RenderTexture 保存」みたいなワードで探している途中で「な、なるほどーー」と思った記事に遭遇しました。

styly.cc

この記事は、カメラの映像と3D物体をRenderTextureオブジェクトを用いて紐付けるという内容が書かれていました。

記事とこの実装が直接関係しているわけではないのですが、RenderTextureの指定先を自由に変更可能であることと、RenderTextureさえ弄れれば画像を公開可能であるということが分かったのがとても大きかったです。


試行錯誤の末、ようやく形になりました。

この時の実装の様子を以下の画像に示します。

f:id:Ray_ar:20220131211905p:plain


なぜわざわざInt16MaltiArrayに直しているのか。これは下手にsensor_msgs/Imageに直接変換してわけわかんないことになるよりも、メッセージが見やすい型で送ったほうが良いだろうと思ったからです。結果、初歩的なエラーをなんとかデバッグコンソールを読みつつ解決することができ、正しく画像の送受信を実現することができました。このときは、「IntMultiArray、何でも入れられるので最強なのでは」と思ってしまいました。

cv_bridgeを実装

当然ながらこの2工程は明らかに無駄だし他の人からすれば何やっているのかさっぱりだと思ったので、省くことにしました。

これまで画像を送受信するときはcv_bridgeを使っていましたが、UnityにはもともとOpenCVがインストールされていないので、自分でcv_bridge風のプログラムを書くことにしました。

cv_bridgeとは?:ROS2の独自型とOpenCVの型を変換するライブラリ。ROSは画像の取扱にOpenCVではなく、独自のメッセージ型を使用する。そのため、OpenCVの型で画像を扱うために型変換を送受信前後に挟む必要がある。

cv_bridgeのコード(noeticブランチ)は以下のURLから確認できます。

github.com

特に難しい処理をしているわけでもなかったので、そのまま2重ループを使って実装しました。デフォルトだと上下左右反転された画像が公開されてしまっていたので、その処理がややこしいというか少し面倒でした。

最終的にはInt32MultiArrayを削った以下の図のような感じの実装になりました。

f:id:Ray_ar:20220131213035p:plain

まー順当。


YOLOX-ROSとの連携もしてみました。特に遅延も感じず、いい感じのデモが完成しました!

https://github.com/Ar-Ray-code/RenderTexture2ROS2Image/raw/main/images_for_readme/unity-demo.gif

このプログラムは、README付きでアップしています↓

github.com

実装を通して

この実装を通して、同じ1日間、本を読んだり座学を受けるよりも勉強になったのでは?と思えるくらいUnityやC#を扱えるようになりました。手を動かすのが最も効率いいんだなーと改めて感じられるいい機会になったと思います。


これからちまちまと知識を吸収して現実世界とUnityを繋いでデモできる環境を整えていきたいですね。