深入解析:【ROS2学习笔记】话题通信篇:话题通信再探

news/2025/10/22 11:32:57/文章来源:https://www.cnblogs.com/wzzkaifa/p/19157562

前言

本系列博文是本人的学习笔记,自用为主,不是教程,学习请移步其他大佬的相关教程。前几篇学习资源来自鱼香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>标签包含所有依赖(创建包时已自动添加,若缺失需手动补充):

learning_topic0.0.0ROS2话题通信学习示例your_nameApache-2.0ament_cmake_pythonrclpystd_msgssensor_msgscv_bridgeopencv-pythonament_lint_autoament_lint_commonament_python
  • 说明: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.mzph.cn/news/943213.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android插件化框架

https://chat.deepseek.com/share/w6duumv7aglpslahak Android插件化框架Shadow深度解析 1. 什么是Android插件化? 1.1 基本概念 Android插件化是一种技术,允许一个已安装的APP(称为宿主)动态加载并运行另一个完整…

完整教程:Python全栈(基础篇)——Day06:后端内容(定义函数+调用函数+实战演示+每日一题)

完整教程:Python全栈(基础篇)——Day06:后端内容(定义函数+调用函数+实战演示+每日一题)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !importa…

【IEEE出版、中国科学院宁波材料所主办】第五届机械自动化与电子信息工程国际学术会议(MAEIE 2025)

IEEE出版、会议规模大,EI检索 第五届机械自动化与电子信息工程国际学术会议(MAEIE 2025) 2025 5th International Conference on Mechanical Automation and Electronic Information Engineering 在这里看会议官网详…

氛围灯动态屏保取色方案二

氛围灯动态屏保取色方案二hue查找:整体偏差不会很大,但是对于亮度较高存在误差,精准度不够 lab查找:整体一般,但是精准度较好,不过算法复杂,增加耗时 hue色相查找存在误差,在有限的256色中,匹配的规则需要调整…

完整教程:Oracle/MySQL/SqlServer/PostgreSQL等数据库的数据类型映射以及各版本数据类型情况说明

完整教程:Oracle/MySQL/SqlServer/PostgreSQL等数据库的数据类型映射以及各版本数据类型情况说明2025-10-22 11:20 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !i…

老弟第一次学 Redis,被坑惨了!小白可懂的保姆级 Redis 教程

这天,产品经理找到你:阿巴阿巴,用户吐槽咱们网站首页加载太慢,快优化!你是小阿巴,刚入职的程序员。 这天,产品经理找到你:阿巴阿巴,用户吐槽咱们网站首页加载太慢,快优化! 你打开监控一看,好家伙!每秒有…

中小企业如何低成本部署电话呼叫软件网页版?一步步教你做

对于许多中小企业而言,电话沟通依然是销售、客服、售后等场景中最直接、最高效的方式。但当业务量增长、员工分布分散后,传统电话模式的问题也随之暴露:号码分散难管理、通话费用高、数据无法留存、外呼行为缺乏监管…

别再手写过滤器!SpringCloud Gateway 内置30 个,少写 80% 重复代码

大家好,我是小富~ 我发现公司的网关项目里有很多的轮子,几乎每个人接手这个项目开发,都会自定义过滤器,导致有非常非常多的过滤器,修改其中一个,指不定就会影响其他的人功能,非常的恼火。 其实在 Spring Cloud…

PCB库文档处理工具

PCB库文档处理工具封装库文档图元清理工具

完整教程:如何更改 SQLserver 数据库存储的位置 想从C盘换到D盘

完整教程:如何更改 SQLserver 数据库存储的位置 想从C盘换到D盘pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "C…

实用指南:Linux 如何创建和计数套接字

实用指南:Linux 如何创建和计数套接字pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mon…

(web cad drawing)Web CAD SDK Integration Method

Preface We have created an online CAD project based on mxcad, which includes various CAD functions such as previewing, editing drawings, and operating the drawing database. After user integration, it s…

记一次 .NET 某药品缺陷高速检测系统 卡慢分析

一:背景 1. 讲故事 上个月有位朋友找到我,说他们公司的程序当内存达到一定阈值(2g+)之后,业务逻辑明显变慢导致下位机超时报警,想让我看下到底怎么回事,这种问题其实抓dump比较难搞,但朋友也说了有一个增长阈值,…

0254-CLAP-参数默认值

环境Time 2022-12-02 WSL-Ubuntu 22.04 CLAP 4.0.29前言 说明 参考:https://docs.rs/clap/latest/clap/index.html 目标 如果没有提供参数,使用默认值。 Cargo.toml [package] edition = "2021" name = &q…

得物火山引擎:Data Agent驱动财务管理智能升级

作为新一代品质生活购物社区,得物 App 以正品电商和品质生活社区作为两大核心服务,成立十年来,得物 App 始终致力于帮助用户得到美好生活,90后用户占比超9成,已成为年轻用户重要的品质生活购物平台。随着 AI 时代…

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

前言 显示等待框意义 在创建WPF应用的时候,如果我们要执行一个耗时的操作,那么给用户显示一个等待窗体是很常见的需求,通过显示一个等待窗体让用户明白运行的这个软件并没有崩溃,能有效消除用户的焦虑与不确定性,…

2025年钢花钢管厂家最新行业资讯推荐,注浆钢管/超前小导钢管/袖阀钢管/地质钢管/管棚钢管/岩心钢管/基建与矿业升级驱动需求,高品质钢管如何选?最新实力厂商推荐榜发布

随着国家在基础设施建设、能源勘探及矿山开发等领域的持续投入,2025年市场对高品质、高规格钢管的需求预计将进一步提升。尤其在隧道支护、地质加固、精密设备制造等场景中,钢管的材质、精度与耐久性直接关系到工程安…

训练常用

1 利用 Screen 保持 VSCode 连接远程任务持续运行 1.1 远程连接 在 Linux 上使用 screen 是一种保持进程持续运行的便捷方式,即使用户断开 SSH 连接,进程也不会中断。连接远程服务器 首先使用 VSCode 或者 PyCharm 连…

《Vuejs设计与实现》第 18 章(同构渲染)(上) - 详解

《Vuejs设计与实现》第 18 章(同构渲染)(上) - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&…

配置git

1 从项目中去掉现有的 Git 信息,并重新建立新的 Git 仓库 删除原有的 Git 信息:打开命令行工具,进入项目所在的目录。 执行以下命令以删除 .git 文件夹,这将移除所有的 Git 版本控制信息:对于 Linux 和 macOS: rm…