【ROS教程】话题通信
2024/8/31 23:02:49
本文主要是介绍【ROS教程】话题通信,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
@TOC
1.流程
话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。在ROS中,实现话题通信只需要如下几步:
- 确定要发布的数据类型,一般都需要自定义.msg文件,修改好CMakeLists.txt文件和package.xml文件并重编译
- 编写发布方和订阅方的cpp文件,修改好CMakeLists.txt文件并重编译
- 分别启动发布方节点和订阅方节点,顺序无所谓
2.自定义发布数据
在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型。但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据, std_msgs 由于描述性较差而显得力不从心,这种场景下必须通过编写.msg文件来自定义消息类型。
2.1 std_msgs内置类型
- 内置类型与 C++ 和 Python 中的对应关系:
Primitive Type | C++ | Python |
---|---|---|
bool | uint8_t | bool |
int8 | int8_t | int |
uint8 | uint8_t | int |
int16 | int16_t | int |
uint16 | uint16_t | int |
int32 | uint32_t | int |
uint64 | uint64_t | long int |
float32 | float | float |
float64 | double | float |
string | std::string | str bytes |
time | ros::Time | rospy.Time |
duration | ros::Duration | rospy.Duration |
- 内置类型的数组与 C++ 和 Python 中的对应关系:
Primitive Type | C++ | Python |
---|---|---|
variable-length | std::vector | tuple |
fixed-length | boost::array<T, length> 或std::vector |
tuple |
2.2 编写.msg文件
示例如下:
#文件名Person.msg string name uint16 age float64 height
2.3 修改package.xml文件
- 查看是否存在如下编译依赖
<build_depend>message_generation</build_depend>
- 查看是否存在如下执行依赖
<exec_depend>message_generation</exec_depend>
2.3.1 完整的package.xml文件
<?xml version="1.0"?> <package format="2"> <name>chat</name> <version>0.0.0</version> <description>The chat package</description> <!-- One maintainer tag required, multiple allowed, one person per tag --> <!-- Example: --> <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> --> <maintainer email="xu736946693@todo.todo">xu736946693</maintainer> <!-- One license tag required, multiple allowed, one license per tag --> <!-- Commonly used license strings: --> <!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 --> <license>TODO</license> <!-- Url tags are optional, but multiple are allowed, one per tag --> <!-- Optional attribute type can be: website, bugtracker, or repository --> <!-- Example: --> <!-- <url type="website">http://wiki.ros.org/chat</url> --> <!-- Author tags are optional, multiple are allowed, one per tag --> <!-- Authors do not have to be maintainers, but could be --> <!-- Example: --> <!-- <author email="jane.doe@example.com">Jane Doe</author> --> <!-- The *depend tags are used to specify dependencies --> <!-- Dependencies can be catkin packages or system dependencies --> <!-- Examples: --> <!-- Use depend as a shortcut for packages that are both build and exec dependencies --> <!-- <depend>roscpp</depend> --> <!-- Note that this is equivalent to the following: --> <!-- <build_depend>roscpp</build_depend> --> <!-- <exec_depend>roscpp</exec_depend> --> <!-- Use build_depend for packages you need at compile time: --> <!-- <build_depend>message_generation</build_depend> --> <!-- Use build_export_depend for packages you need in order to build against this package: --> <!-- <build_export_depend>message_generation</build_export_depend> --> <!-- Use buildtool_depend for build tool packages: --> <!-- <buildtool_depend>catkin</buildtool_depend> --> <!-- Use exec_depend for packages you need at runtime: --> <!-- <exec_depend>message_runtime</exec_depend> --> <!-- Use test_depend for packages you need only for testing: --> <!-- <test_depend>gtest</test_depend> --> <!-- Use doc_depend for packages you need only for building documentation: --> <!-- <doc_depend>doxygen</doc_depend> --> <buildtool_depend>catkin</buildtool_depend> <build_depend>message_generation</build_depend> <build_depend>roscpp</build_depend> <build_depend>rospy</build_depend> <build_depend>std_msgs</build_depend> <build_export_depend>roscpp</build_export_depend> <build_export_depend>rospy</build_export_depend> <build_export_depend>std_msgs</build_export_depend> <exec_depend>message_generation</exec_depend> <exec_depend>roscpp</exec_depend> <exec_depend>rospy</exec_depend> <exec_depend>std_msgs</exec_depend> <!-- The export tag contains other, unspecified, tags --> <export> <!-- Other tools can request additional information be placed here --> </export> </package>
2.4 修改CMakeLists.txt文件
2.4.1 修改find_package指令
# 需要加入 message_generation,必须有 std_msgs find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation )
2.4.2 添加add_message_files指令
## 配置 msg 源文件 add_message_files( FILES Person.msg )
2.4.3 添加generate_messages指令
generate_messages( DEPENDENCIES std_msgs )
2.4.4 修改catkin_package指令
#执行时依赖 catkin_package( # INCLUDE_DIRS include # LIBRARIES demo02_talker_listener CATKIN_DEPENDS roscpp rospy std_msgs message_runtime # DEPENDS system_lib )
其中,add_message_files指令必须要在generate_messages指令的前面,然后在工作空间目录编译即可。
2.5 查看头文件
经过以上几步,在${workspace}/devel/include/${package}/
目录下应该会出现一个头文件,如图:
- 如果没有出现,是无法进行接下来的步骤的。这时,只需要把
${workspace}/
目录下的build目录和devel目录全部删除,然后重新编译即可。
rm -rf build/ rm -rf devel/ catkin_make
3.编写cpp文件
3.1 功能包目录文件树
3.2 修改CMakeLists.txt文件
3.2.1 添加add_executable指令
add_executable(publisher src/publisher.cpp) add_executable(listener src/listener.cpp)
3.2.2 添加add_dependencies指令
add_dependencies(publisher ${PROJECT_NAME}_generate_messages_cpp) add_dependencies(listener ${PROJECT_NAME}_generate_messages_cpp)
3.2.3 添加target_link_libraries指令
target_link_libraries(person_talker ${catkin_LIBRARIES} ) target_link_libraries(person_listener ${catkin_LIBRARIES} )
3.2.4 完整的CMakeLists.txt
- 其中很多语句都是catkin_make自动生成的
cmake_minimum_required(VERSION 3.0.2) project(chat) ## Compile as C++11, supported in ROS Kinetic and newer # add_compile_options(-std=c++11) ## Find catkin macros and libraries ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) ## is used, also find other catkin packages find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation ) ## System dependencies are found with CMake's conventions # find_package(Boost REQUIRED COMPONENTS system) ## Uncomment this if the package has a setup.py. This macro ensures ## modules and global scripts declared therein get installed ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html # catkin_python_setup() ################################################ ## Declare ROS messages, services and actions ## ################################################ ## To declare and build messages, services or actions from within this ## package, follow these steps: ## * Let MSG_DEP_SET be the set of packages whose message types you use in ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). ## * In the file package.xml: ## * add a build_depend tag for "message_generation" ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in ## but can be declared for certainty nonetheless: ## * add a exec_depend tag for "message_runtime" ## * In this file (CMakeLists.txt): ## * add "message_generation" and every package in MSG_DEP_SET to ## find_package(catkin REQUIRED COMPONENTS ...) ## * add "message_runtime" and every package in MSG_DEP_SET to ## catkin_package(CATKIN_DEPENDS ...) ## * uncomment the add_*_files sections below as needed ## and list every .msg/.srv/.action file to be processed ## * uncomment the generate_messages entry below ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) # Generate messages in the 'msg' folder add_message_files( FILES Person.msg ) ## Generate services in the 'srv' folder # add_service_files( # FILES # Service1.srv # Service2.srv # ) ## Generate actions in the 'action' folder # add_action_files( # FILES # Action1.action # Action2.action # ) ## Generate added messages and services with any dependencies listed here # 生成消息时依赖于 std_msgs generate_messages( DEPENDENCIES std_msgs ) ################################################ ## Declare ROS dynamic reconfigure parameters ## ################################################ ## To declare and build dynamic reconfigure parameters within this ## package, follow these steps: ## * In the file package.xml: ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" ## * In this file (CMakeLists.txt): ## * add "dynamic_reconfigure" to ## find_package(catkin REQUIRED COMPONENTS ...) ## * uncomment the "generate_dynamic_reconfigure_options" section below ## and list every .cfg file to be processed ## Generate dynamic reconfigure parameters in the 'cfg' folder # generate_dynamic_reconfigure_options( # cfg/DynReconf1.cfg # cfg/DynReconf2.cfg # ) ################################### ## catkin specific configuration ## ################################### ## The catkin_package macro generates cmake config files for your package ## Declare things to be passed to dependent projects ## INCLUDE_DIRS: uncomment this if your package contains header files ## LIBRARIES: libraries you create in this project that dependent projects also need ## CATKIN_DEPENDS: catkin_packages dependent projects also need ## DEPENDS: system dependencies of this project that dependent projects also need #执行时依赖 catkin_package( # INCLUDE_DIRS include # LIBRARIES demo02_talker_listener CATKIN_DEPENDS roscpp rospy std_msgs message_runtime # DEPENDS system_lib ) ########### ## Build ## ########### ## Specify additional locations of header files ## Your package locations should be listed before other locations include_directories( # include ${catkin_INCLUDE_DIRS} ) ## Declare a C++ library # add_library(${PROJECT_NAME} # src/${PROJECT_NAME}/pkg1.cpp # ) ## Add cmake target dependencies of the library ## as an example, code may need to be generated before libraries ## either from message generation or dynamic reconfigure # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) ## Declare a C++ executable ## With catkin_make all packages are built within a single CMake context ## The recommended prefix ensures that target names across packages don't collide # add_executable(${PROJECT_NAME}_node src/pkg1_node.cpp) add_executable(publisher src/publisher.cpp) add_executable(listener src/listener.cpp) ## Rename C++ executable without prefix ## The above recommended prefix causes long target names, the following renames the ## target back to the shorter version for ease of user use ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") ## Add cmake target dependencies of the executable ## same as for the library above # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) add_dependencies(publisher ${PROJECT_NAME}_generate_messages_cpp) add_dependencies(listener ${PROJECT_NAME}_generate_messages_cpp) ## Specify libraries to link a library or executable target against # target_link_libraries(${PROJECT_NAME}_node # ${catkin_LIBRARIES} # ) ############# ## Install ## ############# # all install targets should use catkin DESTINATION variables # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html ## Mark executable scripts (Python etc.) for installation ## in contrast to setup.py, you can choose the destination # catkin_install_python(PROGRAMS # scripts/my_python_script # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## Mark executables for installation ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html # install(TARGETS ${PROJECT_NAME}_node # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## Mark libraries for installation ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html # install(TARGETS ${PROJECT_NAME} # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} # ) ## Mark cpp header files for installation # install(DIRECTORY include/${PROJECT_NAME}/ # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} # FILES_MATCHING PATTERN "*.h" # PATTERN ".svn" EXCLUDE # ) ## Mark other files for installation (e.g. launch and bag files, etc.) # install(FILES # # myfile1 # # myfile2 # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} # ) ############# ## Testing ## ############# ## Add gtest based cpp test target and link libraries # catkin_add_gtest(${PROJECT_NAME}-test test/test_pkg1.cpp) # if(TARGET ${PROJECT_NAME}-test) # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) # endif() target_link_libraries(publisher ${catkin_LIBRARIES} ) target_link_libraries(listener ${catkin_LIBRARIES} ) ## Add folders to be run by python nosetests # catkin_add_nosetests(test)
3.3 发布方cpp
示例如下:
/* 需求: 实现基本的话题通信,一方发布数据,一方接收数据, 实现的关键点: 1.发送方 2.接收方 3.数据 PS: 二者需要设置相同的话题 消息发布方: 循环发布信息:HelloWorld 后缀数字编号 实现流程: 1.包含头文件 2.初始化 ROS 节点:命名(唯一) 3.实例化 ROS 句柄 4.实例化 发布者 对象 5.组织被发布的数据,并编写逻辑发布数据 */ // 1.包含头文件 #include "ros/ros.h" #include "chat/Person.h" int main(int argc, char *argv[]) { //设置编码 setlocale(LC_ALL,""); //2.初始化 ROS 节点:命名(唯一) // 参数1和参数2 后期为节点传值会使用 // 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一 ros::init(argc,argv,"talker"); //3.实例化 ROS 句柄 ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能 //4.实例化 发布者 对象 //泛型: 发布的消息类型 //参数1: 要发布到的话题 //参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁) ros::Publisher pub = nh.advertise<chat::Person>("chatter",10); //5.组织被发布的数据,并编写逻辑发布数据 //数据(动态组织) chat::Person p; p.name = "sunwukong"; p.age = 2000; p.height = 1.45; //逻辑(一秒1次) ros::Rate r(1); //节点不死 while (ros::ok()) { //发布消息 pub.publish(p); //加入调试,打印发送的消息 ROS_INFO("我叫:%s,今年%d岁,高%.2f米", p.name.c_str(), p.age, p.height);p.age++; //根据前面制定的发送贫频率自动休眠 休眠时间 = 1/频率; r.sleep(); //暂无应用 ros::spinOnce(); } return 0; }
3.4 订阅方cpp
示例如下:
/* 需求: 实现基本的话题通信,一方发布数据,一方接收数据, 实现的关键点: 1.发送方 2.接收方 3.数据 消息订阅方: 订阅话题并打印接收到的消息 实现流程: 1.包含头文件 2.初始化 ROS 节点:命名(唯一) 3.实例化 ROS 句柄 4.实例化 订阅者 对象 5.处理订阅的消息(回调函数) 6.设置循环调用回调函数 */ // 1.包含头文件 #include "ros/ros.h" #include "chat/Person.h" void doMsg(const chat::Person::ConstPtr& person_p){ ROS_INFO("订阅的人信息:%s, %d, %.2f", person_p->name.c_str(), person_p->age, person_p->height); } int main(int argc, char *argv[]) { //设置编码 setlocale(LC_ALL,""); //2.初始化 ROS 节点:命名(唯一) ros::init(argc,argv,"listener"); //3.实例化 ROS 句柄 ros::NodeHandle nh; //4.实例化 订阅者 对象 ros::Subscriber sub = nh.subscribe<chat::Person>("chatter",10,doMsg); //5.处理订阅的消息(回调函数) // 6.设置循环调用回调函数 ros::spin();//循环读取接收的数据,并调用回调函数处理 return 0; }
4.效果
- 如果找不到可执行文件,就把工作目录下的build文件夹和devel文件夹删了重新编译。
本文由博客一文多发平台 OpenWrite 发布!
这篇关于【ROS教程】话题通信的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-09-15Spring Boot项目开发教程:快速入门与实战指南
- 2024-09-15单点登录实战:入门级指南与实操详解
- 2024-09-15登录校验实战:从零构建安全登录系统
- 2024-09-15Java知识库系统学习:从零开始的编程之旅
- 2024-09-15JAVA知识库系统学习:从零基础到入门的全面指南
- 2024-09-15Java主流技术学习:从入门到进阶的实用指南
- 2024-09-15JAVA主流技术学习:从入门到提升
- 2024-09-15Java主流技术学习:从入门到上手的实践指南
- 2024-09-15实战编程技巧:从基础概念到实际应用
- 2024-09-15掌握JAVA主流框架学习:从入门到实践