一.学习内容
本节课主要讲了一下内容:
1.ROS的topic通信模式
2.ROS的service通信模式
3. 关于CMakeList.txt
二.学习讲义
三.学习笔记
1. ROS的topic通信模式
A. 这里我们自己写了一个message数据类型foo,catkin_make后生成的foo.h在目录/devel/include/turtle_move中可以看到。另外在下面源码move_subscriber.cpp的回调函数中我们看到msgs是作为shared pointers(共享指针)传递的,并且它使用到了boost库。如图:
这里用到了C++的const变量,函数模板及shared pointer,大家需要了解下。关于boost标准库,可能很多自称熟悉C++的人甚至都不知道这个,这里推荐罗剑锋的《Boost程序库完全开发指南》。这里贴几页关于msgs共享指针处C++原理PPT:
B. 关于日志消息的宏ROS_INFO在下面源码注解中已注明可参考《机器人操作系统(ROS)浅析》的第4章,这是说明下这里ROS_INFO使用了C++中的定义函数宏功能,这里讲的挺好:https://onevcat.com/2014/01/black-magic-in-macro/
2. ROS的service通信模式
service跟topic是比较类似的,关于topic和service这两部分可分别参考《机器人操作系统(ROS)浅析》的第3章和第8章,书上讲的更仔细些。还是建议大家碰到一些函数的时候多点进去看一看。
3. CMakeList.txt这一块其实我也不是特别懂,对编译底层一直不太了解。
四.相关源码
1. package目录树:
turtle_move
--include
--src
--move_publisher.cpp
--move_subscriber.cpp
--timer.cpp
--msg
--foo.msg
--CMakeLists.txt
--package.xml
源码:
foo.msg:
int16 foo
move_publisher.cpp:
#include
#include
int main(int argc, char** argv)
{
ros::init(argc, argv, "move_publisher");
ros::NodeHandle n;
ros::Publisher pub=n.advertise("turtle1/cmd_vel", 1000);
geometry_msgs::Twist tw;
tw.angular.x=0;
tw.angular.y=0;
tw.angular.z=2;
tw.linear.x=2;
tw.linear.y=0;
tw.linear.z=0;
ros::Rate rate(10);
while(ros::ok()) {
pub.publish(tw);
ros::spinOnce();
rate.sleep();
}
return 0;
}
move_subscriber.cpp:
#include<ros/ros.h>
#include<turtle_move/foo.h>
void callback(const turtle_move::foo::ConstPtr msg){ //回调函数,参数类型为一个消息的共享指针
ROS_INFO("foo is [%d]", msg->foo); //这里生成一条消息并发送到控制台窗口,关于“消息”详见书籍《机器人操作系统(ROS)浅析》第4章 日志消息
}
int main(int argc, char** argv){
ros::init(argc, argv, "move_subscriber"); //初始化ROS客户端,节点默认名"move_subscriber"
ros::NodeHandle n; //创建节点句柄的对象,创建此对象会将你的程序注册为ROS节点管理器的节点
ros::Subscriber sub=n.subscribe("foo_topic", 100, callback);
//创建订阅者对象,最后一个参数指定了回调函数的地址(函数指针)
ros::Publisher pub=n.advertise<turtle_move::foo>("foo_topic", 100);
//发送消息的实际工作是由类名为ros::Publisher的一个对象完成的;ros::NodeHandle.advertise()为一个函数模板
//如果你想从一个节点发布关于多个话题的消息,你需要为每个话题创建一个独立的ros::Publisher对象
turtle_move::foo foo; //创建消息对象本身,并赋值
foo.foo=1;
ros::Rate rate(10); //以赫兹为单位来控制消息发布频率
while(ros::ok()){ //ros::ok()用于检查节点是否停止工作
pub.publish(foo); //发布消息
ros::spinOnce();
//调用此方法要求ROS去执行所有挂起的回调函数,然后然后把控制权交给我们,如果忽略ros::spinOnce会使程序表现的好像没有接收到任何消息。关于ros::spin()和ros::spinOnce()的区别详见书籍《机器人操作系统(ROS)浅析》P70
foo.foo++;
rate.sleep(); //调用此方法来阻止循环的迭代速率超过指定的速率
}
return 0;
}
timer.cpp:
#include<ros/ros.h>
void callback(const ros::TimerEvent &){
ROS_INFO("one sec passed");
}
int main(int argc, char** argv){
ros::init(argc, argv, "timer");
ros::NodeHandle n;
ros::Timer time=n.createTimer(ros::Duration(1), callback);
ros::spin();
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.3)
project(turtle_move)
## 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
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 run_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 run_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
# Message1.msg
# Message2.msg
foo.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
generate_messages(
DEPENDENCIES
std_msgs # Or other packages containing 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 run_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 you 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 turtle_move
# CATKIN_DEPENDS roscpp rospy
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
# include_directories(include)
include_directories(
${catkin_INCLUDE_DIRS}
)
## Declare a C++ library
# add_library(turtle_move
# src/${PROJECT_NAME}/turtle_move.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(turtle_move ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Declare a C++ executable
add_executable(move_publisher src/move_publisher.cpp)
add_executable(move_subscriber src/move_subscriber.cpp)
add_executable(timer src/timer.cpp)
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(turtle_move_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
target_link_libraries(move_publisher
${catkin_LIBRARIES}
)
target_link_libraries(move_subscriber
${catkin_LIBRARIES}
)
target_link_libraries(timer
${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
# install(PROGRAMS
# scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark executables and/or libraries for installation
# install(TARGETS turtle_move turtle_move_node
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# RUNTIME DESTINATION ${CATKIN_PACKAGE_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_turtle_move.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
package.xml:
<package>
<name>turtle_movename>
<version>0.0.0version>
<description>The turtle_move packagedescription>
<maintainer email="[email protected]">aicrobomaintainer>
<license>TODOlicense>
<buildtool_depend>catkinbuildtool_depend>
<build_depend>roscppbuild_depend>
<build_depend>message_generationbuild_depend>
<build_depend>rospybuild_depend>
<run_depend>roscpprun_depend>
<run_depend>rospyrun_depend>
<run_depend>message_runtimerun_depend>
<run_depend>message_generationrun_depend>
<export>
export>
package>
2.package目录树:
addturtle
--include
--src
--addturtle.cpp
--CMakeLists.txt
--package.xml
源码:
addturtle.cpp:
#include
#include //声明请求和响应的类型,每一种服务/话题 数据类型都对应一个我们必须包含的相关头文件
#include
int main(int argc, char** argv)
{
ros::init(argc, argv, "addturtle");
ros::NodeHandle n;
ros::ServiceClient client=n.serviceClient("spawn"); //创建客户端对象,由这个对象完成服务端调用
if(argc!=5) {
ROS_INFO("usage: name theta x y");
return 1;
}
turtlesim::Spawn spawn; //创建一个请求和响应的对象
spawn.request.name=argv[1];
spawn.request.theta=atoll(argv[2]);
spawn.request.x=atoll(argv[3]);
spawn.request.y=atoll(argv[4]);
if(client.call(spawn)){ //调用服务
ROS_INFO_STREAM("success, spawned a turtle named " << spawn.response.name);
}
else{
ROS_ERROR("FAILED TO ADD A TURTLE");
return 1;
}
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.3)
project(addturtle)
## 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
)
## 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 run_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 run_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
# Message1.msg
# Message2.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
# generate_messages(
# DEPENDENCIES
# std_msgs # Or other packages containing 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 run_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 you 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 addturtle
# CATKIN_DEPENDS roscpp rospy
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
# include_directories(include)
include_directories(
${catkin_INCLUDE_DIRS}
)
## Declare a C++ library
# add_library(addturtle
# src/${PROJECT_NAME}/addturtle.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(addturtle ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Declare a C++ executable
add_executable(addturtle src/addturtle.cpp)
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(addturtle_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
target_link_libraries(addturtle
${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
# install(PROGRAMS
# scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark executables and/or libraries for installation
# install(TARGETS addturtle addturtle_node
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# RUNTIME DESTINATION ${CATKIN_PACKAGE_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_addturtle.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
package.xml:
<package>
<name>addturtlename>
<version>0.0.0version>
<description>The addturtle packagedescription>
<maintainer email="[email protected]">aicrobomaintainer>
<license>TODOlicense>
<buildtool_depend>catkinbuildtool_depend>
<build_depend>roscppbuild_depend>
<build_depend>rospybuild_depend>
<run_depend>roscpprun_depend>
<run_depend>rospyrun_depend>
<export>
export>
package>