3、工作空间与功能包:从零搭建你的ROS项目骨架

好,咱们进入第三章。说实话,这一章是整个ROS开发的基石。你想想看,盖房子总得先搭个脚手架吧?工作空间和功能包就是ROS项目的脚手架。我见过太多新手一上来就写代码,结果编译报错找不到包,折腾半天才发现是工作空间没配好。嗯,咱们今天就把它彻底搞明白。

3.1 工作空间(Workspace)是什么?

工作空间,说白了就是一个文件夹。但它不是普通文件夹,它有一套固定的结构。ROS用它来组织、编译和管理你的代码。

我个人习惯把工作空间放在 ~/ros_ws 下。当然你也可以叫 catkin_ws,都行。关键是里面的结构要对。

一个标准的工作空间长这样:

~/ros_ws/
├── src/          # 源代码目录,放功能包
├── build/        # 编译中间文件(自动生成)
├── devel/        # 编译产物(可执行文件、库等,自动生成)
└── install/      # 安装目录(可选,catkin_make install 后生成)

你只需要手动创建 src 目录,其他都是编译工具自动生成的。

3.2 创建工作空间

来,跟着我敲一遍:

# 创建目录
mkdir -p ~/ros_ws/src

# 进入src目录
cd ~/ros_ws/src

# 初始化工作空间
catkin_init_workspace

# 回到工作空间根目录
cd ~/ros_ws

# 编译
catkin_make

第一次编译后,你会看到 builddevel 目录自动出现了。这时候工作空间就搭好了。

小提示: 每次打开新终端,记得 source 一下工作空间的环境变量: source ~/ros_ws/devel/setup.bash 我建议直接写到 ~/.bashrc 里,省得每次都敲。

3.3 功能包(Package)是什么?

工作空间是房子,功能包就是一个个房间。每个功能包完成一个独立的功能。比如一个包负责控制机器人底盘,另一个包负责处理激光雷达数据。

一个功能包必须包含两个文件:

  • package.xml:包的元信息,像身份证一样
  • CMakeLists.txt:编译规则,告诉编译器怎么编译

缺少任何一个,ROS都不认。我在项目中遇到过有人只复制了代码,忘了带 package.xml,结果编译报错找了半天原因。

3.4 创建功能包

catkin_create_pkg 命令创建,语法是:

cd ~/ros_ws/src
catkin_create_pkg 包名 [依赖1] [依赖2] ...

举个例子,创建一个叫 my_robot 的包,依赖 roscppstd_msgs

cd ~/ros_ws/src
catkin_create_pkg my_robot roscpp std_msgs

执行后,src/my_robot 目录下会自动生成:

my_robot/
├── include/       # 头文件目录
├── src/           # 源代码目录
├── CMakeLists.txt
└── package.xml
重要: 包名只能用字母、数字和下划线,而且不能以数字开头。比如 2d_robot 就不行,得改成 robot_2d

3.5 编译功能包

回到工作空间根目录,执行:

cd ~/ros_ws
catkin_make

如果一切顺利,你会看到类似这样的输出:

Base path: /home/yourname/ros_ws
Source space: /home/yourname/ros_ws/src
Build space: /home/yourname/ros_ws/build
Devel space: /home/yourname/ros_ws/devel
...
[100%] Built target my_robot

看到 100% 就说明编译成功了。

注意: 编译时如果报错找不到某个包,八成是依赖没装全。比如缺 roscpp,就执行 sudo apt install ros-noetic-roscpp。我曾经在项目里因为少装了一个 tf2 包,卡了整整一下午。

3.6 package.xml 解析

这个文件是包的身份证。打开看看:

<?xml version="1.0"?>
<package format="2">
  <name>my_robot</name>
  <version>0.0.0</version>
  <description>我的第一个机器人包</description>
  <maintainer email="yourname@example.com">yourname</maintainer>
  <license>BSD</license>

  <buildtool_depend>catkin</buildtool_depend>

  <build_depend>roscpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>roscpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
</package>

关键字段说明:

标签 作用
<name> 包名,必须和文件夹名一致
<version> 版本号,方便管理
<description> 描述这个包是干什么的
<maintainer> 维护者信息,别人有问题可以找你
<license> 开源协议,BSD、MIT、GPL等
<build_depend> 编译时依赖
<exec_depend> 运行时依赖
我的习惯: 每次创建新包,第一件事就是改 package.xml 里的 descriptionmaintainer。不然时间久了,自己都忘了这个包是干嘛的。

3.7 CMakeLists.txt 解析

这个文件是编译说明书。ROS用CMake作为编译系统,所以这个文件遵循CMake语法。核心部分如下:

cmake_minimum_required(VERSION 3.0.2)
project(my_robot)

## 查找依赖包
find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
)

## 声明头文件路径
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

## 声明可执行文件
add_executable(my_robot_node src/my_robot_node.cpp)

## 链接库
target_link_libraries(my_robot_node
  ${catkin_LIBRARIES}
)

关键部分解读:

  • find_package:告诉CMake需要哪些依赖包
  • include_directories:指定头文件搜索路径
  • add_executable:声明要生成的可执行文件,以及它的源文件
  • target_link_libraries:链接需要的库文件

你想想看,如果没有 target_link_libraries,你的代码里调用了ROS的函数,但编译器不知道去哪找这些函数的实现,就会报链接错误。嗯,这个坑我踩过。

3.8 完整流程回顾

咱们把整个流程串起来:

  1. 创建并初始化工作空间:mkdir -p ~/ros_ws/src && cd ~/ros_ws/src && catkin_init_workspace
  2. 创建功能包:catkin_create_pkg my_robot roscpp std_msgs
  3. 编写代码(放到 src/ 目录下)
  4. 修改 CMakeLists.txt 添加编译规则
  5. 编译:cd ~/ros_ws && catkin_make
  6. source环境:source ~/ros_ws/devel/setup.bash

以后每次新增或修改代码,只需要重复第5步和第6步就行。

避坑指南: 我曾经在项目里犯过一个低级错误——在 src 目录下直接 catkin_make。记住,catkin_make 必须在工作空间根目录执行,也就是 ~/ros_ws 下,而不是 ~/ros_ws/src 下。

好了,这一章的内容就到这。工作空间和功能包是ROS开发的起点,看似简单,但细节不少。你只要亲手创建一遍,后面就顺了。下一章咱们开始写真正的ROS节点代码,到时候你会回来感谢这一章的铺垫的。