摘要
ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便。我们的机器人“miiboo”中的大部分程序也采用ROS进行开发,所以本文就重点对ROS基础知识进行详细的讲解,给不熟悉ROS的朋友起到一个抛砖引玉的作用。本章节主要内容: 1.ROS是什么 2.ROS系统整体架构 3.在ubuntu16.04中安装ROS kinetic 4.如何编写ROS的第一个程序hello_world 5.编写简单的消息发布器和订阅器 6.编写简单的service和client 7.理解tf的原理 8.理解roslaunch在大型项目中的作用 9.熟练使用rviz 10.在实际机器人上运行ROS高级功能预览
4.如何编写ROS的第一个程序hello_world
既然ROS已经成功安装好了,大家一定很想亲自动动手编一个通过起手式例程hello_world,可以学到工作空间的创建、功能包的创建、功能包的源代码编写、功能包的编译配置、功能包的编译、功能包的启动运行等知识。ROS的小程序试试手,没错,这一节就隆重请出程序界的起手式例程hello_world。
通过起手式例程hello_world,可以学到工作空间的创建、功能包的创建、功能包的源代码编写、功能包的编译配置、功能包的编译、功能包的启动运行等知识。
(1)工作空间的创建
打开命令行终端,分别输入如下命令:
#先切回主目录
cd ~/
#新建工作空间文件夹
mkdir catkin_ws
#在catkin_ws目录下新建src文件夹
cd catkin_ws
mkdir src
#初始化src目录,生成的CMakeLists.txt为功能包编译配置
cd src
catkin_init_workspace
#切回catkin_ws目录,对该工作空间执行一次编译
cd ~/catkin_ws
catkin_make
#环境变量配置,使新建的catkin_ws工作空间可用
source devel/setup.bash
这时,便已经创建好了一个ROS的工作空间了,接下来就是在catkin_ws工作空间下的src目录下新建功能包并进行功能包程序编写了,如果想了解工作空间的详细目录结构,请参考本章节(二)ROS入门——2.ROS系统整体架构这有对ROS的文件组织结构进行详解。
(2)功能包的创建
继续在命令行终端中,输入如下命令:
#在catkin_ws/src/下创建取名为hello_world的功能包,
#ROS功能包命名规范:只允许使用小写字母、数字和下划线,
#且首字符必须为一个小写字母。
cd ~/catkin_ws/src/
catkin_create_pkg hello_world
这时候在~/catkin_ws/src/目录下能看到一个叫hello_world的文件夹,文件夹名称就是功能包的名称以及功能包的唯一标识符,这个说明功能包创建成功了。
(3)功能包的源代码编写
由于我们只是要编写一个能打印“hello world”的程序,所以就很简单了,这里先以c++代码作为示范,后面会讲解python的。一些在线教程建议在你的功能包目录中创建src目录用来存放c++源文件,这个附加的组织结构是很有益处的,特别是对含有很多种类型文件的大型功能包,不过不是严格必要的。出于编程规范,我这里也会采用这样的建议把c++源文件放在功能包中的src目录下。 所以,首先在hello_world目录下新建src目录,再在新建的src目录下新建一个my_hello_world_node.cpp文件。这里的新建目录和文件的方法可以在图形界面下直接操作会更方便一点,如图11。
(图11)在功能包中新建文件夹及文件
用文本编辑器gedit打开my_hello_world_node.cpp文件,并输入如下内容。
#include “ros/ros.h”
int main(int argc,char **argv)
{
ros::init(argc,argv,"hello_node");
ros::NodeHandle nh;
ROS_INFO_STREAM("hello world!!!");
}
这里对代码做一个解析:
#include “ros/ros.h”
这一句是包含头文件ros/ros.h,这是ROS提供的C++客户端库,是必须包含的头文件,在后面的编译配置中要添加相应的依赖库roscpp。
ros::init(argc,argv,"hello_node");
这一句是初始化ros节点并指明节点的名称,这里给节点取名为hello_node,一旦程序运行后就可以在ros的计算图中被注册为hello_node名称标识的节点。
ros::NodeHandle nh;
这一句是声明一个ros节点的句柄,初始化ros节点必须的。
ROS_INFO_STREAM("hello world!!!");
这一句是调用了roscpp库提供的方法ROS_INFO_STREAM来打印信息,这里打印字符串”hello world!!!”。
(4)功能包的编译配置
声明依赖库:
对于我们的my_hello_world_node.cpp程序来说,我们包含了<ros/ros.h>这个库,因此我们需要添加名为roscpp的依赖库。
首先,用文本编辑器gedit打开功能包目录下的CMakeLists.txt文件,在find_package(catkin REQUIRED …)字段中添加roscpp,添加后的字段如下:
find_package(catkin REQUIRED COMPONENTS roscpp)
同时,找到include_directories(…)字段,去掉${catkin_INCLUDE_DIRS}前面的注释,如下:
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
(图12)在CMakeLists.txt中添加roscpp依赖库
然后,用文本编辑器gedit打开功能包目录下的package.xml文件,找到这样一句话<buildtool_depend>catkin</buildtool_depend>,在这句话的下面添加如下内容:
<build_depend>roscpp</build_depend>
<build_export_depend>roscpp</build_export_depend>
<exec_depend>roscpp</exec_depend>
(图13)在package.xml中添加roscpp依赖库
声明可执行文件:
就接下来,我们需要在CMakeLists.txt中添加两句,我的习惯在文件最后一行添加就好了,来声明我们需要创建的可执行文件。
add_executable(my_hello_world_node src/my_hello_world_node.cpp)
target_link_libraries(my_hello_world_node ${catkin_LIBRARIES})
第一行声明了我们想要的可执行文件的文件名,以及生成此可执行文件所需的源文件列表。如果你有多个源文件,把它们列在此处,并用空格将其区分开。
第二行告诉 Cmake 当链接此可执行文件时需要链接哪些库(在上面的 find_package 中定义)。如果你的包中包括多个可执行文件,为每一个可执行文件复制和修改上述两行代码。
添加好后的效果如图14所示。
(图14)在CMakeLists.txt声明可执行文件
(5)功能包的编译
功能包的编译配置好后,就可以开始编译了,这里有两种编译方式,一种是编译工作空间内的所有功能包,另一种是编译工作空间内的指定功能包,两种编译方式各有用处,下面分别讲解。
第一种,编译工作空间内的所有功能包:
cd ~/catkin_ws/
catkin_make
第二种,编译工作空间内的指定功能包:
其实就是加入参数 -DCATKIN_WHITELIST_PACKAGES=””,在双引号中填入需要编译的功能包名字,用空格分割。
cd ~/catkin_ws/
catkin_make -DCATKIN_WHITELIST_PACKAGES="hello_world"
(6)功能包的启动运行
首先,需要用roscore命令来启动ROS节点管理器,ROS节点管理器是所有节点运行的基础。
打开命令行终端,输入命令:
roscore
然后,用source devel/setup.bash激活catkin_ws工作空间,用rosrun <package_name> <node_name>启动功能包中的节点。
再打开一个命令行终端,分别输入命令:
cd ~/catkin_ws/
source devel/setup.bash
rosrun hello_world my_hello_world_node
看到有输出hello world!!!就说明程序已经正常执行了,按照我们的设计程序正常打印后会自动结束,如图15。
(图15)hello_world功能包中my_hello_world_node节点执行结果
到这里,恭喜你已经学会了ROS的第一个程序hello world!!!