ROS(一)Topic 通信
ROS系统起源于2007年斯坦福大学人工智能实验室的项目与机器人技术公司Willow Garage的个人机器人项目(Personal Robots Program)之间的合作,2008年之后就由Willow Garage来进行推动。
ROS是开源的,是用于机器人的一种后操作系统,或者说次级操作系统。它提供类似操作系统所提供的功能,包含硬件抽象描述、底层驱动程序管理、共用功能的执行、程序间的消息传递、程序发行包管理,它也提供一些工具程序和库用于获取、建立、编写和运行多机整合的程序。
了解ROS的几个概念:
1. 功能包(Package):相当于一个C++工程,包含程序文件,编译描述文件,配置文件等。
2. 功能包集(Stack):实现某种功能的多个功能包集合,例如导航功能包,是ROS软件发布的主要形式。
3. 节点(Node):可执行文件。位于功能包中,实现功能的最小单位,.cpp 和.py文件转换为可执行文件后才可以变为node。
4. 主题(Topic)和服务(Service):节点间通信的两种方式。主题实现节点之间的单向通信,服务包括请求(Request)和响应(Response)的双向通信。
5. 消息(Msg):节点之间通信的内容,相当于C语言中的结构体。
安装ROS,不赘述,参考官方网站,目前主流使用的是Ubuntu14.04+ROS indigo版本。
ROS会有自己的功能包命令,类似于bash命令,常用的有
rospack roscd rosls catkin_create_pkg catkin_make roscore rosrun rosnode rosmsg/rossrv rostopic/rosservice rosparam roslaunch rosbag
具体的操作参考官方文档,这里主要使用catkin创建一个简单的主题发布订阅的功能包。节点之间的通信关系如下图所示:
目前ROS的官方编译系统是catkin,功能包分配更加合理,支持交叉编译,可移植性好。
mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src catkin_init_workspace cd ~/catkin_ws // 空的工程也可以编译 catkin_make // 更新环境变量,将当前工作空间加入$ROS_PACKAGE_PATH source devel/setup.bash catkin_create_pkg my_topic_test std_msgs roscpp rospy // 打开my_topic_test功能包,重要的是编译描述文件CMakeLists.txt和配置文件package.xml // 创建完功能包后,需要编译该功能包,可以编译整个空间中的功能包,也可以只编译指定的功能包 cd ~/catkin_ws catkin_make // catkin_make --pkg my_topic_test
具体实现node在src目录下,新建两个文件分别为talker.cpp, listener.cpp。注意最后需要修改CMakeLists.txt文件。
// publisher: talker #include "ros/ros.h" #include "std_msgs/String.h" #include <sstream> int main(int argc, char** argv) { ros::init(argc, argv, "talker"); ros::NodeHandle n; ros::Publisher my_pub = n.advertise<std_msgs::String>("my_topic", 100); ros::Rate loop_rate(1); int cnt = 1; std_msgs::String msg; while(ros::ok()) { std::stringstream ss; if((cnt%2)==0) ss << "false " << cnt; else ss << "true"; msg.data = ss.str(); ROS_INFO("%s", msg.data.c_str()); my_pub.publish(msg); loop_rate.sleep(); cnt = cnt + 1; } return 0; }
// subscriber: listener #include "ros/ros.h" #include "std_msgs/String.h" void MyTopicCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char** argv) { ros::init(argc, argv, "listener"); ros::NodeHandle n; ros::Subscriber my_sub = n.subscribe("my_topic", 100, MyTopicCallback); ros::spin(); return 0; }
由于我们没有使用自己定义的消息类型,所以package.xml文件不需要更改,CMakeLists.txt文件也比较简单:
cmake_minimum_required(VERSION 2.8.3) project(my_topic_test) ## Find catkin and any catkin packages find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg) ### Declare ROS messages and services #add_message_files(FILES xx.msg) #add_service_files(FILES xx.srv) ## Generate added messages and services generate_messages(DEPENDENCIES std_msgs) ## Declare a catkin package catkin_package() ## Build talker and listener include_directories(include ${catkin_INCLUDE_DIRS}) 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)
注意
其中find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)和include_directories(include ${catkin_INCLUDE_DIRS})的顺序不能改变。不然会找不到ros系统的头文件。
重新编译功能包后,验证结果
roscore
rosrun my_topic_test talker
rosrun my_topic_test listener
发布节点talker向主题my_topic发送消息,同时订阅my_topic主题的节点接收到消息