コンテンツへスキップ

ROS(ロボット・オペレーティング・システム)クイックスタートガイド

ROS Introduction (captioned)fromOpen RoboticsonVimeo.

ROSとは何か?

ロボット・オペレーティング・システム(ROS)は、ロボット工学の研究や産業界で広く使われているオープンソースのフレームワークである。ROSは、開発者がロボットアプリケーションを作成するのに役立つライブラリやツールのコレクションを提供します。ROSは様々なロボットプラットフォームで動作するように設計されており、ロボット開発者にとって柔軟で強力なツールとなっています。

ROSの主な特徴

  1. モジュラー・アーキテクチャ:ROSはモジュラー・アーキテクチャーを採用しており、開発者はノードと呼ばれる再利用可能な小さなコンポーネントを組み合わせることで、複雑なシステムを構築することができる。各ノードは通常、特定の機能を実行し、ノードはトピックまたはサービスを介してメッセージを使用して相互に通信します。

  2. 通信ミドルウェア:ROSは、プロセス間通信と分散コンピューティングをサポートする堅牢な通信インフラストラクチャを提供します。これは、データストリーム(トピック)のパブリッシュ・サブスクライブモデルと、サービスコールのリクエスト・リプライモデルによって実現されます。

  3. ハードウェアの抽象化:ROSはハードウェアを抽象化するレイヤーを提供し、開発者はデバイスにとらわれないコードを書くことができる。これにより、同じコードを異なるハードウェア・セットアップで使用することができ、統合や実験が容易になります。

  4. ツールとユーティリティ:ROSには、可視化、デバッグ、シミュレーションのためのツールやユーティリティが豊富に用意されている。例えば、RVizはセンサーデータやロボットの状態情報を可視化するために使用され、Gazeboはアルゴリズムやロボット設計をテストするための強力なシミュレーション環境を提供します。

  5. 広範なエコシステム:ROSのエコシステムは広大で継続的に成長しており、ナビゲーション、マニピュレーション、知覚など、さまざまなロボットアプリケーションに利用可能な数多くのパッケージがあります。コミュニティは、これらのパッケージの開発とメンテナンスに積極的に貢献しています。

ROSバージョンの進化

2007年に開発されて以来、ROSは複数のバージョンを経て進化し、そのたびにロボット工学コミュニティの高まるニーズに対応するための新機能や改良が導入されてきた。ROSの開発は、主に2つのシリーズに分類することができます:このガイドでは、ROS Noetic Ninjemysとして知られるROS 1のLong Term Support(LTS)バージョンに焦点を当てていますが、コードは以前のバージョンでも動作するはずです。

ROS1とROS2の比較

ROS 1はロボット開発のための強固な基盤を提供したが、ROS 2はその欠点に対処している:

  • リアルタイム性能:リアルタイムシステムと決定論的動作のサポートが向上。
  • セキュリティ様々な環境下で安全かつ信頼性の高い運用を実現するため、セキュリティ機能を強化。
  • スケーラビリティ:マルチロボットシステムや大規模な展開をより良くサポート。
  • クロスプラットフォーム対応:WindowsやmacOSなど、Linux以外の様々なOSとの互換性を拡大。
  • 柔軟な通信:DDSを使用することで、より柔軟で効率的なプロセス間通信を実現。

ROSメッセージとトピック

ROSでは、ノード間の通信はメッセージと トピックを通じて行われる。メッセージはノード間で交換される情報を定義するデータ構造で、トピックはメッセージが送受信される名前付きチャネルです。ノードはトピックにメッセージをパブリッシュしたり、トピックからのメッセージをサブスクライブすることで、相互に通信することができます。このパブリッシュ・サブスクライブモデルにより、ノード間の非同期通信とデカップリングが可能になる。ロボットシステムの各センサーやアクチュエーターは通常、トピックにデータをパブリッシュし、それを他のノードが処理や制御のために消費することができます。このガイドでは、Image、Depth、PointCloud メッセージとカメラトピックに焦点を当てます。

Ultralytics YOLO をROSで設定する

このガイドは、ROSbot ROSリポジトリのフォークであるこのROS環境を使用してテストされています。この環境には、Ultralytics YOLO パッケージ、セットアップを簡単にするDockerコンテナ、包括的なROSパッケージ、迅速なテストのためのGazeboワールドが含まれています。Husarion ROSbot 2 PROで動作するように設計されています。提供されるコード例は、シミュレーションと実世界の両方を含む、あらゆるROS Noetic/Melodic環境で動作します。

フサリオン ROSbot 2 PRO

依存関係のインストール

ROS環境とは別に、以下の依存関係をインストールする必要があります:

  • ROS Numpy パッケージ:ROS Imageメッセージとnumpy配列間の高速変換に必要です。

    pip install ros_numpy
    
  • Ultralytics パッケージで提供される:

    pip install ultralytics
    

ROSでUltralytics sensor_msgs/Image

について sensor_msgs/Image メッセージタイプ は、画像データを表現するためにROSで一般的に使用されています。エンコード、高さ、幅、ピクセルデータのフィールドを含んでおり、カメラや他のセンサーで撮影された画像を送信するのに適しています。画像メッセージは、視覚認識などのタスクのためのロボットアプリケーションで広く使用されています、 オブジェクト検出そしてナビゲーション。

ROS Gazeboにおける検出とセグメンテーション

イメージ・ステップ・バイ・ステップ

次のコード・スニペットは、ROS でUltralytics YOLO パッケージを使用する方法を示しています。この例では、カメラ・トピックをサブスクライブし、YOLO を使用して受信画像を処理し、検出されたオブジェクトを検出と セグメンテーションのために新しいトピックにパブリッシュします。

まず、必要なライブラリをインポートし、2つのモデルをインスタンス化する。 セグメンテーション検出.ROSノード(名前は ultralytics)を使用してROSマスターとの通信を可能にする。安定した接続を確保するために、短い休止時間を設け、ノードが接続を確立するのに十分な時間を与えてから処理を進めます。

import time

import rospy

from ultralytics import YOLO

detection_model = YOLO("yolo11m.pt")
segmentation_model = YOLO("yolo11m-seg.pt")
rospy.init_node("ultralytics")
time.sleep(1)

2つのROSトピックを初期化する。 検出セグメンテーション.これらのトピックは、注釈付き画像を公開するために使用され、さらなる処理のためにアクセスできるようにする。ノード間の通信は sensor_msgs/Image のメッセージがある。

from sensor_msgs.msg import Image

det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)
seg_image_pub = rospy.Publisher("/ultralytics/segmentation/image", Image, queue_size=5)

最後に、以下のサブスクライバを作成する。 /camera/color/image_raw トピックを受け取り、新しいメッセージごとにコールバック関数を呼び出します。このコールバック関数は sensor_msgs/Imageを使ってnumpy配列に変換する。 ros_numpyそして、事前にインスタンス化されたYOLO モデルで画像を処理し、画像に注釈を付けてから、それぞれのトピックに戻す: /ultralytics/detection/image 検出と /ultralytics/segmentation/image セグメンテーションのために。

import ros_numpy


def callback(data):
    """Callback function to process image and publish annotated images."""
    array = ros_numpy.numpify(data)
    if det_image_pub.get_num_connections():
        det_result = detection_model(array)
        det_annotated = det_result[0].plot(show=False)
        det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))

    if seg_image_pub.get_num_connections():
        seg_result = segmentation_model(array)
        seg_annotated = seg_result[0].plot(show=False)
        seg_image_pub.publish(ros_numpy.msgify(Image, seg_annotated, encoding="rgb8"))


rospy.Subscriber("/camera/color/image_raw", Image, callback)

while True:
    rospy.spin()
完全なコード
import time

import ros_numpy
import rospy
from sensor_msgs.msg import Image

from ultralytics import YOLO

detection_model = YOLO("yolo11m.pt")
segmentation_model = YOLO("yolo11m-seg.pt")
rospy.init_node("ultralytics")
time.sleep(1)

det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)
seg_image_pub = rospy.Publisher("/ultralytics/segmentation/image", Image, queue_size=5)


def callback(data):
    """Callback function to process image and publish annotated images."""
    array = ros_numpy.numpify(data)
    if det_image_pub.get_num_connections():
        det_result = detection_model(array)
        det_annotated = det_result[0].plot(show=False)
        det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))

    if seg_image_pub.get_num_connections():
        seg_result = segmentation_model(array)
        seg_annotated = seg_result[0].plot(show=False)
        seg_image_pub.publish(ros_numpy.msgify(Image, seg_annotated, encoding="rgb8"))


rospy.Subscriber("/camera/color/image_raw", Image, callback)

while True:
    rospy.spin()
デバッグ

ROS(ロボット・オペレーティング・システム)ノードのデバッグは、システムが分散しているため困難な場合があります。このプロセスを支援するツールがいくつかあります:

  1. rostopic echo <TOPIC-NAME> :このコマンドを使うと、特定のトピックで発表されたメッセージを見ることができ、データの流れを調べるのに役立ちます。
  2. rostopic list:このコマンドを使用すると、ROS システムで使用可能なすべてのトピックが一覧表示され、アクティブなデータストリームの概要が表示されます。
  3. rqt_graph:この可視化ツールは、ノード間の通信グラフを表示し、ノードがどのように相互接続され、どのように相互作用しているかについての洞察を提供します。
  4. 3D表現など、より複雑なビジュアライゼーションには RViz.RViz (ROS Visualization)は、ROSのための強力な3D可視化ツールです。ロボットの状態や環境をリアルタイムで可視化することができます。RVizを使用すると、センサーデータ(例. sensors_msgs/Image)、ロボットモデルの状態、その他様々な情報を提供し、ロボットシステムのデバッグや動作の理解を容易にします。

検出されたクラスを std_msgs/String

標準的なROSメッセージには以下も含まれる。 std_msgs/String メッセージ多くのアプリケーションでは、注釈付き画像全体を再公開する必要はなく、ロボットのビューに存在するクラスだけが必要です。次の例は std_msgs/String メッセージ で検出されたクラスを再公開します。 /ultralytics/detection/classes トピックで使用される。これらのメッセージはより軽量で、必要不可欠な情報を提供するため、さまざまな用途で利用価値がある。

使用例

カメラと物体を装備した倉庫ロボットを考えてみよう。 検出モデル.大きな注釈付き画像をネットワーク経由で送信する代わりに、ロボットは検出されたクラスのリストを std_msgs/String のメッセージを生成する。例えば、ロボットが "箱"、"パレット"、"フォークリフト "といったオブジェクトを検出すると、これらのクラスを /ultralytics/detection/classes のトピックを参照してください。この情報は、中央監視システムがリアルタイムで在庫を追跡したり、ロボットの経路計画を最適化して障害物を回避したり、検出された箱をピックアップするなどの特定のアクションをトリガーしたりするために使用できる。このアプローチにより、通信に必要な帯域幅が削減され、重要なデータの送信に集中できる。

ストリング・ステップ・バイ・ステップ

この例では、ROS でUltralytics YOLO パッケージを使用する方法を示します。この例では、カメラ・トピックをサブスクライブし、YOLO を使用して受信画像を処理し、検出されたオブジェクトを新しいトピック /ultralytics/detection/classes 使用して std_msgs/String メッセージその ros_numpy パッケージは、ROS ImageメッセージをYOLO で処理するためのnumpy配列に変換するために使用されます。

import time

import ros_numpy
import rospy
from sensor_msgs.msg import Image
from std_msgs.msg import String

from ultralytics import YOLO

detection_model = YOLO("yolo11m.pt")
rospy.init_node("ultralytics")
time.sleep(1)
classes_pub = rospy.Publisher("/ultralytics/detection/classes", String, queue_size=5)


def callback(data):
    """Callback function to process image and publish detected classes."""
    array = ros_numpy.numpify(data)
    if classes_pub.get_num_connections():
        det_result = detection_model(array)
        classes = det_result[0].boxes.cls.cpu().numpy().astype(int)
        names = [det_result[0].names[i] for i in classes]
        classes_pub.publish(String(data=str(names)))


rospy.Subscriber("/camera/color/image_raw", Image, callback)
while True:
    rospy.spin()

ROS深度画像でUltralytics

ROSはRGB画像に加えて深度画像もサポートしており、カメラから物体の距離に関する情報を提供する。深度画像は、障害物回避、3Dマッピング、ローカライゼーションなどのロボットアプリケーションに不可欠です。

深度画像は、各ピクセルがカメラから物体までの距離を表す画像である。色を捉えるRGB画像とは異なり、深度画像は空間情報を捉えるため、ロボットは環境の3D構造を認識することができる。

深度画像の取得

深度画像は、さまざまなセンサーを使って得ることができる:

  1. ステレオカメラ:2台のカメラを使って、画像の視差から奥行きを計算する。
  2. 飛行時間(ToF)カメラ:光が物体から戻ってくるまでの時間を測定する。
  3. 構造化光センサー:パターンを投影し、表面上の変形を測定する。

YOLO 、深度画像を使用する

ROSでは、深度画像は sensor_msgs/Image メッセージタイプには、エンコーディング、高さ、幅、ピクセルデータのフィールドが含まれる。深度画像のエンコーディングフィールドは、"16UC1 "のような形式を使用することが多く、ピクセルごとに16ビットの符号なし整数を示し、各値はオブジェクトまでの距離を表します。深度画像は一般的にRGB画像と組み合わせて使用され、より包括的な環境ビューを提供する。

YOLO を使用すると、RGB画像と深度画像の両方から情報を抽出し、組み合わせることができる。例えば、YOLO 、RGB画像内の物体を検出することができ、この検出を使用して深度画像内の対応する領域をピンポイントで特定することができる。これにより、検出されたオブジェクトの正確な奥行き情報を抽出することができ、ロボットの環境を3次元で理解する能力が向上します。

RGB-Dカメラ

深度画像を扱う場合、RGB画像と深度画像を正しく位置合わせすることが不可欠です。Intel RealSenseシリーズのようなRGB-Dカメラは、同期されたRGB画像と深度画像を提供し、両方のソースからの情報を簡単に組み合わせることができます。RGBカメラと深度カメラを別々に使用する場合は、正確なアライメントを確保するためにキャリブレーションを行うことが重要です。

デプス ステップ・バイ・ステップ

この例では、YOLO を使って画像をセグメンテーションし、抽出したマスクを適用して深度画像内のオブジェクトをセグメンテーションする。これにより、対象物体の各ピクセルの、カメラの焦点中心からの距離を求めることができる。この距離情報を得ることで、カメラとシーン内の特定のオブジェクトとの距離を計算することができます。必要なライブラリをインポートし、ROS ノードを作成し、セグメンテーションモデルと ROS トピックをインス タンス化することから始めます。

import time

import rospy
from std_msgs.msg import String

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)

segmentation_model = YOLO("yolo11m-seg.pt")

classes_pub = rospy.Publisher("/ultralytics/detection/distance", String, queue_size=5)

次に、入力された深度画像メッセージを処理するコールバック関数を定義します。この関数は、深度画像と RGB 画像のメッセージを待ち、それらを numpy 配列に変換し、RGB 画像にセグメンテーションモデルを適用します。次に、検出された各オブジェクトのセグメンテーションマスクを抽出し、深度画像を使用してカメラからのオブジェクトの平均距離を計算します。ほとんどのセンサには、クリップ距離と呼ばれる最大距離があり、その値を超えると inf (np.inf).処理する前に、これらのNULL値をフィルタリングし、その値に 0.最後に、検出されたオブジェクトを、その平均距離とともに /ultralytics/detection/distance というトピックがある。

import numpy as np
import ros_numpy
from sensor_msgs.msg import Image


def callback(data):
    """Callback function to process depth image and RGB image."""
    image = rospy.wait_for_message("/camera/color/image_raw", Image)
    image = ros_numpy.numpify(image)
    depth = ros_numpy.numpify(data)
    result = segmentation_model(image)

    all_objects = []
    for index, cls in enumerate(result[0].boxes.cls):
        class_index = int(cls.cpu().numpy())
        name = result[0].names[class_index]
        mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
        obj = depth[mask == 1]
        obj = obj[~np.isnan(obj)]
        avg_distance = np.mean(obj) if len(obj) else np.inf
        all_objects.append(f"{name}: {avg_distance:.2f}m")

    classes_pub.publish(String(data=str(all_objects)))


rospy.Subscriber("/camera/depth/image_raw", Image, callback)

while True:
    rospy.spin()
完全なコード
import time

import numpy as np
import ros_numpy
import rospy
from sensor_msgs.msg import Image
from std_msgs.msg import String

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)

segmentation_model = YOLO("yolo11m-seg.pt")

classes_pub = rospy.Publisher("/ultralytics/detection/distance", String, queue_size=5)


def callback(data):
    """Callback function to process depth image and RGB image."""
    image = rospy.wait_for_message("/camera/color/image_raw", Image)
    image = ros_numpy.numpify(image)
    depth = ros_numpy.numpify(data)
    result = segmentation_model(image)

    all_objects = []
    for index, cls in enumerate(result[0].boxes.cls):
        class_index = int(cls.cpu().numpy())
        name = result[0].names[class_index]
        mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
        obj = depth[mask == 1]
        obj = obj[~np.isnan(obj)]
        avg_distance = np.mean(obj) if len(obj) else np.inf
        all_objects.append(f"{name}: {avg_distance:.2f}m")

    classes_pub.publish(String(data=str(all_objects)))


rospy.Subscriber("/camera/depth/image_raw", Image, callback)

while True:
    rospy.spin()

ROSでUltralytics sensor_msgs/PointCloud2

ROS Gazeboにおける検出とセグメンテーション

について sensor_msgs/PointCloud2 メッセージタイプ は、3D点群データを表現するためにROSで使用されるデータ構造です。このメッセージタイプはロボットアプリケーションに不可欠で、3Dマッピング、物体認識、ローカリゼーションなどのタスクを可能にする。

点群とは、3次元座標系内で定義されたデータ点の集まりである。これらのデータ点は、3Dスキャン技術によってキャプチャされたオブジェクトやシーンの外面を表しています。クラウド内の各ポイントは X, Yそして Z 座標は空間内の位置に対応し、色や強度などの追加情報も含まれる。

基準フレーム

と一緒に仕事をする場合 sensor_msgs/PointCloud2点群データが取得されたセンサーの基準フレームを考慮することが不可欠である。点群は最初、センサーの参照フレームでキャプチャされる。この参照フレームは /tf_static トピックを参照してください。しかし、特定のアプリケーションの要件によっては、点群を別の参照フレームに変換する必要があるかもしれません。この変換は tf2_ros パッケージで、座標フレームを管理し、それらの間でデータを変換するためのツールを提供する。

点群の取得

ポイントクラウドは、さまざまなセンサーを使って得ることができる:

  1. LIDAR(Light Detection and Ranging):レーザーパルスを使って対象物までの距離を測定し、高精度の3D地図を作成する。
  2. 深度カメラ:各ピクセルの深度情報をキャプチャし、シーンの3D再構築を可能にする。
  3. ステレオカメラ:2台以上のカメラを使用し、三角測量によって深度情報を取得する。
  4. 構造化光スキャナー:既知のパターンを表面に投影し、変形を測定して深さを計算する。

YOLO を点群と共に使用する

YOLO と統合する。 sensor_msgs/PointCloud2 タイプのメッセージでは、深度マップに使用される方法と同様の方法を採用することができる。点群に埋め込まれた色情報を活用することで、2D画像を抽出し、YOLO を使ってこの画像に対してセグメンテーションを行い、その結果得られたマスクを3次元の点に適用することで、関心のある3Dオブジェクトを分離することができる。

点群を扱うには、Open3D (pip install open3d)、ユーザーフレンドリーなPython ライブラリです。Open3Dは、点群データ構造の管理、可視化、複雑な操作をシームレスに実行するための堅牢なツールを提供します。このライブラリを使用することで、YOLO-based segmentationと連動した点群の操作と解析のプロセスを大幅に簡素化し、能力を向上させることができます。

点群ステップバイステップの使い方

必要なライブラリをインポートし、セグメンテーション用のYOLO モデルをインスタンス化する。

import time

import rospy

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolo11m-seg.pt")

関数を作成する pointcloud2_to_arrayを変換する。 sensor_msgs/PointCloud2 メッセージを2つのnumpy配列に格納する。メッセージは sensor_msgs/PointCloud2 メッセージには n に基づく。 width そして height 取得した画像の例えば 480 x 640 画像には 307,200 点である。各ポイントには3つの空間座標(xyz)の対応する色。 RGB フォーマット。これらは2つの別々の情報チャンネルと考えることができる。

この関数は xyz 座標と RGB 値を元のカメラの解像度 (width x height).ほとんどのセンサーには、クリップ距離と呼ばれる最大距離があり、それを超えると値が inf (np.inf).処理する前に、これらのNULL値をフィルタリングし、その値に 0.

import numpy as np
import ros_numpy


def pointcloud2_to_array(pointcloud2: PointCloud2) -> tuple:
    """
    Convert a ROS PointCloud2 message to a numpy array.

    Args:
        pointcloud2 (PointCloud2): the PointCloud2 message

    Returns:
        (tuple): tuple containing (xyz, rgb)
    """
    pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
    split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
    rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
    xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
    xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
    nan_rows = np.isnan(xyz).all(axis=2)
    xyz[nan_rows] = [0, 0, 0]
    rgb[nan_rows] = [0, 0, 0]
    return xyz, rgb

次に /camera/depth/points トピックで点群メッセージを受信し sensor_msgs/PointCloud2 メッセージを、XYZ座標とRGB値を含むnumpy配列に変換する。 pointcloud2_to_array 関数)。YOLO モデルを使って RGB 画像を処理し、セグメンテーションされたオブジェクトを抽出する。検出された各オブジェクトについて、セグメンテーションマスクを抽出し、RGB画像とXYZ座標の両方に適用して、3D空間でオブジェクトを分離する。

マスクはバイナリ値で構成されているので、処理は簡単である。 1 オブジェクトの存在を示し 0 がないことを示す。マスクを適用するには、元のチャンネルにマスクを掛けるだけでよい。この操作により、画像内の目的のオブジェクトが効果的に分離されます。最後に、Open3D点群オブジェクトを作成し、セグメント化されたオブジェクトを、関連する色とともに3D空間で可視化します。

import sys

import open3d as o3d

ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
xyz, rgb = pointcloud2_to_array(ros_cloud)
result = segmentation_model(rgb)

if not len(result[0].boxes.cls):
    print("No objects detected")
    sys.exit()

classes = result[0].boxes.cls.cpu().numpy().astype(int)
for index, class_id in enumerate(classes):
    mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
    mask_expanded = np.stack([mask, mask, mask], axis=2)

    obj_rgb = rgb * mask_expanded
    obj_xyz = xyz * mask_expanded

    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((ros_cloud.height * ros_cloud.width, 3)))
    pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((ros_cloud.height * ros_cloud.width, 3)) / 255)
    o3d.visualization.draw_geometries([pcd])
完全なコード
import sys
import time

import numpy as np
import open3d as o3d
import ros_numpy
import rospy
from sensor_msgs.msg import PointCloud2

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolo11m-seg.pt")


def pointcloud2_to_array(pointcloud2: PointCloud2) -> tuple:
    """
    Convert a ROS PointCloud2 message to a numpy array.

    Args:
        pointcloud2 (PointCloud2): the PointCloud2 message

    Returns:
        (tuple): tuple containing (xyz, rgb)
    """
    pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
    split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
    rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
    xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
    xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
    nan_rows = np.isnan(xyz).all(axis=2)
    xyz[nan_rows] = [0, 0, 0]
    rgb[nan_rows] = [0, 0, 0]
    return xyz, rgb


ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
xyz, rgb = pointcloud2_to_array(ros_cloud)
result = segmentation_model(rgb)

if not len(result[0].boxes.cls):
    print("No objects detected")
    sys.exit()

classes = result[0].boxes.cls.cpu().numpy().astype(int)
for index, class_id in enumerate(classes):
    mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
    mask_expanded = np.stack([mask, mask, mask], axis=2)

    obj_rgb = rgb * mask_expanded
    obj_xyz = xyz * mask_expanded

    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((ros_cloud.height * ros_cloud.width, 3)))
    pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((ros_cloud.height * ros_cloud.width, 3)) / 255)
    o3d.visualization.draw_geometries([pcd])

点群セグメンテーションUltralytics

よくあるご質問

ロボット・オペレーティング・システム(ROS)とは?

ロボットオペレーティングシステム(ROS)は、開発者が堅牢なロボットアプリケーションを作成するのに役立つ、ロボット工学で一般的に使用されているオープンソースのフレームワークです。ROSは、複雑なアプリケーションの開発を容易にする、ロボットシステムの構築とインターフェース用のライブラリとツールのコレクションを提供します。ROSは、トピックまたはサービスを介したメッセージを使用してノード間の通信をサポートします。

Ultralytics YOLO をROSと統合してリアルタイムの物体検出を行うには?

Ultralytics YOLO をROSと統合するには、ROS環境をセットアップし、センサーデータの処理にYOLO 。以下のような必要な依存関係をインストールすることから始める。 ros_numpy とUltralytics YOLO :

pip install ros_numpy ultralytics

次に、ROSノードを作成し、受信データを処理するために画像トピックをサブスクライブする。以下に最小限の例を示す:

import ros_numpy
import rospy
from sensor_msgs.msg import Image

from ultralytics import YOLO

detection_model = YOLO("yolo11m.pt")
rospy.init_node("ultralytics")
det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)


def callback(data):
    array = ros_numpy.numpify(data)
    det_result = detection_model(array)
    det_annotated = det_result[0].plot(show=False)
    det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))


rospy.Subscriber("/camera/color/image_raw", Image, callback)
rospy.spin()

ROSのトピックとは何か、そしてそれらはUltralytics YOLO でどのように使われているのか?

ROSトピックは、パブリッシュ・サブスクライブ・モデルを使用することで、ROSネットワーク内のノード間の通信を容易にします。トピックは、ノードが非同期にメッセージを送受信するために使用する名前付きチャネルです。Ultralytics YOLOコンテキストでは、ノードを画像トピックにサブスクライブさせ、検出や セグメンテーションなどのタスクのためにYOLO 使用して画像を処理し、結果を新しいトピックにパブリッシュすることができます。

例えば、カメラ・トピックをサブスクライブし、受信画像を処理して検出する:

rospy.Subscriber("/camera/color/image_raw", Image, callback)

なぜROSのUltralytics YOLO 、深度画像を使うのか?

で表されるROSの深度画像。 sensor_msgs/Imageこれは、障害物回避、3Dマッピング、ローカライゼーションなどのタスクに不可欠である。以下により 奥行き情報を使って RGB画像とともに、ロボットは3D環境をよりよく理解することができる。

YOLO使えば、RGB画像からセグメンテーション・マスクを抽出し、そのマスクを深度画像に適用することで、正確な3Dオブジェクト情報を得ることができ、ロボットのナビゲーション能力や周囲とのインタラクション能力を向上させることができる。

ROSでYOLO 、3D点群を可視化するには?

YOLO を使ってROSで3D点群を可視化する:

  1. コンバート sensor_msgs/PointCloud2 メッセージをnumpy配列に変換する。
  2. YOLO 、RGB画像を分割する。
  3. 点群にセグメンテーションマスクを適用する。

Open3Dを使ったビジュアライゼーションの例です:

import sys

import open3d as o3d
import ros_numpy
import rospy
from sensor_msgs.msg import PointCloud2

from ultralytics import YOLO

rospy.init_node("ultralytics")
segmentation_model = YOLO("yolo11m-seg.pt")


def pointcloud2_to_array(pointcloud2):
    pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
    split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
    rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
    xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
    xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
    return xyz, rgb


ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
xyz, rgb = pointcloud2_to_array(ros_cloud)
result = segmentation_model(rgb)

if not len(result[0].boxes.cls):
    print("No objects detected")
    sys.exit()

classes = result[0].boxes.cls.cpu().numpy().astype(int)
for index, class_id in enumerate(classes):
    mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
    mask_expanded = np.stack([mask, mask, mask], axis=2)

    obj_rgb = rgb * mask_expanded
    obj_xyz = xyz * mask_expanded

    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((-1, 3)))
    pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((-1, 3)) / 255)
    o3d.visualization.draw_geometries([pcd])

このアプローチは、セグメント化されたオブジェクトの3Dビジュアライゼーションを提供し、ロボットアプリケーションにおけるナビゲーションやマニピュレーションなどのタスクに役立つ。

📅作成:9ヶ月前 ✏️更新 8日前

コメント