【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 开发~后续将学习更深入的 "通信、功能包组织" 等内容。

相关推荐
小白郭莫搞科技6 小时前
鸿蒙跨端框架Flutter学习:CustomTween自定义Tween详解
学习·flutter·harmonyos
阳光九叶草LXGZXJ7 小时前
达梦数据库-学习-47-DmDrs控制台命令(LSN、启停、装载)
linux·运维·数据库·sql·学习
A9better8 小时前
嵌入式开发学习日志53——互斥量
stm32·嵌入式硬件·学习
进阶小白猿9 小时前
Java技术八股学习Day30
java·开发语言·学习
近津薪荼9 小时前
优选算法——双指针6(单调性)
c++·学习·算法
三水不滴9 小时前
Redis缓存更新策略
数据库·经验分享·redis·笔记·后端·缓存
修修修也10 小时前
【无标题】技术欲望是怎样渐进增长的?
学习
whale fall10 小时前
celery -A tool.src.main worker --loglevel=info --queues=worker1_queue & 什么意思
python·学习·apache
wotaifuzao11 小时前
【Keil 5安装】keil 5最新版本安装+环境配置+下载百度资源分享(安装包,注册机等)
stm32·单片机·嵌入式硬件·mcu·学习·keil5·最新keil
ziqi52212 小时前
第二十四天笔记
笔记