3. ROS2工作空间与功能包创建:工作空间结构、使用colcon编译、创建第一个C++/Python功能包

好,咱们直接进入正题。这一章要聊的,是ROS2开发最基础、也最绕不开的东西——工作空间和功能包。说白了,这就是你写代码的“工地”和“工具箱”。

我记得刚接触ROS1那会儿,对工作空间的理解就是“把代码扔进去,然后source一下”。结果经常出现编译冲突、找不到包、路径混乱的问题。后来转到ROS2,发现这套体系其实更清晰了,但前提是——你得理解它的设计逻辑。

3.1 工作空间长什么样?

ROS2的工作空间,本质上就是一个文件夹。但它的内部结构是约定好的。我个人习惯把它叫做ros2_ws,当然你叫什么都行。

一个标准的工作空间包含四个子目录:

目录名 作用
src 放你的功能包源码
build 编译过程中的中间文件
install 编译产物的安装目录
log 编译日志,排查错误时很有用

你想想看,这其实跟C++项目的构建流程很像。源码在src里,编译产物在install里。但ROS2用colcon这个工具来管理这一切。

核心要点:你只需要手动创建src目录。剩下的build、install、log,colcon会自动生成。

3.2 使用colcon编译——没那么玄乎

colcon是ROS2的编译工具。它替代了ROS1时代的catkin_make。说实话,我第一次用colcon的时候,觉得它比catkin慢。但后来发现,它更智能——它只编译你修改过的包,而不是全部重新编译。

基本操作就这几步:

# 创建并进入工作空间
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws

# 编译整个工作空间
colcon build

# 只编译某个功能包
colcon build --packages-select my_package

# 编译并忽略测试
colcon build --cmake-args -DBUILD_TESTING=OFF

嗯,这里要注意。colcon默认是并行编译的,如果你的电脑配置不高,可以加个参数限制一下:

colcon build --parallel-workers 2

我曾经在一个树莓派上编译整个ROS2,没加这个参数,结果直接卡死。后来老老实实改成单线程,虽然慢点,但至少能跑完。

小技巧:每次编译完,别忘了source一下:source install/setup.bash。我建议把它写到~/.bashrc里,省得每次手动敲。

3.3 创建第一个C++功能包

好,咱们来动手。创建一个C++功能包,名字就叫my_cpp_pkg。

cd ~/ros2_ws/src
ros2 pkg create my_cpp_pkg --build-type ament_cmake --dependencies rclcpp std_msgs

这条命令会生成什么?我带你看看:

  • CMakeLists.txt —— 编译规则文件
  • package.xml —— 包的元信息,比如依赖、版本号
  • src/ —— 放C++源文件的地方
  • include/ —— 放头文件的地方

然后我们写一个最简单的节点。在src/下创建my_node.cpp:

#include "rclcpp/rclcpp.hpp"

int main(int argc, char **argv)
{
  rclcpp::init(argc, argv);
  auto node = std::make_shared<rclcpp::Node>("my_cpp_node");
  RCLCPP_INFO(node->get_logger(), "Hello from C++ node!");
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}

别忘了修改CMakeLists.txt,添加可执行文件:

add_executable(my_node src/my_node.cpp)
ament_target_dependencies(my_node rclcpp std_msgs)

install(TARGETS
  my_node
  DESTINATION lib/${PROJECT_NAME}
)

然后编译、运行:

cd ~/ros2_ws
colcon build --packages-select my_cpp_pkg
source install/setup.bash
ros2 run my_cpp_pkg my_node

看到终端打印出“Hello from C++ node!”,就说明成了。

3.4 创建第一个Python功能包

Python包更简单。我个人其实更喜欢用Python做原型验证,因为改代码不用重新编译。

cd ~/ros2_ws/src
ros2 pkg create my_py_pkg --build-type ament_python --dependencies rclpy std_msgs

生成的目录结构是这样的:

  • package.xml
  • setup.py —— Python包的安装配置
  • setup.cfg
  • my_py_pkg/ —— 放Python模块的目录

在my_py_pkg/下创建my_node.py:

import rclpy
from rclpy.node import Node

def main(args=None):
    rclpy.init(args=args)
    node = Node("my_py_node")
    node.get_logger().info("Hello from Python node!")
    rclpy.spin(node)
    rclpy.shutdown()

if __name__ == "__main__":
    main()

然后修改setup.py,在entry_points里添加:

entry_points={
    'console_scripts': [
        'my_node = my_py_pkg.my_node:main',
    ],
},

编译和运行:

colcon build --packages-select my_py_pkg
source install/setup.bash
ros2 run my_py_pkg my_node

注意:Python包虽然不用编译C++代码,但colcon仍然会执行一些安装步骤。所以每次修改了setup.py或新增了文件,还是需要重新colcon build一下。

3.5 工作空间的核心逻辑

为了让你更直观地理解整个流程,我画了一张图:

ROS2工作空间核心流程 src/ 功能包源码 colcon build 编译工具 install/ 编译产物 详细步骤: 1. 在 src/ 下创建功能包(ros2 pkg create) 2. 编写节点代码(C++ 或 Python) 3. 配置 CMakeLists.txt 或 setup.py 4. 执行 colcon build 编译 5. source install/setup.bash 加载环境 6. ros2 run 运行节点 每次新增包或修改依赖 都需要重新 colcon build

这张图把整个流程串起来了。你从src开始,写代码,然后用colcon编译,产物放到install里,最后source一下就能运行。说白了,就是这么回事。

3.6 避坑指南

最后,分享几个我踩过的坑:

  • 路径问题:一定要在ros2_ws根目录执行colcon build,不要在src里面执行。我曾经犯过这个错,结果编译产物全乱套了。
  • 依赖缺失:创建包时忘了加--dependencies,编译时各种报错。后来我习惯先列清楚依赖再创建。
  • Python包入口:记得在setup.py的entry_points里注册你的函数,否则ros2 run找不到节点。

我的习惯:每次新建工作空间,我会先创建一个README.md,把编译命令、包名、依赖都记下来。项目大了之后,这能省不少时间。

好了,这一章的内容就到这儿。工作空间和功能包是ROS2开发的基石,你花点时间把这块搞透,后面写节点、通信、集成都会顺手很多。

可可精品资料库