Trong hệ thống ROS2, ngôn ngữ C++ là một trong những lựa chọn hàng đầu để xây dựng các nút có hiệu suất cao. Bài viết này sẽ hướng dẫn chi tiết cách tạo, cấu hình, biên dịch và thực thi các gói phần mềm kiểu C++ trong ROS2, phân tích cấu trúc và quy trình xây dựng, đồng thời so sánh sự khác biệt giữa nút C++ và Python, kèm theo giải thích cơ chế biến môi trường của ROS2.
Tạo gói phần mềm C++
Sử dụng lệnh ros2 pkg create để tạo gói C++ với hệ thống xây dựng ament_cmake:
ros2 pkg create example_cpp_pkg --build-type ament_cmake --license MIT
--build-type ament_cmake: Chọn hệ thống xây dựngament_cmakephù hợp cho C++.--license MIT: Xác định loại giấy phép sử dụng.
Sau khi thực hiện lệnh, cấu trúc thư mục được tạo ra như sau:
example_cpp_pkg/
├── include/example_cpp_pkg/ # Thư mục chứa file header C++
├── src/ # Thư mục chứa file nguồn C++
│ └── my_cpp_node.cpp # File nguồn nút C++ cần viết
├── CMakeLists.txt # File cấu hình xây dựng chính bằng CMake
├── LICENSE # File giấy phép
└── package.xml # File thông tin mô tả gói phần mềm
Cấu trúc gói phần mềm C++
| File/Thư mục | Mô tả chức năng |
|---|---|
include/example_cpp_pkg/ |
Lưu trữ các file header C++, dùng để khai báo giao diện và định nghĩa lớp giữa các module. |
src/ |
Lưu trữ các file nguồn C++, chứa logic nghiệp vụ của nút. |
CMakeLists.txt |
Xác định quy tắc biên dịch, tìm kiếm phụ thuộc, tạo file thực thi và các logic xây dựng khác, là file cấu hình trung tâm của gói C++. |
package.xml |
Khai báo tên gói, phiên bản, người duy trì, phụ thuộc và các thông tin mô tả khác. |
LICENSE |
Xác định quyền sử dụng, sửa đổi và phân phối mã nguồn (ví dụ ở đây là MIT). |
Viết mã nút C++
Tạo file my_cpp_node.cpp trong thư mục src/, viết logic cơ bản cho nút C++:
#include "rclcpp/rclcpp.hpp"
int main(int argc, char **argv_ptr)
{
rclcpp::init(argc, argv_ptr);
auto node_instance = std::make_shared("my_cpp_node");
RCLCPP_INFO(node_instance->get_logger(), "Xin chao tu nút C++!");
rclcpp::spin(node_instance);
rclcpp::shutdown();
return 0;
}
Cấu hình package.xml thêm phụ thuộc
Mở file package.xml, thêm khai báo phụ thuộc cho thư viện khách hàng C++ rclcpp:
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<!-- Thông tin khác (tên, phiên bản, người duy trì, v.v.) -->
<license>MIT</license>
<depend>rclcpp</depend>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<!-- Các cấu hình khác -->
</package>
Cấu hình CMakeLists.txt (Chú ý: ament_cmake và ament_target_dependencies)
Mở file CMakeLists.txt, cấu hình quy tắc biên dịch và phụ thuộc:
cmake_minimum_required(VERSION 3.9)
project(example_cpp_pkg)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
add_executable(my_cpp_node src/my_cpp_node.cpp)
ament_target_dependencies(my_cpp_node rclcpp)
install(TARGETS
my_cpp_node
DESTINATION lib/${PROJECT_NAME}
)
ament_package()
ament_target_dependencies(tên_nút tên_phụ_thuộc): Là lệnh cấu hình cốt lõi trong gói C++ của ROS2, tự động xử lý đường dẫn header và liên kết thư viện củarclcpp, cách này vẫn tương thích với môi trường ROS2 ngay cả khi kết hợp với lệnh CMake truyền thống.install(...): Cài đặt file thực thi vào thư mụclib/${PROJECT_NAME}, đảm bảoros2 runcó thể tìm thấy nút.
Biên dịch gói: colcon build so với CMake truyền thống
Khuyến nghị: Sử dụng colcon build
Thực hiện trong thư mục gốc không gian làm việc:
colcon build
Sau khi thành công, đầu ra tương tự như:
Starting >>> example_cpp_pkg
Starting >>> example_python_pkg
Finished <<< example_cpp_pkg [0.38s]
Finished <<< example_python_pkg [0.65s]
Summary: 2 packages finished [0.78s]
Ưu điểm: colcon tự động quản lý thứ tự xây dựng nhiều gói và biến môi trường, là phương pháp xây dựng tiêu chuẩn cho không gian làm việc ROS2.
Biên dịch CMake truyền thống (chỉ để tham khảo)
Nếu tạo thủ công thư mục build và thực thi CMake:
mkdir build && cd build
cmake ..
make
Cách này có thể biên dịch ra file thực thi nhưng cần cấu hình thủ công biến môi trường để được công cụ ROS2 nhận diện, không khuyến nghị sử dụng riêng lẻ trong hệ sinh thái ROS2.
Biến môi trường và chạy nút
Chạy trực tiếp file thực thi đã cài đặt
Sau khi xây dựng hoàn tất, file thực thi nằm tại thư mục install/example_cpp_pkg/lib/example_cpp_pkg. Dùng lệnh ldd để xem phụ thuộc thư viện đã liên kết đúng chưa:
ldd install/example_cpp_pkg/lib/example_cpp_pkg/my_cpp_node
Nếu các phụ thuộc (như librclcpp.so) đều được liên kết đúng, có thể chạy trực tiếp:
install/example_cpp_pkg/lib/example_cpp_pkg/my_cpp_node
Đầu ra trên terminal:
[INFO] [1680684100.228612032] [my_cpp_node]: Xin chao tu nút C++!
Biến môi trường AMENT_PREFIX_PATH và ros2 run
Thực hiện lệnh source để cấu hình biến môi trường:
source install/setup.bash
Lệnh này sẽ chỉnh sửa biến môi trường AMENT_PREFIX_PATH, thêm đường dẫn cài đặt của gói vào đường dẫn tìm kiếm gói của ROS2. Có thể kiểm tra qua lệnh:
echo $AMENT_PREFIX_PATH
Đầu ra tương tự:
/home/user/install/example_cpp_pkg:/opt/ros/humble
Bây giờ có thể dùng ros2 run để chạy nút:
ros2 run example_cpp_pkg my_cpp_node
Cũng có thể dùng lệnh ros2 pkg prefix để xem thư mục tiền tố cài đặt của gói:
ros2 pkg prefix example_cpp_pkg
Đầu ra là thư mục gốc cài đặt của gói (ví dụ /home/user/install/example_cpp_pkg).
Phân tích sự khác biệt giữa nút C++ và Python
File thực thi của nút C++ có thể chạy trực tiếp, trong khi nút Python thường cần cấu hình môi trường bổ sung, nguyên nhân cốt lõi là:
| Đặc điểm | Nút C++ (biên dịch) | Nút Python (thông dịch) |
|---|---|---|
| Xử lý phụ thuộc | Liên kết thư viện phụ thuộc vào file thực thi lúc biên dịch (có thể xác minh qua ldd) |
Cần tìm module phụ thuộc qua PYTHONPATH lúc chạy |
| Điều kiện chạy | Chỉ cần file thực thi (phụ thuộc đã được liên kết) | Cần cấu hình PYTHONPATH hoặc chạy script môi trường source để trình thông dịch tìm thấy module |