ROS 2 节点从源码到运行的完整依赖流程

ROS 2 节点从源码到运行的完整依赖流程

1、HelloWorld 节点

bash 复制代码
# 1、创建功能包(工作空间的:src目录下)
# com_yyy 是(自定义)的(功能包)的名词
ros2 pkg create com_yyy --build-type ament_cmake --dependencies rclcpp --node-name helloworld

# 2、编辑源文件
.cpp文件

# 3、编辑配置文件
package.xml、CMakeLists.txt

# 4、编译(工作空间下)
colcon build

# 5、执行(工作空间下)
# helloworld 是node-name 名称
. install/setup.bash

ros2 run com_yyy helloworld

2、执行流程

深入到 文件级、命令级、变量级,覆盖了从代码编写 → 编译 → 链接 → 安装 → 环境激活 → 运行的全链路细节。

bash 复制代码
1. 编写用户源码
   └── 文件: ./src/helloworld.cpp
        └── 内容包含:
             #include <rclcpp/rclcpp.hpp>     ← 尖括号 → 系统/第三方头文件
             int main() { ... }

2. 编写构建描述文件
   └── 文件: ./CMakeLists.txt
        ├── cmake_minimum_required(VERSION 3.8)
        ├── project(com_yyy)
        ├── find_package(ament_cmake REQUIRED)
        ├── find_package(rclcpp REQUIRED)         ← 关键:声明对 rclcpp 的依赖
        ├── add_executable(helloworld src/helloworld.cpp)
        ├── ament_target_dependencies(helloworld rclcpp)
        └── install(TARGETS helloworld DESTINATION lib/${PROJECT_NAME})

3. 构建前:激活 ROS 2 系统环境(提供构建依赖) -> 注意执行source命令:我写在了 ~/.bashrc 文件中, 所以打开任意一个终端,都能用ros2命令
   这个source 就是为了设置环境变量这些:能使用ros2 命令
   └── 执行命令:
        source /opt/ros/humble/setup.bash
        │
        └── 该脚本内部:
             ├── 设置 COLCON_CURRENT_PREFIX="/opt/ros/humble"
             └── source /opt/ros/humble/local_setup.bash
                  │
                  └── /opt/ros/humble/local_setup.bash 内容(节选):
                       export AMENT_PREFIX_PATH="/opt/ros/humble"
                       export CMAKE_PREFIX_PATH="/opt/ros/humble${CMAKE_PREFIX_PATH:+:${CMAKE_PREFIX_PATH}}"
                       export PATH="/opt/ros/humble/bin:$PATH"
                       export LD_LIBRARY_PATH="/opt/ros/humble/lib:$LD_LIBRARY_PATH"
                       export PYTHONPATH="/opt/ros/humble/lib/python3.10/site-packages:$PYTHONPATH"
                       export PKG_CONFIG_PATH="/opt/ros/humble/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"

        → 此时 shell 环境中:
           $ echo $CMAKE_PREFIX_PATH
           /opt/ros/humble

4. 执行构建命令
   └── 命令: colcon build --packages-select com_yyy
        │
        └── colcon 内部行为:
             ├── 创建 build/com_yyy/, install/, log/ 目录
             ├── 在 build/com_yyy/ 中调用:
                  cmake -DCMAKE_INSTALL_PREFIX=../install \
                        -DCMAKE_PREFIX_PATH="/opt/ros/humble" \  ← 显式传入(也读环境)
                        /path/to/ws/src/com_yyy
             │
             └── CMake 执行过程:
                  ├── 读取 CMakeLists.txt
                  ├── 执行 find_package(rclcpp REQUIRED)
                  │    └── 搜索策略(按顺序):
                  │         1. CMAKE_PREFIX_PATH 中每个路径的 share/rclcpp/cmake/
                  │         2. 找到: /opt/ros/humble/share/rclcpp/cmake/rclcppConfig.cmake
                  │
                  ├── 加载 rclcppConfig.cmake
                  │    └── 该文件定义(通过 set 或 import):
                  │         rclcpp_INCLUDE_DIRS = /opt/ros/humble/include
                  │         rclcpp_LIBRARIES    = rclcpp::rclcpp (CMake target)
                  │         (实际是 IMPORTED target,指向 /opt/ros/humble/lib/librclcpp.so)
                  │
                  ├── 执行 ament_target_dependencies(helloworld rclcpp)
                  │    └── 等价于:
                  │         target_link_libraries(helloworld rclcpp::rclcpp)
                  │         (自动附加 include_directories、compile_definitions 等)
                  │
                  └── 生成 build.ninja 或 Makefile
                       └── 编译规则示例(ninja -t commands | grep helloworld):
                            g++ -I/opt/ros/humble/include \
                                -I/usr/include/eigen3 \
                                -isystem /opt/ros/humble/include/opencv4 \
                                -std=c++17 \
                                -o CMakeFiles/helloworld.dir/src/helloworld.cpp.o \
                                -c /path/to/ws/src/com_yyy/src/helloworld.cpp

5. 编译与链接
   └── 执行: ninja (或 make)
        │
        └── 链接命令示例:
             g++ CMakeFiles/helloworld.dir/src/helloworld.cpp.o \
                 -o helloworld \
                 -L/opt/ros/humble/lib \
                 -lrclcpp -lrcutils -lrmw_implementation ... \
                 -Wl,-rpath,/opt/ros/humble/lib   ← 关键:嵌入运行时库搜索路径

        → 生成: build/com_yyy/helloworld (未安装)

6. 安装(部署)
   └── 执行: cmake --install . --prefix ../install
        │
        └── 复制文件到 install/ 目录:
             ├── install/com_yyy/lib/com_yyy/helloworld
             ├── install/com_yyy/share/com_yyy/package.xml
             └── install/com_yyy/share/ament_index/resource_index/packages/com_yyy (注册包)

        → 同时,colcon 自动生成:
             ├── install/_local_setup_util.sh
             ├── install/local_setup.bash
             └── install/setup.bash

        其中 install/local_setup.bash 内容(节选):
             export AMENT_PREFIX_PATH="/path/to/ws/install${AMENT_PREFIX_PATH:+:${AMENT_PREFIX_PATH}}"
             export PATH="/path/to/ws/install/com_yyy/lib/com_yyy:$PATH"
             export LD_LIBRARY_PATH="/path/to/ws/install/com_yyy/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
             export CMAKE_PREFIX_PATH="/path/to/ws/install${CMAKE_PREFIX_PATH:+:${CMAKE_PREFIX_PATH}}"

7. 运行前:激活当前工作空间环境
   └── 执行: source install/setup.bash
        │
        └── 该脚本:
             ├── 设置 COLCON_CURRENT_PREFIX="/path/to/ws/install"
             ├── source /opt/ros/humble/local_setup.bash      ← 继承上游(chaining)
             └── source /path/to/ws/install/local_setup.bash  ← 加载本工作空间
                  → 最终环境变量(优先级从高到低):
                     PATH = /path/to/ws/install/com_yyy/lib/com_yyy:/opt/ros/humble/bin:...
                     LD_LIBRARY_PATH = /path/to/ws/install/com_yyy/lib:/opt/ros/humble/lib:...
                     AMENT_PREFIX_PATH = /path/to/ws/install:/opt/ros/humble

8. 启动节点
   └── 执行: ros2 run com_yyy helloworld
        │
        └── ros2 CLI 工作流程:
             ├── 读取 AMENT_PREFIX_PATH,分割为前缀列表
             ├── 对每个前缀检查 share/<pkg>/package.xml 是否存在
             │    → 找到 /path/to/ws/install/share/com_yyy/package.xml
             ├── 在该前缀下查找可执行文件:
             │    → install/com_yyy/lib/com_yyy/helloworld
             └── execvp("helloworld", ...) 启动进程

        → 进程启动后:
             ├── 动态链接器 (ld-linux.so) 加载依赖库
             ├── 根据 ELF 中的 RPATH(来自 -Wl,-rpath,...)和 LD_LIBRARY_PATH 查找 .so
             │    → 成功加载 /opt/ros/humble/lib/librclcpp.so
             └── 程序正常运行,打印日志

3、补充关键细节说明

3-1、关于 RPATH(运行时库路径嵌入)

  • 即使你没设 LD_LIBRARY_PATH,程序也能找到 librclcpp.so,因为 CMake 默认启用了:

    cmake 复制代码
    set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
    set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")  # 或类似
  • 你可以用 readelf -d helloworld | grep RPATH 查看。


3-2、 ament_index 是什么?

  • install/share/ament_index/resource_index/packages/com_yyy 是一个空文件
  • 它的作用是让 ros2 pkg listget_package_share_directory() 能快速发现你的包

3-3、为什么需要两次 source

场景 必须 source? 原因
colcon build 是(至少 source 系统 ROS) 否则 CMake 找不到 rclcpp
ros2 run 自己的节点 是(必须 source install/) 否则 ros2 不知道你的包存在
ros2 run demo_nodes_cpp talker 只需 source 系统 ROS 因为它在 /opt/ros/...

3-4、 验证命令(供你实操)

bash 复制代码
# 1. 查看构建时 CMake 用了哪些 include
cat build/com_yyy/compile_commands.json | jq '.[].command' | grep -o '\-I[^ ]*'

# 2. 查看可执行文件的 RPATH
readelf -d install/com_yyy/lib/com_yyy/helloworld | grep RPATH

# 3. 查看运行时库依赖
ldd install/com_yyy/lib/com_yyy/helloworld | grep rclcpp

# 4. 查看环境变量
source install/setup.bash
echo $AMENT_PREFIX_PATH

相关推荐
花花少年1 天前
快速体验ros2之发布者-订阅者模式
ros2·发布者-订阅者
飘忽不定的bug2 天前
ubuntu22.04部署ROS2-humble
linux·ubuntu·ros2
zylyehuo2 天前
Ubuntu22.04 外接显示屏显示异常
ros2·夯实基础
滴啦嘟啦哒3 天前
【机械臂】【总览】基于VLA结构的指令驱动式机械臂
python·ros2·vla
kyle~3 天前
导航---Nav2导航框架概览
c++·机器人·ros2·导航
米有哥4 天前
[Embodied AI] Mac上安装ROS2
人工智能·macos·ros2
叠叠乐7 天前
ros2 找功能包的get_package_share_directory
ros2
漫漫求11 天前
ros2常用命令
ros2
奔跑的花短裤14 天前
ROS2安装
ros·ros2·ros1