8. Tạo một ROS Subscriber

8. Tạo một ROS Subscriber

Trong phần này, mình sẽ hướng dẫn bạn tạo một image subscriber đơn giản (hay "Người In Ấn" trong ví dụ từ phần trước). Subscriber này sẽ liên tục đọc hình ảnh từ topic image_raw (mà bạn đã tạo từ chương 7) và hiển thị chúng. Tất nhiên, bạn có thể làm được nhiều thứ hơn là chỉ hiển thị ảnh (chẳng hạn như đưa ảnh vào một số thuật toán học máy (Machine Learning) mà bạn sẽ thực hiện trong chương tiếp theo) hoặc thậm chí bạn có thể show ảnh ngay từ publisher bẳng OpenCV nhưng hãy bắt đầu thật cơ bản. Subscriber này chỉ là một ví dụ để bạn thấy được các chương trình trong ROS giao tiếp với nhau như thế nào.

Code

Tạo một tập lệnh Python mới trong thư mục my_cam và đặt tên cho nó là image_subscriber.py. Nếu bạn đã đọc và làm chương 7 thì code bên dưới sẽ thấy quen vì cấu trúc khá giống với publisher. Mình vẫn khuyên bạn nên làm theo phần giải thích bên dưới và tự code thay vì copy&paste.

#!/usr/bin/python3

import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image

def callback(image_msg):
    """This function is called to handle the subscribed messages

    Args:
        image_msg (Image): message type Image from sensor_msgs
    """
    try:
        cv_image = bridge.imgmsg_to_cv2(image_msg)
        cv2.imshow('ROS Image Subscriber', cv_image)
        cv2.waitKey(10)
    except CvBridgeError as error:
        print(error)

if __name__=="__main__":
    bridge = CvBridge()
    rospy.init_node("image_subscriber", anonymous=True)
    print("Subscribe images from topic /image_raw ...")

    image_subcriber = rospy.Subscriber("image_raw", Image, callback)

    try:
        # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()
    except KeyboardInterrupt:
        print("Shutting down!")

Giải thích Code

Phần đầu tiên giống hệt như trong image_publisher.py và về cơ bản là để import tất cả các thư viện cần thiết.

#!/usr/bin/python3

import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image

Tiếp theo, một hàm callback được định nghĩa nhưng mình muốn giải thích hàm main trước và đến với hàm callback này sau. Tương tự như publisher, trong main bạn cần tạo một đối tượng CvBridge và khởi tạo một Node có tên image_subscriber.

if __name__=="__main__":
    bridge = CvBridge()
    rospy.init_node("image_subscriber", anonymous=True)
    print("Subscribe images from topic /image_raw ...")

Sau đó, một subscriber được khởi tạo bằng cách sử dụng hàm rospy.Subscriber("image_raw", Image, callback) trong đó image_raw là topic mà bạn muốn subscribe, Image là kiểu dữ liệu của image_rawcallback là một hàm sẽ luôn được gọi khi subscriber nhận message mới. Cuối cùng, rospy.spin() được gọi để giữ Node của bạn chạy liên tục cho đến khi nó bị dừng (ví dụ: bằng Ctrl + C).

    image_subcriber = rospy.Subscriber("image_raw", Image, callback)
    try:
        # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()
    except KeyboardInterrupt:
        print("Shutting down!")

Hàm callback luôn được định nghĩa với message là tham số (argument) đầu tiên.

def callback(image_msg):

Bên trong callback, trước hết bạn cần chuyển ROS message image_msg sang định dạng của OpenCV (mình đặt tên nó ở đây là cv_image) bằng cách sử dụng hàm imgmsg_to_cv2. Sau đó, bạn có thể hiển thị hình ảnh bằng cách sử dụng hàm cv2.imshow. Hàm này có hai tham số: thứ nhất là tên cửa sổ (ở đây là ROS Image Subscriber) và thứ hai là hình ảnh (cv_image). Cuối cùng, cv2.waitKey(10) được sử dụng để delay trong một phần nghìn giây (ms) nhất định (ở đây là 10 mili giây) trước khi chuyển sang khung hình tiếp theo.

    try:
        cv_image = bridge.imgmsg_to_cv2(image_msg)
        cv2.imshow('ROS Image Subscriber', cv_image)
        cv2.waitKey(10)
    except CvBridgeError as error:
        print(error)

Chạy subscriber

Để chạy file Python này từ terminal, thì bạn cũng cần làm cho nó executable (có thể thực thi được) bằng cách nhấp chuột phải vào file và chọn Properties > Permissions và tích Allow executing file as program hoặc sử dụng lệnh sudo chmod +x image_subscriber.py. Sau đó, mở 3 terminal hoặc một terminator với 3 terminal nhỏ như bên dưới.

Trong terminal thứ nhất, chạy ROS Master:

roscore

Trong cái thứ hai, chạy image publisher (nhớ kết nối webcam với máy ảo nếu bạn dùng VMware):

rosrun my_cam image_publisher.py

Trong terminal thứ ba, chạy subscriber:

rosrun my_cam image_subscriber.py

Sau đó, bạn sẽ thấy một cửa sổ có tiêu đề ROS Image Subscriber hiện lên với hình ảnh truyền trực tiếp từ webcam của bạn giống như của mình trong ảnh trên.

Sau khi hoàn thành chương 7 và 8, giờ bạn đã biết cách code ROS publisher và subscriber. Bạn cũng biết cách lấy hình ảnh từ camera, một trong những cảm biến phổ biến nhất trong chế tạo robot. Trong chương tiếp theo, như đã hứa, mình sẽ giúp bạn sử dụng một trong những công cụ có sẵn để khai thác hình ảnh subscribed được thành những thông tin hữu ích thay vì chỉ xem chúng trên màn hình.

Trích dẫn

  1. Ảnh bìa: http://wiki.ros.org/jade

Did you find this article valuable?

Support Trinh Nguyen by becoming a sponsor. Any amount is appreciated!