[足式机器人]Part5 ROS2学习笔记-CH00-2-基础入门部分

本文仅供学习使用
本文参考:
基础部分 : 古月居-ROS2入门21讲 , 鱼香ROS


6. 使用RCLCPP编写节点

节点需要存在于功能包当中、功能包需要存在于工作空间当中。所以我们要想创建节点,就要先创建一个工作空间,再创建功能包。

6.1 创建工作空间和功能包

6.1.1 工作空间

工作空间就是文件夹,所以很简单。

mkdir -p  d2lros2/chapt2/town2_ws/src

6.1.2 创建example_cpp功能包

创建village_wang功能包,使用ament-cmake作为编译类型,并为其添加rclcpp依赖。

cd d2lros2/chapt2/town2_ws/src

使用ament-cmake作为编译类型的,依赖变成了rclcpp

ros2 pkg create village_wang --build-type ament_cmake --dependencies rclcpp

pkg create创建包的意思
--build-type 用来指定该包的编译类型,一共有三个可选项ament_pythonament_cmakecmake
--dependencies 指的是这个功能包的依赖,这里给了一个ros2的C++客户端接口rclcpp

在这里插入图片描述

6.2 创建节点

接着我们在village_wang/src下创建一个wang2.cpp文件:

6.3 编写代码

6.3.1 编写代码

#include "rclcpp/rclcpp.hpp"


int main(int argc, char **argv)
{
    /* 初始化rclcpp  */
    rclcpp::init(argc, argv);
    /*产生一个node_01的节点*/
    auto node = std::make_shared<rclcpp::Node>("wang2");
    // 打印一句自我介绍
    RCLCPP_INFO(node->get_logger(), "wang2已经启动.");
    /* 运行节点,并检测退出信号 Ctrl+C*/
    rclcpp::spin(node);
    /* 停止运行 */
    rclcpp::shutdown();
    return 0;
}

主函数中首先初始化rclcpp,然后新建了一个Node节点的对象,命名为wang2,接着使用rclcpp让这个节点暴露在外面,并检测退出信号(Ctrl+C),检测到退出信号后,就会执行rcl.shutdown()关闭节点。

6.3.2 修改CmakeLists

wang2.cpp中输入上面的内容后,还需要修改一下CMakeLists.txt。将其添加为可执行文件,并使用install指令将其安装到install目录。

CmakeLists.txt最后一行加入下面两行代码。

add_executable(wang2_node src/wang2.cpp)
ament_target_dependencies(wang2_node rclcpp)

添加这两行代码的目的是让编译器编译wang2_node这个文件,接着在上面两行代码下面添加下面的代码。

install(TARGETS
  wang2_node
  DESTINATION lib/${PROJECT_NAME}
)

这个是C++比Python要麻烦的地方,需要手动将编译好的文件安装到install/village_wang/lib/village_wang

6.4 编译运行节点

town2_ws下依次输入下面的命令

6.4.1 编译节点

colcon build

6.4.2 source环境

source install/setup.bash

6.4.3 运行节点

ros2 run village_wang wang2_node

6.5 测试

当节点运行起来后,可以再尝试使用ros2 node list 指令来查看现有的节点。这个时候你应该能看到:/wang2

C++版本的ros2节点,但是这仅仅是编写ROS2节点方式之一,相比之下,更推荐使用面向对象的方式编写节点

7. 使用RCLPY编写节点

很多路径搞的比较混乱——容易出错-重新整理——注意路径流程

7.1 创建Python功能包

创建一个名字叫做madong_py python版本的功能包。

cd chapt2/town2_ws/src
ros2 pkg create madong_py  --build-type ament_python --dependencies rclpy

目录结构类似于:
在这里插入图片描述

7.2 编写程序

编写ROS2节点的一般步骤

  1. 导入库文件
  2. 初始化客户端库
  3. 新建节点
  4. spin循环节点
  5. 关闭客户端库

town2_ws/madong_py/madong_py下创建noparty_01.py(可与节点名不同)编写代码。

import rclpy
from rclpy.node import Node

def main(args=None):
    """
    ros2运行该节点的入口函数
    编写ROS2节点的一般步骤
    1. 导入库文件
    2. 初始化客户端库
    3. 新建节点对象
    4. spin循环节点
    5. 关闭客户端库
    """
    rclpy.init(args=args) # 初始化rclpy
    node = Node("noparty_01")  # 新建一个节点(决定ros
     node 中的名称)  
    node.get_logger().info("大家好,我是noparty_01")
    rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
    rclpy.shutdown() # 关闭rclpy

代码编写完成用Crtl+S进行保存。接着修改setup.py

    entry_points={
        'console_scripts': [
            "noparty_name_node = madong_py.noparty_01:main" # madong_py.noparty_01(py文件名)
        ],
    },
)

setup.py这段配置是声明一个ROS2的节点,声明后使用colcon build才能检测到,从而将其添加到install目录下。

完成上面的工作后,就可以编译运行了。

7.3 编译运行节点

打开vscode终端,进入town2_ws

7.3.1 编译运行节点

colcon build

7.3.2 source环境

source install/setup.bash

7.3.3 运行节点

ros2 run madong_py noparty_name_node

7.4 测试

当节点运行起来后,可以再尝试使用ros2 node list 指令来查看现有的节点。/noparty_01

8. OOP-面向对象编程思想 介绍

除了使用上节中的只定义一个函数就完成编写一个Python节点外,还有另外两种方式。

要做机器人离不开计算机编程,而计算机编程经过多年的发展,演变出了三种不同且常用的编程思想,分别是:

  1. 面向过程编程思想。缩写:POP
  2. 面向对象编程思想。缩写:OOP
  3. 函数式思想。缩写:FP

8.1 了解原因

在阅读机器人相关开源程序代码时,比如导航框架Nav2、机械臂运动控制框架Moveit时发现,别人的代码,每一行好像都看得懂,但放一起就看不懂了,看别人函数调来调去,很快人就给整蒙了。不知道如何下手。

这其实就是对别人的编程思想不了解造成的,所以提一提常见的三种编程思想,让大家脑子里有个概念,以后遇到了看不明白的程序,知道该往哪个方向去学习。

8.2 思想辨析——用三种思想把大象装进冰箱

编程是为了什么?——编程思想就是解决问题的思路

想把一只大象装进冰箱,分别用三种思想,我们看看有什么不一样。

  • 面向过程思想POP
    可以分为三步:1. 打开冰箱门; 2. 把大象塞进去; 3. 关上冰箱门;
    面向过程编程就是分析出解决问题所需要步骤,然后分别实现每一步,再一步步执行即可。
  • 面向对象思想OOP
    任何我们想要探究的事物都可以当作一个对象,比如我们可以把你家的冰箱理解为一个对象,我们就可以研究你家冰箱由哪些部分(指令装置等)组成,你家冰箱能干什么(制冷、调温等); 对象的行为其实是对其属性的操作,比如对制冷器操作就可以制冷,给灯带通电就可以照明。
    对象 = 属性+行为 1. 调用:冰箱->打开门(行为) ; 2. 调用:冰箱->装东西(行为); 3. 调用:冰箱->关闭门(行为)
    我们把冰箱当作了一个独立的对象,我们是通过和冰箱这个对象交互完成了整个过程。
  • 函数式思想FP
    定义关进(冰箱,大象)函数
    实现函数:关门(放入(开门(冰箱),大象))
    ——可以看到多层的函数嵌套调用

8.3 面向对象编程

面向对象中有五个重要的概念理解这五个概念相当于对OOP编程有了了解

8.3.1 类与对象(抽象与具体)

我们通过调用你家美的冰箱的开门、装东西和关门三个行为来把大象装进冰箱。这时我们可以把你家的美的冰箱(具体的)称之为一个对象,而冰箱(抽象的)就称为一个

在ROS2设计时这种抽象和具体的思想发挥着非常重要的作用,比如说DDS是有很多厂家的,ROS2为了匹配不同厂家的DDS,就设计了DDS抽象层,而每一个具体的DDS厂家,我们可以称之为一个DDS的对象,是具体的。

python中的概念

8.3.2 封装、继承与多态

封装就是将属性和行为封装在一起。上面已经介绍了对象 = 属性+行为,比如冰箱将冰箱的温度值(属性)和对温度值的操作(行为)等封装在一起。——<name> = li4

继承继承可以帮我们减少很多的工作量,比如ROS2中的执行器类,通过继承执行器类实现了单线程执行器和多线程执行器,更多具体的例子我们在后续的学习中遇到再说。——类函数

多态,其实很简单,我们可以说鲤鱼是鱼类,草鱼是鱼类,鲤鱼是鱼类。同一个鱼类可以有多种不同的类型,即多态。 更多的用法,等到写代码的时候再和小鱼一起解锁——父类与子类

8.4 如何选择code思想

根据你的功能需求来,如果只需要实现一个很简单的功能,比如只是做一个键盘控制器,实现控制小车前进后退,直接采用面向过程的设计思想即可。

但如果是做一个稍大的工程,且后续要考虑功能的拓展性,这个时候就需要采用面向对象的思路来了。

8.5 使用OOP方法编实现作家李四

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node


class WriterNode(Node):
    """
    创建一个作家节点,并在初始化时输出一个话
    """
    def __init__(self,name):
        super().__init__(name)
        self.get_logger().info("大家好,我是%s,我是一名作家!" % name)


def main(args=None):
    """
    ros2运行该节点的入口函数
    1. 导入库文件
    2. 初始化客户端库
    3. 新建节点
    4. spin循环节点
    5. 关闭客户端库
    """
    rclpy.init(args=args) # 初始化rclpy
    node = WriterNode("li4")  # 新建一个节点
    rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
    rclpy.shutdown() # 关闭rclpy

9. 使用面向对象方式编写ROS2节点

9.1 C++版本

ros2 pkg create village_town_ws --build-type ament_cmake --dependencies rclcpp

打开终端,进入/d2lros2/chapt2运行上面的指令,创建完成后的目录结构如下:
在这里插入图片描述

d2lros2/chapt2/village_town_ws/src下新建node_03.cpp,接着输入下面的代码。

#include "rclcpp/rclcpp.hpp"  // vscode报错-不用理会 如何取消:小鱼ros2 P25

/*
    创建一个类节点,名字叫做Node03,继承自Node.
*/
class Node03 : public rclcpp::Node
{

public:
    // 构造函数,有一个参数为节点名称
    Node03(std::string name) : Node(name)
    {
        // 打印一句
        RCLCPP_INFO(this->get_logger(), "大家好,我是%s.",name.c_str());
    }

private:
   
};

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    /*产生一个node_03的节点*/
    auto node = std::make_shared<Node03>("node_03");
    /* 运行节点,并检测退出信号*/
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

主函数中首先初始化rclcpp,然后新建了一个Node节点的对象,命名为node_03,接着使用rclcpp让这个节点暴露在外面,并检测退出信号(Ctrl+C),检测到退出信号后,就会执行rcl.shutdown()关闭节点。

接着修改CMakeLists.txt,添加下方代码(添加rclcpp依赖)。

add_executable(node_03 src/node_03.cpp)
ament_target_dependencies(node_03 rclcpp) 

install(TARGETS
  node_03
  DESTINATION lib/${PROJECT_NAME}
)

添加这两行代码的目的是让编译器编译node_03.cpp这个文件,不然不会主动编译。接着在上面两行代码下面添加下面的代码。

这个是C++比Python要麻烦的地方,需要手动将编译好的文件安装到install/village_town_ws/lib/village_town_ws

colcon build --packages-select village_town_ws  

接着即可自行编译测试

source install/setup.bash
ros2 run village_town_ws node_03

Ctrl + Shift +5 ——vscode 切分终端

9.2 Python版本

d2lros2/chapt2/chapt2_ws/example_py/example_py下新建node_04.py,输入下面的代码

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node


class Node04(Node):
    """
    创建一个Node04节点,并在初始化时输出一个话
    """
    def __init__(self,name):
        super().__init__(name)
        self.get_logger().info("大家好,我是%s!" % name)


def main(args=None):
    rclpy.init(args=args) # 初始化rclpy
    node = Node04("node_04")  # 新建一个节点
    rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
    rclpy.shutdown() # 关闭rclpy

接着修改setup.py

entry_points={
    'console_scripts': [
        "node_02 = example_py.node_02:main",
        "node_04 = example_py.node_04:main"
    ],
},

把节点写成一个类的形式对我们组织代码和使用ROS2的新特性有很多的好处

10. Colcon使用进阶

使用CMake(GCC或Makefile)和 Python Setup打包工具依然可以完成ROS2代码的编译,那为什么还需要Colcon呢?

10.1 ROS生态中的构建系统和构建工具

10.1.1 构建系统与构建工具

构建系统构建工具 的区分点在于针对的对象不同,构建系统只针对一个单独的包进行构建,而构建工具重点在于按照依赖关系依次调用构建系统完成一系列功能包的构建。

ROS中用到的构建系统:CMakeament_cmakecatkinPython setuptools
ROS中用到的构建工具:colconcatkin_makecatkin_make_isolatedcatkin_tools

很明显colcon作为构建工具,通过调用(构建系统)CMakePython setuptools完成构建。

10.1.2 常见构建系统

  • CMake
    CMake 是一个跨平台构建系统生成器。项目使用独立于平台的文件指定其生成过程。用户通过使用CMake为其平台上的本机工具生成构建系统来构建项目。
    通常用法有:cmakemakemake intsall
  • Python setuptools
    setuptools是Python包的打包常用工具。Python 包使用文件来描述依赖项,以及如何构建和安装内容。在ROS2中,功能包可以是“普通”Python包,而在ROS1中,任何Python功能都是从CMake文件触发setup.py进行打包。
  • catkin
    catkin基于CMake,并提供了一组方便的函数,使编写CMake包更容易。它自动生成 CMake 配置文件以及 pkg 配置文件。它还提供了注册不同类型测试的函数。

10.1.2 常见构建工具

  • catkin_make
    该工具仅调用 CMake 一次,并使用 CMake 的函数在单个上下文中处理所有包。虽然这是一种有效的方法,因为所有包中的所有目标都可以并行化,但它具有明显的缺点。由于所有函数名称、目标和测试都共享一个命名空间,并且规模更大,这很容易导致冲突
  • colcon
    colcon是一个命令行工具,用于改进构建,测试和使用多个软件包的工作流程。它自动化了流程,处理了订购并设置了使用软件包的环境。
  • ament_tools
    ament_tools由用于构建 ROS 2 包的独立 Python 3 包提供。它是为引导ROS 2项目而开发的,因此仅针对Python 3,并且可以在Linux,MacOS和Windows上运行。
    ament_tools支持构建以下软件包:
    带有package.xml文件的 ROS 2 包。
    带有package.xml普通的 CMake 包。
    没有清单文件的普通 CMake 包(从 CMake 文件中提取包名称和依赖项)。
    带有package.xml文件的 Python 包。
    没有清单文件的 Python 包(从setup.py文件中提取包名称和依赖项)。

10.2 Colcon构建进阶_build参数

我们平时用的最多的场景是编译功能包,所以这里重点介绍build时候的一些参数。

  • 构建指令:
    --packages-select ,仅生成单个包(或选定的包)。
    --packages-up-to,构建选定的包,包括其依赖项。
    --packages-above,整个工作区,然后对其中一个包进行了更改。此指令将重构此包以及(递归地)依赖于此包的所有包。
  • 指定构建后安装的目录:
    可以通过 --build-base参数和--install-base,指定构建目录和安装目录。
  • 合并构建目录
    --merge-install,使用 作为所有软件包的安装前缀,而不是安装基中的软件包特定子目录--install-base
    如果没有此选项,每个包都将提供自己的环境变量路径,从而导致非常长的环境变量值。
    使用此选项时,添加到环境变量的大多数路径将相同,从而导致环境变量值更短。
  • 符号链接安装
    启用--symlink-install后将不会把文拷贝到install目录,而是通过创建符号链接的方式。
  • 错误时继续安装
    启用--continue-on-error,当发生错误的时候继续进行编译。
  • CMake参数
    --cmake-args,将任意参数传递给CMake。与其他选项匹配的参数必须以空格为前缀。
  • 控制构建线程
    --executor EXECUTOR,用于处理所有作业的执行程序。默认值是根据所有可用执行程序扩展的优先级选择的。要查看完整列表,请调用 colcon extensions colcon_core.executor --verbose
    sequential [colcon-core]一次处理一个包。
    parallel [colcon-parallel-executor]处理多个作业平行
    --parallel-workers NUMBER要并行处理的最大作业数。默认值为 os.cpu_count() 给出的逻辑 CPU 内核数。
  • 开启构建日志
    使用--log-level可以设置日志级别,比如--log-level info
  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiongLoure

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值