ROS 编写简单的发布者和订阅者(C++)
2025-08-15
ROS
00

目录

ros::Rate loop_rate(10);
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
1. add_executable(talker src/talker.cpp)
2. targetlinklibraries(talker ${catkin_LIBRARIES})
3. adddependencies(talker beginnertutorialsgeneratemessages_cpp)
4. add_executable(listener src/listener.cpp)
5. targetlinklibraries(listener ${catkin_LIBRARIES})
6. adddependencies(listener beginnertutorialsgeneratemessages_cpp)
总结
关键点
类比理解
1. find_package
2. addmessagefiles
3. addservicefiles
4. generate_messages
5. catkin_package
6. include_directories
7. addexecutable / targetlinklibraries / adddependencies
rosrun beginner_tutorials talker
rosrun beginner_tutorials listener

https://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29

bash
展开代码
root@euler-MS-7D30:~/xiedong/learning-ros/catkin_ws# roscd beginner_tutorials roscd: No such package/stack 'beginner_tutorials' root@euler-MS-7D30:~/xiedong/learning-ros/catkin_ws# . devel/setup.bash root@euler-MS-7D30:~/xiedong/learning-ros/catkin_ws# roscd beginner_tutorials root@euler-MS-7D30:~/xiedong/learning-ros/catkin_ws/src/beginner_tutorials# root@euler-MS-7D30:~/xiedong/learning-ros/catkin_ws/src/beginner_tutorials/src# wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/roscpp_tutorials/talker/talker.cpp

image.png

这个程序的主要功能是:

  1. 初始化一个名为"talker"的ROS节点
  2. 创建一个发布者,向"chatter"话题发布字符串消息
  3. 以10Hz的频率不断发布包含"hello world"和计数的消息
  4. 同时将发布的消息内容打印到控制台

bash
展开代码
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/roscpp_tutorials/listener/listener.cpp

这个程序的主要功能是:

  1. 初始化一个名为"listener"的ROS节点
  2. 创建一个订阅者,订阅"chatter"话题
  3. 每当收到新消息时,调用chatterCallback函数处理
  4. 在回调函数中打印接收到的消息内容

与之前的"talker"程序配合使用时:

  • "talker"发布消息到"chatter"话题
  • "listener"订阅该话题并接收消息
  • 这样就实现了两个ROS节点之间的单向通信

这种发布-订阅模式是ROS中最基本也是最重要的通信机制之一,广泛应用于机器人系统中不同模块间的数据交换。在实际应用中,消息类型通常会替换为更复杂的自定义消息类型,以传输各种传感器数据、控制指令等。

ros::Rate loop_rate(10);

这句话是 C++ 的“类实例化”语法,也叫“构造对象”语法。 等价于: ros::Rate loop_rate = ros::Rate(10);


ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

这句话的作用是让 ROS 节点订阅名为 "chatter" 的话题,并在收到消息时调用 chatterCallback 回调函数。详细解释如下:

ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

  • n 是 ros::NodeHandle 的实例,负责与 ROS 系统通信。
  • subscribe 是 NodeHandle 的成员函数,用于订阅某个话题(topic)。
  • "chatter" 是你要订阅的话题名称。
  • 1000 是消息队列的长度(缓冲区大小),如果消息来得太快,最多缓存 1000 条,超过就丢弃最旧的。
  • chatterCallback 是收到消息时自动调用的回调函数,参数类型要和话题消息类型一致。

这句代码的意思是:“订阅 chatter 话题,每当有新消息到来时,就调用 chatterCallback 处理消息,并且最多缓存 1000 条未处理的消息。”


这几句加进去:

bash
展开代码
add_executable(talker src/talker.cpp) target_link_libraries(talker ${catkin_LIBRARIES}) add_dependencies(talker beginner_tutorials_generate_messages_cpp) add_executable(listener src/listener.cpp) target_link_libraries(listener ${catkin_LIBRARIES}) add_dependencies(listener beginner_tutorials_generate_messages_cpp)

image.png

这几行代码是 ROS/Catkin 项目中的 CMake 构建指令,用于编译和链接 ROS 节点(可执行文件)。以下是逐行解析其核心功能:


1. add_executable(talker src/talker.cpp)

  • 功能:将 src/talker.cpp 编译成一个名为 talker 的可执行文件(ROS 节点)。
  • 作用
    • 定义了一个 ROS 发布者(Publisher)节点,对应之前的 talker.cpp 代码。
    • 编译后会生成 talker 二进制文件(通常在 devel/lib/<package_name>/ 目录下)。

2. target_link_libraries(talker ${catkin_LIBRARIES})

  • 功能:将 talker 可执行文件链接到 ROS 的核心库(catkin_LIBRARIES)。
  • 作用
    • 确保 talker 能调用 ROS 的 API(如 ros::init(), ros::Publisher 等)。
    • ${catkin_LIBRARIES} 是 Catkin 工具链提供的预定义变量,包含所有必要的 ROS 依赖库(如 roscppstd_msgs 等)。

3. add_dependencies(talker beginner_tutorials_generate_messages_cpp)

  • 功能:显式声明 talker 依赖于 beginner_tutorials_generate_messages_cpp
  • 作用
    • 确保在编译 talker 之前,先编译生成该包(beginner_tutorials)的自定义消息(如果有)。
    • 如果包内定义了自定义消息(如 .msg 文件),ROS 需要先将其转换为 C++ 代码(通过 message_generation),然后才能被 talker 使用。

4. add_executable(listener src/listener.cpp)

  • 功能:将 src/listener.cpp 编译成名为 listener 的可执行文件(ROS 节点)。
  • 作用
    • 定义了一个 ROS 订阅者(Subscriber)节点,对应之前的 listener.cpp 代码。
    • 编译后会生成 listener 二进制文件。

5. target_link_libraries(listener ${catkin_LIBRARIES})

  • 功能:将 listener 链接到 ROS 核心库(catkin_LIBRARIES)。
  • 作用
    • 确保 listener 能使用 ROS 的订阅功能(如 ros::Subscriber、回调函数等)。

6. add_dependencies(listener beginner_tutorials_generate_messages_cpp)

  • 功能:声明 listener 依赖于 beginner_tutorials_generate_messages_cpp
  • 作用
    • talker 类似,确保自定义消息(如果有)先被生成,再编译 listener

总结

指令功能
add_executable将源代码编译为可执行文件(ROS 节点)
target_link_libraries链接 ROS 核心库,使节点能调用 ROS API
add_dependencies确保自定义消息先于节点编译,避免未定义符号错误

关键点

  1. ROS 节点的构建流程
    • 先编译消息(如果有)→ 再编译节点 → 最后链接依赖库。
  2. catkin_LIBRARIES
    • 是 ROS 项目的“万能”依赖项,包含 roscppstd_msgs 等基础库。
  3. 依赖关系的重要性
    • 如果包内有自定义消息(如 MyMessage.msg),必须通过 add_dependencies 确保消息生成先完成,否则编译会失败。

类比理解

  • add_executable ≈ 告诉编译器:“把这份代码变成可执行程序”。
  • target_link_libraries ≈ 告诉链接器:“这个程序需要 ROS 的库才能运行”。
  • add_dependencies ≈ 告诉构建系统:“先搞定消息生成,再编译这个程序”。

cmake错误,CMakeLists.txt改为这样:

bash
展开代码
cmake_minimum_required(VERSION 2.8.3) project(beginner_tutorials) find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation ) add_message_files( FILES Num.msg ) add_service_files( FILES AddTwoInts.srv ) generate_messages( DEPENDENCIES std_msgs ) catkin_package( CATKIN_DEPENDS message_runtime roscpp rospy std_msgs ) include_directories( include ${catkin_INCLUDE_DIRS} ) add_executable(talker src/talker.cpp) target_link_libraries(talker ${catkin_LIBRARIES}) add_dependencies(talker ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) add_executable(listener src/listener.cpp) target_link_libraries(listener ${catkin_LIBRARIES}) add_dependencies(listener ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

CMakeLists.txt 里的 ROS 相关指令:


1. find_package

作用:查找并加载 catkin 以及你需要用到的 ROS 包(如 roscpp、rospy、std_msgs、message_generation 等),让后续的 CMake 指令能用到这些包的功能和头文件。

示例

cmake
展开代码
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation )

通俗理解:告诉 CMake,“我要用到这些包,请帮我找好它们。”


2. add_message_files

作用:声明本包要用到的自定义消息(.msg 文件),让 catkin 知道需要为这些消息生成代码。

示例

cmake
展开代码
add_message_files( FILES Num.msg )

通俗理解:告诉 CMake,“我要用这些自定义消息,请帮我生成相关代码。”


3. add_service_files

作用:声明本包要用到的自定义服务(.srv 文件),让 catkin 知道需要为这些服务生成代码。

示例

cmake
展开代码
add_service_files( FILES AddTwoInts.srv )

通俗理解:告诉 CMake,“我要用这些自定义服务,请帮我生成相关代码。”


4. generate_messages

作用:根据上面声明的消息和服务,自动生成 C++/Python 等语言的消息/服务代码。
DEPENDENCIES 里写上你消息/服务里用到的其他消息包(比如 std_msgs)。

示例

cmake
展开代码
generate_messages( DEPENDENCIES std_msgs )

通俗理解:告诉 CMake,“现在请为我声明的消息和服务生成代码。”


5. catkin_package

作用:声明本包对外提供哪些功能、依赖哪些包。这样其他包在依赖你时能自动找到你的头文件、库、消息等。

示例

cmake
展开代码
catkin_package( CATKIN_DEPENDS message_runtime roscpp rospy std_msgs )

通俗理解:告诉 CMake,“我的包对外提供哪些功能,依赖哪些包。”


6. include_directories

作用:指定头文件搜索路径。一般要包含本包的 include 目录和 catkin 自动生成的头文件路径。

示例

cmake
展开代码
include_directories( include ${catkin_INCLUDE_DIRS} )

通俗理解:告诉 CMake,“编译时请到这些目录找头文件。”


7. add_executable / target_link_libraries / add_dependencies

作用

  • add_executable:声明要编译的可执行文件(比如 talker、listener)。
  • target_link_libraries:指定可执行文件要链接哪些库(比如 ${catkin_LIBRARIES})。
  • add_dependencies:指定可执行文件依赖哪些生成目标(比如消息/服务生成),确保先生成消息/服务代码再编译你的程序。

示例

cmake
展开代码
add_executable(talker src/talker.cpp) target_link_libraries(talker ${catkin_LIBRARIES}) add_dependencies(talker ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

通俗理解

  • add_executable:我要生成一个叫 talker 的程序,源码在 src/talker.cpp。
  • target_link_libraries:编译时要链接 ROS 的库。
  • add_dependencies:先生成消息/服务代码,再编译我的程序,避免找不到头文件。

在ws目录执行catkin_make

bash
展开代码
Scanning dependencies of target beginner_tutorials_generate_messages Scanning dependencies of target talker Scanning dependencies of target listener [ 76%] Built target beginner_tutorials_generate_messages [ 82%] Building CXX object beginner_tutorials/CMakeFiles/listener.dir/src/listener.cpp.o [ 88%] Building CXX object beginner_tutorials/CMakeFiles/talker.dir/src/talker.cpp.o [ 94%] Linking CXX executable /root/xiedong/learning-ros/catkin_ws/devel/lib/beginner_tutorials/talker [ 94%] Built target talker [100%] Linking CXX executable /root/xiedong/learning-ros/catkin_ws/devel/lib/beginner_tutorials/listener [100%] Built target listener

可见有可执行文件:

image.png

catkin_make 后,所有 add_executable 生成的目标(如 talker、listener)都在 devel/lib/包名/ 目录下。 你可以用 rosrun 包名 可执行文件名 或直接用绝对路径运行。

bash
展开代码
rosrun beginner_tutorials talker rosrun beginner_tutorials listener

rosrun beginner_tutorials talker

  • 作用:运行 beginner_tutorials 包里的 talker 可执行程序。
  • 等价于:直接执行 ~/xiedong/learning-ros/catkin_ws/devel/lib/beginner_tutorials/talker,但 rosrun 会自动帮你查找路径和设置环境变量。

rosrun beginner_tutorials listener

  • 作用:运行 beginner_tutorials 包里的 listener 可执行程序。
  • 等价于:直接执行 ~/xiedong/learning-ros/catkin_ws/devel/lib/beginner_tutorials/listener

下面就可以执行节点了:

bash
展开代码
. devel/setup.bash nohup roscore & rosrun beginner_tutorials talker rosrun beginner_tutorials listener

image.png

image.png

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Dong

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!