4、工作空间与功能包创建

好,咱们正式开始动手搭建ROS2项目。这一章我带你走一遍最基础、也最关键的流程——创建工作空间和功能包。说白了,这就是你所有机器人代码的「家」。

我记得刚接触ROS2时,第一件事就是被工作空间这个概念搞晕了。其实没那么复杂,你把它想象成一个项目文件夹就行。里面放你的代码、配置文件、编译脚本,一切井井有条。

4.1 创建工作空间

工作空间(workspace)在ROS2里通常叫 colcon_ws 或者 ros2_ws。我个人习惯用 ros2_ws,简单好记。

打开终端,敲下面这几行命令:

mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
colcon build

这里解释一下:mkdir -p 会一次性创建 ros2_ws 和它下面的 src 文件夹。src 就是放功能包的地方。然后 colcon build 是ROS2的编译工具,它会扫描 src 里的所有包,把它们编译好。

小提示:第一次编译时,如果提示找不到 colcon,说明你没装这个工具。运行 sudo apt install python3-colcon-common-extensions 就能搞定。

编译完成后,你会看到工作空间里多了几个文件夹:buildinstalllog。别慌,这些都是自动生成的。build 放编译中间文件,install 放编译好的可执行文件和库,log 放编译日志。你平时主要打交道的还是 src 文件夹。

4.2 创建功能包

工作空间建好了,接下来往里面放功能包。功能包(package)是ROS2里最小的代码单元。一个包可以包含节点、消息定义、配置文件等等。

创建功能包用 ros2 pkg create 命令。比如我要创建一个叫 robot_base 的包:

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

参数说明:

  • --build-type ament_cmake:指定用CMake作为构建系统。ROS2支持 ament_cmakeament_python 两种,C++项目用前者,Python项目用后者。
  • --dependencies rclcpp std_msgs:声明这个包依赖 rclcpp(ROS2的C++客户端库)和 std_msgs(标准消息类型)。

命令执行后,src/robot_base 文件夹下会自动生成一堆文件。核心的有两个:package.xmlCMakeLists.txt。嗯,这两个文件你得好好理解,后面所有配置都靠它们。

注意:包名只能用字母、数字和下划线,而且不能以数字开头。我曾经见过有人用 my-robot 这种带横杠的名字,结果编译报错半天找不到原因。

4.3 理解 package.xml

package.xml 是功能包的「身份证」。它告诉ROS2这个包叫什么、谁写的、依赖哪些其他包。说白了,就是元数据文件。

打开它看看:

<?xml version="1.0"?>
<package format="3">
  <name>robot_base</name>
  <version>0.0.0</version>
  <description>机器人底盘控制功能包</description>
  <maintainer email="your_email@example.com">your_name</maintainer>
  <license>Apache-2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>std_msgs</depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

重点看这几个标签:

  • <name>:包名,必须和文件夹名一致。
  • <version>:版本号。我习惯用 0.0.1 起步,后面迭代再改。
  • <description>:一句话描述这个包是干嘛的。别偷懒,写清楚点,方便别人(包括未来的你)理解。
  • <maintainer>:维护者信息。填你的名字和邮箱。
  • <license>:许可证。开源项目常用 Apache-2.0BSD-3-Clause
  • <depend>:运行时依赖。这里声明了 rclcppstd_msgs,编译和运行时都会用到。
关键点:每当你新增一个依赖库,比如要用到 geometry_msgs,记得在 package.xml 里加一行 <depend>geometry_msgs</depend>。否则编译时ROS2会找不到头文件。

4.4 理解 CMakeLists.txt

CMakeLists.txt 是编译脚本。它告诉CMake怎么编译你的代码、链接哪些库、安装哪些文件。

自动生成的内容大概长这样:

cmake_minimum_required(VERSION 3.8)
project(robot_base)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

# 添加可执行文件
add_executable(robot_node src/robot_node.cpp)
target_link_libraries(robot_node ${rclcpp_LIBRARIES} ${std_msgs_LIBRARIES})

# 安装规则
install(TARGETS
  robot_node
  DESTINATION lib/${PROJECT_NAME}
)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

我来拆解一下:

  • cmake_minimum_required:指定CMake最低版本。ROS2 Humble要求3.8以上。
  • project():项目名,和包名一致。
  • find_package():查找依赖包。每个依赖都要写一行,和 package.xml 里的 <depend> 对应。
  • add_executable():声明一个可执行文件,源文件路径写清楚。
  • target_link_libraries():链接库。把找到的依赖库链接到你的可执行文件上。
  • install():安装规则。编译好的二进制文件要放到 lib/${PROJECT_NAME} 目录下。
  • ament_package():ROS2特有的宏,必须放在最后。
避坑指南:我曾经犯过一个低级错误——在 CMakeLists.txt 里忘了加 find_package(rclcpp REQUIRED),结果编译时一直报「找不到头文件」。排查了半天才发现是这里漏了。所以每次改依赖,两个文件都要同步更新。

4.5 编译与测试

包写好了,怎么验证它能不能用?回到工作空间根目录,重新编译:

cd ~/ros2_ws
colcon build --packages-select robot_base

--packages-select 参数可以只编译指定的包,省时间。如果你改了很多包,直接 colcon build 全部编译也行。

编译成功后,记得刷新环境变量:

source install/setup.bash

然后你就可以用 ros2 run robot_base robot_node 来运行你的节点了。如果一切顺利,终端里应该能看到你的程序输出。

小技巧:source ~/ros2_ws/install/setup.bash 加到 ~/.bashrc 文件里,这样每次打开终端就不用手动刷新了。我个人的习惯是加一行注释,方便以后定位。

4.6 本章小结

这一章我们干了三件事:建工作空间、创建功能包、理解两个核心配置文件。你想想看,其实ROS2的项目结构并不复杂,关键是把 package.xmlCMakeLists.txt 这两个文件搞明白。后面所有章节的代码,都跑不出这个框架。

下一章,我会带你写第一个真正的ROS2节点——让机器人动起来。嗯,那才是真正有意思的部分。