ros2

功能包(pkg)

一个功能包可以被认为是ROS2代码的容器。如果希望能够管理代码或与他人共享代码,那么需要将其组织在一个包中。通过包,可以发布ROS2工作,并允许其他人轻松地构建和使用它。

功能包 和 程序 的关系

一个功能包里可以包含多个程序。这些程序分成不同职责,共同构成一个功能包的完整功能。通过cmake可控制多个可执行文件:

1
2
3
4
5
# ...
add_executable(program1 src/program1.cpp ...)
# ...
add_executable(program2 src/program2.cpp ...)
# ...

程序 和 节点 的关系

一个程序(对应一个main函数)里一般性跑一个节点,因为spin一个节点是阻塞线程的操作。当然你可以异步跑多个节点,但不常用。

创建并运行一个功能包

  1. 使用如下命令在当前目录下创建一个ros2包:
1
ros2 pkg create <包名> --build-type ament_cmake --node-name <程序名> --dependencies <依赖>
  • ros2 pkg create:创建包的 固定语法
  • --build-type:构建包的选项,一般C++写ament_cmake,python写 ament_python
  • --node-name:可选参数,若指定将会默认添加一个src/<程序名>.cpp文件,并指定成程序名称。
  • --dependencies:可选参数,添加依赖项,常见的依赖如rclcpp(ros2的c++接口)。

下图为在ubuntu命令行创建一个名为demo_cpp_pkg的包的示例:

一个包的基本结构:

1
2
3
4
5
demo_cpp_pkg/
├── CMakeLists.txt 编译配置
├── package.xml 包元信息
├── src/ 你自己写代码的地方
└── include/demo_cpp_pkg/ (可选)头文件
  1. 新建src/main.cpp,写入如下基本节点代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "rclcpp/rclcpp.hpp"

using namespace rclcpp;
using namespace std;

int main(int argc, char** argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared<Node>("cpp_node");
RCLCPP_INFO(node->get_logger(), "你好!C++节点");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
  1. 修改CMakeLists.txt成如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
cmake_minimum_required(VERSION 3.8)
project(demo_cpp_pkg)

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

# find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# 1. 查找rclcpp的头文件和库
find_package(rclcpp REQUIRED)
# 2. 添加可执行文件 main
add_executable(main src/main.cpp)
# 3. 为 main 添加依赖
ament_target_dependencies(
main
rclcpp
)
# 4. 将 main拷贝到 install目录
install(TARGETS
main
DESTINATION lib/${PROJECT_NAME})

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()

ament_package()

其中:ament_target_dependencies函数是ament的扩展函数,等同于绑定依赖的include库和链接libraries,即下两行代码:

1
2
target_include_directories(main PUBLIC ${rclcpp_INCLUDE_DIRS})
target_link_libraries(main ${rclcpp_LIBRARIES})
  1. 使用cmake编译(vscode按下f7)。

  2. 使用colcon构建包:colcon build

  3. source install/setup/bash

  4. 运行命令

    1
    ros2 run <包名> <程序名>

    示例中即为:

    1
    ros2 run demo_cpp_pkg main

tf2

(坐标变换工具)

命令行

1
2
3
4
5
6
7
8
9
10
# 发布base_link到base_laser之间的变换
ros2 run tf2_ros static_transform_publisher --x 0.1 --y 0.0 --z 0.2 --roll 0.0 --pitch 0.0 --yaw 0.0 --frame-id base_link --child-frame-id base_laser

# 发布base_laser到wall_point之间的变换
ros2 run tf2_ros static_transform_publisher --x 0.3 --y 0.0 --z 0.0 --roll 0.0 --pitch 0.0 --yaw 0.0 --frame-id base_laser --child-frame-id wall_point

# 查询base_link 到wall_point之间的关系
ros2 run tf2_ros tf2_echo [source_frame] [target_frame]
# 即:
ros2 run tf2_ros tf2_echo base_link wall_point

urdf

(Unified Robot Description Format)

urdf是一种用于表示/仿真机器人模型的XML格式。

下面是 URDF 中常见的标签及其作用简明总览,分为核心结构几何与外观运动与连接三大类:


一、核心结构标签

标签 说明 示例/备注
<robot> 所有 URDF 的根标签,定义机器人名称 <robot name="my_bot">
<link> 描述一个部件(如一个刚体) 机器人上每个零件都需定义为一个 link
<joint> 描述两个 link 之间的连接关系 定义运动、旋转、固定等

二、几何与外观标签(在 <visual><collision><inertial> 中使用)

标签 说明 示例
<visual> link 的可视化外观 RViz2 中展示用
<collision> link 的碰撞体 用于仿真、碰撞检测
<inertial> link 的惯性信息 包括质量、惯性矩、质心等
<origin> 坐标原点偏移,定义相对于父元素的位置和姿态 <origin xyz="0 0 1" rpy="0 0 0"/>
<geometry> 定义几何形状(与 visualcollision 配合) 包含 box、cylinder、sphere、mesh
<box> 长方体几何 <box size="1 1 1"/>
<cylinder> 圆柱体几何 <cylinder length="1" radius="0.5"/>
<sphere> 球体几何 <sphere radius="0.3"/>
<mesh> 加载外部模型文件(如 .dae, .stl <mesh filename="package://path/model.dae"/>
<material> 材质颜色或纹理 <material name="gray"><color rgba="0.5 0.5 0.5 1"/></material>
<color> 定义颜色值 RGBA 四维(透明度在最后)

三、连接与运动标签(joint 内部)

标签 说明 示例
<parent> 父 link 名称 <parent link="base_link"/>
<child> 子 link 名称 <child link="wheel_link"/>
<axis> 关节运动的轴向 <axis xyz="0 0 1"/> 表示绕 Z 轴
<limit> 关节限制(适用于 revolute/prismatic) <limit lower="-1.57" upper="1.57" effort="1" velocity="1"/>
<dynamics> 摩擦/阻尼等动态参数 可选,增强仿真精度
<type> 关节类型 revolute, continuous, prismatic, fixed, floating, planar

四、其它辅助标签(常用但非必须)

标签 用途 说明
<transmission> 与控制器配合使用 在控制机器人时才需要
<gazebo> Gazebo 特定配置(带插件) 与仿真配合用
<xacro:macro> Xacro 宏定义 重复结构抽象
<xacro:property> 定义变量 用于参数传递或配置

xacro

(Xml Macro)

ROS还提供了用于简化urdf编写的xacro格式。文件后缀名.xacro。编写好文件后不能直接使用,应先转成urdf格式。

1
2
3
4
5
# 安装xacro包
sudo apt install ros-$ROS_DISTRO-xacro

# 转换成urdf
xacro <macro文件名>

在RViz中显示机器人

当我们编写好urdf/xacro机器人描述文件后,rviz并不能自动地去识别不同部件的坐标变换关系。实际上,urdf和rivz中间的桥梁是由robot_state_publisher包(和joint_state_publisher包)搭建起来的。

如上图的关系所示,robot_state_publisher包解析urdf中的tf变换关系。遇到静态tf(如定义为fixed的joint)通过/tf_static话题发布;遇到动态tf关系,先发布到/robot_description话题,另一边被joint_state_publisher包订阅,自动扫描动态的关节,并将其数值发布到/joint_states话题,最后robot_state_publisher包收到后,通过/tf话题发布。

步骤

  1. 要想urdf加载进rviz,应该编写一个launch文件。在launch目录下新建一个display.launch.py,内容大致如下(大同小异,理解为主,切勿无脑照抄):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.substitutions import Command, FindExecutable
from ament_index_python.packages import get_package_share_directory
import os

def generate_launch_description():
# 获取urdf路径
urdf_file = os.path.join(
get_package_share_directory("gimbal"),
"urdf",
"gimbal.urdf.xacro"
)

# xacro转urdf(通过xacro <xacro文件路径> 命令)
urdf_content = Command([
FindExecutable(name="xacro"),
" ",
urdf_file
])

return LaunchDescription([
# robot_state_publisher节点
Node(
package="robot_state_publisher",
executable="robot_state_publisher",
parameters=[
{ "robot_description": urdf_content }
]
),
# joint_state_publisher节点
Node(
package="joint_state_publisher",
executable="joint_state_publisher"
),
# RViz2节点
Node(
package="rviz2",
executable="rviz2",
)
])
  1. 修改CMakeLists.txt,添加install命令,部署目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # ...

    # 将必要的目录(launch, urdf等)部署到share目录下
    install(DIRECTORY
    launch
    urdf
    DESTINATION share/${PROJECT_NAME}/)

    # ...
  2. 编译并部署

    1
    2
    colcon build
    source install/setup.bash
  3. 通过launch文件启动

    1
    ros2 launch <功能包名> display.launch.py

    RViz将自动启动。

  4. 在RViz内进一步调整:

    1. Fixed Frame默认为world,需要手动切换成你urdf的根部件(如base_link

    2. 切换好以后很大概率机器人模型依旧加载不出来,只显示坐标轴。如下图:

      解决方法是:点开左下角Add - 添加RobotModel可视化 - 手动选择Description Topic下拉框中的/robot_description话题让rviz重新加载

自定义消息类型XXX.msg

ROS2中有许多内置的包,如std_msgsgeometry_msgs,它们都有自己的消息类型用于节点间传输。当我们有这样的需求时也可自定义消息类型,步骤如下:

  1. 自定义消息最好单开一个功能包存放,以便实现复用。当然如果你项目小的话挤在一个包里也行,看具体需求。这里我要声明装甲板相关的消息,因此创建一个叫armor_interface的包。

    1
    ros2 pkg create armor_interface --build-type ament_cmake ...
  2. 一个消息类型其实就是一个XXX.msg文件。在包目录下新建msg文件夹,添加下面两个文件:

    1. Armor.msg:表示一个装甲板

      1
      2
      3
      4
      5
      string name
      string color
      string type
      geometry_msgs/Vector3 rvec
      geometry_msgs/Pose pose
    2. Armors.msg:表示多个装甲板的集合,用于传输

      1
      2
      std_msgs/Header header
      Armor[] data
  3. 修改CMakeLists.txt:

    1. 添加必要的包

      1
      2
      3
      find_package(rosidl_default_generators REQUIRED)  # 编译器自动识别msg文件并编译成代码
      find_package(std_msgs REQUIRED)
      find_package(geometry_msgs REQUIRED)
    2. 生成自定义消息的CMake命令 rosidl_generate_interfaces

      1
      2
      3
      4
      5
      6
      7
      8
      rosidl_generate_interfaces(${PROJECT_NAME}
      "msg/Armor.msg"
      "msg/Armors.msg"

      DEPENDENCIES
      std_msgs
      geometry_msgs
      )
  4. 修改package.xml

    package.xml添加一行(不然不给编译)

    1
    <member_of_group>rosidl_interface_packages</member_of_group>
  5. 编译&部署包

    1
    2
    colcon build
    source install/setup.bash

ros2
https://becks723.github.io/2025/06/11/ros2/
作者
Becks723
发布于
2025年6月11日
许可协议