当前位置: 首页 > news >正文

【ROS2学习笔记】话题通信篇:话题通信再探

前言

本系列博文是本人的学习笔记,自用为主,不是教程,学习请移步其他大佬的相关教程。前几篇学习资源来自鱼香ROS大佬的详细教程,适合深入学习,但对本人这样的初学者不算友好,而且涉及python与C++混合编程内容,增加了学习成本,后续笔记将以@古月居的ROS2入门21讲为主,侵权即删。

一、基础概念

1. 话题通信核心概念

1.1 什么是话题?

话题是 ROS2 中节点(Node)之间传递数据的桥梁,用于实现节点间的单向数据传输。

  • 场景举例:相机节点(A)获取图像数据,视频监控节点(B)需要显示图像,此时 A 通过话题将图像数据传给 B,B 才能完成可视化。

1.2 话题的通信模型:发布 / 订阅(Pub/Sub)

话题基于DDS(数据分发服务) 实现,核心是 “发布者 - 订阅者” 模式,类比生活中的 “微信公众号”:

ROS2 概念微信公众号类比作用说明
话题名称公众号名称(如 “古月居”)唯一标识,发布者和订阅者通过名称匹配
发布者(Publisher)公众号小编发送数据的节点(主动推送数据)
订阅者(Subscriber)公众号订阅用户接收数据的节点(被动接收数据)
消息类型公众号文章格式(如图文)数据的固定格式(如字符串、图像),确保收发双方理解一致

1.3 话题的 2 个关键特性

(1)多对多通信
  • 一个话题可以有多个发布者,也可以有多个订阅者:
    • 例 1:2 个摇杆节点(发布者)同时向 “/cmd_vel” 话题发控制指令,1 个机器人节点(订阅者)接收。
    • 例 2:1 个相机节点(发布者)向 “/image_raw” 话题发图像,2 个节点(订阅者:监控 + 识别)同时接收。
  • ⚠️ 注意:多发布者时需设置优先级,避免机器人 “混乱”。
(2)异步通信
  • 发布者发送数据后,不关心订阅者何时接收 / 处理(类似公众号发文章,小编不知道用户何时阅读)。
  • 适用场景:周期发布的数据(如传感器数据、控制指令)。
  • 不适用场景:需要即时响应的指令(如修改参数)。

1.4 消息接口(Msg):统一数据格式

  • 问题:如果发布者发 “英文”,订阅者理解为 “中文”,数据会失效。
  • 解决方案:消息(Msg) ——ROS2 定义的标准化数据格式,与编程语言无关。
    • 标准消息:ROS2 已内置(如std_msgs/msg/String(字符串)、sensor_msgs/msg/Image(图像))。
    • 自定义消息:通过.msg文件定义(如自定义 “温度 + 湿度” 消息)。
  • 例:sensor_msgs/msg/Image包含的信息:图像宽度、高度、像素格式(如 bgr8)、像素数据等。

二、项目实战(全流程)

1. 第一步:创建 ROS2 工作空间

工作空间是 ROS2 项目的 “容器”,用于存放功能包、代码、编译产物等,所有开发都需在工作空间中进行。标准 ROS2 工作空间结构如下:

工作空间名称/
├── build/       # 编译过程中生成的中间文件(自动创建)
├── install/     # 编译后的可执行文件、库、环境变量(自动创建)
├── log/         # 编译和运行日志(自动创建)
└── src/         # 核心目录:存放功能包(需手动创建)

1.1 创建工作空间目录

打开终端,执行以下命令,创建名为ros2_ws的工作空间(名称可自定义,建议用_ws后缀标识):

# 1. 进入用户主目录(也可选择其他路径,如~/code)
cd ~# 2. 创建工作空间根目录ros2_ws
mkdir -p ros2_ws/src  # -p:确保父目录(ros2_ws)和子目录(src)都创建# 3. 进入工作空间根目录
cd ros2_ws
  • 说明:src目录是必须手动创建的核心目录,后续所有功能包都放在src下;buildinstalllog会在编译时自动生成,无需手动创建。

1.2 初始化工作空间(可选,仅首次)

若工作空间是首次创建,可执行以下命令初始化(主要用于生成编译配置模板,对 Python 项目非强制,但建议执行以保证规范):

# 在ros2_ws目录下执行(确保当前路径是~/ros2_ws)
colcon build --symlink-install
  • colcon build:ROS2 的编译工具,用于编译工作空间中的功能包;
  • --symlink-install:创建符号链接(而非复制文件),修改 Python 代码后无需重新编译,直接运行即可(对 Python 开发非常友好,建议每次编译都加此参数)。

执行后,会自动生成buildinstalllog三个目录,工作空间初始化完成。

2. 第二步:创建功能包

功能包是 ROS2 代码的 “最小组织单元”,一个功能包可包含多个节点、话题、服务等。需在src目录下创建功能包,且必须指定依赖项(如rclpy(ROS2 Python 接口)、std_msgs(标准消息)等)。

2.1 进入 src 目录并创建功能包

ros2_ws目录下,执行以下命令创建名为learning_topic的功能包(名称对应之前的示例,便于衔接):

# 1. 进入src目录(当前路径:~/ros2_ws)
cd src# 2. 创建功能包:指定包名、依赖项
ros2 pkg create learning_topic \
--build-type ament_python \  # 编译类型:ament_python(Python项目),C++项目用ament_cmake
--dependencies rclpy std_msgs sensor_msgs cv_bridge opencv-python \  # 依赖项(空格分隔)
--node-name topic_helloworld_pub  # 可选:创建包时自动生成一个节点文件(这里先指定发布者节点名)
  • 依赖项说明(必须包含,否则后续代码会报错):
    • rclpy:ROS2 Python 核心接口库(所有 Python 节点都需要);
    • std_msgs:ROS2 标准消息库(提供 String 等基础消息类型);
    • sensor_msgs:ROS2 传感器消息库(提供 Image 等图像消息类型,机器视觉案例需用);
    • cv_bridge:ROS2 与 OpenCV 的图像格式转换工具(机器视觉案例需用);
    • opencv-python:Python 版 OpenCV 库(机器视觉案例需用)。

2.2 查看功能包结构

创建完成后,src目录下会生成learning_topic文件夹,结构如下:

learning_topic/
├── learning_topic/        # 包的核心代码目录(与包名同名)
│   ├── __init__.py        # Python包初始化文件(空文件即可)
│   └── topic_helloworld_pub.py  # 自动生成的发布者节点文件(后续修改)
├── resource/              # 资源文件目录(如配置文件,暂不用)
│   └── learning_topic
├── test/                  # 测试文件目录(暂不用)
├── package.xml            # 功能包配置文件(指定依赖、作者等)
├── setup.cfg              # Python包安装配置(自动生成,无需修改)
└── setup.py               # 编译配置文件(指定入口点、依赖等,关键文件)

3. 第三步:编写代码(在功能包中)

接下来,在learning_topic/learning_topic/目录下编写之前的 3 个核心节点代码(Hello World 发布者 / 订阅者、相机发布者 / 订阅者)。首先进入代码目录:

# 进入核心代码目录(当前路径:~/ros2_ws/src/learning_topic)
cd learning_topic

3.1 案例一:Hello World 话题通信(发布者 + 订阅者)

3.1.1 发布者代码(topic_helloworld_pub.py)

若之前创建包时已自动生成该文件,直接覆盖内容;若未生成,新建文件并写入以下代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2话题示例-发布“Hello World”话题
"""# 导入ROS2 Python核心接口库
import rclpy
# 导入ROS2节点类(所有自定义节点需继承此类)
from rclpy.node import Node
# 导入ROS2标准字符串消息类型
from std_msgs.msg import String"""
自定义发布者节点类,继承自Node
"""
class PublisherNode(Node):def __init__(self, name):# 调用父类Node的初始化方法,设置节点名称super().__init__(name)# 创建发布者对象:消息类型String、话题名"chatter"、队列长度10self.pub = self.create_publisher(String, "chatter", 10)# 创建定时器:周期0.5秒,触发回调函数timer_callbackself.timer = self.create_timer(0.5, self.timer_callback)# (新增)打印节点初始化日志,方便调试self.get_logger().info("Hello World发布者节点已启动!")# 定时器回调函数:定时发布消息def timer_callback(self):# 创建String消息对象msg = String()# 给消息赋值msg.data = "Hello World! 这是ROS2话题通信示例"# 发布消息self.pub.publish(msg)# 打印发布日志self.get_logger().info(f"已发布:{msg.data}")# 主入口函数
def main(args=None):# 初始化ROS2 Python接口rclpy.init(args=args)# 创建发布者节点对象node = PublisherNode("topic_helloworld_pub")# 循环运行节点(阻塞线程,确保回调函数执行)rclpy.spin(node)# 销毁节点(释放资源)node.destroy_node()# 关闭ROS2接口rclpy.shutdown()
3.1.2 订阅者代码(新建 topic_helloworld_sub.py)

learning_topic/learning_topic/目录下新建文件,命名为topic_helloworld_sub.py,写入以下代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2话题示例-订阅“Hello World”话题
"""# 导入ROS2核心库
import rclpy
# 导入ROS2节点类
from rclpy.node import Node
# 导入标准字符串消息类型
from std_msgs.msg import String"""
自定义订阅者节点类,继承自Node
"""
class SubscriberNode(Node):def __init__(self, name):# 初始化节点,设置名称super().__init__(name)# 创建订阅者对象:消息类型String、话题名"chatter"、回调函数、队列长度10self.sub = self.create_subscription(String, "chatter", self.listener_callback, 10)# (新增)打印节点初始化日志self.get_logger().info("Hello World订阅者节点已启动!")# 订阅者回调函数:收到消息后执行def listener_callback(self, msg):# 打印收到的消息self.get_logger().info(f"已接收:{msg.data}")# 主入口函数
def main(args=None):# 初始化ROS2rclpy.init(args=args)# 创建订阅者节点node = SubscriberNode("topic_helloworld_sub")# 循环运行节点rclpy.spin(node)# 销毁节点node.destroy_node()# 关闭ROS2rclpy.shutdown()

3.2 案例二:机器视觉识别(相机发布者 + 订阅者)

3.2.1 相机发布者代码(新建 topic_webcam_pub.py)

learning_topic/learning_topic/目录下新建文件,命名为topic_webcam_pub.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2话题示例-发布相机图像话题
"""import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image  # 图像消息类型
from cv_bridge import CvBridge      # ROS-OpenCV图像转换
import cv2                          # OpenCV库class ImagePublisher(Node):def __init__(self, name):super().__init__(name)# 创建图像发布者:话题名"image_raw"(ROS2相机标准话题名)self.pub = self.create_publisher(Image, "image_raw", 10)# 定时器:0.1秒触发一次(10帧/秒)self.timer = self.create_timer(0.1, self.timer_callback)# 初始化相机(0表示默认摄像头,如笔记本内置相机)self.cap = cv2.VideoCapture(0)# 检查相机是否正常打开(新增:避免相机故障导致报错)if not self.cap.isOpened():self.get_logger().error("无法打开相机!请检查相机连接")return# 初始化图像转换对象self.cv_bridge = CvBridge()self.get_logger().info("相机发布者节点已启动!")def timer_callback(self):# 读取一帧图像:ret(是否成功)、frame(OpenCV格式图像)ret, frame = self.cap.read()if not ret:self.get_logger().warning("读取相机图像失败!")return# 将OpenCV图像(BGR)转换为ROS图像消息(格式bgr8)ros_image = self.cv_bridge.cv2_to_imgmsg(frame, "bgr8")# 发布图像消息self.pub.publish(ros_image)self.get_logger().info("正在发布相机图像...")def main(args=None):rclpy.init(args=args)node = ImagePublisher("topic_webcam_pub")rclpy.spin(node)# (新增)释放相机资源if node.cap.isOpened():node.cap.release()node.destroy_node()rclpy.shutdown()
3.2.2 红色物体识别订阅者代码(新建 topic_webcam_sub.py)

learning_topic/learning_topic/目录下新建文件,命名为topic_webcam_sub.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2话题示例-订阅图像并识别红色物体
"""import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
import numpy as np  # 数值计算库(处理颜色阈值)# 红色物体的HSV颜色范围(抗光照干扰,比RGB更适合颜色识别)
lower_red = np.array([0, 90, 128])   # 下限
upper_red = np.array([180, 255, 255])# 上限class ImageSubscriber(Node):def __init__(self, name):super().__init__(name)# 订阅图像话题"image_raw"self.sub = self.create_subscription(Image, "image_raw", self.listener_callback, 10)self.cv_bridge = CvBridge()self.get_logger().info("视觉识别订阅者节点已启动!")# 红色物体识别函数def detect_red_object(self, frame):# 将BGR图像转换为HSV图像hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)# 二值化:只保留红色区域(白色),其他区域黑色mask = cv2.inRange(hsv, lower_red, upper_red)# 检测红色区域的轮廓contours, _ = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)# 过滤小轮廓(噪声)for cnt in contours:if len(cnt) < 150:  # 轮廓像素数小于150,视为噪声continue# 绘制轮廓(绿色,线宽2)cv2.drawContours(frame, [cnt], -1, (0, 255, 0), 2)# 计算轮廓外接矩形,标记中心点x, y, w, h = cv2.boundingRect(cnt)center_x = x + w // 2center_y = y + h // 2# 绘制中心点(绿色,半径5,填充)cv2.circle(frame, (center_x, center_y), 5, (0, 255, 0), -1)# (新增)在图像上标注中心点坐标cv2.putText(frame, f"Center: ({center_x}, {center_y})", (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)# 显示处理后的图像cv2.imshow("Red Object Detection", frame)cv2.waitKey(10)  # 等待10ms,避免图像窗口卡死# 订阅回调函数def listener_callback(self, msg):self.get_logger().info("正在接收相机图像...")# 将ROS图像消息转换为OpenCV图像frame = self.cv_bridge.imgmsg_to_cv2(msg, "bgr8")# 调用红色物体识别函数self.detect_red_object(frame)def main(args=None):rclpy.init(args=args)node = ImageSubscriber("topic_webcam_sub")rclpy.spin(node)# (新增)关闭OpenCV窗口,释放资源cv2.destroyAllWindows()node.destroy_node()rclpy.shutdown()

4. 第四步:配置编译文件(关键!让 ROS2 识别代码)

ROS2 需要通过setup.py(Python 项目)和package.xml(通用配置)识别节点和依赖,必须正确配置才能编译运行。

4.1 配置 setup.py(指定入口点,即终端命令)

打开~/ros2_ws/src/learning_topic/setup.py文件,找到entry_points字段,修改为以下内容(指定每个 Python 脚本对应的终端命令):

entry_points={'console_scripts': [# 格式:"终端命令名" = "包名.文件名:main函数"'topic_helloworld_pub = learning_topic.topic_helloworld_pub:main','topic_helloworld_sub = learning_topic.topic_helloworld_sub:main','topic_webcam_pub = learning_topic.topic_webcam_pub:main','topic_webcam_sub = learning_topic.topic_webcam_sub:main',],
},
  • 作用:编译后,在终端输入topic_helloworld_pub,即可运行对应的 Python 脚本。

4.2 配置 package.xml(确认依赖项)

打开~/ros2_ws/src/learning_topic/package.xml文件,确保<exec_depend>标签包含所有依赖(创建包时已自动添加,若缺失需手动补充):

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"><name>learning_topic</name><version>0.0.0</version><description>ROS2话题通信学习示例</description><maintainer email="your_email@example.com">your_name</maintainer><license>Apache-2.0</license><!-- 构建依赖(编译时需要) --><buildtool_depend>ament_cmake_python</buildtool_depend><depend>rclpy</depend><depend>std_msgs</depend><depend>sensor_msgs</depend><depend>cv_bridge</depend><!-- 运行依赖(运行时需要,关键!) --><exec_depend>opencv-python</exec_depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_python</build_type></export>
</package>
  • 说明:opencv-python是 Python 库,需通过<exec_depend>指定,否则运行时可能提示 “找不到 cv2 模块”。

4.3 赋予 Python 脚本可执行权限(关键!避免 “权限不足”)

ROS2 运行 Python 脚本需要可执行权限,在终端执行以下命令(进入learning_topic/learning_topic目录):

# 进入代码目录(当前路径:~/ros2_ws/src/learning_topic/learning_topic)
cd ~/ros2_ws/src/learning_topic/learning_topic# 赋予所有Python脚本可执行权限
chmod +x *.py
  • 验证:执行ls -l,若脚本名前有x(如-rwxr-xr-x),说明权限已添加。

5. 第五步:编译工作空间

回到工作空间根目录(~/ros2_ws),执行编译命令,将代码编译为 ROS2 可识别的可执行文件:

# 进入工作空间根目录
cd ~/ros2_ws# 编译工作空间,添加--symlink-install(Python代码修改后无需重新编译)
colcon build --symlink-install --packages-select learning_topic
  • --packages-select learning_topic:只编译learning_topic功能包(避免编译所有功能包,节省时间);
  • 编译成功标志:终端最后显示 “[100%] Built target ...”,无红色错误信息。

6. 第六步:激活环境并运行节点

编译完成后,需要 “激活” 工作空间的环境变量,让 ROS2 找到编译后的功能包和节点。

6.1 激活环境

~/ros2_ws目录下执行以下命令:

# 激活当前工作空间的环境(每次打开新终端都需执行,或配置自动激活)
source install/setup.bash
  • 自动激活配置(可选):若不想每次手动激活,可将命令添加到~/.bashrc文件:
    # 打开.bashrc文件
    gedit ~/.bashrc
    # 在文件末尾添加一行:
    source ~/ros2_ws/install/setup.bash
    # 保存并关闭文件,执行以下命令使配置生效:
    source ~/.bashrc
    

6.2 运行 Hello World 案例

需要打开两个终端(均已激活环境):

终端 1:运行发布者
ros2 run learning_topic topic_helloworld_pub
  • 预期输出:
    [INFO] [topic_helloworld_pub] [1710000000.123456]:Hello World发布者节点已启动!
    [INFO] [topic_helloworld_pub] [1710000000.123456]:已发布:Hello World! 这是ROS2话题通信示例
    [INFO] [topic_helloworld_pub] [1710000000.623456]:已发布:Hello World! 这是ROS2话题通信示例
    
终端 2:运行订阅者
ros2 run learning_topic topic_helloworld_sub
  • 预期输出:
    [INFO] [topic_helloworld_sub] [1710000001.123456]:Hello World订阅者节点已启动!
    [INFO] [topic_helloworld_sub] [1710000001.123456]:已接收:Hello World! 这是ROS2话题通信示例
    [INFO] [topic_helloworld_sub] [1710000001.623456]:已接收:Hello World! 这是ROS2话题通信示例
    

6.3 运行机器视觉案例

同样需要两个终端,且确保电脑已连接相机(内置或 USB 外接):

终端 1:运行相机发布者
ros2 run learning_topic topic_webcam_pub
  • 预期输出:
    [INFO] [topic_webcam_pub] [1710000010.123456]:相机发布者节点已启动!
    [INFO] [topic_webcam_pub] [1710000010.223456]:正在发布相机图像...
    [INFO] [topic_webcam_pub] [1710000010.323456]:正在发布相机图像...
    
终端 2:运行视觉识别订阅者
ros2 run learning_topic topic_webcam_sub
  • 预期效果:
    1. 弹出 “Red Object Detection” 窗口,显示相机实时画面;
    2. 将红色物体(如苹果、红色笔)对准相机,画面中会用绿色轮廓和中心点标记红色物体,并显示中心点坐标。

6.4 案例三:复用 ROS2 标准相机驱动(优化版)

若不想自己写相机发布者,可直接使用 ROS2 官方的usb_cam驱动,步骤如下:

  1. 安装usb_cam驱动:
    sudo apt install ros-humble-usb-cam
    
  2. 终端 1:运行官方相机驱动(发布/image_raw话题):
    ros2 run usb_cam usb_cam_node_exe
    
  3. 终端 2:运行之前的视觉识别订阅者(无需修改代码):
    topic_webcam_sub
    
  • 效果与案例二完全一致,体现 ROS2 “模块化复用” 的优势。

7. 第七步:话题调试工具(验证通信是否正常)

若运行节点后无预期效果,可使用 ROS2 自带的话题工具排查问题,常用命令如下:

命令功能示例(针对 Hello World)
ros2 topic list查看当前所有活跃话题输出:/chatter /image_raw /rosout
ros2 topic info /chatter查看话题详情(发布者 / 订阅者数量、消息类型)输出:Type: std_msgs/msg/StringPublishers: 1
ros2 topic echo /chatter实时打印话题数据输出所有 “Hello World” 消息
ros2 topic hz /chatter查看话题发布频率输出:average rate: 2.00 Hz(每 0.5 秒 1 次)

8. 常见问题排查(初学者必看)

  1. “命令未找到”(如 topic_helloworld_pub: command not found)

    • 原因:未激活环境或编译失败;
    • 解决:执行source ~/ros2_ws/install/setup.bash,或重新编译工作空间。
  2. “找不到 cv2 模块”(ModuleNotFoundError: No module named 'cv2')

    • 原因:未安装 opencv-python;
    • 解决:执行pip install opencv-python(若有多个 Python 版本,用pip3)。
  3. “相机无法打开”(无法打开相机!请检查相机连接)

    • 原因:相机被占用(如其他软件打开了相机)或未连接;
    • 解决:关闭其他使用相机的软件,重新插拔 USB 相机,或更换相机设备号(将cv2.VideoCapture(0)改为1)。
  4. “订阅者收不到消息”

    • 原因:话题名不匹配(如发布者用 “chatter”,订阅者用 “chat”)或消息类型不匹配;
    • 解决:检查代码中话题名和消息类型是否完全一致,用ros2 topic list确认话题名。

9. 全流程总结

  1. 创建工作空间mkdir -p ~/ros2_ws/src → cd ~/ros2_ws
  2. 创建功能包cd src → ros2 pkg create learning_topic --build-type ament_python --dependencies ...
  3. 编写代码:在learning_topic/learning_topic目录下创建 Python 脚本;
  4. 配置文件:修改setup.py(入口点)和package.xml(依赖);
  5. 赋予权限chmod +x *.py
  6. 编译工作空间cd ~/ros2_ws → colcon build --symlink-install --packages-select learning_topic
  7. 激活环境source install/setup.bash
  8. 运行节点:打开多个终端,分别运行发布者和订阅者;
  9. 调试:用ros2 topic list/info/echo排查问题。

按照以上步骤,即可从 “零” 开始完成 ROS2 话题通信的全流程开发,后续学习服务、动作等通信机制,也可复用此工作空间和功能包结构。

http://www.dtcms.com/a/434285.html

相关文章:

  • 网络编程中“地址重用(SO_REUSEADDR)”
  • 汕头网站建设推广厂家wordpress 响应式图片
  • Rust的错误处理
  • 可视化地图
  • Rust与C接口交互
  • 【C++实战(64)】C++ 邂逅SQLite3:数据库编程实战之旅
  • 泉州网页建站模板开发网址
  • 中华建设杂志网站记者管理网站英文
  • React 18+TS中使用Cesium 1.95
  • View:new关键词干了什么事,还有原型链是什么
  • 如何在新的Spring Boot项目中关闭Spring Security?
  • 药企做网站需要哪些手续国内新闻最新消息今天在线
  • 【Flutter】GetX最佳实践与避坑指南
  • AIFoto 1.15.4 | AI图片工具,AI擦除衣服,变性感衣服
  • 数据合规与ISO标准体系
  • 在Ubuntu22.04系统下安装Jellyfin
  • 福州做网站的app排名优化公司
  • 【Linux系统】快速入门一些常用的基础指令
  • AI自动化测试:接口测试全流程自动化的实现方法——从需求到落地的全链路实践
  • 打开网站建设中是什么意思表白网站制作代码
  • 【MySQL】MVCC:从核心原理到幻读解决方案
  • Unity游戏基础-4(人物移动、相机移动、UI事件处理 代码详解)
  • 神经网络中优化器的作用
  • 电子商务网站建设的流程图什么是软文
  • 【代码管理】git使用指南(新手向)
  • 【大模型】Agent之:从Prompt到Context的演进之路
  • Docker 搭建 Nginx 并启用 HTTPS 具体部署流程
  • 【代码随想录day 34】 力扣 62.不同路径
  • 点击app图标进入网站怎么做小程序软件开发制作
  • 【Rust GUI开发入门】编写一个本地音乐播放器(15. 记录运行日志)