【ROS2学习笔记】节点篇:ROS 2编程基础

前言

本系列博文是本人的学习笔记,自用为主,不是教程,学习请移步其他大佬的相关教程。主要学习途径为@鱼香ROS大佬的教程,欢迎各位大佬交流学习,若有错误,轻喷。

一、面向对象编程(OOP)基础

面向对象编程是现代语言的核心特性,与 C 语言 "面向过程" 不同,它通过 ** 类(Class)** 对 "事物" 进行封装,类包含:

  • 属性:描述事物的特征(如 "人" 的年龄、"手机" 的品牌)。
  • 方法:描述事物的行为(如 "人" 吃饭、"手机" 开机)。

1. Python 类的基本创建与使用

(1)定义空类

class 关键字定义类,__init__构造方法 (创建对象时自动调用),self 代表类的实例本身。

python 复制代码
class PersonNode:
    def __init__(self) -> None:
        pass
(2)添加属性与方法

__init__ 中定义属性,用函数定义 "行为方法"。

python 复制代码
class PersonNode:
    def __init__(self, name: str, age: int) -> None:
        print('PersonNode 的 __init__ 方法被调用了')
        self.age = age   # 定义"年龄"属性
        self.name = name # 定义"姓名"属性
    
    def eat(self, food_name: str):
        print(f'我叫{self.name},今年{self.age}岁,我现在正在吃{food_name}')
(3)实例化与调用

创建类的 "对象",并调用方法。

python 复制代码
def main():
    # 实例化 PersonNode(传入姓名、年龄)
    node = PersonNode('法外狂徒张三', 18)
    # 调用 eat 方法(传入食物名)
    node.eat('鱼香肉丝')

2. 类的继承(代码复用)

子类可继承父类的属性和方法,减少重复代码。注意 :若子类定义了 __init__,需用 super().__init__() 显式调用父类构造方法,否则父类属性不会被初始化。

示例:WriterNode 继承 PersonNode,并新增 "书籍" 属性:

python 复制代码
# 从父类模块导入 PersonNode
from demo_python_pkg.person_node import PersonNode

class WriterNode(PersonNode):
    def __init__(self, name: str, age: int, book: str) -> None:
        # 调用父类 PersonNode 的 __init__,初始化 name、age
        super().__init__(name, age)
        self.book = book  # 新增"书籍"属性

def main():
    # 实例化 WriterNode(传入姓名、年龄、书籍)
    node = WriterNode('法外狂徒张三', 18, '张三自传')
    # 调用从父类继承的 eat 方法
    node.eat('鱼香肉丝')

二、让类成为 ROS 2 节点:继承 Node

ROS 2 的 Node 类提供了节点的核心能力(如日志输出、话题通信等)。让自定义类继承 Node,就能拥有这些能力,成为真正的 ROS 2 节点。

示例:改造 PersonNode 继承 Node,使用 ROS 2 日志系统:

python 复制代码
import rclpy
from rclpy.node import Node  # 导入 Node 类

class PersonNode(Node):
    def __init__(self, node_name: str, name: str, age: int) -> None:
        # 调用父类 Node 的 __init__,传入"节点名"
        super().__init__(node_name)
        self.age = age
        self.name = name
    
    def eat(self, food_name: str):
        # 使用 ROS 2 日志(替代 print)
        self.get_logger().info(f'我叫{self.name},今年{self.age}岁,我现在正在吃{food_name}')

def main():
    rclpy.init()  # 初始化 rclpy
    # 实例化 PersonNode(传入节点名、姓名、年龄)
    node = PersonNode('person_node', '法外狂徒张三', 18)
    node.eat('鱼香肉丝')
    rclpy.spin(node)  # 让节点保持运行(若有回调逻辑需持续执行)
    rclpy.shutdown()  # 关闭 rclpy

三、多线程与回调函数

  • 多线程 :让程序并行执行(如同时下载多个文件,无需 "等一个完了再下下一个")。
  • 回调函数:"事件触发后自动执行的函数"(如下载完成后,自动调用函数处理结果)。

Python 多线程 + 回调示例(下载小说)

利用 threading 库创建线程,requests 库发 HTTP 请求,结合回调函数处理下载结果。

python 复制代码
import threading  # 导入线程模块,用于实现多线程功能
import requests   # 导入请求模块,用于发送HTTP请求下载网络内容

class Download:  # 定义Download类,封装下载相关的方法
    def download(self, url, callback):  # 定义下载方法,参数为目标URL和回调函数
        print(f'线程:{threading.get_ident()} 开始下载: {url}')  # 打印当前线程ID和开始下载的URL
        response = requests.get(url)  # 发送GET请求获取URL对应的内容
        response.encoding = 'utf-8'  # 设置响应内容的编码为UTF-8,保证中文等字符正常显示
        callback(url, response.text)  # 下载完成后调用回调函数,传递URL和下载的文本内容
    
    def start_download(self, url, callback):  # 定义启动下载的方法,用于创建新线程执行下载
        # 创建新线程,执行 download 方法
        thread = threading.Thread(target=self.download, args=(url, callback))  # 创建线程,指定目标方法和参数
        thread.start()  # 启动线程,开始执行下载任务

# 定义"下载完成"的回调函数:处理结果
def download_finish_callback(url, result):  # 定义下载完成后的回调函数,参数为URL和下载结果
    print(f'{url}下载完成,共: {len(result)}字,内容为: {result[:5]}...')  # 打印下载完成信息(URL、内容长度、前5个字符预览)

def main():  # 定义主函数,程序执行的入口
    d = Download()  # 创建Download类的实例d
    # 同时下载 3 个文件,都用 download_finish_callback 处理结果
    d.start_download('http://localhost:8000/novel1.txt', download_finish_callback)  # 启动线程下载第一个小说文件
    d.start_download('http://localhost:8000/novel2.txt', download_finish_callback)  # 启动线程下载第二个小说文件
    d.start_download('http://localhost:8000/novel3.txt', download_finish_callback)  # 启动线程下载第三个小说文件
测试准备(本地模拟小说与 HTTP 服务)

在终端执行以下命令,创建小说文件并启动 HTTP 服务:

bash 复制代码
# 1. 创建 3 个小说文件
echo "第一章 少年踏上修仙路,因诛仙力量被驱逐。" > novel1.txt
echo "第二章 学习修仙,结交朋友,明白责任。" > novel2.txt
echo "第三章 张家杰回村,抵抗邪恶,成为守护者。" > novel3.txt

# 2. 启动 HTTP 服务(端口 8000)
python3 -m http.server

运行代码后,3 个下载任务会并行执行 ,下载完成后自动调用 download_finish_callback 处理结果。

四、小结与点评

本章核心知识点:

  • 面向对象编程:掌握 "类、属性、方法、继承",是 ROS 2 复杂逻辑封装的基础。
  • 继承 Node:让自定义类成为真正的 ROS 2 节点,获得日志、通信等核心能力。
  • 多线程与回调:实现 "并行执行" 与 "事件驱动",为后续复杂任务(如多传感器数据处理)打基础。

通过本章,你已入门 ROS 2 开发~后续将学习更深入的 "通信、功能包组织" 等内容。

相关推荐
我命由我123453 小时前
Photoshop - Photoshop 工具栏(2)矩形框选工具
经验分享·笔记·学习·ui·photoshop·ps·美工
序属秋秋秋3 小时前
《C++进阶之C++11》【异常】
c++·笔记·学习·c++11·异常·新特性
张书名5 小时前
《强化学习数学原理》学习笔记6——贝尔曼最优方程的压缩性质
笔记·学习
悠哉悠哉愿意6 小时前
【ROS2学习笔记】话题通信篇:话题通信项目实践——系统状态监测与可视化工具
笔记·学习·ros2
hssfscv6 小时前
JAVA学习笔记——9道综合练习习题+二维数组
java·笔记·学习
charlie11451419110 小时前
精读 C++20 设计模式:行为型设计模式 — 访问者模式
c++·学习·设计模式·访问者模式·c++20
长路归期无望10 小时前
C语言小白实现多功能计算器的艰难历程
c语言·开发语言·数据结构·笔记·学习·算法
知识分享小能手11 小时前
微信小程序入门学习教程,从入门到精通,微信小程序常用API(上)——知识点详解 + 案例实战(4)
前端·javascript·学习·微信小程序·小程序·html5·微信开放平台
yuxb7312 小时前
Ceph 分布式存储学习笔记(二):池管理、认证和授权管理与集群配置(下)
笔记·ceph·学习