Zum Inhalt springen

ROS (Robot Operating System) Kurzanleitung

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 Werkzeugen, die Entwicklern helfen, Roboteranwendungen zu erstellen. ROS ist so konzipiert, dass es mit verschiedenen Roboterplattformen zusammenarbeitet, was es zu einem flexiblen und leistungsstarken Werkzeug fĂŒr Robotiker macht.

Hauptmerkmale von ROS

  1. Modulare Architektur: ROS hat eine modulare Architektur, die es Entwicklern ermöglicht, komplexe Systeme zu bauen, indem sie kleinere, wiederverwendbare Komponenten, sogenannte Nodes, kombinieren. Jeder Knoten erfĂŒllt in der Regel eine bestimmte Funktion, und die Knoten kommunizieren untereinander mit Nachrichten ĂŒber Topics 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. So 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, Fehlersuche und Simulation geliefert. RViz wird zum Beispiel 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 wie 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 wurde ROS in mehreren Versionen weiterentwickelt, die jeweils neue Funktionen und Verbesserungen enthielten, um den wachsenden Anforderungen der Robotik-Gemeinschaft 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 aber auch mit frĂŒheren Versionen funktionieren.

ROS 1 im Vergleich zu ROS 2

WĂ€hrend ROS 1 eine solide Grundlage fĂŒr die Roboterentwicklung bot, behebt ROS 2 seine MĂ€ngel, indem es Folgendes 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 Botschaften und Themen

In ROS wird die Kommunikation zwischen Knoten durch Nachrichten und Themen erleichtert. Eine Nachricht ist eine Datenstruktur, die die zwischen den 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 Topic veröffentlichen oder Nachrichten aus einem Topic abonnieren, um miteinander zu kommunizieren. Dieses Publish-Subscribe-Modell ermöglicht eine asynchrone Kommunikation und Entkopplung zwischen den Knotenpunkten. Jeder Sensor oder Aktor in einem Robotersystem veröffentlicht normalerweise Daten in einem Topic, die dann von anderen Knoten zur Verarbeitung oder Steuerung genutzt werden können. In diesem Leitfaden konzentrieren wir uns auf Bild-, Tiefen- und PointCloud-Nachrichten sowie auf Kamerathemen.

Aufrichtend 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 den Husarion ROSbot 2 PRO konzipiert. Die mitgelieferten Codebeispiele funktionieren in jeder ROS Noetic/Melodic-Umgebung, sowohl in der Simulation als auch in der realen Welt.

Husarion ROSbot 2 PRO

Installation von AbhÀngigkeiten

Abgesehen von der ROS-Umgebung mĂŒssen Sie die folgenden AbhĂ€ngigkeiten installieren:

  • ROS Numpy Paket: Es wird fĂŒr die schnelle Konvertierung zwischen ROS Image-Nachrichten und Numpy-Arrays benötigt.

    pip install ros_numpy
    
  • Ultralytics Paket:

    pip install ultralytics
    

Gebrauchen Ultralytics mit ROS sensor_msgs/Image

Die sensor_msgs/Image Nachrichtentyp wird in ROS hĂ€ufig zur Darstellung von Bilddaten verwendet. Sie 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 aufgenommen wurden. Bildnachrichten werden in Roboteranwendungen hĂ€ufig fĂŒr Aufgaben wie visuelle Wahrnehmung, Objekterkennung und Navigation verwendet.

Erkennung und Segmentierung in ROS Gazebo

Bild-fĂŒr-Schritt-Nutzung

Der folgende Codeschnipsel zeigt, wie du das Paket Ultralytics YOLO mit ROS nutzen kannst. 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.

Importiere zunĂ€chst die erforderlichen Bibliotheken und instanziiere zwei Modelle: eines fĂŒr Segmentierung und eine fĂŒr Erkennung. Initialisiere einen ROS-Knoten (mit dem Namen ultralytics), um die Kommunikation mit dem ROS-Master zu ermöglichen. Um eine stabile Verbindung zu gewĂ€hrleisten, fĂŒgen wir eine kurze Pause ein, 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)

Initialisiere 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 Knotenpunkten wird durch sensor_msgs/Image Meldungen.

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 abschließend einen Abonnenten, der Nachrichten auf der Registerkarte /camera/color/image_raw und ruft fĂŒr jede neue Nachricht eine Callback-Funktion auf. Diese Callback-Funktion empfĂ€ngt Nachrichten vom Typ sensor_msgs/Imagekonvertiert sie in ein numpy-Array mit ros_numpyverarbeitet die Bilder mit den zuvor instanziierten YOLO Modelle, kommentiert die Bilder und veröffentlicht sie dann wieder zu den jeweiligen Themen: /ultralytics/detection/image zur Detektion 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()
Debuggen

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

  1. rostopic echo <TOPIC-NAME> : Mit diesem Befehl können Sie Nachrichten anzeigen, die zu einem bestimmten Thema veröffentlicht wurden, um den Datenfluss zu ĂŒberprĂŒfen.
  2. rostopic list: Mit diesem Befehl listen Sie alle verfĂŒgbaren Themen im ROS-System auf und erhalten einen Überblick ĂŒber die aktiven Datenströme.
  3. rqt_graph: Dieses Visualisierungstool zeigt das Kommunikationsdiagramm zwischen Knoten an und bietet Einblicke in die Verbindung von Knoten und deren Interaktion.
  4. FĂŒr komplexere Visualisierungen, wie z. B. 3D-Darstellungen, kannst du RViz. RViz (ROS Visualization) ist ein leistungsstarkes 3D-Visualisierungstool fĂŒr ROS. Es ermöglicht es dir, den Zustand deines Roboters und seiner Umgebung in Echtzeit zu visualisieren. Mit RViz kannst du Sensordaten anzeigen (z. B. sensors_msgs/Image), RobotermodellzustĂ€nde und verschiedene andere Arten von Informationen, die das Debuggen und Verstehen des Verhaltens Ihres Robotersystems erleichtern.

Erkannte Klassen veröffentlichen mit std_msgs/String

Zu den Standard-ROS-Nachrichten gehören auch std_msgs/String Meldungen. In vielen Anwendungen ist es nicht erforderlich, das gesamte kommentierte Bild erneut zu veröffentlichen. Stattdessen werden nur die Klassen benötigt, die in der Ansicht des Roboters vorhanden sind. Das folgende Beispiel zeigt, wie Sie std_msgs/String Nachrichten um die gefundenen Klassen auf der Website zu veröffentlichen. /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 Lagerhausroboter, der mit einer Kamera und einem Objekt Erkennungsmodell. Anstatt große kommentierte Bilder ĂŒber das Netzwerk zu senden, kann der Roboter eine Liste der erkannten Klassen als std_msgs/String Meldungen. Wenn der Roboter beispielsweise Objekte wie "Box", "Palette" und "Gabelstapler" erkennt, veröffentlicht er diese Klassen an die /ultralytics/detection/classes Thema. Diese Informationen können dann von einem zentralen Überwachungssystem verwendet werden, um den Bestand in Echtzeit zu verfolgen, die Wegplanung des Roboters zu optimieren, um Hindernissen auszuweichen, oder bestimmte Aktionen wie das Aufheben einer erkannten Kiste auszulösen. Dieser Ansatz reduziert die fĂŒr die Kommunikation erforderliche Bandbreite und konzentriert sich auf die Übertragung kritischer Daten.

Schritt-fĂŒr-Schritt-Verwendung von Strings

In diesem Beispiel wird veranschaulicht, wie Sie die Ultralytics YOLO Paket mit ROS. In diesem Beispiel abonnieren wir ein Kamerathema, verarbeiten das eingehende Bild mit YOLOund veröffentlichen Sie die erkannten Objekte in einem neuen Thema /ultralytics/detection/classes benutzend std_msgs/String Meldungen. Das ros_numpy -Paket wird verwendet, um die ROS-Image-Nachricht in ein numpy-Array fĂŒr die Verarbeitung mit YOLO.

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()

Gebrauchen 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 den Abstand von der Kamera zu einem Objekt darstellt. Im Gegensatz zu RGB-Bildern, die Farbe erfassen, erfassen Tiefenbilder rÀumliche Informationen, sodass Roboter die 3D-Struktur ihrer Umgebung wahrnehmen können.

Abrufen von Tiefenbildern

Tiefenbilder können mit verschiedenen Sensoren aufgenommen werden:

  1. Stereokameras: Verwende zwei Kameras, um die Tiefe anhand des Bildunterschieds zu berechnen.
  2. Time-of-Flight (ToF) Kameras: Sie messen die Zeit, die das Licht braucht, um von einem Objekt zurĂŒckzukehren.
  3. Strukturierte Lichtsensoren: Projiziere ein Muster und messe seine Verformung auf OberflÀchen.

Benutzend YOLO mit Tiefenbildern

In ROS werden Tiefenbilder durch die sensor_msgs/Image Nachrichtentyp, der Felder fĂŒr Codierung, Höhe, Breite und Pixeldaten enthĂ€lt. Das Codierungsfeld fĂŒr Tiefenbilder verwendet hĂ€ufig ein Format wie "16UC1", das eine 16-Bit-Ganzzahl ohne Vorzeichen 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.

Benutzend YOLOist es möglich, Informationen sowohl aus RGB- als auch aus Tiefenbildern zu extrahieren und zu kombinieren. Zum Beispiel YOLO kann Objekte innerhalb eines RGB-Bildes erkennen, und diese Erkennung kann verwendet werden, um entsprechende Bereiche 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 ist es wichtig, dass die RGB- und Tiefenbilder korrekt aufeinander abgestimmt sind. RGB-D-Kameras, wie z. B. die Intel RealSense-Serie, liefern synchronisierte RGB- und Tiefenbilder, so dass es einfacher ist, Informationen aus beiden Quellen zu kombinieren. Wenn du getrennte RGB- und Tiefenkameras verwendest, ist es wichtig, sie zu kalibrieren, um eine genaue Ausrichtung zu gewÀhrleisten.

Tiefe Schritt-fĂŒr-Schritt-Nutzung

In diesem Beispiel verwenden wir YOLO , um ein Bild zu segmentieren, und wenden Sie 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 Brennpunkt der Kamera bestimmen. Durch den Erhalt dieser Entfernungsinformationen können wir den Abstand zwischen der Kamera und dem spezifischen Objekt in der Szene berechnen. Beginnen Sie mit dem Importieren der erforderlichen Bibliotheken, dem Erstellen eines ROS-Knotens und dem Instanziieren eines Segmentierungsmodells und eines ROS-Themas.

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 als NĂ€chstes eine RĂŒckruffunktion, die die eingehende Tiefenbildnachricht verarbeitet. Die Funktion wartet auf die Tiefenbild- und RGB-Bildmeldungen, konvertiert sie in numpy-Arrays und wendet das Segmentierungsmodell auf das RGB-Bild an. Anschließend extrahiert es die Segmentierungsmaske fĂŒr jedes erkannte Objekt und berechnet anhand des Tiefenbildes den durchschnittlichen Abstand des Objekts von der Kamera. Die meisten Sensoren haben einen maximalen Abstand, den sogenannten Clip-Abstand, ab dem Werte als inf (np.inf). Vor der Verarbeitung ist es wichtig, diese Nullwerte herauszufiltern und ihnen den Wert 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()

Gebrauchen Ultralytics mit ROS sensor_msgs/PointCloud2

Erkennung und Segmentierung in ROS Gazebo

Die sensor_msgs/PointCloud2 Nachrichtentyp ist eine Datenstruktur, die in ROS verwendet wird, um 3D-Punktwolkendaten darzustellen. 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 wird. Jeder Punkt in der Cloud hat X, Y, und Z Koordinaten, die seiner Position im Raum entsprechen und auch zusĂ€tzliche Informationen wie Farbe und IntensitĂ€t enthalten können.

Bezugsrahmen

Bei der Arbeit mit sensor_msgs/PointCloud2ist es wichtig, das Bezugssystem des Sensors zu berĂŒcksichtigen, von dem die Punktwolkendaten erfasst wurden. Die Punktwolke wird zunĂ€chst im Bezugssystem des Sensors erfasst. Sie können dieses Bezugssystem bestimmen, indem Sie auf die /tf_static Thema. AbhĂ€ngig von Ihren spezifischen Anwendungsanforderungen mĂŒssen Sie die Punktwolke jedoch möglicherweise in ein anderes Bezugssystem konvertieren. Diese Transformation kann mit der tf2_ros -Paket, das Werkzeuge zum Verwalten von Koordinatenrahmen und zum Transformieren von Daten zwischen ihnen bereitstellt.

Abrufen von Punktwolken

Punktwolken können mit verschiedenen Sensoren erhalten werden:

  1. LIDAR (Light Detection and Ranging): Verwendet Laserimpulse, um Entfernungen zu Objekten zu messen und hochprÀzise 3D-Karten zu erstellen.
  2. Tiefenkameras: Erfassen Tiefeninformationen fĂŒr jedes Pixel und ermöglichen so eine 3D-Rekonstruktion der Szene.
  3. Stereokameras: Nutze 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.

Benutzend YOLO mit Punktwolken

Integrieren YOLO mit sensor_msgs/PointCloud2 können wir eine Ă€hnliche Methode wie bei Tiefenkarten anwenden. Durch die Nutzung der in der Punktwolke eingebetteten Farbinformationen können wir ein 2D-Bild extrahieren und eine Segmentierung dieses Bildes mit YOLO, und wenden Sie dann die resultierende Maske auf die dreidimensionalen Punkte an, um das gewĂŒnschte 3D-Objekt zu isolieren.

FĂŒr den Umgang mit Punktwolken empfehlen wir die Verwendung von Open3D (pip install open3d), eine benutzerfreundliche Python Bibliothek. Open3D bietet robuste Tools 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 FĂ€higkeit verbessern, Punktwolken in Verbindung mit YOLO-basierte Segmentierung.

Punktwolken Schritt fĂŒr Schritt verwenden

Importieren Sie die erforderlichen Bibliotheken und instanziieren Sie die YOLO Modell 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")

Erstellen einer Funktion pointcloud2_to_array, die eine sensor_msgs/PointCloud2 message in zwei numpy-Arrays ein. Das sensor_msgs/PointCloud2 Nachrichten enthalten n Punkte auf der Grundlage der width und height des aufgenommenen Bildes. Zum Beispiel ist ein 480 x 640 Bild hat 307,200 Punkte. Jeder Punkt enthÀlt 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 sogenannten Clip-Abstand, ab dem Werte als inf (np.inf). Vor der Verarbeitung ist es wichtig, diese Nullwerte herauszufiltern und ihnen den Wert 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

Abonnieren Sie als NĂ€chstes die /camera/depth/points , um die Punktwolkenmeldung zu empfangen und die sensor_msgs/PointCloud2 numpy-Arrays mit den XYZ-Koordinaten und RGB-Werten (mit dem pointcloud2_to_array Funktion). Verarbeiten Sie das RGB-Bild mit der YOLO Modell, 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Ă€ren Werten besteht, mit 1 das Vorhandensein des Objekts anzuzeigen und 0 die Abwesenheit angeben. Um die Maske anzuwenden, multiplizieren Sie einfach die OriginalkanĂ€le mit der Maske. Dieser Vorgang isoliert effektiv das Objekt von Interesse innerhalb des Bildes. Erstellen Sie abschließend 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 Entwicklern bei der Erstellung robuster Roboteranwendungen zu helfen. Es bietet eine Sammlung von Bibliotheken und Werkzeugen fĂŒr den Aufbau von und den Umgang mit Robotersystemen und erleichtert die Entwicklung komplexer Anwendungen. ROS unterstĂŒtzt die Kommunikation zwischen Knotenpunkten mit Hilfe von Nachrichten ĂŒber Topics oder Dienste.

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

Um Ultralytics YOLO in ROS zu integrieren, musst du eine ROS-Umgebung einrichten und YOLO fĂŒr die Verarbeitung von Sensordaten verwenden. Beginne mit der Installation der erforderlichen AbhĂ€ngigkeiten wie ros_numpy und Ultralytics YOLO :

pip install ros_numpy ultralytics

Als nÀchstes erstellst du einen ROS-Knoten und abonnierst 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, indem sie ein Publish-Subscribe-Modell verwenden. Ein Topic ist ein benannter Kanal, den Knoten nutzen, um Nachrichten asynchron zu senden und zu empfangen. Im Kontext von Ultralytics YOLO kannst du 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.

Abonniere zum Beispiel ein Kamerathema und verarbeite 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 Roboter ihre 3D-Umgebung besser verstehen.

Mit YOLO kannst du 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 zu verbessern, zu navigieren und mit seiner Umgebung zu interagieren.

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

Um 3D-Punktwolken in ROS mit YOLO zu visualisieren:

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

Hier ist ein Beispiel, das Open3D fĂŒr die Visualisierung verwendet:

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 am 2024-06-19, Aktualisiert am 2024-07-05
Autoren: glenn-jocher (2), RizwanMunawar (1), ambitious-octopus (3)

Kommentare