Overslaan naar inhoud

ROS (Robot Operating System) snelstartgids

ROS Introductie (bijschrift) from Open Robotics on Vimeo.

Wat is ROS?

Het Robot Operating System (ROS) is een open-source raamwerk dat veel gebruikt wordt in roboticaonderzoek en de industrie. ROS biedt een verzameling bibliotheken en gereedschappen om ontwikkelaars te helpen bij het maken van robottoepassingen. ROS is ontworpen om te werken met verschillende robotplatforms, waardoor het een flexibel en krachtig hulpmiddel is voor robotici.

Belangrijkste kenmerken van ROS

  1. Modulaire architectuur: ROS heeft een modulaire architectuur, waardoor ontwikkelaars complexe systemen kunnen bouwen door kleinere, herbruikbare componenten, nodes genaamd, te combineren. Elk knooppunt voert meestal een specifieke functie uit en knooppunten communiceren met elkaar door middel van berichten over onderwerpen of diensten.

  2. Communicatie Middleware: ROS biedt een robuuste communicatie-infrastructuur die communicatie tussen processen en gedistribueerd computergebruik ondersteunt. Dit wordt bereikt door een publish-subscribe model voor gegevensstromen (topics) en een request-reply model voor service-aanroepen.

  3. Hardware-abstractie: ROS biedt een abstractielaag over de hardware, waardoor ontwikkelaars apparaatagnostische code kunnen schrijven. Hierdoor kan dezelfde code worden gebruikt met verschillende hardwareopstellingen, wat integratie en experimenteren vergemakkelijkt.

  4. Gereedschappen en hulpprogramma's: ROS wordt geleverd met een uitgebreide set gereedschappen en hulpprogramma's voor visualisatie, debuggen en simulatie. RViz wordt bijvoorbeeld gebruikt voor het visualiseren van sensorgegevens en informatie over de toestand van de robot, terwijl Gazebo een krachtige simulatieomgeving biedt voor het testen van algoritmen en robotontwerpen.

  5. Uitgebreid ecosysteem: Het ecosysteem van ROS is enorm en groeit voortdurend, met talloze pakketten die beschikbaar zijn voor verschillende roboticatoepassingen, zoals navigatie, manipulatie, perceptie en meer. De gemeenschap draagt actief bij aan de ontwikkeling en het onderhoud van deze pakketten.

Evolutie van ROS-versies

Sinds de ontwikkeling in 2007 is ROS geĆ«volueerd door meerdere versies, waarbij telkens nieuwe mogelijkheden en verbeteringen werden geĆÆntroduceerd om te voldoen aan de groeiende behoeften van de robotica gemeenschap. De ontwikkeling van ROS kan worden onderverdeeld in twee hoofdreeksen: ROS 1 en ROS 2. Deze handleiding richt zich op de Long Term Support (LTS) versie van ROS 1, bekend als ROS Noetic Ninjemys, maar de code zou ook moeten werken met eerdere versies.

ROS 1 tegen ROS 2

Terwijl ROS 1 een solide basis bood voor de ontwikkeling van robots, pakt ROS 2 de tekortkomingen aan door het volgende aan te bieden:

  • Real-time prestaties: Verbeterde ondersteuning voor realtime systemen en deterministisch gedrag.
  • Beveiliging: Verbeterde beveiligingsfuncties voor een veilige en betrouwbare werking in verschillende omgevingen.
  • Schaalbaarheid: Betere ondersteuning voor systemen met meerdere robots en grootschalige implementaties.
  • Ondersteuning voor meerdere platforms: Uitgebreide compatibiliteit met verschillende besturingssystemen naast Linux, waaronder Windows en macOS.
  • Flexibele communicatie: Gebruik van DDS voor flexibelere en efficiĆ«ntere communicatie tussen processen.

ROS-berichten en -onderwerpen

In ROS wordt communicatie tussen knooppunten vergemakkelijkt door berichten en onderwerpen. Een bericht is een gegevensstructuur die de informatie definieert die wordt uitgewisseld tussen knooppunten, terwijl een onderwerp een benoemd kanaal is waarover berichten worden verzonden en ontvangen. Knooppunten kunnen berichten publiceren naar een onderwerp of zich abonneren op berichten van een onderwerp, waardoor ze met elkaar kunnen communiceren. Dit publish-subscribe model maakt asynchrone communicatie en ontkoppeling tussen knooppunten mogelijk. Elke sensor of actuator in een robotsysteem publiceert meestal gegevens naar een topic, die vervolgens kunnen worden geconsumeerd door andere nodes voor verwerking of besturing. Voor het doel van deze handleiding zullen we ons richten op Beeld, Diepte en PointCloud berichten en camera onderwerpen.

Instellen Ultralytics YOLO met ROS

Deze handleiding is getest met deze ROS-omgeving, die een fork is van de ROSbot ROS repository. Deze omgeving bevat het Ultralytics YOLO pakket, een Docker container voor eenvoudige installatie, uitgebreide ROS pakketten en Gazebo werelden voor snel testen. Het is ontworpen om te werken met de Husarion ROSbot 2 PRO. De meegeleverde codevoorbeelden werken in elke ROS Noetic/Melodic omgeving, zowel simulatie als in de echte wereld.

Husarion ROSbot 2 PRO

Installatie van afhankelijkheden

Naast de ROS-omgeving moet u de volgende afhankelijkheden installeren:

  • ROS Numpy pakket: Dit is nodig voor een snelle conversie tussen ROS Beeldberichten en numpy arrays.

    pip install ros_numpy
    
  • Ultralytics verpakking:

    pip install ultralytics
    

Gebruiken Ultralytics met ROS sensor_msgs/Image

De sensor_msgs/Image berichttype wordt vaak gebruikt in ROS om afbeeldingsgegevens te representeren. Het bevat velden voor codering, hoogte, breedte en pixelgegevens, waardoor het geschikt is voor het verzenden van afbeeldingen die zijn vastgelegd door camera's of andere sensoren. Beeldberichten worden veel gebruikt in robottoepassingen voor taken zoals visuele waarneming, objectdetectie en navigatie.

Detectie en segmentatie in ROS Gazebo

Stap-voor-stap gebruik van afbeeldingen

Het volgende codefragment laat zien hoe je het pakket Ultralytics YOLO kunt gebruiken met ROS. In dit voorbeeld abonneren we ons op een cameratopic, verwerken we het binnenkomende beeld met YOLO en publiceren we de gedetecteerde objecten naar nieuwe topics voor detectie en segmentatie.

Importeer eerst de benodigde bibliotheken en installeer twee modellen: een voor segmentatie en Ć©Ć©n voor detectie. Initialiseer een ROS knooppunt (met de naam ultralytics) om communicatie met de ROS-master mogelijk te maken. Om een stabiele verbinding te garanderen, nemen we een korte pauze in, zodat de node voldoende tijd heeft om de verbinding tot stand te brengen voordat hij verder gaat.

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)

Initialiseer twee ROS onderwerpen: Ć©Ć©n voor detectie en Ć©Ć©n voor segmentatie. Deze onderwerpen worden gebruikt om de geannoteerde afbeeldingen te publiceren, waardoor ze toegankelijk worden voor verdere verwerking. De communicatie tussen knooppunten wordt vergemakkelijkt door gebruik te maken van sensor_msgs/Image Berichten.

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)

Maak ten slotte een abonnee aan die luistert naar berichten op de /camera/color/image_raw onderwerp en roept een callback-functie op voor elk nieuw bericht. Deze callback-functie ontvangt berichten van het type sensor_msgs/Image, converteert ze naar een numpy array met behulp van ros_numpy, verwerkt de beelden met de eerder geĆÆnstantieerde YOLO modelleert, annoteert de afbeeldingen en publiceert ze vervolgens terug naar de respectievelijke onderwerpen: /ultralytics/detection/image voor opsporing en /ultralytics/segmentation/image voor segmentatie.

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

Het debuggen van ROS-knooppunten (Robot Operating System) kan een uitdaging zijn vanwege het gedistribueerde karakter van het systeem. Verschillende tools kunnen helpen bij dit proces:

  1. rostopic echo <TOPIC-NAME> : Met deze opdracht kunt u berichten bekijken die over een specifiek onderwerp zijn gepubliceerd, zodat u de gegevensstroom kunt inspecteren.
  2. rostopic list: Gebruik dit commando om alle beschikbare onderwerpen in het ROS-systeem weer te geven, zodat u een overzicht krijgt van de actieve gegevensstromen.
  3. rqt_graph: Deze visualisatietool geeft de communicatiegrafiek tussen knooppunten weer en geeft inzicht in hoe knooppunten met elkaar verbonden zijn en hoe ze op elkaar inwerken.
  4. Voor complexere visualisaties, zoals 3D-weergaven, kun je het volgende gebruiken RViz. RViz (ROS Visualization) is een krachtig 3D visualisatieprogramma voor ROS. Hiermee kun je de toestand van je robot en zijn omgeving in real-time visualiseren. Met RViz kun je sensorgegevens bekijken (bijv. sensors_msgs/Image), robotmodelstatussen en verschillende andere soorten informatie, waardoor het gemakkelijker wordt om het gedrag van uw robotsysteem te debuggen en te begrijpen.

Detecteerde klassen publiceren met std_msgs/String

Standaard ROS-berichten bevatten ook std_msgs/String Berichten. In veel toepassingen is het niet nodig om de hele geannoteerde afbeelding opnieuw te publiceren; In plaats daarvan zijn alleen de klassen nodig die aanwezig zijn in de weergave van de robot. In het volgende voorbeeld wordt gedemonstreerd hoe u std_msgs/String berichten om de gedetecteerde klassen opnieuw te publiceren op de /ultralytics/detection/classes onderwerp. Deze berichten zijn lichter en bieden essentiƫle informatie, waardoor ze waardevol zijn voor verschillende toepassingen.

Voorbeeld van een use case

Beschouw een magazijnrobot met een camera en object detectiemodel. In plaats van grote geannoteerde afbeeldingen over het netwerk te sturen, kan de robot een lijst met gedetecteerde klassen publiceren als std_msgs/String Berichten. Wanneer de robot bijvoorbeeld objecten zoals "doos", "pallet" en "vorkheftruck" detecteert, publiceert hij deze klassen naar de /ultralytics/detection/classes onderwerp. Deze informatie kan vervolgens door een centraal monitoringsysteem worden gebruikt om de voorraad in realtime te volgen, de padplanning van de robot te optimaliseren om obstakels te vermijden, of specifieke acties te activeren, zoals het oppakken van een gedetecteerde doos. Deze aanpak vermindert de bandbreedte die nodig is voor communicatie en richt zich op het verzenden van kritieke gegevens.

Stap-voor-stap gebruik van tekenreeksen

Dit voorbeeld laat zien hoe u de Ultralytics YOLO pakket met ROS. In dit voorbeeld abonneren we ons op een camera-onderwerp, verwerken we de inkomende afbeelding met behulp van YOLOen publiceer de gedetecteerde objecten in een nieuw onderwerp /ultralytics/detection/classes Gebruik std_msgs/String Berichten. De ros_numpy wordt gebruikt om het ROS-afbeeldingsbericht om te zetten in een numpy-array voor verwerking met 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()

Gebruiken Ultralytics met ROS Depth Images

Naast RGB-beelden ondersteunt ROS ook dieptebeelden, die informatie geven over de afstand van objecten tot de camera. Dieptebeelden zijn cruciaal voor robottoepassingen zoals het vermijden van obstakels, 3D-kartering en lokalisatie.

Een dieptebeeld is een afbeelding waarbij elke pixel de afstand van de camera tot een object weergeeft. In tegenstelling tot RGB-afbeeldingen die kleur vastleggen, leggen dieptebeelden ruimtelijke informatie vast, waardoor robots de 3D-structuur van hun omgeving kunnen waarnemen.

Dieptebeelden verkrijgen

Dieptebeelden kunnen worden verkregen met behulp van verschillende sensoren:

  1. Stereocamera's: Gebruik twee camera's om diepte te berekenen op basis van beeldongelijkheid.
  2. Time-of-Flight (ToF) camera's: Meten de tijd die licht nodig heeft om terug te keren van een object.
  3. Sensoren met gestructureerd licht: Projecteer een patroon en meet de vervorming ervan op oppervlakken.

Gebruik YOLO met dieptebeelden

In ROS worden dieptebeelden weergegeven door de sensor_msgs/Image Berichttype, dat velden bevat voor codering, hoogte, breedte en pixelgegevens. Het coderingsveld voor diepteafbeeldingen gebruikt vaak een indeling zoals "16UC1", wat een 16-bits niet-ondertekend geheel getal per pixel aangeeft, waarbij elke waarde de afstand tot het object vertegenwoordigt. Dieptebeelden worden vaak gebruikt in combinatie met RGB-beelden om een uitgebreider beeld van de omgeving te geven.

Gebruik YOLO, is het mogelijk om informatie uit zowel RGB- als dieptebeelden te extraheren en te combineren. Bijvoorbeeld YOLO kan objecten in een RGB-afbeelding detecteren en deze detectie kan worden gebruikt om overeenkomstige gebieden in de diepteafbeelding te lokaliseren. Dit maakt het mogelijk om nauwkeurige diepte-informatie voor gedetecteerde objecten te extraheren, waardoor het vermogen van de robot om zijn omgeving in drie dimensies te begrijpen wordt verbeterd.

RGB-D-camera's

Bij het werken met dieptebeelden is het essentieel om ervoor te zorgen dat de RGB- en dieptebeelden correct op elkaar zijn afgestemd. RGB-D camera's, zoals de Intel RealSense serie, leveren gesynchroniseerde RGB- en dieptebeelden, waardoor het eenvoudiger wordt om informatie van beide bronnen te combineren. Als je aparte RGB- en dieptecamera's gebruikt, is het cruciaal om ze te kalibreren voor een nauwkeurige uitlijning.

Diepte stap-voor-stap gebruik

In dit voorbeeld gebruiken we YOLO om een afbeelding te segmenteren en het geĆ«xtraheerde masker toe te passen om het object in de diepteafbeelding te segmenteren. Dit stelt ons in staat om de afstand van elke pixel van het object van belang tot het brandpuntscentrum van de camera te bepalen. Door deze afstandsinformatie te verkrijgen, kunnen we de afstand tussen de camera en het specifieke object in de scĆØne berekenen. Begin met het importeren van de benodigde bibliotheken, het maken van een ROS-knooppunt en het instantiĆ«ren van een segmentatiemodel en een ROS-onderwerp.

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)

Definieer vervolgens een callback-functie die het inkomende dieptebeeldbericht verwerkt. De functie wacht op de dieptebeeld- en RGB-afbeeldingsberichten, converteert deze naar numpy-arrays en past het segmentatiemodel toe op het RGB-beeld. Vervolgens wordt het segmentatiemasker voor elk gedetecteerd object geĆ«xtraheerd en wordt de gemiddelde afstand van het object tot de camera berekend met behulp van het dieptebeeld. De meeste sensoren hebben een maximale afstand, ook wel de clipafstand genoemd, waarboven waarden worden weergegeven als inf (np.inf). VĆ³Ć³r de verwerking is het belangrijk om deze null-waarden eruit te filteren en er een waarde van aan toe te kennen: 0. Ten slotte publiceert het de gedetecteerde objecten samen met hun gemiddelde afstanden tot de /ultralytics/detection/distance onderwerp.

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

Gebruiken Ultralytics met ROS sensor_msgs/PointCloud2

Detectie en segmentatie in ROS Gazebo

De sensor_msgs/PointCloud2 berichttype is een gegevensstructuur die in ROS wordt gebruikt om 3D puntenwolkgegevens weer te geven. Dit berichttype is een integraal onderdeel van robottoepassingen en maakt taken zoals 3D-kartering, objectherkenning en lokalisatie mogelijk.

Een puntenwolk is een verzameling gegevenspunten die zijn gedefinieerd binnen een driedimensionaal coƶrdinatensysteem. Deze datapunten vertegenwoordigen het buitenoppervlak van een object of een scĆØne, vastgelegd via 3D-scantechnologieĆ«n. Elk punt in de cloud heeft X, Yen Z coƶrdinaten, die overeenkomen met zijn positie in de ruimte, en kunnen ook aanvullende informatie bevatten, zoals kleur en intensiteit.

Referentiekader

Bij het werken met sensor_msgs/PointCloud2, is het essentieel om rekening te houden met het referentiekader van de sensor waaruit de puntenwolkgegevens zijn verkregen. De puntenwolk wordt in eerste instantie vastgelegd in het referentiekader van de sensor. U kunt dit referentiekader bepalen door te luisteren naar de /tf_static onderwerp. Afhankelijk van uw specifieke toepassingsvereisten moet u de puntenwolk mogelijk converteren naar een ander referentiekader. Deze transformatie kan worden bereikt met behulp van de tf2_ros pakket, dat hulpprogramma's biedt voor het beheren van coƶrdinatenkaders en het transformeren van gegevens tussen deze frames.

Puntenwolken verkrijgen

Puntenwolken kunnen worden verkregen met behulp van verschillende sensoren:

  1. LIDAR (Light Detection and Ranging): Gebruikt laserpulsen om afstanden tot objecten te meten en zeer nauwkeurige 3D-kaarten te maken.
  2. Dieptecamera's: Leggen diepte-informatie vast voor elke pixel, waardoor 3D-reconstructie van de scĆØne mogelijk wordt.
  3. Stereocamera's: Gebruik twee of meer camera's om diepte-informatie te verkrijgen via driehoeksmeting.
  4. Scanners met gestructureerd licht: Projecteer een bekend patroon op een oppervlak en meet de vervorming om de diepte te berekenen.

Gebruik YOLO met puntenwolken

Integreren YOLO met sensor_msgs/PointCloud2 typ berichten, kunnen we een methode gebruiken die vergelijkbaar is met die voor dieptekaarten. Door gebruik te maken van de kleurinformatie die in de puntenwolk is ingebed, kunnen we een 2D-afbeelding extraheren en segmentatie op deze afbeelding uitvoeren met behulp van YOLOen pas vervolgens het resulterende masker toe op de driedimensionale punten om het 3D-object van belang te isoleren.

Voor het afhandelen van puntenwolken raden we aan om Open3D (pip install open3d), een gebruiksvriendelijke Python bibliotheek. Open3D biedt robuuste tools voor het beheren van puntenwolkgegevensstructuren, het visualiseren ervan en het naadloos uitvoeren van complexe bewerkingen. Deze bibliotheek kan het proces aanzienlijk vereenvoudigen en ons vermogen verbeteren om puntenwolken te manipuleren en te analyseren in combinatie met YOLO-gebaseerde segmentatie.

Puntenwolken stapsgewijs gebruik

Importeer de benodigde bibliotheken en maak de YOLO model voor segmentatie.

import time

import rospy

from ultralytics import YOLO

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

Een functie maken pointcloud2_to_array, die een sensor_msgs/PointCloud2 bericht in twee numpy arrays. De sensor_msgs/PointCloud2 berichten bevatten n punten op basis van de width en height van het verworven beeld. Bijvoorbeeld, een 480 x 640 afbeelding zal hebben 307,200 Punten. Elk punt bevat drie ruimtelijke coƶrdinaten (xyz) en de overeenkomstige kleur in RGB formatteren. Deze kunnen worden beschouwd als twee afzonderlijke informatiekanalen.

De functie retourneert de xyz coƶrdinaten en RGB waarden in het formaat van de oorspronkelijke cameraresolutie (width x height). De meeste sensoren hebben een maximale afstand, ook wel de clipafstand genoemd, waarboven waarden worden weergegeven als inf (np.inf). VĆ³Ć³r de verwerking is het belangrijk om deze null-waarden eruit te filteren en er een waarde van aan toe te kennen: 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

Abonneer u vervolgens op de /camera/depth/points onderwerp om het puntenwolkbericht te ontvangen en de sensor_msgs/PointCloud2 bericht in numpy-arrays die de XYZ-coƶrdinaten en RGB-waarden bevatten (met behulp van de pointcloud2_to_array functie). Verwerk de RGB-afbeelding met behulp van de YOLO model om gesegmenteerde objecten te extraheren. Pak voor elk gedetecteerd object het segmentatiemasker uit en pas het toe op zowel de RGB-afbeelding als de XYZ-coƶrdinaten om het object in de 3D-ruimte te isoleren.

Het verwerken van het masker is eenvoudig omdat het bestaat uit binaire waarden, met 1 het aangeven van de aanwezigheid van het voorwerp en 0 het aangeven van de afwezigheid. Om het masker aan te brengen, vermenigvuldigt u eenvoudig de oorspronkelijke kanalen met het masker. Deze bewerking isoleert effectief het object van belang in de afbeelding. Maak ten slotte een Open3D-puntenwolkobject en visualiseer het gesegmenteerde object in de 3D-ruimte met bijbehorende kleuren.

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])
Volledige 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])

Puntwolksegmentatie met Ultralytics

FAQ

Wat is het Robot Operating System (ROS)?

Het Robot Operating System (ROS) is een open-source raamwerk dat veel gebruikt wordt in de robotica om ontwikkelaars te helpen robuuste robottoepassingen te maken. Het biedt een verzameling bibliotheken en gereedschappen voor het bouwen van en interfacen met robotsystemen, waardoor de ontwikkeling van complexe toepassingen eenvoudiger wordt. ROS ondersteunt communicatie tussen knooppunten door middel van berichten over onderwerpen of diensten.

Hoe integreer ik Ultralytics YOLO met ROS voor realtime objectdetectie?

De integratie van Ultralytics YOLO met ROS bestaat uit het opzetten van een ROS-omgeving en het gebruik van YOLO voor het verwerken van sensorgegevens. Begin met het installeren van de benodigde afhankelijkheden zoals ros_numpy en Ultralytics YOLO :

pip install ros_numpy ultralytics

Maak vervolgens een ROS knooppunt en abonneer je op een afbeeldingsonderwerp om de binnenkomende gegevens te verwerken. Hier is een minimaal voorbeeld:

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

Wat zijn ROS-onderwerpen en hoe worden ze gebruikt in Ultralytics YOLO ?

ROS topics vergemakkelijken de communicatie tussen knooppunten in een ROS netwerk door gebruik te maken van een publish-subscribe model. Een topic is een benoemd kanaal dat nodes gebruiken om asynchroon berichten te verzenden en te ontvangen. In de context van Ultralytics YOLO kun je een knooppunt zich laten abonneren op een afbeeldingsonderwerp, de afbeeldingen verwerken met YOLO voor taken als detectie of segmentatie, en de resultaten publiceren naar nieuwe onderwerpen.

Abonneer je bijvoorbeeld op een cameratopic en verwerk het binnenkomende beeld voor detectie:

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

Waarom dieptebeelden gebruiken met Ultralytics YOLO in ROS?

Dieptebeelden in ROS, weergegeven door sensor_msgs/Imagegeven de afstand van objecten tot de camera, cruciaal voor taken als obstakelvermijding, 3D-kartering en lokalisatie. Door diepte-informatie gebruiken Samen met RGB-beelden kunnen robots hun 3D-omgeving beter begrijpen.

Met YOLO kun je segmentatiemaskers uit RGB-beelden extraheren en deze maskers toepassen op dieptebeelden om precieze 3D-objectinformatie te verkrijgen, waardoor de robot beter kan navigeren en interageren met zijn omgeving.

Hoe kan ik 3D puntenwolken visualiseren met YOLO in ROS?

3D puntenwolken visualiseren in ROS met YOLO:

  1. Converteer sensor_msgs/PointCloud2 berichten naar numpy arrays.
  2. Gebruik YOLO om RGB-afbeeldingen te segmenteren.
  3. Pas het segmentatiemasker toe op de puntenwolk.

Hier is een voorbeeld waarbij Open3D wordt gebruikt voor visualisatie:

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

Deze benadering biedt een 3D-visualisatie van gesegmenteerde objecten, handig voor taken als navigatie en manipulatie.



Aangemaakt 2024-06-19, Bijgewerkt 2024-07-05
Auteurs: glenn-jocher (2), RizwanMunawar (1), ambitious-octopus (3)

Reacties