ROS入门:搭建环境与测试
本文记录了在Ubuntu18.04.5 LTS
操作系统下安装ROS Melodic
的过程,并编写了一个简单的demo用于测试。
安装及环境配置
ROS
中的基础知识,在此处不再赘述。若有需要可以学习中国大学mooc上的课程机器人操作系统入门。
配置软件源并安装ROS
首先在系统的软件和更新中,将软件源更换成阿里云、清华源等国内源以加速下载,并勾选上main
universe
multiuniverse
restricted
的选项,以允许下载所有软件。
添加ros
的软件源。为了加快速度这里选择了清华大学提供的镜像源。
$ sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/ros-latest.list'
添加秘钥。如果速度慢或者连接不上可以换用教育网或者魔法上网。
$ sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
刷新软件源列表:
$ sudo apt update
接下来,就可以安装ros
了。ros
分为三个版本,分别为desktop-full
desktop
base
。其中,desktop-full
为桌面版本,除了ros
rqt
rviz
等基础组件之外,还包含了 gazebo
等附加应用;desktop
也为桌面版本,但只包含了基础组件;而base
则只包含了最基本的命令行工具,并没有GUI支持。本文以完整版为例,你也可以根据自己的需要,选择下面3条指令中的一条指令进行安装。
# 以下指令根据需要三选一即可
$ sudo apt install ros-melodic-desktop-full
$ sudo apt install ros-melodic-desktop
$ sudo apt install ros-melodic-ros-base
下载及安装过程比较漫长,可以泡杯咖啡休息一下。若下载过程中出现连接失败,不要慌张,首先检查你是否在使用国内的软件源,确认所使用的软件源正确后,重新运行一遍安装指令即可补齐下载失败的包,并成功安装。
ros
并未将自身安装到类似/usr/bin
这类系统path路径下,而是安装到了/opt/ros
下。因此,直接运行是无法找到可执行文件的。好在,ros
自身提供了环境配置文件,我们只需要使用这个配置文件激活ros
运行环境就可以了。不过,每次打开终端都要激活环境显得有些繁琐。因此,我们将激活ros
运行环境的指令添加到bash
的启动脚本中,这样就不需要每次都手动激活了。执行完上述部分之后,可以重启终端使其生效,或运行source
指令手动激活。
$ echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
环境配置
首先,我们需要安装ros-dep
,这是ros
用于管理包依赖的工具,但是没有跟随主程序一同安装。安装方法非常简单,直接使用Linux的包管理器进行安装即可。
$ sudo apt-get install python-rosdep
接下来初始化ros-dep
。若执行的时候出现错误,多半原因是因为网络问题,请自行魔法上网解决。
$ sudo rosdep init
$ rosdep update
运行测试
最后,我们运行ros自带的小乌龟模拟器turtlesim
来测试ros
是否能够正常运行。分别打开3个终端窗口,分别在其中运行ros
核心、turtlesim
的界面以及控制器程序。
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun turtlesim turtle_teleop_key
然后,在执行最后一条命令的控制终端窗口中,使用方向键,即可控制小乌龟的移动。
对于turtlesim
所使用的topic
及msg
,可以在turtlesim_node
运行的时候使用如下指令进行查询。
$ rostopic list | grep turtle
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
从turtlesim
官方文档中可以看到,turtlesim_node
订阅了turtleX/cmd_vel
这个topic
,其中的msg
名称为geometry_msgs/Twist
,定义为
# This expresses velocity in free space broken into its linear and angular parts.
Vector3 linear
Vector3 angular
即geometry_msgs/Twist
包含两个数据,分别为线速度以及角速度的3维向量数据。我们可以使用rqt
工具对上述msg
进行测试。
在命令行中运行rqt
指令,打开rqt
窗口,点击上方菜单栏的Plugins
->Topics
->Message Publisher
打开消息发送工具。选择好对应的Topic
以及Type
并点击右侧绿色的加号将其添加进下方列表中;接着在其中的liner
->x
中输入数值1,并打钩Topic
前方的复选框,即可看到小乌龟向前方以设定的速度1
向前移动。liner
->y
则可以控制小乌龟的水平移动,angular
->z
可以控制小乌龟的旋转。
除此之外,还可以使用/reset
这个Service
来使小乌龟复位。值得一提的是,每次复位之后小乌龟的样子都会改变。
使用rqt_graph
指令,还可以绘制ros
当前节点的图形。
Demo编写
本文将基于ros
以及turtlesim
,编写一个demo程序,使用键盘来控制小乌龟的移动,实现与上一节中官方示例相同的效果。值得注意的是,对于文件的编辑操作,可以使用Visual Studio Code
来完成,只需要使用VSC
打开package
所在的目录,即可对工程内的所有文件进行方便地编辑。若安装了ROS
插件,则更可以直接在VSC
内对工程进行编译,可以大大提高开发效率。
每个catkin
工程都是一个workspace
,一个workspace
之中可以含有多个package
,同时一个package
可以包含多个node
,每个node
均是一个可执行文件,是ros
软件的最基本单位,在node
中可以对message
进行订阅与发布,同时提供service
或调用service
。
工程搭建
我们将此次创建的demo所在的工作空间命名为turtlesim_demo
。catkin
要求一个合格的工作空间目录下必须要包含src
目录,因此我们一并创建该目录。
$ mkdir ~/code/turtlesim_demo/src -p
接下来,我们使用catkin
来初始化该工作空间。
$ cd ~/code/turtlesim_demo
$ catkin_make
然后,我们需要创建一个package
。创建package
的命令如下。
catkin_create_pkg <pkg_name> [deps]
在此,我们创建一个package
,用于存放控制turtlesim
的代码。这里我们先不并添加依赖,而是在后面手动进行添加。
$ cd ~/code/turtlesim_demo/src
$ catkin_create_pkg turtlesim_demo
这样,我们就创建好了一个package。接下来,我们根据1.3
小节中对turtlesim
所订阅的topic
的分析,创建一个可以被turtlesim
所识别的消息。
$ cd ~/code/turtle_demo/src/turtlesim_demo
$ mkdir msg
$ cd msg
$ nano turtle.msg
因为本demo没有使用自定义的message
格式,只使用了ros
自带的基本message
,因此message
的编写在此处可以暂时略过。
然后,创建demo程序的源文件。
$ cd ~/code/turtle_demo/src/turtlesim_demo/src
$ touch demo.cpp
创建好源文件之后,我们暂时不编辑其中的内容,而是先编辑turtlesim_demo
节点的CMakeLists.txt
文件,用以描述我们的package
与node
。
$ nano ~/code/turtle_demo/src/turtlesim_demo/CMakeLists.txt
如下是去除注释后的CMakeLists.txt
文件。其中,find_package
宏与catkin_package
宏的区别在于,前者是针对本项目自身需要而声明依赖,而后者则是针对依赖本项目的其他项目声明其所需要的额外依赖。对文件的修改,重点在于增加对项目依赖项的添加以及对可执行文件的声明。在find_package
宏中,roscpp
用来添加对ROS Client Library
的支持,std_msgs
用来支持标准Message
。除此之外,还增加了geometry_msgs
包,用来增加turtlesim
所使用的geometry_msgs/Twist
消息类型。
由于本demo只使用了turtlesim
中的数据类型,并未自己编写消息或调用系统基本的消息类型,因此并未使用到message_generation
与std_msgs
包,用来根据 .msg
文件生成头文件或添加系统基本的消息类型。实际上,这二者是非常常见的依赖包,只要是略复杂的项目应该都会使用到它们,因此本工程也包含了它们。
cmake_minimum_required(VERSION 3.0.2) # 所依赖的最低cmake版本 由系统自动生成
project(turtlesim_demo) # 工程名
find_package(catkin REQUIRED COMPONENTS # 加载catkin宏和指定对其他ROS功能包的依赖关系
roscpp # 使用cpp进行ros编程所必须的Client Library
std_msgs # 基础消息库 包含了string int等类型
std_srvs # 基础服务库 包含了/reset等服务
message_generation # 由.msg文件编译生成.h文件所必须的库
geometry_msgs # 其中包含了turtlesim所使用的vector消息类型
)
## add_message_files(FILES mymsg.msg) # 如果需要添加自己编写的msg 请在此处添加位于msg目录中的文件
## generate_messages(DEPENDENCIES geometry_msgs) # 根据geometry_msgs生成对应的.h文件 这里由于是系统自带的message因此不用手动生成
catkin_package( # 声明要传递给依赖本项目的其他功能包的内容
CATKIN_DEPENDS roscpp std_msgs std_srvs geometry_msgs # 告知其他功能包依赖本项目所需要的依赖
)
include_directories( # 项目include目录
include ${catkin_INCLUDE_DIRS}
)
add_executable(${PROJECT_NAME} src/turtlesim_demo.cpp) # 根据源文件生成node可执行文件 第一个参数为可执行文件名 第二个参数为源文件路径
add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) # 向可执行文件添加依赖库 本质是将前面的find_package与catkin_package宏所添加的依赖添加到可执行文件中
target_link_libraries(${PROJECT_NAME} # 向可执行文件添加链接库
${catkin_LIBRARIES}
)
然后,我们编辑package.xml
文件中的内容。package.xml
文件中主要描述了包的基本信息以及其编译依赖、运行依赖和其他包依赖本包时所需的依赖。
首先,我们需要去除其中<build_depend>message_generation</build_depend>
行和<exec_depend>message_runtime</exec_depend>
行的注释,然后在最后添加对geometry_msgs
的依赖,使其与CMakeLists.txt
相对应。完整的package.xml
文件如下。
<?xml version="1.0"?>
<package format="2">
<!-- 包名 版本 作者 协议等基本信息 -->
<name>turtlesim_demo</name>
<version>0.1.0</version>
<description>The turtlesim_demo package</description>
<maintainer email="wangyz1997@126.com">wangyz</maintainer>
<license>BSD</license>
<!-- catkin是编译所必须的 -->
<buildtool_depend>catkin</buildtool_depend>
<!-- 此处应该与find_package中的包相同 -->
<build_depend>roscpp</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>std_srvs</build_depend>
<build_depend>geometry_msgs</build_depend>
<build_depend>message_generation</build_depend>
<!-- 此处应该与catkin_package中的包相同 -->
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<build_export_depend>std_srvs</build_export_depend>
<build_export_depend>message_runtime</build_export_depend>
<!-- 此处应该为以上两段依赖的并集 -->
<exec_depend>roscpp</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>std_srvs</exec_depend>
<exec_depend>geometry_msgs</exec_depend>
<exec_depend>message_runtime</exec_depend>
<export> </export>
</package>
源码编写
编写src/turtlesim_demo.cpp
文件,对程序的具体描述均在注释中。
#include <ros/ros.h> // 所有ros app都依赖此头文件
#include <geometry_msgs/Twist.h> //包含了Twist消息的定义
#include <std_srvs/Empty.h> //包含了没有参数的服务基本类
int main(int argc, char** argv) {
ros::init(argc, argv, "turtle_demo"); //初始化Client Library 并给出当前node的名字
ros::NodeHandle node_h; //实例化node
geometry_msgs::Twist msg; //创建一个Twist类message对象
std_srvs::Empty reset_srv; //创建一个Empty类service对象
ros::Publisher pub = node_h.advertise<geometry_msgs::Twist>("turtle1/cmd_vel", 1); //创建发布message的发布者
ros::ServiceClient client = node_h.serviceClient<std_srvs::Empty>("/reset"); //创建调用service的client
ros::Rate loop_rate(1.0); //ros自带的tick功能
client.call(reset_srv); //调用/reset 复位乌龟位置
while(ros::ok()) { //主循环 当roscore被关闭或Ctrl+C中断等发生时 会跳出主循环
msg.linear.x = 1.0; //向前的速度
msg.linear.y = 0.0;
msg.angular.z = 1.0; //让小乌龟逆时针做半径为1的圆周运动
pub.publish(msg); //发布消息
loop_rate.sleep(); //tick 延时
}
return 0;
}
此时,我们可以查看整个工程的目录结构。
wangyz@ubuntu-vm:~/code/turtle_demo$ tree
.
├── build
├── devel
└── src
└── turtlesim_demo
├── build
├── include
│ └── turtlesim_demo
├── src
│ └── turtlesim_demo.cpp
├── CMakeLists.txt
└── package.xml
编写好源代码之后,我们可以试着对工程进行编译。
$ cd ~/code/turtle_demo
$ catkin_make
...
[100%] Built target turtlesim_demo
此时,工程应该已经可以被正常编译了。别忘了在终端中激活catkin
的workspace
。
$ roscore
$ rosrun turtlesim turtlesim_node
$ source ~/code/turtle_demo/devel/setup.bash # 激活workspace
$ rosrun turtlesim_demo turtlesim_demo
一切顺利的话,你应该能看到小乌龟在逆时针转圈了!
OpenPose工程编写
$ pwd
/home/wangyz/code/robotics_project
$ catkin_create_pkg openpose_gesture_controller roscpp std_msgs std_srvs geometry_msgs message_generation message_runtime