Краткое руководство по эксплуатации ROS (Robot Operating System)
ROS Introduction (captioned) from Open Robotics on Vimeo.
Что такое ROS?
Robot Operating System (ROS) - это фреймворк с открытым исходным кодом, широко используемый в исследованиях и промышленности в области робототехники. ROS представляет собой набор библиотек и инструментов, помогающих разработчикам создавать приложения для роботов. ROS разработана для работы с различными роботизированными платформами, что делает ее гибким и мощным инструментом для робототехников.
Ключевые особенности ROS
-
Модульная архитектура: ROS имеет модульную архитектуру, позволяющую разработчикам создавать сложные системы путем объединения небольших многократно используемых компонентов, называемых узлами. Каждый узел обычно выполняет определенную функцию, а узлы взаимодействуют друг с другом с помощью сообщений через темы или сервисы.
-
Коммуникационное программное обеспечение: ROS предлагает надежную коммуникационную инфраструктуру, которая поддерживает межпроцессное взаимодействие и распределенные вычисления. Это достигается за счет модели публикации-подписки для потоков данных (тем) и модели запроса-ответа для вызовов сервисов.
-
Аппаратная абстракция: ROS обеспечивает уровень абстракции над аппаратным обеспечением, позволяя разработчикам писать код, не зависящий от устройства. Это позволяет использовать один и тот же код с различными аппаратными установками, облегчая интеграцию и эксперименты.
-
Инструменты и утилиты: ROS поставляется с богатым набором инструментов и утилит для визуализации, отладки и моделирования. Например, RViz используется для визуализации данных датчиков и информации о состоянии робота, а Gazebo представляет собой мощную среду моделирования для тестирования алгоритмов и конструкций роботов.
-
Обширная экосистема: Экосистема ROS обширна и постоянно развивается, в ней доступно множество пакетов для различных робототехнических приложений, включая навигацию, манипулирование, восприятие и многое другое. Сообщество активно участвует в разработке и сопровождении этих пакетов.
Эволюция версий ROS
С момента создания в 2007 году ROS прошла через множество версий, в каждой из которых появлялись новые функции и улучшения для удовлетворения растущих потребностей робототехнического сообщества. Развитие ROS можно разделить на две основные серии: ROS 1 и ROS 2. Данное руководство посвящено версии ROS 1, известной как ROS Noetic Ninjemys, которая находится на долгосрочной поддержке (LTS), однако код может работать и с более ранними версиями.
РОС 1 против РОС 2
Если ROS 1 обеспечивала прочную основу для разработки роботов, то ROS 2 устраняет ее недостатки, предлагая:
- Производительность в реальном времени: Улучшена поддержка систем реального времени и детерминированного поведения.
- Безопасность: Усовершенствованные функции защиты для безопасной и надежной работы в различных условиях.
- Масштабируемость: Улучшенная поддержка многороботных систем и масштабных развертываний.
- Кроссплатформенная поддержка: Расширенная совместимость с различными операционными системами, помимо Linux, включая Windows и macOS.
- Гибкая коммуникация: Использование DDS для более гибкого и эффективного межпроцессного взаимодействия.
Сообщения и темы ROS
В ROS связь между узлами осуществляется с помощью сообщений и тем. Сообщение - это структура данных, определяющая информацию, которой обмениваются узлы, а тема - это именованный канал, по которому отправляются и принимаются сообщения. Узлы могут публиковать сообщения в теме или подписываться на сообщения из темы, что позволяет им общаться друг с другом. Эта модель публикации-подписки позволяет осуществлять асинхронную связь и разделение между узлами. Каждый датчик или исполнительный механизм в роботизированной системе обычно публикует данные в теме, которые затем могут быть использованы другими узлами для обработки или управления. В рамках данного руководства мы рассмотрим сообщения Image, Depth и PointCloud, а также темы камер.
Настройка Ultralytics YOLO с помощью ROS
Данное руководство было протестировано с использованием этой среды ROS, которая является форком репозитория ROSbot ROS. Эта среда включает в себя пакет Ultralytics YOLO , контейнер Docker для простой настройки, комплексные пакеты ROS и миры Gazebo для быстрого тестирования. Она предназначена для работы с Husarion ROSbot 2 PRO. Приведенные примеры кода будут работать в любой среде ROS Noetic/Melodic, включая как симуляцию, так и реальный мир.
Установка зависимостей
Помимо среды ROS, вам потребуется установить следующие зависимости:
-
Пакет ROS Numpy: Он необходим для быстрого преобразования сообщений ROS Image в массивы numpy.
-
Ultralytics пакет:
Используйте Ultralytics с ROS sensor_msgs/Image
Сайт sensor_msgs/Image
тип сообщения широко используется в ROS для представления данных изображения. Оно содержит поля для кодировки, высоты, ширины и пиксельных данных, что делает его пригодным для передачи изображений, полученных с помощью камер или других датчиков. Сообщения с изображениями широко используются в робототехнических приложениях для решения таких задач, как визуальное восприятие, обнаружение объектов, и навигация.
Пошаговое использование изображений
Следующий фрагмент кода демонстрирует, как использовать пакет Ultralytics YOLO в ROS. В этом примере мы подписываемся на тему камеры, обрабатываем входящее изображение с помощью YOLO, а обнаруженные объекты публикуем в новые темы для обнаружения и сегментации.
Сначала импортируйте необходимые библиотеки и создайте две модели: одну для сегментация и один для обнаружение. Инициализируйте узел ROS (с именем ultralytics
) для обеспечения связи с мастером ROS. Чтобы обеспечить стабильное соединение, мы включаем короткую паузу, давая узлу достаточно времени для установления соединения, прежде чем продолжить работу.
import time
import rospy
from ultralytics import YOLO
detection_model = YOLO("yolo11m.pt")
segmentation_model = YOLO("yolo11m-seg.pt")
rospy.init_node("ultralytics")
time.sleep(1)
Инициализируйте две темы ROS: одну для обнаружение и один для сегментация. Эти темы будут использоваться для публикации аннотированных изображений, делая их доступными для дальнейшей обработки. Связь между узлами осуществляется с помощью sensor_msgs/Image
сообщения.
from sensor_msgs.msg import Image
det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)
seg_image_pub = rospy.Publisher("/ultralytics/segmentation/image", Image, queue_size=5)
Наконец, создайте подписчика, который будет прослушивать сообщения на /camera/color/image_raw
тему и вызывает функцию обратного вызова для каждого нового сообщения. Эта функция обратного вызова получает сообщения типа sensor_msgs/Image
, преобразует их в массив numpy с помощью ros_numpy
обрабатывает изображения с помощью ранее созданных моделей YOLO , аннотирует их и затем публикует в соответствующих темах: /ultralytics/detection/image
для обнаружения и /ultralytics/segmentation/image
для сегментации.
import ros_numpy
def callback(data):
"""Callback function to process image and publish annotated images."""
array = ros_numpy.numpify(data)
if det_image_pub.get_num_connections():
det_result = detection_model(array)
det_annotated = det_result[0].plot(show=False)
det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))
if seg_image_pub.get_num_connections():
seg_result = segmentation_model(array)
seg_annotated = seg_result[0].plot(show=False)
seg_image_pub.publish(ros_numpy.msgify(Image, seg_annotated, encoding="rgb8"))
rospy.Subscriber("/camera/color/image_raw", Image, callback)
while True:
rospy.spin()
Полный код
import time
import ros_numpy
import rospy
from sensor_msgs.msg import Image
from ultralytics import YOLO
detection_model = YOLO("yolo11m.pt")
segmentation_model = YOLO("yolo11m-seg.pt")
rospy.init_node("ultralytics")
time.sleep(1)
det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)
seg_image_pub = rospy.Publisher("/ultralytics/segmentation/image", Image, queue_size=5)
def callback(data):
"""Callback function to process image and publish annotated images."""
array = ros_numpy.numpify(data)
if det_image_pub.get_num_connections():
det_result = detection_model(array)
det_annotated = det_result[0].plot(show=False)
det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))
if seg_image_pub.get_num_connections():
seg_result = segmentation_model(array)
seg_annotated = seg_result[0].plot(show=False)
seg_image_pub.publish(ros_numpy.msgify(Image, seg_annotated, encoding="rgb8"))
rospy.Subscriber("/camera/color/image_raw", Image, callback)
while True:
rospy.spin()
Отладка
Отладка узлов ROS (Robot Operating System) может быть сложной из-за распределенной природы системы. Несколько инструментов могут помочь в этом процессе:
rostopic echo <TOPIC-NAME>
: Эта команда позволяет просматривать сообщения, опубликованные в определенной теме, что помогает изучить поток данных.rostopic list
: С помощью этой команды можно получить список всех доступных тем в системе ROS, что позволит вам получить представление об активных потоках данных.rqt_graph
: Этот инструмент визуализации отображает граф связи между узлами, позволяя понять, как узлы связаны между собой и как они взаимодействуют.- Для более сложных визуализаций, таких как 3D-представления, вы можете использовать RViz. RViz (ROS Visualization) - это мощный инструмент 3D-визуализации для ROS. Он позволяет визуализировать состояние вашего робота и его окружения в режиме реального времени. С помощью RViz можно просматривать данные датчиков (напр.
sensors_msgs/Image
), состояния модели робота и различные другие виды информации, что облегчает отладку и понимание поведения роботизированной системы.
Публикуйте обнаруженные классы с помощью std_msgs/String
Стандартные сообщения ROS также включают std_msgs/String
сообщения. Во многих приложениях нет необходимости переиздавать все аннотированное изображение; вместо этого нужны только классы, присутствующие в представлении робота. Следующий пример демонстрирует, как использовать std_msgs/String
сообщения чтобы повторно опубликовать обнаруженные классы на /ultralytics/detection/classes
тема. Эти сообщения более легкие и содержат важную информацию, что делает их ценными для различных приложений.
Пример использования
Рассмотрим складского робота, оснащенного камерой и объектом модель обнаружения. Вместо того чтобы отправлять по сети большие аннотированные изображения, робот может опубликовать список обнаруженных классов в виде std_msgs/String
сообщения. Например, когда робот обнаруживает объекты типа "коробка", "паллета" и "вилочный погрузчик", он публикует эти классы в /ultralytics/detection/classes
тема. Эта информация может быть использована центральной системой мониторинга для отслеживания инвентаря в режиме реального времени, оптимизации планирования траектории движения робота, чтобы избежать препятствий, или для запуска определенных действий, таких как захват обнаруженной коробки. Такой подход позволяет снизить пропускную способность канала связи и сосредоточиться на передаче критически важных данных.
Пошаговое использование строк
Этот пример демонстрирует, как использовать пакет Ultralytics YOLO в ROS. В этом примере мы подписываемся на тему камеры, обрабатываем входящее изображение с помощью YOLO, а обнаруженные объекты публикуем в новой теме /ultralytics/detection/classes
используя std_msgs/String
сообщения. Сайт ros_numpy
Пакет используется для преобразования сообщения ROS Image в массив numpy для обработки с помощью 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("yolo11m.pt")
rospy.init_node("ultralytics")
time.sleep(1)
classes_pub = rospy.Publisher("/ultralytics/detection/classes", String, queue_size=5)
def callback(data):
"""Callback function to process image and publish detected classes."""
array = ros_numpy.numpify(data)
if classes_pub.get_num_connections():
det_result = detection_model(array)
classes = det_result[0].boxes.cls.cpu().numpy().astype(int)
names = [det_result[0].names[i] for i in classes]
classes_pub.publish(String(data=str(names)))
rospy.Subscriber("/camera/color/image_raw", Image, callback)
while True:
rospy.spin()
Использование Ultralytics с изображениями глубины ROS
Помимо RGB-изображений, ROS поддерживает изображения глубины, которые предоставляют информацию об удаленности объектов от камеры. Изображения глубины крайне важны для таких робототехнических приложений, как обход препятствий, 3D-картография и локализация.
Изображение глубины - это изображение, каждый пиксель которого представляет собой расстояние от камеры до объекта. В отличие от RGB-изображений, передающих цвет, изображения глубины передают пространственную информацию, позволяя роботам воспринимать трехмерную структуру окружающей среды.
Получение изображений глубины
Изображения глубины могут быть получены с помощью различных датчиков:
- Стереокамеры: Использование двух камер для расчета глубины на основе расхождения изображений.
- Камеры с временным пролетом (ToF): Измеряют время, за которое свет возвращается от объекта.
- Датчики структурированного света: Проецируйте рисунок и измеряйте его деформацию на поверхности.
Использование YOLO с изображениями глубины
В ROS изображения глубины представлены с помощью sensor_msgs/Image
тип сообщения, включающий поля для кодировки, высоты, ширины и пиксельных данных. Поле кодировки для изображений глубины часто использует формат типа "16UC1", указывающий на 16-битное целое число без знака на пиксель, где каждое значение представляет собой расстояние до объекта. Изображения глубины обычно используются в сочетании с RGB-изображениями для получения более полного представления об окружающей среде.
С помощью YOLO можно извлекать и объединять информацию как из RGB-изображений, так и из изображений глубины. Например, YOLO может обнаруживать объекты на RGB-изображении, и это обнаружение может быть использовано для определения соответствующих областей на изображении глубины. Это позволяет извлекать точную информацию о глубине для обнаруженных объектов, расширяя возможности робота по восприятию окружающей среды в трех измерениях.
Камеры RGB-D
При работе с изображениями глубины необходимо обеспечить правильное совмещение RGB-изображений и изображений глубины. Камеры RGB-D, такие как серия Intel RealSense, обеспечивают синхронизацию изображений RGB и глубины, что облегчает объединение информации из обоих источников. Если используются отдельные камеры RGB и глубины, очень важно откалибровать их, чтобы обеспечить точное выравнивание.
Глубина Пошаговое использование
В этом примере мы используем YOLO для сегментации изображения и применяем извлеченную маску для сегментации объекта на изображении глубины. Это позволяет нам определить расстояние каждого пикселя интересующего нас объекта от фокусного центра камеры. Получив эту информацию о расстоянии, мы сможем рассчитать расстояние между камерой и конкретным объектом в сцене. Начните с импорта необходимых библиотек, создания узла ROS, инстанцирования модели сегментации и темы ROS.
import time
import rospy
from std_msgs.msg import String
from ultralytics import YOLO
rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolo11m-seg.pt")
classes_pub = rospy.Publisher("/ultralytics/detection/distance", String, queue_size=5)
Затем определите функцию обратного вызова, которая обрабатывает входящее сообщение с изображением глубины. Функция ожидает сообщений с изображением глубины и RGB-изображением, преобразует их в массивы numpy и применяет модель сегментации к RGB-изображению. Затем она извлекает маску сегментации для каждого обнаруженного объекта и вычисляет среднее расстояние объекта от камеры по изображению глубины. Большинство датчиков имеют максимальное расстояние, известное как расстояние клипа, за пределами которого значения представляются как inf (np.inf
). Перед обработкой важно отфильтровать эти нулевые значения и присвоить им значение 0
. Наконец, он публикует обнаруженные объекты вместе с их средним расстоянием до /ultralytics/detection/distance
тема.
import numpy as np
import ros_numpy
from sensor_msgs.msg import Image
def callback(data):
"""Callback function to process depth image and RGB image."""
image = rospy.wait_for_message("/camera/color/image_raw", Image)
image = ros_numpy.numpify(image)
depth = ros_numpy.numpify(data)
result = segmentation_model(image)
all_objects = []
for index, cls in enumerate(result[0].boxes.cls):
class_index = int(cls.cpu().numpy())
name = result[0].names[class_index]
mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
obj = depth[mask == 1]
obj = obj[~np.isnan(obj)]
avg_distance = np.mean(obj) if len(obj) else np.inf
all_objects.append(f"{name}: {avg_distance:.2f}m")
classes_pub.publish(String(data=str(all_objects)))
rospy.Subscriber("/camera/depth/image_raw", Image, callback)
while True:
rospy.spin()
Полный код
import time
import numpy as np
import ros_numpy
import rospy
from sensor_msgs.msg import Image
from std_msgs.msg import String
from ultralytics import YOLO
rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolo11m-seg.pt")
classes_pub = rospy.Publisher("/ultralytics/detection/distance", String, queue_size=5)
def callback(data):
"""Callback function to process depth image and RGB image."""
image = rospy.wait_for_message("/camera/color/image_raw", Image)
image = ros_numpy.numpify(image)
depth = ros_numpy.numpify(data)
result = segmentation_model(image)
all_objects = []
for index, cls in enumerate(result[0].boxes.cls):
class_index = int(cls.cpu().numpy())
name = result[0].names[class_index]
mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
obj = depth[mask == 1]
obj = obj[~np.isnan(obj)]
avg_distance = np.mean(obj) if len(obj) else np.inf
all_objects.append(f"{name}: {avg_distance:.2f}m")
classes_pub.publish(String(data=str(all_objects)))
rospy.Subscriber("/camera/depth/image_raw", Image, callback)
while True:
rospy.spin()
Используйте Ultralytics с ROS sensor_msgs/PointCloud2
Сайт sensor_msgs/PointCloud2
тип сообщения это структура данных, используемая в ROS для представления данных 3D облака точек. Этот тип сообщений является неотъемлемой частью робототехнических приложений, позволяя решать такие задачи, как 3D-картографирование, распознавание объектов и локализация.
Облако точек - это набор точек данных, определенных в трехмерной системе координат. Эти точки представляют собой внешнюю поверхность объекта или сцены, полученную с помощью технологий 3D-сканирования. Каждая точка в облаке имеет X
, Y
, и Z
координаты, которые соответствуют его положению в пространстве, а также могут включать дополнительную информацию, такую как цвет и интенсивность.
Система отсчета
При работе с sensor_msgs/PointCloud2
При этом необходимо учитывать систему отсчета датчика, с которого были получены данные облака точек. Изначально облако точек снимается в системе отсчета датчика. Вы можете определить эту систему отсчета, прослушав /tf_static
тема. Однако в зависимости от конкретных требований приложения вам может понадобиться преобразовать облако точек в другую систему отсчета. Это преобразование можно выполнить с помощью функции tf2_ros
пакет, который предоставляет инструменты для управления координатными рамками и преобразования данных между ними.
Получение облаков точек
Облака точек могут быть получены с помощью различных датчиков:
- LIDAR (Light Detection and Ranging): Использует лазерные импульсы для измерения расстояния до объектов и создания высокоточных 3D-карт.
- Камеры глубины: Захватывают информацию о глубине для каждого пикселя, что позволяет воссоздать 3D-сцену.
- Стереокамеры: Использование двух или более камер для получения информации о глубине с помощью триангуляции.
- Сканеры структурированного света: Проецируют известный рисунок на поверхность и измеряют деформацию для расчета глубины.
Использование YOLO с точечными облаками
Чтобы интегрировать YOLO с sensor_msgs/PointCloud2
Для получения сообщений такого типа мы можем использовать метод, аналогичный тому, что применяется для карт глубины. Используя информацию о цвете, заложенную в облаке точек, мы можем извлечь двумерное изображение, выполнить сегментацию этого изображения с помощью YOLO, а затем применить полученную маску к трехмерным точкам, чтобы выделить интересующий нас 3D-объект.
Для работы с облаками точек мы рекомендуем использовать Open3D (pip install open3d
), удобная библиотека Python . Open3D предоставляет надежные инструменты для управления структурами данных облака точек, их визуализации и беспрепятственного выполнения сложных операций. Эта библиотека может значительно упростить процесс и расширить наши возможности по манипулированию и анализу облаков точек в сочетании с сегментацией на основе YOLO.
Пошаговое использование облаков точек
Импортируйте необходимые библиотеки и создайте модель YOLO для сегментации.
import time
import rospy
from ultralytics import YOLO
rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolo11m-seg.pt")
Создайте функцию pointcloud2_to_array
, который преобразует sensor_msgs/PointCloud2
сообщение в два массива numpy. Массив sensor_msgs/PointCloud2
сообщения содержат n
баллы, основанные на width
и height
полученного изображения. Например. 480 x 640
изображение будет иметь 307,200
точки. Каждая точка включает в себя три пространственные координаты (xyz
) и соответствующий цвет в RGB
формат. Их можно рассматривать как два отдельных канала передачи информации.
Функция возвращает xyz
координаты и RGB
значения в формате исходного разрешения камеры (width x height
). Большинство датчиков имеют максимальное расстояние, известное как расстояние клипа, за пределами которого значения представляются как inf (np.inf
). Перед обработкой важно отфильтровать эти нулевые значения и присвоить им значение 0
.
import numpy as np
import ros_numpy
def pointcloud2_to_array(pointcloud2: PointCloud2) -> tuple:
"""
Convert a ROS PointCloud2 message to a numpy array.
Args:
pointcloud2 (PointCloud2): the PointCloud2 message
Returns:
(tuple): tuple containing (xyz, rgb)
"""
pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
nan_rows = np.isnan(xyz).all(axis=2)
xyz[nan_rows] = [0, 0, 0]
rgb[nan_rows] = [0, 0, 0]
return xyz, rgb
Затем подпишитесь на /camera/depth/points
тема для получения сообщения об облаке точек и преобразования sensor_msgs/PointCloud2
сообщение в массивы numpy, содержащие координаты XYZ и значения RGB (с помощью pointcloud2_to_array
функция). Обработайте RGB-изображение с помощью модели YOLO , чтобы выделить сегментированные объекты. Для каждого обнаруженного объекта извлекаем маску сегментации и применяем ее как к RGB-изображению, так и к координатам XYZ, чтобы выделить объект в 3D-пространстве.
Обработка маски проста, поскольку она состоит из двоичных значений, причем 1
указывающий на наличие объекта и 0
указывает на отсутствие. Чтобы применить маску, просто умножьте исходные каналы на маску. Эта операция позволяет эффективно изолировать интересующий объект на изображении. Наконец, создайте объект облака точек Open3D и визуализируйте сегментированный объект в 3D-пространстве с соответствующими цветами.
import sys
import open3d as o3d
ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
xyz, rgb = pointcloud2_to_array(ros_cloud)
result = segmentation_model(rgb)
if not len(result[0].boxes.cls):
print("No objects detected")
sys.exit()
classes = result[0].boxes.cls.cpu().numpy().astype(int)
for index, class_id in enumerate(classes):
mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
mask_expanded = np.stack([mask, mask, mask], axis=2)
obj_rgb = rgb * mask_expanded
obj_xyz = xyz * mask_expanded
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((ros_cloud.height * ros_cloud.width, 3)))
pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((ros_cloud.height * ros_cloud.width, 3)) / 255)
o3d.visualization.draw_geometries([pcd])
Полный код
import sys
import time
import numpy as np
import open3d as o3d
import ros_numpy
import rospy
from sensor_msgs.msg import PointCloud2
from ultralytics import YOLO
rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolo11m-seg.pt")
def pointcloud2_to_array(pointcloud2: PointCloud2) -> tuple:
"""
Convert a ROS PointCloud2 message to a numpy array.
Args:
pointcloud2 (PointCloud2): the PointCloud2 message
Returns:
(tuple): tuple containing (xyz, rgb)
"""
pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
nan_rows = np.isnan(xyz).all(axis=2)
xyz[nan_rows] = [0, 0, 0]
rgb[nan_rows] = [0, 0, 0]
return xyz, rgb
ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
xyz, rgb = pointcloud2_to_array(ros_cloud)
result = segmentation_model(rgb)
if not len(result[0].boxes.cls):
print("No objects detected")
sys.exit()
classes = result[0].boxes.cls.cpu().numpy().astype(int)
for index, class_id in enumerate(classes):
mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
mask_expanded = np.stack([mask, mask, mask], axis=2)
obj_rgb = rgb * mask_expanded
obj_xyz = xyz * mask_expanded
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((ros_cloud.height * ros_cloud.width, 3)))
pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((ros_cloud.height * ros_cloud.width, 3)) / 255)
o3d.visualization.draw_geometries([pcd])
ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
Что такое операционная система робота (ROS)?
Robot Operating System (ROS) - это фреймворк с открытым исходным кодом, широко используемый в робототехнике и помогающий разработчикам создавать надежные приложения для роботов. Она предоставляет набор библиотек и инструментов для создания и взаимодействия с роботизированными системами, облегчая разработку сложных приложений. ROS поддерживает связь между узлами с помощью сообщений через темы или сервисы.
Как интегрировать Ultralytics YOLO с ROS для обнаружения объектов в реальном времени?
Интеграция Ultralytics YOLO с ROS включает в себя настройку среды ROS и использование YOLO для обработки данных датчиков. Начните с установки необходимых зависимостей, таких как ros_numpy
и Ultralytics YOLO :
Затем создайте узел ROS и подпишитесь на тему изображений, чтобы обрабатывать поступающие данные. Вот минимальный пример:
import ros_numpy
import rospy
from sensor_msgs.msg import Image
from ultralytics import YOLO
detection_model = YOLO("yolo11m.pt")
rospy.init_node("ultralytics")
det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)
def callback(data):
array = ros_numpy.numpify(data)
det_result = detection_model(array)
det_annotated = det_result[0].plot(show=False)
det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))
rospy.Subscriber("/camera/color/image_raw", Image, callback)
rospy.spin()
Что такое темы ROS и как они используются в Ultralytics YOLO ?
Темы ROS обеспечивают связь между узлами в сети ROS с помощью модели публикации-подписки. Тема - это именованный канал, который узлы используют для асинхронной отправки и получения сообщений. В контексте Ultralytics YOLO вы можете заставить узел подписаться на тему изображений, обрабатывать изображения с помощью YOLO для таких задач, как обнаружение или сегментация, и публиковать результаты в новых темах.
Например, подпишитесь на тему камеры и обработайте входящее изображение для обнаружения:
Зачем использовать изображения глубины с Ultralytics YOLO в ROS?
Глубинные изображения в ROS, представленные sensor_msgs/Image
Они позволяют определить расстояние до объектов, находящихся на расстоянии от камеры, что очень важно для таких задач, как предотвращение столкновений с препятствиями, 3D-картографирование и локализация. По ссылке использование информации о глубине Вместе с RGB-изображениями роботы могут лучше понимать окружающую их 3D-среду.
С помощью YOLO можно извлекать маски сегментации из RGB-изображений и применять их к изображениям глубины для получения точной информации о 3D-объектах, что улучшает способность робота ориентироваться и взаимодействовать с окружающей средой.
Как визуализировать 3D-облака точек с помощью YOLO в ROS?
Визуализация 3D-облаков точек в ROS с помощью YOLO:
- Конвертировать
sensor_msgs/PointCloud2
сообщения в массивы numpy. - Используйте YOLO для сегментации RGB-изображений.
- Примените маску сегментации к облаку точек.
Вот пример использования Open3D для визуализации:
import sys
import open3d as o3d
import ros_numpy
import rospy
from sensor_msgs.msg import PointCloud2
from ultralytics import YOLO
rospy.init_node("ultralytics")
segmentation_model = YOLO("yolo11m-seg.pt")
def pointcloud2_to_array(pointcloud2):
pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
return xyz, rgb
ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
xyz, rgb = pointcloud2_to_array(ros_cloud)
result = segmentation_model(rgb)
if not len(result[0].boxes.cls):
print("No objects detected")
sys.exit()
classes = result[0].boxes.cls.cpu().numpy().astype(int)
for index, class_id in enumerate(classes):
mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
mask_expanded = np.stack([mask, mask, mask], axis=2)
obj_rgb = rgb * mask_expanded
obj_xyz = xyz * mask_expanded
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((-1, 3)))
pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((-1, 3)) / 255)
o3d.visualization.draw_geometries([pcd])
Этот подход обеспечивает 3D-визуализацию сегментированных объектов, что полезно для таких задач, как навигация и манипулирование в робототехнике.