Tiếp theo, chúng ta sẽ tạo một file tên là simple_publisher.py trong thư mục publisher_pkg ở trong package publisher_pkg mà chúng ta vừa tạo. Các bạn lưu ý là file này phải nằm trong thư mục cùng tên nhưng nằm trong package vừa tạo nhé. Cụ thể là đường dẫn tới file simple_publisher.py là ~/ros2_ws/src/publisher_pkg/publisher_pkg/simple_publisher.py
Tiếp theo, các bạn hãy copy những dòng code sau vào file simple_publisher.py
import rclpy
# import the ROS2 python libraries
from rclpy.node import Node
# import the Twist interface from the geometry_msgs package
from geometry_msgs.msg import Twist
class SimplePublisher(Node):
def __init__(self):
# Here you have the class constructor
# call super() in the constructor to initialize the Node object
# the parameter you pass is the node name
super().__init__('simple_publisher')
# create the publisher object
# in this case, the publisher will publish on /cmd_vel Topic with a queue size of 10 messages.
# use the Twist module for /cmd_vel Topic
self.publisher_ = self.create_publisher(Twist, 'cmd_vel', 10)
# define the timer period for 0.5 seconds
timer_period = 0.5
# create a timer sending two parameters:
# - the duration between 2 callbacks (0.5 seconds)
# - the timer function (timer_callback)
self.timer = self.create_timer(timer_period, self.timer_callback)
def timer_callback(self):
# Here you have the callback method
# create a Twist message
msg = Twist()
# define the linear x-axis velocity of /cmd_vel Topic parameter to 0.5
msg.linear.x = 0.5
# define the angular z-axis velocity of /cmd_vel Topic parameter to 0.5
msg.angular.z = 0.5
# Publish the message to the Topic
self.publisher_.publish(msg)
# Display the message on the console
self.get_logger().info('Publishing: "%s"' % msg)
def main(args=None):
# initialize the ROS communication
rclpy.init(args=args)
# declare the node constructor
simple_publisher = SimplePublisher()
# pause the program execution, waits for a request to kill the node (ctrl+c)
rclpy.spin(simple_publisher)
# Explicity destroys the node
simple_publisher.destroy_node()
# shutdown the ROS communication
rclpy.shutdown()
if __name__ == '__main__':
main()
File simple_publisher.py này chứa nội dung của một topic publisher cơ bản. Hiện tại thì các bạn chưa cần hiểu những dòng code này, mình sẽ giải thích ở phần sau. Chúng ta sẽ tiếp tục các bước tiếp theo để chạy thử code xem nó làm được gì trước nhé.
Tạo file launch
Đầu tiên, chúng ta sẽ tạo một thư mục launch ở trong package đang làm việc:
cd ~/ros2_ws/src/publisher_pkg
mkdir launch
Tiếp theo, ta sẽ tạo một file launch để chạy node publisher tên là publisher_pkg_launch_file.launch.py
cd ~/ros2_ws/src/publisher_pkg/launch
touch publisher_pkg_launch_file.launch.py
chmod +x publisher_pkg_launch_file.launch.py
Các bạn copy các dòng code sau vào trong file launch vừa mới tạo:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='publisher_pkg',
executable='simple_publisher',
output='screen'),
])
Chỉnh sửa file setup.py
Tiếp theo, các bạn hãy chỉnh sửa file setup.py để thiết lập các file vừa tạo với hệ thống package:
Trên Terminal sẽ hiển thị các nội dung message mà node mình vừa tạo đang publish lên topic /cmd_vel. Đồng thời robot cũng bắt đầu di chuyển thành vòng tròn.
Để kiểm tra thông tin đang ở trên topic /cmd_vel, các bạn chạy lệnh :
ros2 topic echo /cmd_vel
Giải thích code tạo publisher
Quy trình hoạt động
def main(args=None):
# initialize the ROS communication
rclpy.init(args=args)
# declare the node constructor
simple_publisher = SimplePublisher()
# pause the program execution, waits for a request to kill the node (ctrl+c)
rclpy.spin(simple_publisher)
# Explicity destroys the node
simple_publisher.destroy_node()
# shutdown the ROS communication
rclpy.shutdown()
Đầu tiên hệ thống sẽ khởi tạo giao tiếp ROS2 bằng lệnh
rclpy.init(args=args)
Khai báo và khởi tạo node publisher
simple_publisher = SimplePublisher()
Tạm dừng việc thực thi chương trình, chờ yêu cầu hủy node (ctrl+c)
rclpy.spin(simple_publisher)
Hủy node
simple_publisher.destroy_node()
Tắt hệ thống giao tiếp ROS2
rclpy.shutdown()
Tạo Class publisher
Phần code này cũng tương tự như khi tạo một class trong python thông thường với hàm khởi tạo __init__ và các hàm chức năng khác. Trong đó quan trọng nhất là các lệnh sau để thực hiện các chức năng liên quan tới ROS:
Khởi tạo một node có tên là 'simple_publisher':
super().__init__('simple_publisher')
Tạo một publisher cho topic /cmd_vel sử dụng Twist message với kích thước hàng đợi là 10:
Để hệ thống nhận diện được các câu lệnh của ROS2 thì chúng ta cần source file setup.bash của ROS2 trước.
Source file setup của ROS2 trên Terminal 1: source /opt/ros/humble/setup.bash
Để tạo package ROS2, chúng ta cần có một không gian làm việc ROS2.
Cùng tạo một không gian làm việc ROS2 tên là ros2_ws bằng cách tạo folder ros2_ws và một thư mục nguồn src chứacode của các package bằng các lệnh sau: mkdir ros_ws
cd ros_ws
mkdir src
Tạo một package tên là my_package ở trong thư mục src của không gian làm việc vừa tạo bằng trình tạo package tựđộng của ROS2: cd ~/ros_ws/src
ros2 pkg create --build-type ament_python my_package --dependencies rclpy
Một câu lệnh tạo package có cú pháp như sau: ros2 pkg create --build-type ament_python <package_name> --dependencies <package_dependency_1> <package_dependency_2>
Trong đó:
ros2: câu lệnh của ROS2
pkg: (package) thực hiện các hành động liên quan tới package
create: tạo một package mới
–build-type: truyền tham số về cách build package
ament_python: package sẽ được build dựa trên python
<package_name>: tên của package muốn tạo
–dependencies: truyền tham số tên các package mà package muốn tạo phụ thuộc
<package_dependency_1>: tên của package phụ thuộc
Compile package trong ROS2
Sau khi tạo xong package, bạn nên build package vừa tạo. Đây là cách nhanh nhất để xác định xem các package phụthuộc mà bạn đã liệt kê có hoạt động hay không và kiểm tra xem dữ liệu đã nhập có sai sót gì không. Thực hiện các lệnhsau để build các package trong không gian làm việc ros_ws: cd ~/ros_ws
colcon build
Để build từng package riêng lẻ thì ta dùng lệnh sau:
cd ~/ros_ws
colcon build --packages-select <package_name>
Sau mỗi lần build xong package, hãy tạo thói quen source file setup.bash từ thư mục install để ROS2 có thể tìm thấycác package trong không gian làm việc
source ~/ros_ws/install/setup.bash
Để xác nhận rằng package đã được tạo thành công và đã được tích hợp vào hệ thống ROS2, hãy liệt kê các package đãđược khai báo với ROS2. ros2 pkg list
Nếu package vừa tạo có tên trong danh sách thì chúng ta đã thành công.
Một cách nhanh hơn là ta có thể sử dụng lệnh grep trong Terminal để tìm nhanh tên package vừa tạo:
Bước chân vào thế giới của Robotics, không thể nào không nhắc đến ROS(Robot Operating System), một hệ điều hành mạnh mẽ cho lập trình robots. Ở trong post này, hãy cùng nhau học cách làm sao để chạy thử mô hình turtlebot3 trên Gazebo và lưu các dữ liệu thông qua rosbag trên ROS2 Humble.
Khởi động rosject
Để có thể thực hiện các bước trong blog này, chúng ta cần có ROS2 được cài đặt trên hệ thống, cũng như ros2 ROS2 Workspace. Để thuận tiện hơn, tại The Construct đã chuẩn bị một rosject để các bạn dễ dàng truy cập và khởi tạo các project:
Chỉ với một cú click chuột vào link phía trên, các bạn có thể tạo một rosject của riêng bạn, bạn có thể chỉnh sửa các nội dung liên quan. Như hình bên dưới là một rosject hoàn chỉnh, bạn chỉ việc nhấn vào nút RUN để khởi động rosject.
Sau khi nhấn vào nút RUN bạn sẽ thấy rosject được chạy trên màn hình. Ở đây, rosject cung cấp cho bạn cả terminal để có thể nhập các câu lệnh:
Bây giờ cùng nhau đến bước tiếp theo trong ví dụ này nhé.
Khởi động Turtlebot3 package
Bước đầu tiên, các bạn có thể kiểm tra trên ROS2 đã được cài đặt turtlebot3 package hay chưa bằng câu lệnh như sau:
Ở đây turtlebot3 package đã được cài đặt sẵn nên trên terminal là danh sách các packages kèm theo turtlebot3. Ngoài ra, các bạn có thể cài đặt thông qua câu lệnh dưới đây:
sudo apt install
ros-humble-turtlebot3*
Mô phỏng trên Gazebo
Sau khi đã thành công kiểm tra hoặc cài đặt turtlebot3 trong ROS2, tiếp theo các bạn sẽ mô phỏng robot trên môi trường Gazebo.
Các bạn cần lưu ý là nếu chúng ta chỉ có một robot thì mình không cần setup_domain ID, vì ROS sẽ tự động cài mặc định ROS_DOMAIN_ID=0. Trong trường hợp nếu bạn có nhiều hơn một robots thì khi đó bạn sẽ khởi tạo từng ID riêng cho robot của mình.
Để xây dựng ROS2 workspace cho turtlebot3, đầu tiên đi vào môi trường catkin workspace có sẵn:
cd
ros2_ws/
Có 2 cách để kích hoạt môi trường hoạt động, nếu bạn dùng debian package thì sử dụng:
/source
/opt/ros/humble/setup.bash
Nếu bạn sử dụng package ở trong ros package bạn tạo thì chạy dòng lệnh sau: source
install/setup.bash
Tiếp theo lựa chọn và cài đặt mẫu robot bạn muốn sử dụng. Bạn có thể thay đổi mẫu robot bạn muốn sử dụng bằng câu lệnh bên dưới. Ở đây chúng ta sử dụng robot burger:
export
TURTLEBOT3_MODEL=burger
Tiếp theo, bạn sử dụng câu lệnh bên dưới để sử dụng turtlebot3 trong môi trường Gazebo:
Cửa sổ Gazebo sẽ xuất hiện như trên cùng với robot burger. Chúc mừng bạn đã thành công khởi động turtlebot3 trên Gazebo.
Lưu dữ liệu cùng với Rosbag trên ROS2 Humble
Khoan đóng terminal Gazebo nhé. Vẫn còn nhiều điều hay mà trong blog này sẽ chia sẽ với các bạn. Khi làm việc với robot, các bạn sẽ phải dùng nhiều dữ liệu từ nhiều topic ngoài ra còn để truy xuất dữ liệu, trình bày trên biểu đồ,…với các ứng dụng đó thì
Rosbag chính là cứu tinh cho bạn.
Đầu tiên, chúng ta mở một cửa sổ khác để kiểm tra các topic được public trên robot. ros2 topic list
Như các bạn có thể thấy trên đây là các topics của turtlebot3 trên Gazebo. Chúng ta có thể xem dữ liệu của topic bằng từ khóa echo , ở đây mình lấy ví dụ từ topic /odom: ros2 topic echo
/odom
Công dụng của rosbag chỉ với một câu lệnh sẽ lưu các nội dung liên quan đến topic
bạn muốn record.
ros2 bag record
/topic_name
Với câu lệnh trên, rosbag sẽ tự động được lưu ngay trên đường dẫn mà bạn sử dụng rosbag. Ngoài ra, bạn có thể lưu nhiều topics và thay đổi tên cũng như nơi lưu bag file. Dưới đây, mình có ví dụ lưu 2 topics là /turtle1/cmd_vel và /turtle1/pose với tên file là
turtlebot. Ký tựcho phép bạn lựa chọn tên của bag file. ros2 bag record -o turtlebot /turtle1/cmd_vel
/turtle1/pose
Sau khi lưu bag file bạn có thể kiểm tra bag file đã lưu bằng câu lệnh: ros2 bag info
file_name
Cám ơn các bạn đã theo dõi blog đến đây. Hy vọng blog này sẽ giúp ích cho các bạn trong quá trình học và tìm hiểu về ROS cũng như Robotics. Cùng đón chờ nhiều blog bổ ích như thế này trên The Construct nhé!
Để liệt kê tất cả các topic đang hoạt động, ta sử dụng câu lệnh sau:
ros2 topic list
Để tìm kiếm một topic cụ thể, chúng ta sử dụng thêm lệnh grep như khi sử dụng Terminal bình thường:
ros2 topic list | grep cmd_vel
Xem thông tin chi tiết về một topic
Để xem thông tin chi tiết về một topic nào đó, các bạn có thể sử dụng lệnh info. Ví dụ mình sẽ sử dụng lệnh info để xem thông tin của topic cmd_vel vừa được liệt kê ở trong phần trước:
ros2 topic info /cmd_vel
Thông tin về topic sẽ được hiển thị trên Terminal bao gồm các trường như sau:
Type: kiểu dữ liệu của topic
Publisher count: số lượng publisher đang hoạt động được kết nối tới topic
Subscription count: số lượng subscriber đang hoạt động được kết nối tới topic
Tương tự như vậy, các bạn có thể xem thông tin về bất cứ topic nào mà mình quan tâm. Ví dụ như topic /scan là dữ liệu mà lidar trên robot quét, topic /camera/image_raw là dữ liệu hình ảnh mà camera nhận được:
ros2 topic info /scan
ros2 topic info /camera/image_raw
Các bạn cũng có thể xem trực tiếp dữ liệu nào đang được lưu truyền trên topic bằng lệnh echo. Mình sẽ lấy ví dụ về topic cmd_vel ở trên:
ros2 topic echo /cmd_vel
Không có gì xuất hiện, các bạn có thấy gì kì lạ không?
Các bạn không thao tác nhầm ở đâu đâu. Terminal không xuất hiện gì cả vì hiện tại đang không có dữ liệu nào lưu hành trên topic này. Các bạn sẽ được hướng dẫn cách gửi dữ liệu lên topic trong phần dưới đây.
Xuất bản (Publish) dữ liệu lên một topic
Như các bạn thấy thì hiện tại topic /cmd_vel đang không có dữ liệu nào cả. Vì vậy, chúng ta sẽ tiếp tục tìm hiểu cách gửi dữ liệu, hay là publish dữ liệu lên một topic.
Để publish dữ liệu lên một topic, chúng ta cần biết kiểu dữ liệu của topic đó trước. Sử dụng lệnh sau để xem lại kiểu dữ liệu mà topic /cmd_vel sử dụng:
ros2 topic info /cmd_vel
Theo kết quả hiển thị trên Terminal, kiểu dữ liệu của /cmd_vel là geometry_msgs/msg/Twist. Chúng ta cùng xem một message loại này thì gồm những thành phần gì bằng lệnh:
ros2 interface show geometry_msgs/msg/Twist
Một message geometry_msgs/msg/Twist bao gồm hai vector 3 chiều là linear (tốc độ dài) và angular (tốc độ góc) trong không gian ba chiều. Các bạn lưu ý là mỗi tọa độ của vector là một số thực (float64) nhé.
OK. Bây giờ các bạn đã có đủ thông tin để publish các message tới topic /cmd_vel. Chúng ta cùng publish một message lên topic /cmd_vel để turtlebot di chuyển trong không gian mô phỏng nhé. Ta sử dụng câu lệnh sau:
geometry_msgs/msg/Twist: tên của interface/loại message
Phần còn lại: nột dung message muốn publish
Sau khi lệnh trên được chạy, các bạn sẽ thấy Terminal thông báo đang publish các message lên topic /cmd_vel, đồng thời turtlebot cũng bắt đầu di chuyển thành vòng tròn.
Kiểm tra topic hoạt động
Để kiểm tra xem topic có đang hoạt động ổn định hay không, chúng ta cùng thực hiện lại các lệnh tương tự như phần đầu của bài viết và so sánh.
Đầu tiên là xem thông tin về topic bằng lệnh:
ros2 topic info /cmd_vel
Terminal hiển thị hiện tại đã có thêm một publisher, vậy là chúng ta đã publish dữ liệu lên topic thành công.
Tiếp theo, chúng ta sẽ kiểm tra dữ liệu nào đang được lưu truyền trên topic bằng lệnh:
ros2 topic echo /cmd_vel
Trên Terminal sẽ xuất hiện các message đang được lưu hành trên topic.
OK xong. Vậy là qua bài viết này các bạn đã làm quen với các câu lệnh cơ bản để làm việc với topic trong ROS2. Chúc các bạn thực hành thành công.
Khi làm việc với robots trong các môi trường khác nhau thì bản đồ (map) là một trong những thông tin hữu ích giúp đỡ cho robot có thể định vị tọa độ, cũng như xây dựng phương hướng di chuyển để né tránh chướng ngại vật. Cho nên, trong bài blog sẽ chia sẽ cách để các bạn tạo ra map bằng việc kết hợp các package có sẵn trong ROS2 như turtlebot3, navigation. Bên cạnh đó mình cũng giới thiệu Cartographer một công cụ rất hữu ích sử dụng thuật toán SLAM được ROS tích hợp. Đây là package sẽ hỗ trợ các bạn rất nhiều trong các dự án liên quan tới robot. Tuy nhiên, blog này không đào sâu vào thuật toán SLAM mà chỉ giới thiệu tới các bạn cách cài đặt và một ví dụ về catographer.
Khởi động rosject
The Construct đã tạo ra một công cụ rất hữu ích là rosject, nơi các bạn dễ dàng truy cập và khởi tạo các project cùng với ROS ở các phiên bản khác nhau:
Như hình bên dưới là một rosject hoàn chỉnh, bạn chỉ việc nhấn vào nút RUN để khởi động rosject.
Sau khi nhấn vào nút RUN bạn sẽ thấy rosject được chạy trên màn hình. Ở đây, rosject cung cấp cho bạn cả terminal để có thể nhập các câu lệnh:
Bây giờ cùng nhau đến bước tiếp theo trong ví dụ này nhé.
Cài đặt các package cần thiết
Đầu tiên các bạn cần cài đặt các package cần thiết để có thể thực hiện project này, ở đây chúng ta sử dụng turtlebot3 và ros2 navigation, cartographer, gazebo:
Sau khi cài đặt thành công các package phía trên. Cuối cùng là cài đặt package liên quan đến turtlebot3. Các bạn có thể cài đặt thông qua câu lệnh dưới đây:
sudo apt install ros-humble-turtlebot3*
Mô phỏng trên Gazebo cùng robot
Sau khi đã thành công kiểm tra hoặc cài đặt turtlebot3 trong ROS2, tiếp theo các bạn sẽ mô phỏng robot trên môi trường Gazebo.
Tiếp theo, sau khi đã cài đặt đầy đủ các package cần thiết. Bước tiếp theo bạn cần chọn model robot cho project của bạn. mình sử dụng waffle trong project này:
export TURTLEBOT3_MODEL=waffle
Sau đó để sử dụng môi trường gazebo và robot, bạn thực hiện câu lệnh:
Cửa sổ Gazebo sẽ xuất hiện như trên cùng với robot waffle.
Khởi động Rviz cùng với cartographer
Như bạn thấy môi trường và robot đã có, tiếp theo bắt đầu với SLAM bằng việc sử dụng cartographer package. Ở cửa sổ thứ 2, các bạn thực hiện câu lệnh này, tuy nhiên khi mở cửa sổ mới đồng nghĩa với việc môi trường làm việc ko thể nhớ loại robot nào bạn đang dùng nên bạn cần export mỗi lần mở cửa sổ mới nhé:
Ở đây mình có thêm vào use_sim_time vì dùng thời gian thực của gazebo nếu như chúng ta làm việc với robot thực thì các bạn ko cần sử dụng use_sim_time. Ở đây sau khi thực hiện câu lệnh, RVIZ sẽ xuất hiện với môi trường grid map, ở đây là mô phỏng 2D từ gazebo qua, bạn có thể tùy chỉnh các lựa chọn ở mục bên trái của RVIZ để có được trải nghiệm tốt hơn về mô phỏng.
Tạo và lưu bản đồ cùng nav2_map_server
Như các bạn đã biết, để có một bản đồ hoàn chỉnh hay còn gọi là môi trường đã biết trước, robot cần nhận biết hết các sự kiện trong môi trường. Cho nên trong project này, mình sẽ điều khiển robot di chuyển bằng cách sử dụng teleop_keyboard để robot có thể sử dụng cảm biến nhận diện môi trường xung quanh. Đầu tiên, các bạn cần đồng nhất mẫu robot mà bạn đang sử dụng trong môi trường gazebo cũng như Rviz. Tiếp theo là sử dụng turtlebot3_teleop package để di chuyển robot. Dưới đây là các câu lệnh để thực hiện:
export TURTLEBOT3_MODEL=waffle
ros2 run turtlebot3_teleop teleop_keyboard
Ở đây, với mong muốn từng khu vực hay chướng ngại vật sẽ được thể hiện rõ trên map nên các bạn cố gắng di chuyển robot đến những khu vực đó.
Như các bạn đã thấy, mình đã di chuyển robot để có thể quét hết toàn bộ bản đồ của môi trường. Bản đồ sẽ thể hiện rõ như hình trên. Các bạn mở cho mình một cửa sổ khác và lưu map lại nhé, bằng việc sử dụng câu lệnh sau:
ros2 run nav2_map_server map_saver_cli -f turtlebot_map
Hy vọng qua blog này các bạn đã có thêm một số kiến thức cũng như công cụ hỗ trợ cho các dự án liên quan tới robotics sử dụng ROS. Bên cạnh đó, các bạn có thể theo dõi các blog khác cũng như các khóa học liên quan trên The Construct nhé.