基恩士激光测距 + C#上位机:从串口帧解析到实时曲线的完整实战

简介:这份资源是面向工业自动化开发者与C#初学者的实战项目,演示如何通过串口通信将基恩士CL3000系列激光测距仪接入.NET程序,实现基准面设置、触发测量、结果解析及配合运动控制连续采集高度数据,可延伸至自动化检测、在线尺寸测量等场景。压缩包共34个文件、159KB,包含11个C#源码文件(Form、CL3000Helper等核心类)、工程配置与项目文件(sln/csproj/config)、编译产物(exe/dll/pdb)以及资源文件(resx/resources),代码结构完整,便于直接打开调试和学习完整调用流程。已有627人下载学习,适合想掌握硬件设备串口控制、数据解析与上位机界面联调的开发者。样例中涉及SerialPort参数配置、指令发送与返回值处理,并附有运动控制联动思路,可帮助读者理解从设备通信到业务逻辑集成的关键环节,是一份接地气的C#工业设备编程参考。

1. 基恩士激光测距 + C# 上位机:从串口帧到可用界面的完整落地

先说个真实翻车场景。某条产线的检测工位上,基恩士激光测距传感器的面板数值跳动正常,但配套 C# 上位机软件死活显示不出距离。排查到下班才发现,串口接收缓冲区多了一个换行符,帧解析时没做 Trim,数据直接被正则拒了。这类问题在这个领域不是个例,搞工业上位机的多少都踩过类似的坑。

这份资料给到的是一套完整的基恩士激光测距 + C# 编程实例:用 C# 写一个上位机程序,通过串口读取激光测距传感器的测量值,实时显示在界面上、绘制趋势曲线,并落盘保存。它非常适合正在做产线自动化、设备数据采集、检测软件开发的人,也是想入门 C# 工业通讯编程的一个真实度很高的实战样本。下面按架构、核心代码、调试、二次开发逐层拆开讲。

2. 技术选型与工程结构:从协议到界面的分层设计

2.1 通讯方式选型:串口是下限,以太网是上限

基恩士的激光测距产品线很宽,不同系列的信号输出方式差别很大,常见的有模拟量信号(0~5V 或 4~20mA)、串口(RS-232C / RS-422)、部分型号自带以太网口。对 C# 上位机来说,最直接的方式是串口和以太网两种。这个实例以串口为主线,同时保留了以太网方向,工程结构上两边都预留了接口。

通讯方式适用场景优点缺点
串口 RS-232C/RS-422单台设备直连 PC/PLC,距离短协议直观、接线简单点位一对一,不便组网
以太网 TCP多台传感器集中采集,产线组网传输距离远、便于扩展协议相对复杂,要处理连接状态
模拟量信号接 PLC 模拟量模块硬件成本低精度受线材和干扰影响,不适合数据记录

选择串口优先的原因很实际:基恩士传感器的串口协议大多数是 ASCII 命令 + 响应的模式,帧短、好解析、容易验证,调试时用一个小助手工具就能直接看到原始报文,比以太网那头黑匣子式的连接状态要直观得多。我一般会建议首次做这类项目的开发者先把串口链路跑通,再去碰以太网,学习曲线能平滑不少。

2.2 C# 工程目录与分层设计

整个工程保持了很传统的四层结构:协议层负责帧的组装和拆解,通讯层负责串口/TCP 连接的收发,业务层把解析结果转换并推送到 UI,界面层只管展示。实际目录结构大致是这样:

LaserDistanceMeter/ ├── Utility/ // 字节工具、BCC 校验、Hex 转字符串 │ ├── ByteHelper.cs │ └── CrcValidator.cs ├── Communication/ // 串口封装、TCP 客户端封装 │ ├── LaserSerialPort.cs │ └── LaserTcpClient.cs ├── Protocol/ // 协议解析,按传感器型号隔离 │ ├── LaserFrameParser.cs │ └── LaserCommandBuilder.cs ├── Service/ // 采集流程、断线重连、数据落盘 │ ├── LaserDataService.cs │ └── CsvExporter.cs └── UI/ // WinForms 主窗体、配置界面 ├── MainForm.cs └── SettingsForm.cs

这个分层最重要的价值在于隔离变化:换传感器型号时只需要改 Protocol 层的指令和解析规则,换通讯方式时只需要替换 Communication 层的实现,数据服务、界面逻辑完全不需要动。实际项目里我见过把串口开关、协议解析、界面刷新全堆在一个窗体类里的写法,看起来很快,但遇到现场设备型号调整就得改 UI 层代码,改动面非常大,容易牵连出一堆兼容性问题。

2.3 一条距离值从传感器走到界面的完整链路

完整的数据链路可以拆成下面几步,每一步出了问题都会直接反映到最终展示值上。这个实例的核心并不在界面,而是在这几个字节级步骤上:

  1. 传感器按设定频率(比如 10ms)通过串口发出一帧测量结果。
  2. 串口接收线程把字节送入缓冲区,按帧头和帧尾切出完整单帧。
  3. 协议层做校验位检查,再把数据字段解析成 float 距离值。
  4. 业务层把数值包装成事件,交给 UI 线程刷新文本框和曲线。
  5. 同时把带时间戳的记录写入 CSV 文件。

拿这个链路对照实际调试过程非常有用——面板数值正常但上位机无数据显示,问题一定出在 2 或 3 步,要么拼帧没拼上,要么校验失败导致帧被丢弃,极少是 UI 层的问题。有了这个判断顺序,排查时间能少一半。

3. 核心模块拆解:串口通讯与帧解析的实现链路

3.1 串口通讯基类:从打开到后台接收线程

先看通讯层最基本的一个类,负责串口的打开、关闭和后台数据接收。工业串口通讯和普通文件读写的主要区别在于:数据是持续异步到达的,所以必须要有一个独立的接收线程在后台持续读缓冲区,不能指望界面上某个按钮去触发一次读取。

using System; using System.IO.Ports; using System.Threading; public class LaserSerialPort : IDisposable { private SerialPort _port; private Thread _receiveThread; private volatile bool _running; // 构造:默认 115200, 8N1,实际使用时按传感器型号调整 public LaserSerialPort(string portName, int baudRate = 115200) { _port = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One); _port.ReadTimeout = 500; _port.WriteTimeout = 500; } public void Open() { if (_port.IsOpen) return; _port.Open(); _running = true; _receiveThread = new Thread(ReceiveLoop) { IsBackground = true, Name = "LaserSerialRx" }; _receiveThread.Start(); } private void ReceiveLoop() { var buffer = new byte[4096]; while (_running) { try { int n = _port.Read(buffer, 0, buffer.Length); if (n > 0) { OnDataReceived?.Invoke(buffer, n); } } catch (TimeoutException) { // 超时忽略,继续循环 } catch (Exception ex) { OnError?.Invoke(ex.Message); break; } } } public event Action<byte[], int> OnDataReceived; public event Action<string> OnError; public void Dispose() { _running = false; _port?.Close(); _port?.Dispose(); } }

这段代码做了三件关键的事情:打开串口、启动后台接收线程、把收到的原始字节通过事件抛给上层。注意几个参数的含义:

  • ReadTimeout = 500很关键。如果串口已经打开但一直收不到数据,Read方法会阻塞线程,设置超时之后每 500ms 返回一次,线程才有机会检查退出标记,否则关闭窗体时线程会卡死在 Read 上,程序不干净退出。
  • volatile bool _running用于跨线程控制循环状态。工业程序里常见问题就是关闭串口时接收线程还在跑,之后往已释放的资源上写数据,直接抛异常。
  • 事件回调里拿到的buffer是同一个数组,上层解析必须在回调完成前拷贝数据或同步解析,不能在回调返回后再异步使用这个数组里的内容,否则会被下一次接收覆盖。

3.2 帧校验与数据解析:把距离值从字节流里抠出来

串口收到的是一连串没有边界的字节流,协议解析做的事情就是给这段流找到边界、校验完整性、再取数据字段。基恩士激光测距这一类传感器,很多型号采用 ASCII 命令响应式协议,即上位机发一个短命令,传感器返回一段以文本表示的帧。

using System; using System.Text; public class LaserFrameParser { // 传入串口收到的原始字节,尝试解析出一帧距离值 public static bool TryParse(byte[] buffer, int count, out float distance) { distance = 0f; if (count < 16) return false; // 常见帧格式长得像这样: // ": SR,001,12.345\r\n" // 冒号开头代表帧头,CRLF 代表帧尾 string text = Encoding.ASCII.GetString(buffer, 0, count); text = text.TrimEnd('\r', '\n'); if (!text.StartsWith(":")) return false; string[] parts = text.Split(','); if (parts.Length < 3) return false; return float.TryParse(parts[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out distance); } }

这个解析逻辑看起来简单,但在实际串口环境下有两个必须处理的坑:

第一是粘包。传感器如果按固定频率连续发送,串口缓冲区里可能一次到达多个帧,比如": SR,001,10.111\r\n: SR,001,10.112\r\n",上面这个写法只能解析出第一个数字,后半个帧会黏在下一次读取里。我一般会做一个环形缓冲或者累积字符串,找到完整帧尾再切割,而不是每次收到多少就解析多少。

第二是解析失败的信息丢失。如果TryParse返回 false 就忽略,后面根本无法判断是协议不匹配、命令字不对还是校验失败。所以解析失败时我会把原始字节转成 Hex 字符串写入日志,排查时对照传感器手册的命令说明就很快。

3.3 心跳与自动重连:工业现场最容易翻车的地方

工业串口连接不是一劳永逸的。传感器断电、串口线被踩、PLC 侧复位都可能导致通讯断开,如果上位机没有重连机制,操作员只能在现象里发现“怎么又不更新了”然后再手动重开软件。常见的做法是为采集服务加一个心跳任务,定时发送查询命令,连续多次无响应就重连。

public class LaserDataService { private readonly LaserSerialPort _serial; private int _missCount; private const int MissLimit = 5; public void Start() { var timer = new System.Windows.Forms.Timer { Interval = 500 }; timer.Tick += (s, e) => Heartbeat(); timer.Start(); } private void Heartbeat() { if (!_serial.IsOpen) { TryReconnect(); return; } _serial.Send("MR,001\r\n"); // 查询指令,不同型号自己在协议层替换 _missCount++; if (_missCount >= MissLimit) { TryReconnect(); _missCount = 0; } } }

心跳周期 500ms、连续 5 次没响应就重连,这个组合意味着传感器短暂卡顿不会触发重连,但真正断线 2.5 秒内就能被发现。重连时先 Dispose 旧的串口对象再重新 Open,顺序不能反,否则新的连接还没建立,旧资源又占着端口,端口就会报 Access Denied。

4. 数据呈现与落盘:实时曲线和 CSV 导出的落地

4.1 实时曲线:用图表控件画距离趋势

数据解析出来之后,接下来就是展示层的活。WinForms 自带的 Chart 控件足够满足产线实时监测的需求,不需要引入额外的绘图库。更新曲线时最容易犯的错误是在接收线程里直接访问 UI 控件,这会导致跨线程操作异常,表现为界面随机闪退或者控件不刷新。

public class MainForm : Form { private Chart _chart; private int _pointIndex; private void OnDistanceUpdated(float mm) { if (InvokeRequired) { // 跨线程调用,转到 UI 线程执行 BeginInvoke(new Action<float>(OnDistanceUpdated), mm); return; } // 最新值显示在文本框中 txtDistance.Text = mm.ToString("0.000"); // 追加到曲线 Series var series = _chart.Series["distance"]; series.Points.AddXY(_pointIndex++, mm); // 保留最近 500 个点,避免无限制增长导致界面卡顿 while (series.Points.Count > 500) { series.Points.RemoveAt(0); } } }

这里BeginInvoke是 WinForms 跨线程更新控件的标准姿势,它会异步把委托排队到 UI 线程消息循环里执行。InvokeRequired判断当前线程是不是 UI 线程,如果是接收线程触发的回调就转一手。每次只保留 500 个点,是为了避免长时间运行后内存里的序列点越积越多,绘图开销猛增,界面变得迟钝。曲线只用于观察趋势,不需要完整的历史,完整数据交给 CSV 落盘。

4.2 数据落盘:CSV 导出与编码细节

数据记录是这类采集程序的重要功能,现场的生产追溯、质检记录都依赖它。CSV 是最通用的落盘格式,便于事后用 Excel 或脚本分析。落盘逻辑按时间戳追加写入,这一点在生产环境里特别重要——不能等程序退出才统一写,一旦中途断电,之前的数据就全丢了。

public static class CsvExporter { private static readonly object LockObj = new object(); public static void AppendDistance(string filePath, DateTime time, float distance) { // 多线程写入时加锁,防止两帧数据互相穿插 lock (LockObj) { string line = string.Format("{0:yyyy-MM-dd HH:mm:ss.fff},{1:F3}", time, distance); File.AppendAllText(filePath, line + Environment.NewLine, new UTF8Encoding(true)); // 带 BOM,Excel 直接打开不乱码 } } }

几条关键细节:LockObj保证多线程场景下数据行不会交叉;时间戳精确到毫秒,因为传感器采集频率高,同一秒内会有多条记录,没有毫秒就分不清先后;new UTF8Encoding(true)生成带 BOM 的 UTF-8 文件,Excel 直接打开中文不乱码,如果你用记事本另存过 UTF-8 无 BOM 的 CSV,应该懂这个参数的重要性。生成的文件内容大致是这个样子:

时间距离(mm)
2025-01-10 14:23:01.10212.345
2025-01-10 14:23:01.11212.347
2025-01-10 14:23:01.12212.344

5. 调试避坑记录:串口、编码与线程的五类翻车现场

5.1 串口打开报 Access Denied,程序重启后恢复

现象:上位机启动时Open()抛异常,提示串口被占用,重启软件又正常。

原因:上次运行没有正常释放串口资源。常见于调试过程中直接点停止或程序异常退出,Dispose()没有被执行,系统还认为这个端口被占用。

解决:一是给串口对象加using或finally保证释放;二是在调试工具里用进程管理器查看残留进程,把之前跑挂的调试实例杀掉。我一般会在Open()外层包一个重试逻辑,第一次失败等 200ms 再试三次,能绕过不少偶发占用。

5.2 数据一会儿正常一会儿乱码,测量值随机跳变

现象:数值大部分时候正确,偶尔出一个完全离谱的距离,比如 1.2mm 跳成 45.0mm。

原因:多半是波特率或校验位不匹配,或者接线距离太长、线缆质量差导致字节位错误。还有一种情况是传感器默认输出的是 ASCII 码,上位机按二进制去读了,导致高字节被只读了一半,数据整体错位。

解决:先用串口调试助手手工发命令,看原始返回是不是符合说明书里的帧格式。对不上就先调整串口参数,而不是改代码。如果原始数据中间夹着?或者乱码符号,优先怀疑波特率。

5.3 界面假死,只有最小化和关闭能用

现象:程序运行一段时间,界面点哪里都没反应,曲线不刷新。

原因:接收线程在每次数据到达时都Invoke发到 UI 线程,如果 UI 线程的处理逻辑太重,比如在 UI 事件里同步写文件,消息队列就会积压,最终卡死。

解决:写文件等耗时操作不要放在 UI 线程里,用后台队列或独立线程处理,界面只做展示。我在项目里的做法是再加一个Queue<DataRecord>,UI 线程只负责取队列里的最新值刷新,数据落盘单独开线程消费。

5.4 距离值总是差一个固定常数,比如偏大 0.05mm

现象:面板显示 10.00mm,上位机显示 10.05mm,差值固定。

原因:传感器或通讯模块配置了多段量程、零点偏移,或者输出单位不一致。最典型的是帧里的数据单位是 μm,代码里当成 mm 用,个别型号返回的是带符号的距离,按无符号解析就会在一个固定方向上偏移。

解决:把原始帧的值先原样打印,和传感器面板对比,确认单位和小数位,再在解析层做统一换算,不要在 UI 层到处除以 1000,很容易漏改。

5.5 CSV 用 Excel 打开中文乱码,用记事本打开正常

现象:CSV 文件里如果是纯数字没问题,但中文字段全是乱码。

原因:文件是 UTF-8 无 BOM 编码,Excel 默认按 ANSI 去读,导致中文解析错位。

解决:写入时使用new UTF8Encoding(true)带 BOM 输出,这个问题在工程里几乎必遇,写法在前面落盘代码里已经贴过,项目里所有 CSV 写入都要保持这个设定,不要一部分带 BOM 一部分不带。

6. 二次开发思路:协议抽象、以太网改造与验证方法

6.1 把协议解析抽成策略类,换传感器型号只改一处

原工程的LaserFrameParser直接解析具体帧格式,换型号就得改这个类里的解析逻辑,很容易改坏现有功能。我会在这个基础上抽一个策略接口,把不同型号的差异隔离开:

public interface ILaserFrameParser { bool TryParse(byte[] buffer, int count, out float distance); } public class TypeAParser : ILaserFrameParser { // 原解析逻辑 } public class TypeBParser : ILaserFrameParser { // 新型号解析逻辑 }

然后在工厂里根据配置文件里的型号字符串创建对应解析器。这样接入新传感器时,新增一个类、改一行配置即可,老型号不受影响。

6.2 串口改成 TCP 采集,上层代码基本不动

通讯层再补一个LaserTcpClient,实现和LaserSerialPort相同的数据事件接口,接收循环里用NetworkStream.Read代替SerialPort.Read,上层的数据服务、界面曲线完全不感知。这是分层设计最直接的回报——通讯替换被限制在一个文件里,而不是整片代码。

var tcp = new LaserTcpClient("192.168.1.20", 9000); tcp.OnDataReceived += (data, len) => { if (LaserFrameParser.TryParse(data, len, out float d)) { OnDistanceUpdated(d); } }; tcp.Open();

6.3 改造完成的验证方法

验证建议分两走:先跑软的,再上硬的。软验证用一个模拟数据源,定时发送预设好的帧文本,验证解析和界面逻辑;硬验证接真机,打开串口调试工具边看原始报文边对比界面值。模拟器验证通过不代表现场没问题,串口这潭水必须实测过才算数。

聊到验证,就想起那次的教训:当时改完解析逻辑,只在模拟器上跑通了就上产线,结果真机数据里有帧尾多一个空格的小差异,解析全部失败,白跑一趟现场。从那以后我每次都强制走一遍完整流程——模拟器验证解析逻辑、真机抓原始报文对比格式、再上 UI。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

HDFS NameNode元数据修复:fsck诊断与edits恢复实战

HDFS NameNode元数据修复:fsck诊断与edits恢复实战

凌晨两点&#xff0c;群里弹出告警&#xff1a;NameNode 进程起来了&#xff0c;但集群一直停在 Safe Mode ON。新任务全部卡住&#xff0c;读请求半路超时&#xff0c;业务方在群里连发问号。我打开 NameNode 日志&#xff0c;顺手敲了hdfs dfsadmin -safemode get和hdfs fsck…

2026/10/20 22:16:04 阅读更多 →
SKILL.md:测试工程师的轻量级能力契约规范

SKILL.md:测试工程师的轻量级能力契约规范

1. 项目概述&#xff1a;SKILL.md 不是文档&#xff0c;是 Agent 的“上岗说明书”你有没有遇到过这种情况&#xff1a;团队里新来了一个测试同学&#xff0c;刚配好环境、装完工具&#xff0c;对着一堆自动化脚本和接口文档发懵——“这个用例跑不通&#xff0c;是环境问题&am…

2026/10/20 22:14:33 阅读更多 →
从脚手架到产品:DeepSeek Harness插件化架构设计与实践

从脚手架到产品:DeepSeek Harness插件化架构设计与实践

做模型集成这个领域久了&#xff0c;你会慢慢发现一个规律&#xff1a;大多数工具最后不是死于功能太少&#xff0c;而是死于接口太死。DeepSeek Harness 这个项目&#xff0c;最初只是我在某个模型接入需求里随手搭的脚手架&#xff0c;后来它因为一套插件机制越长越像产品&am…

2026/10/20 22:14:33 阅读更多 →

最新新闻

动作单元驱动的能量流管理:知识工作者的复利提效法

动作单元驱动的能量流管理:知识工作者的复利提效法

1. 项目概述&#xff1a;这不是“躺平”&#xff0c;而是用系统性思维重构日常工作的能量守恒“躺平挖 alpha”这个标题一出来&#xff0c;很多人第一反应是调侃——又一个打鸡血式的时间管理法&#xff1f;或者干脆是反内卷的消极宣言&#xff1f;其实完全不是。我在某实验室带…

2026/10/20 22:54:43 阅读更多 →
截断SVD为何最优?Eckart-Young-Mirsky定理精讲与工程实践

截断SVD为何最优?Eckart-Young-Mirsky定理精讲与工程实践

如果你平时的工作离不开矩阵分解&#xff0c;那你一定绕不开Eckart-Young-Mirsky定理。这个定理还有一个更常用的名字——截断SVD最优性定理。说白了就是&#xff1a;任意一个矩阵&#xff0c;你想用一个低秩矩阵去近似它&#xff0c;只要用谱范数或Frobenius范数来衡量误差&am…

2026/10/20 22:54:43 阅读更多 →
深度学习实战:番茄成熟度识别与采摘点检测全流程解析

深度学习实战:番茄成熟度识别与采摘点检测全流程解析

智慧农业这几年喊得响&#xff0c;但真正能落地的场景里&#xff0c;番茄成熟度识别绝对算一个刚需。不管是大棚里挂满枝头的樱桃番茄&#xff0c;还是连栋温室里的串收大果&#xff0c;采摘自动化要解决的第一件事&#xff0c;就是让机器知道“哪个该摘、哪个不该摘、该摘的位…

2026/10/20 22:54:43 阅读更多 →
阿里云腾讯云华为云对比:计算存储网络数据库安全五维选型避坑指南

阿里云腾讯云华为云对比:计算存储网络数据库安全五维选型避坑指南

简介&#xff1a;这份文档面向企业技术人员、运维人员及云计算初学者&#xff0c;系统梳理主流云平台的核心概念与选型思路&#xff0c;帮助读者理解云计算平台的基本原理、企业应用价值以及不同厂商之间的差异。资源为单个doc文件&#xff0c;压缩包约306KB&#xff0c;内容以…

2026/10/20 22:54:43 阅读更多 →
未来编程的角色责任:从编码执行者到全链路负责人

未来编程的角色责任:从编码执行者到全链路负责人

每次聊到“未来编程的角色与责任”&#xff0c;我总想起自己刚入行那会儿&#xff1a;接到需求就闷头写代码&#xff0c;写完能跑就觉得万事大吉。后来才慢慢明白&#xff0c;编程从来不只是把逻辑翻译成机器指令那么简单&#xff0c;它背后牵扯的是一个人在整个系统里的定位&a…

2026/10/20 22:54:43 阅读更多 →
交互模拟API与动态沙盒:从代码执行到Agentic响应流的工程实践

交互模拟API与动态沙盒:从代码执行到Agentic响应流的工程实践

如果你最近上手过带代码执行能力的大模型应用&#xff0c;多半有过类似的体验&#xff1a;同样是"帮我分析这份数据"这句请求&#xff0c;传统接口只回你一段建议自己动手的说明文字&#xff0c;而升级后的交互模拟 API 会直接给你一个能跑代码、能读文件、能出图表的…

2026/10/20 22:53:41 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →