1、工作空间
类似的,在ROS机器人开发中,我们针对机器人某些功能进行代码开始时,各种编写的代码、参数、脚本等文件,也需要放置在某一个文件夹里进行管理,这个文件夹在ROS系统中就叫做工作空间。
所以工作空间是一个存放项目开发相关文件的文件夹,也是开发过程中存放所有资料的大本营。
ROS系统中一个典型的工作空间结构如图所示,这个dev_ws就是工作空间的根目录,里边会有四个子目录,或者叫做四个子空间。
- src,代码空间,未来编写的代码、脚本,都需要人为的放置到这里;
- build,编译空间,保存编译过程中产生的中间文件;
- install,安装空间,放置编译得到的可执行文件和脚本;
- log,日志空间,编译和运行过程中,保存各种警告、错误、信息等日志。
总体来讲,这四个空间的文件夹,我们绝大部分操作都是在src中进行的,编译成功后,就会执行install里边的结果,build和log两个文件夹用的很少。
创建工作空间
了解了工作空间的概念和结果,接下来我们可以使用如下命令创建一个工作空间,并且下载教程的代码:
1 | $ mkdir -p ~/dev_ws/src |
自动安装依赖
我们从社区中下载的各种代码,多少都会有一些依赖,我们可以手动一个一个安装,也可以使用rosdep工具自动安装:
1 | $ sudo apt install -y python3-pip |
编译工作空间
依赖安装完成后,就可以使用如下命令编译工作空间啦,如果有缺少的依赖,或者代码有错误,编译过程中会有报错,否则编译过程应该不会出现任何错误:
1 | $ sudo apt install python3-colcon-ros |
编译成功后,就可以在工作空间中看到自动生产的build、log、install文件夹了。
创建功能包
如何在ROS2中创建一个功能包呢?我们可以使用这个指令:
1 | $ ros2 pkg create --build-type <build-type> <package_name> |
ros2命令中:
- pkg:表示功能包相关的功能;
- create:表示创建功能包;
- build-type:表示新创建的功能包是C还是Python的,如果使用C或者C,那这里就跟ament_cmake,如果使用Python,就跟ament_python;
- package_name:新建功能包的名字。
比如在终端中分别创建C++和Python版本的功能包:
1 | $ cd ~/dev_ws/src |
编译功能包
在创建好的功能包中,我们可以继续完成代码的编写,之后需要编译和配置环境变量,才能正常运行:
1 | $ cd ~/dev_ws |
功能包的结构
功能包并不是普通的文件夹,那如何判断一个文件夹是否是功能包呢?我们来分析下刚才新创建两个功能包的结构。
C++功能包
首先看下C++类型的功能包,其中必然存在两个文件:package.xml和CMakerLists.txt。
package.xml文件的主要内容如下,包含功能包的版权描述,和各种依赖的声明。
CMakeLists.txt文件是编译规则,C++代码需要编译才能运行,所以必须要在该文件中设置如何编译,使用CMake语法。
Python功能包
C++功能包需要将源码编译成可执行文件,但是Python语言是解析型的,不需要编译,所以会有一些不同,但也会有这两个文件:package.xml和setup.py。
package.xml文件的主要内容和C++版本功能包一样,包含功能包的版权描述,和各种依赖的声明。
setup.py文件里边也包含一些版权信息,除此之外,还有“entry_points”配置的程序入口,在后续编程讲解中,我们会给大家介绍如何使用。
Hello World节点(面向过程)
ROS2中节点的实现当然是需要编写程序了,我们从Hello World例程开始,先来实现一个最为简单的节点,功能并不复杂,就是循环打印一个“Hello World”字符串到终端中。
运行效果
大家先不要着急看代码,是骡子是马,先拉出来溜溜,我们通过ros2 run命令,运行编译好的课程代码,看下这个节点执行的效果如何,然后再来分析代码的实现过程,做到知其然也知其所以然。
1 | $ ros2 run learning_node node_helloworld |
运行成功后,可以在终端中看到循环打印“Hello World”字符串的效果。
代码解析
这个节点是如何实现的呢?我们来看下代码。
learning_node/node_helloworld.py
1 | #!/usr/bin/env python3 |
完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:
1 | entry_points={ |
创建节点流程
代码中出现的函数大家未来会经常用到,大家先不用纠结函数的具体使用方法,更重要的是理解节点的编码流程。
总结一下,想要实现一个节点,代码的实现流程是这样做:
- 编程接口初始化
- 创建节点并初始化
- 实现节点功能
- 销毁节点并关闭接口
大家如果有学习过C++或者Pyhton的话,应该可以发现这里我们使用的是面向过程的编程方法,这种方式虽然实现简单,但是对于稍微复杂一点的机器人系统,就很难做到模块化编码。
说些什么吧!