Hướng dẫn bắt đầu nhanh ROS (Hệ điều hành robot)
Giới thiệu ROS (chú thích) từ Open Robotics trên Vimeo.
ROS là gì?
Hệ điều hành robot (ROS) là một khung mã nguồn mở được sử dụng rộng rãi trong nghiên cứu và công nghiệp robot. ROS cung cấp một bộ sưu tập các thư viện và công cụ để giúp các nhà phát triển tạo ra các ứng dụng robot. ROS được thiết kế để làm việc với các nền tảng robot khác nhau, làm cho nó trở thành một công cụ linh hoạt và mạnh mẽ cho các nhà nghiên cứu robot.
Các tính năng chính của ROS
Kiến trúc mô-đun: ROS có kiến trúc mô-đun, cho phép các nhà phát triển xây dựng các hệ thống phức tạp bằng cách kết hợp các thành phần nhỏ hơn, có thể tái sử dụng được gọi là các nút. Mỗi nút thường thực hiện một chức năng cụ thể và các nút giao tiếp với nhau bằng cách sử dụng các thông điệp qua các chủ đề hoặc dịch vụ.
Communication Middleware: ROS cung cấp một cơ sở hạ tầng truyền thông mạnh mẽ hỗ trợ giao tiếp giữa các tiến trình và điện toán phân tán. Điều này đạt được thông qua mô hình đăng ký xuất bản cho các luồng dữ liệu (chủ đề) và mô hình yêu cầu-trả lời cho các cuộc gọi dịch vụ.
Trừu tượng hóa phần cứng: ROS cung cấp một lớp trừu tượng trên phần cứng, cho phép các nhà phát triển viết mã bất khả tri thiết bị. Điều này cho phép cùng một mã được sử dụng với các thiết lập phần cứng khác nhau, tạo điều kiện tích hợp và thử nghiệm dễ dàng hơn.
Công cụ và tiện ích: ROS đi kèm với một bộ công cụ và tiện ích phong phú để trực quan hóa, gỡ lỗi và mô phỏng. Ví dụ, RViz được sử dụng để trực quan hóa dữ liệu cảm biến và thông tin trạng thái robot, trong khi Gazebo cung cấp một môi trường mô phỏng mạnh mẽ để kiểm tra các thuật toán và thiết kế robot.
Hệ sinh thái mở rộng: Hệ sinh thái ROS rộng lớn và liên tục phát triển, với nhiều gói có sẵn cho các ứng dụng robot khác nhau, bao gồm điều hướng, thao tác, nhận thức và hơn thế nữa. Cộng đồng đóng góp tích cực vào việc phát triển và duy trì các gói này.
Sự phát triển của các phiên bản ROS
Kể từ khi phát triển vào năm 2007, ROS đã phát triển qua nhiều phiên bản, mỗi phiên bản giới thiệu các tính năng và cải tiến mới để đáp ứng nhu cầu ngày càng tăng của cộng đồng robot. Sự phát triển của ROS có thể được phân loại thành hai loạt chính: ROS 1 và ROS 2. Hướng dẫn này tập trung vào phiên bản Hỗ trợ dài hạn (LTS) của ROS 1, được gọi là ROS Noetic Ninjemys, mã cũng sẽ hoạt động với các phiên bản trước đó.
ROS 1 so với ROS 2
Trong khi ROS 1 cung cấp một nền tảng vững chắc cho sự phát triển robot, ROS 2 giải quyết những thiếu sót của nó bằng cách cung cấp:
- Hiệu suất thời gian thực: Cải thiện hỗ trợ cho các hệ thống thời gian thực và hành vi xác định.
- Bảo mật: Các tính năng bảo mật nâng cao để hoạt động an toàn và đáng tin cậy trong các môi trường khác nhau.
- Khả năng mở rộng: Hỗ trợ tốt hơn cho các hệ thống đa robot và triển khai quy mô lớn.
- Hỗ trợ đa nền tảng: Khả năng tương thích mở rộng với các hệ điều hành khác nhau ngoài Linux, bao gồm Windows và macOS.
- Giao tiếp linh hoạt: Sử dụng DDS để giao tiếp giữa các tiến trình linh hoạt và hiệu quả hơn.
Thông điệp và chủ đề ROS
Trong ROS, giao tiếp giữa các nút được tạo điều kiện thông qua các thông điệp và chủ đề. Thông điệp là một cấu trúc dữ liệu xác định thông tin được trao đổi giữa các nút, trong khi một chủ đề là một kênh được đặt tên mà tin nhắn được gửi và nhận. Các nút có thể xuất bản tin nhắn cho một chủ đề hoặc đăng ký tin nhắn từ một chủ đề, cho phép chúng giao tiếp với nhau. Mô hình đăng ký xuất bản này cho phép giao tiếp không đồng bộ và tách rời giữa các nút. Mỗi cảm biến hoặc bộ truyền động trong một hệ thống robot thường xuất bản dữ liệu cho một chủ đề, sau đó có thể được tiêu thụ bởi các nút khác để xử lý hoặc điều khiển. Với mục đích của hướng dẫn này, chúng tôi sẽ tập trung vào các thông điệp Hình ảnh, Độ sâu và PointCloud và các chủ đề máy ảnh.
Thiết lập Ultralytics YOLO với ROS
Hướng dẫn này đã được thử nghiệm bằng cách sử dụng môi trường ROS này, là một nhánh của kho lưu trữ ROSbot ROS. Môi trường này bao gồm Ultralytics YOLO gói, một container Docker để dễ dàng thiết lập, các gói ROS toàn diện và thế giới Gazebo để kiểm tra nhanh. Nó được thiết kế để hoạt động với Husarion ROSbot 2 PRO. Các ví dụ mã được cung cấp sẽ hoạt động trong bất kỳ môi trường ROS Noetic / Melodic nào, bao gồm cả mô phỏng và thế giới thực.
Cài đặt phụ thuộc
Ngoài môi trường ROS, bạn sẽ cần cài đặt các phụ thuộc sau:
Gói ROS Numpy: Điều này là cần thiết để chuyển đổi nhanh chóng giữa tin nhắn ROS Image và mảng numpy.
Ultralytics Đóng gói:
Dùng Ultralytics với ROS sensor_msgs/Image
Các sensor_msgs/Image
Loại tin nhắn thường được sử dụng trong ROS để biểu diễn dữ liệu hình ảnh. Nó chứa các trường để mã hóa, chiều cao, chiều rộng và dữ liệu pixel, làm cho nó phù hợp để truyền hình ảnh được chụp bởi máy ảnh hoặc các cảm biến khác. Tin nhắn hình ảnh được sử dụng rộng rãi trong các ứng dụng robot cho các nhiệm vụ như nhận thức thị giác, phát hiện đối tượngvà điều hướng.
Sử dụng hình ảnh từng bước
Đoạn mã sau đây minh họa cách sử dụng Ultralytics YOLO gói với ROS. Trong ví dụ này, chúng tôi đăng ký một chủ đề máy ảnh, xử lý hình ảnh đến bằng cách sử dụng YOLOvà xuất bản các đối tượng được phát hiện sang các chủ đề mới để phát hiện và phân đoạn.
Đầu tiên, nhập các thư viện cần thiết và khởi tạo hai mô hình: một cho Phân đoạn và một cho Detection. Khởi tạo nút ROS (với tên ultralytics
) để cho phép giao tiếp với ROS master. Để đảm bảo kết nối ổn định, chúng tôi bao gồm một khoảng dừng ngắn, cho nút đủ thời gian để thiết lập kết nối trước khi tiếp tục.
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)
Khởi tạo hai chủ đề ROS: một cho Detection và một cho Phân đoạn. Các chủ đề này sẽ được sử dụng để xuất bản các hình ảnh được chú thích, làm cho chúng có thể truy cập để xử lý thêm. Giao tiếp giữa các nút được tạo điều kiện bằng cách sử dụng sensor_msgs/Image
Thư.
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)
Cuối cùng, tạo một thuê bao lắng nghe tin nhắn trên /camera/color/image_raw
chủ đề và gọi hàm callback cho mỗi tin nhắn mới. Hàm callback này nhận các thông điệp kiểu sensor_msgs/Image
, chuyển đổi chúng thành một mảng numpy bằng cách sử dụng ros_numpy
, xử lý hình ảnh với bản khởi tạo trước đó YOLO mô hình, chú thích hình ảnh, và sau đó xuất bản chúng trở lại các chủ đề tương ứng: /ultralytics/detection/image
để phát hiện và /ultralytics/segmentation/image
để phân khúc.
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()
Mã hoàn chỉnh
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()
Gỡ lỗi
Việc gỡ lỗi các nút ROS (Hệ điều hành robot) có thể là một thách thức do tính chất phân tán của hệ thống. Một số công cụ có thể hỗ trợ quá trình này:
rostopic echo <TOPIC-NAME>
: Lệnh này cho phép bạn xem các tin nhắn được xuất bản về một chủ đề cụ thể, giúp bạn kiểm tra luồng dữ liệu.rostopic list
: Sử dụng lệnh này để liệt kê tất cả các chủ đề có sẵn trong hệ thống ROS, cung cấp cho bạn tổng quan về các luồng dữ liệu đang hoạt động.rqt_graph
: Công cụ trực quan hóa này hiển thị biểu đồ giao tiếp giữa các nút, cung cấp thông tin chi tiết về cách các nút được kết nối với nhau và cách chúng tương tác.- Đối với các hình ảnh trực quan phức tạp hơn, chẳng hạn như biểu diễn 3D, bạn có thể sử dụng RViz. RViz (ROS Visualization) là một công cụ trực quan hóa 3D mạnh mẽ cho ROS. Nó cho phép bạn hình dung trạng thái của robot và môi trường của nó trong thời gian thực. Với RViz, bạn có thể xem dữ liệu cảm biến (ví dụ:
sensors_msgs/Image
), trạng thái mô hình robot và nhiều loại thông tin khác, giúp gỡ lỗi và hiểu hành vi của hệ thống robot của bạn dễ dàng hơn.
Xuất bản các lớp được phát hiện với std_msgs/String
Thông điệp ROS tiêu chuẩn cũng bao gồm std_msgs/String
Thư. Trong nhiều ứng dụng, không cần thiết phải xuất bản lại toàn bộ hình ảnh được chú thích; Thay vào đó, chỉ cần các lớp có trong chế độ xem của robot. Ví dụ sau đây minh họa cách sử dụng std_msgs/String
Thư để phát hành lại các lớp được phát hiện trên /ultralytics/detection/classes
chủ đề. Những thông điệp này nhẹ hơn và cung cấp thông tin cần thiết, làm cho chúng có giá trị cho các ứng dụng khác nhau.
Trường hợp sử dụng ví dụ
Hãy xem xét một robot kho được trang bị camera và đồ vật Mô hình phát hiện. Thay vì gửi hình ảnh chú thích lớn qua mạng, robot có thể xuất bản danh sách các lớp được phát hiện dưới dạng std_msgs/String
Thư. Ví dụ, khi robot phát hiện các đối tượng như "hộp", "pallet" và "xe nâng", nó sẽ xuất bản các lớp này lên /ultralytics/detection/classes
chủ đề. Thông tin này sau đó có thể được sử dụng bởi một hệ thống giám sát trung tâm để theo dõi hàng tồn kho trong thời gian thực, tối ưu hóa kế hoạch đường đi của robot để tránh chướng ngại vật hoặc kích hoạt các hành động cụ thể như nhặt một hộp được phát hiện. Cách tiếp cận này làm giảm băng thông cần thiết cho giao tiếp và tập trung vào việc truyền dữ liệu quan trọng.
Sử dụng chuỗi từng bước
Ví dụ này minh họa cách sử dụng Ultralytics YOLO gói với ROS. Trong ví dụ này, chúng tôi đăng ký một chủ đề máy ảnh, xử lý hình ảnh đến bằng cách sử dụng YOLOvà phát hành các đối tượng được phát hiện sang chủ đề mới /ultralytics/detection/classes
Sử dụng std_msgs/String
Thư. Các ros_numpy
gói được sử dụng để chuyển đổi tin nhắn ROS Image thành mảng numpy để xử lý với 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()
Dùng Ultralytics với ROS Depth Images
Ngoài hình ảnh RGB, ROS hỗ trợ hình ảnh độ sâu, cung cấp thông tin về khoảng cách của các đối tượng từ máy ảnh. Hình ảnh độ sâu rất quan trọng đối với các ứng dụng robot như tránh chướng ngại vật, lập bản đồ 3D và bản địa hóa.
Hình ảnh chiều sâu là hình ảnh trong đó mỗi pixel đại diện cho khoảng cách từ máy ảnh đến một đối tượng. Không giống như hình ảnh RGB chụp màu, hình ảnh độ sâu nắm bắt thông tin không gian, cho phép robot nhận biết cấu trúc 3D của môi trường của chúng.
Thu được hình ảnh độ sâu
Hình ảnh độ sâu có thể thu được bằng các cảm biến khác nhau:
- Camera âm thanh nổi: Sử dụng hai camera để tính toán độ sâu dựa trên sự chênh lệch hình ảnh.
- Máy ảnh thời gian bay (ToF): Đo thời gian ánh sáng cần để quay trở lại từ một vật thể.
- Cảm biến ánh sáng có cấu trúc: Chiếu một mẫu và đo biến dạng của nó trên bề mặt.
Sử dụng YOLO với Hình ảnh chiều sâu
Trong ROS, hình ảnh độ sâu được thể hiện bằng sensor_msgs/Image
Loại tin nhắn, bao gồm các trường để mã hóa, chiều cao, chiều rộng và dữ liệu pixel. Trường mã hóa cho hình ảnh độ sâu thường sử dụng định dạng như "16UC1", cho biết số nguyên không dấu 16 bit trên mỗi pixel, trong đó mỗi giá trị đại diện cho khoảng cách đến đối tượng. Hình ảnh chiều sâu thường được sử dụng kết hợp với hình ảnh RGB để cung cấp cái nhìn toàn diện hơn về môi trường.
Sử dụng YOLO, có thể trích xuất và kết hợp thông tin từ cả RGB và hình ảnh độ sâu. Chẳng hạn YOLO có thể phát hiện các đối tượng trong hình ảnh RGB và phát hiện này có thể được sử dụng để xác định các vùng tương ứng trong hình ảnh độ sâu. Điều này cho phép trích xuất thông tin độ sâu chính xác cho các đối tượng được phát hiện, tăng cường khả năng hiểu môi trường của robot theo ba chiều.
Máy ảnh RGB-D
Khi làm việc với hình ảnh độ sâu, điều cần thiết là phải đảm bảo rằng RGB và hình ảnh độ sâu được căn chỉnh chính xác. Máy ảnh RGB-D, chẳng hạn như Intel Dòng RealSense , cung cấp RGB và hình ảnh độ sâu được đồng bộ hóa, giúp kết hợp thông tin từ cả hai nguồn dễ dàng hơn. Nếu sử dụng RGB và camera độ sâu riêng biệt, điều quan trọng là phải hiệu chỉnh chúng để đảm bảo căn chỉnh chính xác.
Độ sâu từng bước sử dụng
Trong ví dụ này, chúng tôi sử dụng YOLO để phân đoạn hình ảnh và áp dụng mặt nạ được trích xuất để phân đoạn đối tượng trong hình ảnh độ sâu. Điều này cho phép chúng tôi xác định khoảng cách của từng điểm ảnh của đối tượng quan tâm từ tâm tiêu cự của máy ảnh. Bằng cách thu thập thông tin khoảng cách này, chúng ta có thể tính toán khoảng cách giữa máy ảnh và đối tượng cụ thể trong cảnh. Bắt đầu bằng cách nhập các thư viện cần thiết, tạo nút ROS và khởi tạo mô hình phân đoạn và chủ đề 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("yolov8m-seg.pt")
classes_pub = rospy.Publisher("/ultralytics/detection/distance", String, queue_size=5)
Tiếp theo, xác định một hàm callback xử lý thông điệp hình ảnh độ sâu đến. Hàm chờ hình ảnh độ sâu và thông báo hình ảnh RGB, chuyển đổi chúng thành mảng tê và áp dụng mô hình phân đoạn cho hình ảnh RGB. Sau đó, nó trích xuất mặt nạ phân đoạn cho mỗi đối tượng được phát hiện và tính toán khoảng cách trung bình của đối tượng từ máy ảnh bằng cách sử dụng hình ảnh độ sâu. Hầu hết các cảm biến có khoảng cách tối đa, được gọi là khoảng cách clip, ngoài đó các giá trị được biểu diễn dưới dạng inf (np.inf
). Trước khi xử lý, điều quan trọng là phải lọc ra các giá trị null này và gán cho chúng một giá trị 0
. Cuối cùng, nó xuất bản các đối tượng được phát hiện cùng với khoảng cách trung bình của chúng đến /ultralytics/detection/distance
chủ đề.
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()
Mã hoàn chỉnh
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()
Dùng Ultralytics với ROS sensor_msgs/PointCloud2
Các sensor_msgs/PointCloud2
Loại tin nhắn là một cấu trúc dữ liệu được sử dụng trong ROS để biểu diễn dữ liệu đám mây điểm 3D. Loại thông báo này không thể thiếu cho các ứng dụng robot, cho phép các tác vụ như lập bản đồ 3D, nhận dạng đối tượng và bản địa hóa.
Đám mây điểm là một tập hợp các điểm dữ liệu được xác định trong hệ tọa độ ba chiều. Các điểm dữ liệu này đại diện cho bề mặt bên ngoài của một đối tượng hoặc một cảnh, được chụp thông qua các công nghệ quét 3D. Mỗi điểm trong đám mây có X
, Y
và Z
tọa độ, tương ứng với vị trí của nó trong không gian, và cũng có thể bao gồm thông tin bổ sung như màu sắc và cường độ.
Khung tham chiếu
Khi làm việc với sensor_msgs/PointCloud2
, điều cần thiết là phải xem xét khung tham chiếu của cảm biến mà từ đó dữ liệu đám mây điểm được thu thập. Đám mây điểm ban đầu được chụp trong khung tham chiếu của cảm biến. Bạn có thể xác định khung tham chiếu này bằng cách nghe /tf_static
chủ đề. Tuy nhiên, tùy thuộc vào yêu cầu ứng dụng cụ thể của bạn, bạn có thể cần phải chuyển đổi đám mây điểm thành một khung tham chiếu khác. Sự chuyển đổi này có thể đạt được bằng cách sử dụng tf2_ros
gói, cung cấp các công cụ để quản lý khung tọa độ và chuyển đổi dữ liệu giữa chúng.
Lấy đám mây điểm
Đám mây điểm có thể thu được bằng các cảm biến khác nhau:
- LIDAR (Phát hiện và đo khoảng cách bằng ánh sáng) : Sử dụng các xung laser để đo khoảng cách đến các vật thể và tạo ra bản đồ 3D có độ chính xác cao.
- Camera độ sâu: Chụp thông tin độ sâu cho từng pixel, cho phép tái tạo 3D cảnh.
- Camera âm thanh nổi: Sử dụng hai hoặc nhiều camera để có được thông tin độ sâu thông qua tam giác.
- Máy quét ánh sáng có cấu trúc: Chiếu một mẫu đã biết lên bề mặt và đo biến dạng để tính toán độ sâu.
Sử dụng YOLO với Point Clouds
Để tích hợp YOLO với sensor_msgs/PointCloud2
Nhập thông điệp, chúng ta có thể sử dụng một phương pháp tương tự như phương pháp được sử dụng cho bản đồ độ sâu. Bằng cách tận dụng thông tin màu sắc được nhúng trong đám mây điểm, chúng ta có thể trích xuất hình ảnh 2D, thực hiện phân đoạn trên hình ảnh này bằng cách sử dụng YOLO, và sau đó áp dụng mặt nạ kết quả vào các điểm ba chiều để cô lập đối tượng quan tâm 3D.
Để xử lý các đám mây điểm, chúng tôi khuyên bạn nên sử dụng Open3D (pip install open3d
), thân thiện với người dùng Python thư viện. Open3D cung cấp các công cụ mạnh mẽ để quản lý cấu trúc dữ liệu đám mây điểm, trực quan hóa chúng và thực hiện các hoạt động phức tạp một cách liền mạch. Thư viện này có thể đơn giản hóa đáng kể quy trình và tăng cường khả năng thao tác và phân tích các đám mây điểm kết hợp với YOLO-phân khúc dựa trên.
Cách sử dụng từng bước Point Clouds
Nhập các thư viện cần thiết và khởi tạo YOLO mô hình cho phân khúc.
import time
import rospy
from ultralytics import YOLO
rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolov8m-seg.pt")
Tạo hàm pointcloud2_to_array
, biến đổi một sensor_msgs/PointCloud2
nhắn tin thành hai mảng numpy. Các sensor_msgs/PointCloud2
Thư chứa n
Điểm dựa trên width
và height
của hình ảnh thu được. Ví dụ, một 480 x 640
hình ảnh sẽ có 307,200
Điểm. Mỗi điểm bao gồm ba tọa độ không gian (xyz
) và màu tương ứng trong RGB
định dạng. Đây có thể được coi là hai kênh thông tin riêng biệt.
Hàm trả về xyz
tọa độ và RGB
giá trị ở định dạng độ phân giải máy ảnh gốc (width x height
). Hầu hết các cảm biến có khoảng cách tối đa, được gọi là khoảng cách clip, ngoài đó các giá trị được biểu diễn dưới dạng inf (np.inf
). Trước khi xử lý, điều quan trọng là phải lọc ra các giá trị null này và gán cho chúng một giá trị 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
Tiếp theo, đăng ký /camera/depth/points
chủ đề để nhận tin nhắn đám mây điểm và chuyển đổi sensor_msgs/PointCloud2
nhắn tin vào mảng numpy chứa tọa độ XYZ và giá trị RGB (sử dụng pointcloud2_to_array
chức năng). Xử lý hình ảnh RGB bằng cách sử dụng YOLO mô hình để trích xuất các đối tượng được phân đoạn. Đối với mỗi đối tượng được phát hiện, trích xuất mặt nạ phân đoạn và áp dụng nó cho cả hình ảnh RGB và tọa độ XYZ để cô lập đối tượng trong không gian 3D.
Xử lý mặt nạ rất đơn giản vì nó bao gồm các giá trị nhị phân, với 1
cho biết sự hiện diện của đối tượng và 0
cho thấy sự vắng mặt. Để đắp mặt nạ, chỉ cần nhân các kênh ban đầu với mặt nạ. Thao tác này cô lập hiệu quả đối tượng quan tâm trong hình ảnh. Cuối cùng, tạo một đối tượng đám mây điểm Open3D và trực quan hóa đối tượng được phân đoạn trong không gian 3D với các màu liên quan.
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])
Mã hoàn chỉnh
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])
FAQ
Hệ điều hành Robot (ROS) là gì?
Hệ điều hành robot (ROS) là một khung mã nguồn mở thường được sử dụng trong robot để giúp các nhà phát triển tạo ra các ứng dụng robot mạnh mẽ. Nó cung cấp một bộ sưu tập các thư viện và công cụ để xây dựng và giao tiếp với các hệ thống robot, cho phép phát triển dễ dàng hơn các ứng dụng phức tạp. ROS hỗ trợ giao tiếp giữa các nút bằng cách sử dụng tin nhắn qua các chủ đề hoặc dịch vụ.
Làm cách nào để tích hợp Ultralytics YOLO với ROS để phát hiện đối tượng theo thời gian thực?
Tích hợp Ultralytics YOLO với ROS liên quan đến việc thiết lập môi trường ROS và sử dụng YOLO để xử lý dữ liệu cảm biến. Bắt đầu bằng cách cài đặt các phụ thuộc bắt buộc như ros_numpy
và Ultralytics YOLO:
Tiếp theo, tạo một nút ROS và đăng ký một chủ đề hình ảnh để xử lý dữ liệu đến. Đây là một ví dụ tối thiểu:
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()
Các chủ đề ROS là gì và chúng được sử dụng như thế nào trong Ultralytics YOLO?
Các chủ đề ROS tạo điều kiện giao tiếp giữa các nút trong mạng ROS bằng cách sử dụng mô hình đăng ký xuất bản. Chủ đề là một kênh được đặt tên mà các nút sử dụng để gửi và nhận tin nhắn không đồng bộ. Trong bối cảnh Ultralytics YOLO, bạn có thể làm cho một nút đăng ký một chủ đề hình ảnh, xử lý hình ảnh bằng cách sử dụng YOLO cho các nhiệm vụ như phát hiện hoặc phân đoạn và xuất bản kết quả cho các chủ đề mới.
Ví dụ: đăng ký một chủ đề máy ảnh và xử lý hình ảnh đến để phát hiện:
Tại sao nên sử dụng hình ảnh chiều sâu với Ultralytics YOLO trong ROS?
Hình ảnh độ sâu trong ROS, đại diện bởi sensor_msgs/Image
, cung cấp khoảng cách của các đối tượng từ máy ảnh, rất quan trọng cho các nhiệm vụ như tránh chướng ngại vật, lập bản đồ 3D và bản địa hóa. Bằng cách Sử dụng thông tin chuyên sâu cùng với hình ảnh RGB, robot có thể hiểu rõ hơn về môi trường 3D của chúng.
Với YOLO, bạn có thể trích xuất mặt nạ phân đoạn từ hình ảnh RGB và áp dụng các mặt nạ này vào hình ảnh chiều sâu để có được thông tin đối tượng 3D chính xác, cải thiện khả năng điều hướng và tương tác với môi trường xung quanh của robot.
Làm thế nào tôi có thể hình dung các đám mây điểm 3D với YOLO trong ROS?
Để trực quan hóa các đám mây điểm 3D trong ROS với YOLO:
- Convert
sensor_msgs/PointCloud2
tin nhắn đến mảng numpy. - Dùng YOLO để phân đoạn hình ảnh RGB.
- Áp dụng mặt nạ phân đoạn cho đám mây điểm.
Dưới đây là một ví dụ sử dụng Open3D để trực quan hóa:
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])
Cách tiếp cận này cung cấp hình ảnh trực quan 3D của các đối tượng được phân đoạn, hữu ích cho các tác vụ như điều hướng và thao tác.