Zum Inhalt springen

ROS (Robot Operating System) Schnellstartanleitung

ROS Introduction (captioned) from Open Robotics on Vimeo.

Was ist ROS?

Das Robot Operating System (ROS) ist ein Open-Source-Framework, das in der Robotikforschung und -industrie weit verbreitet ist. ROS bietet eine Sammlung von Bibliotheken und Tools, die Entwicklern bei der Erstellung von Roboteranwendungen helfen. ROS ist so konzipiert, dass es mit verschiedenen Roboterplattformen funktioniert, was es zu einem flexiblen und leistungsstarken Werkzeug für Robotiker macht.

Hauptmerkmale von ROS

  1. Modulare Architektur: ROS verfügt über eine modulare Architektur, die es Entwicklern ermöglicht, komplexe Systeme durch die Kombination kleinerer, wiederverwendbarer Komponenten, so genannter Knoten, aufzubauen. Jeder Knoten führt in der Regel eine bestimmte Funktion aus, und die Knoten kommunizieren untereinander mit Nachrichten über Themen oder Dienste.

  2. Kommunikations-Middleware: ROS bietet eine robuste Kommunikationsinfrastruktur, die Kommunikation zwischen Prozessen und verteiltes Rechnen unterstützt. Dies wird durch ein Publish-Subscribe-Modell für Datenströme (Topics) und ein Request-Reply-Modell für Dienstaufrufe erreicht.

  3. Hardware-Abstraktion: ROS bietet eine Abstraktionsebene über der Hardware, die es Entwicklern ermöglicht, geräteunabhängigen Code zu schreiben. Dadurch kann derselbe Code mit verschiedenen Hardwarekonfigurationen verwendet werden, was die Integration und das Experimentieren erleichtert.

  4. Werkzeuge und Dienstprogramme: ROS wird mit einer Vielzahl von Tools und Dienstprogrammen für die Visualisierung, das Debugging und die Simulation geliefert. RViz wird beispielsweise zur Visualisierung von Sensordaten und Roboterzustandsinformationen verwendet, während Gazebo eine leistungsstarke Simulationsumgebung zum Testen von Algorithmen und Roboterdesigns bietet.

  5. Umfangreiches Ökosystem: Das ROS-Ökosystem ist riesig und wächst ständig. Es gibt zahlreiche Pakete für verschiedene Roboteranwendungen, darunter Navigation, Manipulation, Wahrnehmung und mehr. Die Community trägt aktiv zur Entwicklung und Pflege dieser Pakete bei.

Entwicklung der ROS-Versionen

Seit seiner Entwicklung im Jahr 2007 hat ROS mehrere Versionen durchlaufen, die jeweils neue Funktionen und Verbesserungen enthielten, um den wachsenden Anforderungen der Robotikgemeinschaft gerecht zu werden. Die Entwicklung von ROS kann in zwei Hauptreihen eingeteilt werden: ROS 1 und ROS 2. Dieser Leitfaden konzentriert sich auf die Long Term Support (LTS) Version von ROS 1, bekannt als ROS Noetic Ninjemys, der Code sollte auch mit früheren Versionen funktionieren.

ROS 1 vs. ROS 2

Während ROS 1 eine solide Grundlage für die Entwicklung von Robotern darstellte, behebt ROS 2 seine Mängel, indem es neue Möglichkeiten bietet:

  • Leistung in Echtzeit: Verbesserte Unterstützung für Echtzeitsysteme und deterministisches Verhalten.
  • Sicherheit: Verbesserte Sicherheitsfunktionen für einen sicheren und zuverlässigen Betrieb in verschiedenen Umgebungen.
  • Skalierbarkeit: Bessere Unterstützung für Multi-Roboter-Systeme und groß angelegte Einsätze.
  • Plattformübergreifende Unterstützung: Erweiterte Kompatibilität mit verschiedenen Betriebssystemen über Linux hinaus, einschließlich Windows und macOS.
  • Flexible Kommunikation: Verwendung von DDS für eine flexiblere und effizientere Kommunikation zwischen den Prozessen.

ROS-Meldungen und Themen

In ROS wird die Kommunikation zwischen Knoten durch Nachrichten und Themen erleichtert. Eine Nachricht ist eine Datenstruktur, die die zwischen Knoten ausgetauschten Informationen definiert, während ein Thema ein benannter Kanal ist, über den Nachrichten gesendet und empfangen werden. Knoten können Nachrichten in einem Thema veröffentlichen oder Nachrichten aus einem Thema abonnieren, um miteinander zu kommunizieren. Dieses Publish-Subscribe-Modell ermöglicht eine asynchrone Kommunikation und Entkopplung zwischen den Knoten. Jeder Sensor oder Aktor in einem Robotersystem veröffentlicht normalerweise Daten in einem Topic, die dann von anderen Knoten zur Verarbeitung oder Steuerung verwendet werden können. In diesem Leitfaden konzentrieren wir uns auf Bild-, Tiefen- und PointCloud-Nachrichten und Kamerathemen.

Einrichten von Ultralytics YOLO mit ROS

Diese Anleitung wurde mit dieser ROS-Umgebung getestet, die ein Fork des ROSbot ROS-Repository ist. Diese Umgebung enthält das Paket Ultralytics YOLO , einen Docker-Container für die einfache Einrichtung, umfassende ROS-Pakete und Gazebo-Welten für schnelle Tests. Sie ist für die Arbeit mit dem Husarion ROSbot 2 PRO konzipiert. Die mitgelieferten Code-Beispiele funktionieren in jeder ROS Noetic/Melodic-Umgebung, sowohl in der Simulation als auch in der realen Welt.

Husarion ROSbot 2 PRO

Abhängigkeiten Installation

Neben der ROS-Umgebung müssen Sie die folgenden Abhängigkeiten installieren:

  • ROS Numpy-Paket: Dies ist für die schnelle Konvertierung zwischen ROS Image-Nachrichten und Numpy-Arrays erforderlich.

    pip install ros_numpy
    
  • Ultralytics Paket:

    pip install ultralytics
    

Verwenden Sie Ultralytics mit ROS sensor_msgs/Image

Die sensor_msgs/Image Nachrichtentyp wird in ROS üblicherweise zur Darstellung von Bilddaten verwendet. Es enthält Felder für Kodierung, Höhe, Breite und Pixeldaten und eignet sich daher für die Übertragung von Bildern, die von Kameras oder anderen Sensoren erfasst wurden. Bildnachrichten werden häufig in Roboteranwendungen für Aufgaben wie die visuelle Wahrnehmung verwendet, Objekterkennungund Navigation.

Erkennung und Segmentierung in ROS Gazebo

Bild Schritt-für-Schritt-Verwendung

Der folgende Codeschnipsel zeigt, wie das Paket Ultralytics YOLO mit ROS verwendet werden kann. In diesem Beispiel abonnieren wir ein Kamerathema, verarbeiten das eingehende Bild mit YOLO und veröffentlichen die erkannten Objekte in neuen Themen zur Erkennung und Segmentierung.

Zunächst importieren Sie die erforderlichen Bibliotheken und instanziieren zwei Modelle: eines für Segmentierung und eine für Erkennung. Initialisieren Sie einen ROS-Knoten (mit dem Namen ultralytics), um die Kommunikation mit dem ROS-Master zu ermöglichen. Um eine stabile Verbindung zu gewährleisten, wird eine kurze Pause eingefügt, damit der Knoten genügend Zeit hat, die Verbindung herzustellen, bevor er fortfährt.

import time

import rospy

from ultralytics import YOLO

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

Initialisieren Sie zwei ROS-Themen: eines für Erkennung und eine für Segmentierung. Diese Themen werden verwendet, um die kommentierten Bilder zu veröffentlichen und sie für die weitere Bearbeitung zugänglich zu machen. Die Kommunikation zwischen den Knoten wird erleichtert durch sensor_msgs/Image Nachrichten.

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)

Erstellen Sie schließlich einen Abonnenten, der die Nachrichten auf der /camera/color/image_raw Thema und ruft für jede neue Nachricht eine Callback-Funktion auf. Diese Callback-Funktion empfängt Nachrichten des Typs sensor_msgs/Imageund konvertiert sie in ein Numpy-Array mit ros_numpyverarbeitet die Bilder mit den zuvor instanziierten YOLO Modellen, kommentiert die Bilder und veröffentlicht sie dann wieder in den jeweiligen Themenbereichen: /ultralytics/detection/image zur Erkennung und /ultralytics/segmentation/image für die Segmentierung.

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()
Vollständiger Code
import time

import ros_numpy
import rospy
from sensor_msgs.msg import Image

from ultralytics import YOLO

detection_model = YOLO("yolov8m.pt")
segmentation_model = YOLO("yolov8m-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()
Fehlersuche

Das Debuggen von ROS-Knoten (Robot Operating System) kann aufgrund der verteilten Natur des Systems eine Herausforderung sein. Mehrere Tools können bei diesem Prozess helfen:

  1. rostopic echo <TOPIC-NAME> : Mit diesem Befehl können Sie die zu einem bestimmten Thema veröffentlichten Nachrichten anzeigen und so den Datenfluss überprüfen.
  2. rostopic list: Verwenden Sie diesen Befehl, um alle im ROS-System verfügbaren Themen aufzulisten und sich einen Überblick über die aktiven Datenströme zu verschaffen.
  3. rqt_graph: Dieses Visualisierungstool zeigt den Kommunikationsgraphen zwischen den Knoten an und gibt Aufschluss darüber, wie die Knoten miteinander verbunden sind und wie sie interagieren.
  4. Für komplexere Visualisierungen, wie z. B. 3D-Darstellungen, können Sie RViz. RViz (ROS Visualization) ist ein leistungsstarkes 3D-Visualisierungstool für ROS. Es ermöglicht Ihnen, den Zustand Ihres Roboters und seiner Umgebung in Echtzeit zu visualisieren. Mit RViz können Sie Sensordaten anzeigen (z.B. sensors_msgs/Image), Zustände des Robotermodells und verschiedene andere Arten von Informationen, die die Fehlersuche und das Verständnis des Verhaltens Ihres Robotersystems erleichtern.

Erkannte Klassen veröffentlichen mit std_msgs/String

Zu den Standard-ROS-Nachrichten gehören auch std_msgs/String Nachrichten. In vielen Anwendungen ist es nicht notwendig, das gesamte kommentierte Bild neu zu veröffentlichen; stattdessen werden nur die Klassen benötigt, die in der Ansicht des Roboters vorhanden sind. Das folgende Beispiel zeigt, wie man std_msgs/String Nachrichten um die gefundenen Klassen auf der Website /ultralytics/detection/classes Thema. Diese Nachrichten sind leichter und liefern wichtige Informationen, was sie für verschiedene Anwendungen wertvoll macht.

Beispiel für einen Anwendungsfall

Betrachten wir einen Lagerroboter, der mit einer Kamera und einem Objekt ausgestattet ist Erkennungsmodell. Anstatt große kommentierte Bilder über das Netz zu senden, kann der Roboter eine Liste der erkannten Klassen als std_msgs/String Nachrichten. Wenn der Roboter zum Beispiel Objekte wie "Kiste", "Palette" und "Gabelstapler" erkennt, veröffentlicht er diese Klassen in der /ultralytics/detection/classes Thema. Diese Informationen können dann von einem zentralen Überwachungssystem verwendet werden, um das Inventar in Echtzeit zu verfolgen, die Bahnplanung des Roboters zu optimieren, um Hindernisse zu umgehen oder bestimmte Aktionen auszulösen, wie z. B. das Aufnehmen einer erkannten Kiste. Dieser Ansatz reduziert die für die Kommunikation benötigte Bandbreite und konzentriert sich auf die Übermittlung kritischer Daten.

String Schritt-für-Schritt-Verwendung

Dieses Beispiel zeigt, wie das Paket Ultralytics YOLO mit ROS verwendet werden kann. In diesem Beispiel abonnieren wir ein Kamerathema, verarbeiten das eingehende Bild mit YOLO und veröffentlichen die erkannten Objekte in einem neuen Thema /ultralytics/detection/classes mit std_msgs/String Nachrichten. Die Website ros_numpy Paket wird verwendet, um die ROS-Image-Nachricht in ein Numpy-Array für die Verarbeitung mit YOLO zu konvertieren.

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("yolov8m.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()

Verwendung von Ultralytics mit ROS-Tiefenbildern

Zusätzlich zu RGB-Bildern unterstützt ROS auch Tiefenbilder, die Informationen über die Entfernung von Objekten zur Kamera liefern. Tiefenbilder sind entscheidend für Roboteranwendungen wie Hindernisvermeidung, 3D-Kartierung und Lokalisierung.

Ein Tiefenbild ist ein Bild, bei dem jedes Pixel die Entfernung zwischen der Kamera und einem Objekt darstellt. Im Gegensatz zu RGB-Bildern, die Farben erfassen, erfassen Tiefenbilder räumliche Informationen, die es Robotern ermöglichen, die 3D-Struktur ihrer Umgebung wahrzunehmen.

Gewinnung von Tiefenbildern

Tiefenbilder können mit verschiedenen Sensoren aufgenommen werden:

  1. Stereokameras: Verwenden Sie zwei Kameras, um die Tiefe auf der Grundlage der Bilddisparität zu berechnen.
  2. Lichtlaufzeitkameras (ToF-Kameras): Sie messen die Zeit, die das Licht braucht, um von einem Objekt zurückzukehren.
  3. Sensoren für strukturiertes Licht: Projizieren Sie ein Muster und messen Sie dessen Verformung auf Oberflächen.

Verwendung von YOLO mit Tiefenbildern

In ROS werden die Tiefenbilder durch den sensor_msgs/Image Nachrichtentyp, der Felder für Kodierung, Höhe, Breite und Pixeldaten enthält. Das Kodierungsfeld für Tiefenbilder verwendet oft ein Format wie "16UC1", das eine vorzeichenlose 16-Bit-Ganzzahl pro Pixel angibt, wobei jeder Wert die Entfernung zum Objekt darstellt. Tiefenbilder werden häufig in Verbindung mit RGB-Bildern verwendet, um einen umfassenderen Überblick über die Umgebung zu erhalten.

Mit YOLO ist es möglich, Informationen sowohl aus RGB- als auch aus Tiefenbildern zu extrahieren und zu kombinieren. So kann YOLO beispielsweise Objekte in einem RGB-Bild erkennen, und diese Erkennung kann dazu verwendet werden, entsprechende Regionen im Tiefenbild zu lokalisieren. Dies ermöglicht die Extraktion präziser Tiefeninformationen für erkannte Objekte und verbessert die Fähigkeit des Roboters, seine Umgebung in drei Dimensionen zu verstehen.

RGB-D-Kameras

Bei der Arbeit mit Tiefenbildern muss unbedingt sichergestellt werden, dass die RGB- und Tiefenbilder korrekt aufeinander abgestimmt sind. RGB-D-Kameras, wie z. B. die Intel RealSense-Serie, liefern synchronisierte RGB- und Tiefenbilder, was die Kombination von Informationen aus beiden Quellen erleichtert. Wenn Sie separate RGB- und Tiefenkameras verwenden, müssen Sie diese unbedingt kalibrieren, um eine genaue Ausrichtung zu gewährleisten.

Tiefe Schritt-für-Schritt-Anwendung

In diesem Beispiel verwenden wir YOLO , um ein Bild zu segmentieren, und wenden die extrahierte Maske an, um das Objekt im Tiefenbild zu segmentieren. Auf diese Weise können wir den Abstand jedes Pixels des interessierenden Objekts vom Fokuszentrum der Kamera bestimmen. Anhand dieser Entfernungsinformationen können wir die Entfernung zwischen der Kamera und dem jeweiligen Objekt in der Szene berechnen. Beginnen Sie mit dem Import der erforderlichen Bibliotheken, erstellen Sie einen ROS-Knoten und instanziieren Sie ein Segmentierungsmodell und ein ROS-Thema.

import time

import rospy
from std_msgs.msg import String

from ultralytics import YOLO

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

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

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

Definieren Sie anschließend eine Callback-Funktion, die die eingehende Tiefenbildnachricht verarbeitet. Die Funktion wartet auf die Tiefenbild- und RGB-Bildnachrichten, konvertiert sie in Numpy-Arrays und wendet das Segmentierungsmodell auf das RGB-Bild an. Anschließend extrahiert sie die Segmentierungsmaske für jedes erkannte Objekt und berechnet die durchschnittliche Entfernung des Objekts von der Kamera anhand des Tiefenbildes. Die meisten Sensoren haben einen maximalen Abstand, den so genannten Clip-Abstand, über den hinaus die Werte als inf (np.inf). Vor der Verarbeitung ist es wichtig, diese Nullwerte herauszufiltern und ihnen einen Wert von 0. Schließlich veröffentlicht es die erkannten Objekte zusammen mit ihren durchschnittlichen Entfernungen zum /ultralytics/detection/distance Thema.

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)

    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

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


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

while True:
    rospy.spin()
Vollständiger Code
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("yolov8m-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)

    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

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


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

while True:
    rospy.spin()

Verwenden Sie Ultralytics mit ROS sensor_msgs/PointCloud2

Erkennung und Segmentierung in ROS Gazebo

Die sensor_msgs/PointCloud2 Nachrichtentyp ist eine Datenstruktur, die in ROS zur Darstellung von 3D-Punktwolkendaten verwendet wird. Dieser Nachrichtentyp ist ein wesentlicher Bestandteil von Roboteranwendungen und ermöglicht Aufgaben wie 3D-Kartierung, Objekterkennung und Lokalisierung.

Eine Punktwolke ist eine Sammlung von Datenpunkten, die in einem dreidimensionalen Koordinatensystem definiert sind. Diese Datenpunkte stellen die äußere Oberfläche eines Objekts oder einer Szene dar, die mit 3D-Scantechnologien erfasst wurden. Jeder Punkt in der Wolke hat X, Yund Z Koordinaten, die seiner Position im Raum entsprechen, und kann auch zusätzliche Informationen wie Farbe und Intensität enthalten.

Bezugsrahmen

Bei der Arbeit mit sensor_msgs/PointCloud2ist es wichtig, den Referenzrahmen des Sensors zu berücksichtigen, von dem die Punktwolkendaten erfasst wurden. Die Punktwolke wird zunächst im Referenzrahmen des Sensors erfasst. Sie können diesen Bezugsrahmen bestimmen, indem Sie die /tf_static Thema. Je nach Ihren spezifischen Anwendungsanforderungen müssen Sie die Punktwolke jedoch möglicherweise in einen anderen Bezugsrahmen umwandeln. Diese Umwandlung kann mit der Funktion tf2_ros Paket, das Werkzeuge für die Verwaltung von Koordinatenrahmen und die Transformation von Daten zwischen ihnen bietet.

Gewinnung von Punktwolken

Punktwolken können mit verschiedenen Sensoren erstellt werden:

  1. LIDAR (Light Detection and Ranging): Mithilfe von Laserimpulsen werden Entfernungen zu Objekten gemessen und hochpräzise 3D-Karten erstellt.
  2. Tiefenkameras: Erfassen Tiefeninformationen für jedes Pixel und ermöglichen so eine 3D-Rekonstruktion der Szene.
  3. Stereokameras: Verwenden Sie zwei oder mehr Kameras, um durch Triangulation Tiefeninformationen zu erhalten.
  4. Strukturierte Licht-Scanner: Sie projizieren ein bekanntes Muster auf eine Oberfläche und messen die Verformung, um die Tiefe zu berechnen.

Verwendung von YOLO mit Punktwolken

Zur Integration von YOLO mit sensor_msgs/PointCloud2 können wir eine Methode anwenden, die derjenigen für Tiefenkarten ähnelt. Durch die Nutzung der in der Punktwolke eingebetteten Farbinformationen können wir ein 2D-Bild extrahieren, dieses Bild mit YOLO segmentieren und dann die resultierende Maske auf die dreidimensionalen Punkte anwenden, um das 3D-Objekt von Interesse zu isolieren.

Für die Bearbeitung von Punktwolken empfehlen wir die Verwendung von Open3D (pip install open3d), einer benutzerfreundlichen Bibliothek Python . Open3D bietet robuste Werkzeuge für die Verwaltung von Punktwolken-Datenstrukturen, deren Visualisierung und die nahtlose Ausführung komplexer Operationen. Diese Bibliothek kann den Prozess erheblich vereinfachen und unsere Möglichkeiten zur Bearbeitung und Analyse von Punktwolken in Verbindung mit der YOLO-basierten Segmentierung verbessern.

Punktwolken Schritt-für-Schritt-Anwendung

Importieren Sie die erforderlichen Bibliotheken und instanziieren Sie das Modell YOLO für die Segmentierung.

import time

import rospy

from ultralytics import YOLO

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

Eine Funktion erstellen pointcloud2_to_array, die eine Umwandlung von sensor_msgs/PointCloud2 Nachricht in zwei Numpy-Arrays. Die sensor_msgs/PointCloud2 Nachrichten enthalten n Punkte auf der Grundlage der width und height des aufgenommenen Bildes. Zum Beispiel, ein 480 x 640 Bild wird haben 307,200 Punkte. Jeder Punkt umfasst drei Raumkoordinaten (xyz) und die entsprechende Farbe in RGB Format. Diese können als zwei getrennte Informationskanäle betrachtet werden.

Die Funktion gibt die xyz Koordinaten und RGB Werte im Format der ursprünglichen Kameraauflösung (width x height). Die meisten Sensoren haben einen maximalen Abstand, den so genannten Clip-Abstand, über den hinaus die Werte als inf (np.inf). Vor der Verarbeitung ist es wichtig, diese Nullwerte herauszufiltern und ihnen einen Wert von 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

Als nächstes abonnieren Sie die /camera/depth/points Thema, um die Punktwolkennachricht zu empfangen und die sensor_msgs/PointCloud2 Nachricht in Numpy-Arrays mit den XYZ-Koordinaten und RGB-Werten (unter Verwendung der pointcloud2_to_array Funktion). Verarbeiten Sie das RGB-Bild mit dem Modell YOLO , um segmentierte Objekte zu extrahieren. Extrahieren Sie für jedes erkannte Objekt die Segmentierungsmaske und wenden Sie sie sowohl auf das RGB-Bild als auch auf die XYZ-Koordinaten an, um das Objekt im 3D-Raum zu isolieren.

Die Verarbeitung der Maske ist einfach, da sie aus Binärwerten besteht, wobei 1 die das Vorhandensein des Objekts anzeigen und 0 was auf das Fehlen von Kanälen hinweist. Um die Maske anzuwenden, multiplizieren Sie einfach die Originalkanäle mit der Maske. Durch diesen Vorgang wird das betreffende Objekt im Bild effektiv isoliert. Erstellen Sie schließlich ein Open3D-Punktwolkenobjekt und visualisieren Sie das segmentierte Objekt im 3D-Raum mit den zugehörigen Farben.

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])
Vollständiger Code
import sys
import time

import numpy as np
import open3d as o3d
import ros_numpy
import rospy

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolov8m-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])

Punktwolken-Segmentierung mit Ultralytics

FAQ

Was ist das Robot Operating System (ROS)?

Das Robot Operating System (ROS) ist ein Open-Source-Framework, das in der Robotik häufig verwendet wird, um Entwickler bei der Erstellung robuster Roboteranwendungen zu unterstützen. Es bietet eine Sammlung von Bibliotheken und Werkzeugen für den Aufbau von und die Verbindung mit Robotersystemen und erleichtert die Entwicklung komplexer Anwendungen. ROS unterstützt die Kommunikation zwischen Knoten mithilfe von Nachrichten über Topics oder Dienste.

Wie integriere ich Ultralytics YOLO mit ROS zur Objekterkennung in Echtzeit?

Die Integration von Ultralytics YOLO mit ROS umfasst die Einrichtung einer ROS-Umgebung und die Verwendung von YOLO zur Verarbeitung von Sensordaten. Beginnen Sie mit der Installation der erforderlichen Abhängigkeiten wie ros_numpy und Ultralytics YOLO :

pip install ros_numpy ultralytics

Als nächstes erstellen Sie einen ROS-Knoten und abonnieren ein Bildthema, um die eingehenden Daten zu verarbeiten. Hier ist ein minimales Beispiel:

import ros_numpy
import rospy
from sensor_msgs.msg import Image

from ultralytics import YOLO

detection_model = YOLO("yolov8m.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()

Was sind ROS-Themen und wie werden sie in Ultralytics YOLO verwendet?

ROS-Topics erleichtern die Kommunikation zwischen Knoten in einem ROS-Netzwerk durch die Verwendung eines Publish-Subscribe-Modells. Ein Topic ist ein benannter Kanal, den Knoten zum asynchronen Senden und Empfangen von Nachrichten verwenden. Im Kontext von Ultralytics YOLO können Sie einen Knoten dazu bringen, ein Bildthema zu abonnieren, die Bilder mit YOLO für Aufgaben wie Erkennung oder Segmentierung zu verarbeiten und die Ergebnisse in neuen Themen zu veröffentlichen.

Abonnieren Sie zum Beispiel ein Kamerathema und verarbeiten Sie das eingehende Bild zur Erkennung:

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

Warum Tiefenbilder mit Ultralytics YOLO in ROS verwenden?

Tiefenbilder in ROS, dargestellt durch sensor_msgs/Imageliefern die Entfernung von Objekten zur Kamera, die für Aufgaben wie Hindernisvermeidung, 3D-Kartierung und Lokalisierung entscheidend ist. Unter Verwendung von Tiefeninformationen zusammen mit RGB-Bildern können die Roboter ihre 3D-Umgebung besser verstehen.

Mit YOLO können Sie Segmentierungsmasken aus RGB-Bildern extrahieren und diese Masken auf Tiefenbilder anwenden, um präzise 3D-Objektinformationen zu erhalten und so die Fähigkeit des Roboters zur Navigation und Interaktion mit seiner Umgebung zu verbessern.

Wie kann ich 3D-Punktwolken mit YOLO in ROS visualisieren?

Zur Visualisierung von 3D-Punktwolken in ROS mit YOLO:

  1. Konvertieren sensor_msgs/PointCloud2 Nachrichten in Numpy-Arrays.
  2. Verwenden Sie YOLO , um RGB-Bilder zu segmentieren.
  3. Wenden Sie die Segmentierungsmaske auf die Punktwolke an.

Hier ist ein Beispiel für die Verwendung von Open3D zur Visualisierung:

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("yolov8m-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])

Dieser Ansatz bietet eine 3D-Visualisierung von segmentierten Objekten, die für Aufgaben wie Navigation und Manipulation nützlich ist.

📅 Erstellt vor 5 Monaten ✏️ Aktualisiert vor 2 Monaten

Kommentare