RFCOMM协议深度解析:蓝牙虚拟串口的原理、帧结构与实战排查

1. 从一个“看不见的串口”说起:RFCOMM到底在解决什么问题

很多人第一次接触RFCOMM,是在调试蓝牙模块的时候。你打开一个串口工具,选好COM口,敲几个AT指令,模块就乖乖回你数据。但突然有一天,你发现这个串口并不是真的插在电脑上的USB转TTL,而是通过蓝牙连过去的——远端设备明明没有物理串口线,本地却凭空多出来一个COM口。这背后干活儿的,就是RFCOMM。

RFCOMM的全称是Radio Frequency Communication,直译过来叫“射频通信”。但这个名字其实有点误导人,它跟“射频”本身没太大关系,真正干的事是在蓝牙链路上模拟出一条标准的RS-232串口。你可以把它理解成一根“虚拟串口线”:一端连着你的应用程序,另一端连着蓝牙协议栈,中间的数据被封装成帧,通过L2CAP层发出去,到了对端再拆开还原成串口数据。对上层应用来说,它根本感知不到蓝牙的存在,只觉得自己在操作一个普通的串口。

这个机制解决的核心痛点是兼容性。串口是几十年前就定下来的工业标准,海量的设备、工具、代码都围绕串口构建。如果为了用蓝牙,要求所有应用都改成调用蓝牙API,那迁移成本高得离谱。RFCOMM的思路很聪明:不动上层,只在下面加一层“翻译”,让老应用零改动就能跑在蓝牙上。这也是为什么直到今天,大量蓝牙模块、车载系统、工业采集设备、医疗仪器还在用RFCOMM做数据传输。

适合读这篇内容的人,大概分三类:一是做蓝牙模块固件或驱动的开发者,需要理解协议栈分层;二是做上位机或嵌入式应用的人,想搞清楚为什么串口有时候会断、会卡、会丢包;三是刚入门蓝牙协议栈的学生或爱好者,想找一个切入点把L2CAP、SDP、RFCOMM这条线串起来。我会尽量用“人话”把协议细节讲透,同时给出可以直接参考的配置和排查方法。

2. RFCOMM的整体设计与协议栈定位

2.1 它在蓝牙协议栈里站在哪一层

要理解RFCOMM,先得知道它在协议栈里的位置。蓝牙协议栈大致可以分成三层:底层是控制器(Controller),负责射频、基带、链路管理;中间是主机(Host),跑L2CAP、RFCOMM、SDP这些逻辑;最上面是应用层(Profile/App)。RFCOMM属于Host层,坐在L2CAP之上、应用之下。

具体来说,数据流向是这样的:应用把数据写进虚拟串口,RFCOMM把数据切成帧,加上地址、控制、长度、校验等字段,交给L2CAP;L2CAP再把RFCOMM帧塞进自己的数据包,通过HCI传到控制器,最后经射频发出去。对端收到后反向拆解,一层层还原,最终把数据交给对端的应用。这个分层的好处是每一层只管自己的事:L2CAP管多路复用和分段重组,RFCOMM管串口语义,应用管业务逻辑。

提示:很多人会把RFCOMM和SPP搞混。SPP(Serial Port Profile)是“串口剖面”,是一个应用场景的规范;RFCOMM是实现这个规范所依赖的传输协议。SPP规定了设备之间怎么建立串口连接、怎么传数据,而RFCOMM提供了底层的多路串口通道。简单说,SPP是“要做什么”,RFCOMM是“怎么做”。

2.2 为什么是“模拟”而不是“真串口”

有人会问,既然蓝牙有自己的数据传输通道,为什么不直接定义一个“蓝牙串口”,而要费劲去模拟RS-232?原因在于RS-232不只是一根线,它包含了一整套信号语义:TX、RX、RTS、CTS、DTR、DSR、DCD、RI,还有波特率、数据位、停止位、校验位这些参数。工业设备依赖这些信号做流控、做状态指示、做唤醒。如果蓝牙重新定义一套,那所有设备都得改。

RFCOMM的做法是:把RS-232的9针信号“映射”成蓝牙链路里的控制信号。它定义了两种帧类型——数据帧和控制帧。数据帧承载实际的串口数据,控制帧承载MSC(Modem Status Command)等信号变化。比如本地把DTR拉高,RFCOMM就发一个控制帧告诉对端“我这边DTR变了”,对端再把这个变化反映到自己的虚拟串口上。这样,上层应用看到的信号行为跟真串口几乎一致。

当然,模拟终归是模拟。真串口的信号是物理电平,变化是即时的;RFCOMM的控制帧要经过编码、排队、传输,会有延迟。所以对时序要求极高的场景(比如某些硬实时流控),RFCOMM可能不够用。但对绝大多数数据透传场景,它已经足够。

2.3 多路复用:一条链路跑多个串口

RFCOMM最实用的设计之一,是支持在一条蓝牙链路上同时跑多个串口通道。它用“数据链路连接标识”(DLCI)来区分不同的通道,DLCI从2到61,理论上一条链路可以开60个串口。这个设计很像TCP的端口:一条物理链路,多个逻辑连接,互不干扰。

这个能力在实际中很有用。比如一个蓝牙网关,同时连了温湿度传感器、电子秤、打印机三个设备,每个设备走一个DLCI,上位机就能同时开三个COM口分别读写,不用为每个设备单独建一条蓝牙链路。链路建立的开销被摊薄了,功耗和延迟都更优。

DLCI的分配有讲究。DLCI 0是控制通道,用来协商参数、建链、拆链;DLCI 1通常保留;DLCI 2及以上才是数据通道。建链时,发起方会发一个PN(Parameter Negotiation)命令,里面带上自己要用的DLCI、帧大小、流控方式等。对端如果同意,就回一个PN响应,通道就算通了。如果DLCI已经被占用,对端会拒绝,发起方得换一个。

3. 帧结构深度拆解:每一个字节都有它的道理

3.1 基本帧格式长什么样

RFCOMM的帧结构借鉴了HDLC(高级数据链路控制),但做了简化。一个标准帧由以下几部分组成:

字段长度作用
地址1字节包含DLCI和帧类型(命令/响应)
控制1字节标识帧的种类,如SABM、UA、DM、UIH
长度1或2字节指示信息字段的字节数
信息可变实际载荷,控制帧放参数,数据帧放串口数据
FCS1字节帧校验序列,用于检错

地址字段的低6位是DLCI,第2位是C/R位(命令/响应),最低位是EA位(地址扩展)。控制字段里,最常用的是UIH(Unnumbered Information with Header check),它表示这是一个带校验的数据帧。长度字段有个技巧:如果长度小于128,用1字节表示,最高位为0;如果大于等于128,用2字节,第一字节最高位为1,低7位是长度低7位,第二字节是长度高8位。这个设计是为了兼容HDLC,同时支持大帧。

FCS用的是CRC-8,多项式是x^8 + x^2 + x + 1。发送方算好FCS附在帧尾,接收方重新算一遍,不一致就丢帧。这个校验能挡住大部分传输错误,但挡不住恶意篡改——RFCOMM本身没有加密,安全靠上层。

3.2 控制帧的几种类型和用途

控制帧不承载业务数据,只用来管理链路。常见的几种:

  • SABM(Set Asynchronous Balanced Mode):建链请求。发起方发SABM,对端如果同意就回UA,通道建立。
  • UA(Unnumbered Acknowledgment):肯定应答。收到SABM或DISC后回UA,表示“我收到了,同意”。
  • DM(Disconnected Mode):拒绝或断开。如果对端不想建链,或者通道已断,回DM。
  • DISC(Disconnect):拆链请求。一方要关通道,发DISC,对端回UA,通道关闭。
  • UIH(Unnumbered Information with Header check):数据帧。承载串口数据,带FCS校验。
  • MSC(Modem Status Command):调制解调器状态命令。用来传递RTS、CTS、DTR、DSR等信号的变化。

这些帧的交互构成了RFCOMM的“信令面”。数据面就是UIH帧的来回。信令面和数据面共用同一条L2CAP通道,靠地址字段里的DLCI区分。

注意:SABM和UA的交互是“三次握手”的简化版。发起方发SABM后,会启动一个定时器(通常叫T1),如果在超时前没收到UA,就重发SABM,重试几次后放弃。这个机制保证了建链的可靠性,但也意味着如果对端不响应,建链会卡住一段时间。调试时如果发现连不上,先看是不是卡在SABM重试。

3.3 长度字段的编码细节与坑

长度字段的编码是新手最容易踩坑的地方。前面说了,小于128用1字节,大于等于128用2字节。但具体怎么区分?规则是:第一个字节的最高位(bit 7)如果是0,表示这是1字节长度,低7位就是长度值;如果是1,表示这是2字节长度,低7位是长度的低7位,第二个字节是长度的高8位。

举个例子:长度是100,二进制是01100100,最高位0,所以1字节表示,就是0x64。长度是200,二进制是11001000,超过127,得用2字节。第一字节:最高位1,低7位是200的低7位,200 & 0x7F = 0x48,所以第一字节是0x80 | 0x48 = 0xC8;第二字节是200 >> 7 = 1,即0x01。所以长度字段是0xC8 0x01。

这个编码方式跟很多协议不一样,写解析代码时容易搞错。我见过有人直接把两字节当小端整数读,结果长度算出来完全不对。正确做法是先读第一字节,判断最高位,再决定读几个字节。

4. 建链、传数据、拆链:一次完整交互的实操记录

4.1 从SDP查询到L2CAP通道建立

RFCOMM通道不是凭空建的,得先知道对端在哪个L2CAP通道上监听。这个信息通过SDP(服务发现协议)查。流程大致是:

  1. 发起方通过SDP查询对端的服务记录,找UUID为0x1101(Serial Port)的记录。
  2. 服务记录里有一个ProtocolDescriptorList,里面包含RFCOMM的通道号(Server Channel)。
  3. 发起方用这个通道号,向对端的L2CAP PSM 0x0003发起连接。
  4. L2CAP通道建立后,RFCOMM层开始在这个通道上跑信令。

这里有个细节:RFCOMM的L2CAP PSM固定是0x0003,所有RFCOMM流量都走这个PSM。但一个设备可能有多个RFCOMM服务,靠Server Channel区分。Server Channel是1到30的值,在SDP记录里声明。发起方连上L2CAP后,在RFCOMM信令里用这个Server Channel作为DLCI来建数据通道。

实测中,SDP查询有时候会慢,尤其是对端服务多的时候。如果应用对连接速度敏感,可以缓存SDP结果,下次直接连。但缓存有风险:对端服务可能变了,通道号可能变。稳妥做法是每次连接前查一次,或者设一个合理的缓存过期时间。

4.2 PN协商:参数谈不拢就建不了链

L2CAP通道通了之后,发起方要发PN命令,协商数据通道的参数。PN命令里带这些字段:

  • DLCI:发起方想用的数据通道号。
  • 帧大小:发起方愿意接收的最大帧长,默认127,可协商到更大。
  • 初始信用:如果用了基于信用的流控,这里给初始信用值。
  • 优先级:通道优先级,一般设0。
  • ACK定时器:等应答的超时时间,单位是秒的十分之一。
  • 最大重传次数:重传几次后放弃。

对端收到PN后,如果同意,回一个PN响应,里面的参数可能跟请求一样,也可能调整。比如对端觉得帧太大,会回一个更小的值。发起方收到响应后,用双方都接受的值作为最终参数。如果对端拒绝(比如DLCI被占),会回DM,发起方得换DLCI重试。

提示:帧大小协商很关键。如果发起方声明能收127字节,对端却发来200字节的帧,发起方会直接丢帧。所以双方必须就帧大小达成一致。实际开发中,建议把帧大小设成双方都支持的最大值,减少分片开销。但也不能太大,L2CAP的MTU有限制,太大反而会触发L2CAP分片,增加延迟。

4.3 数据帧的发送与接收流程

通道建好后,数据帧(UIH)就可以来回发了。发送流程:

  1. 应用把数据写到RFCOMM的发送缓冲区。
  2. RFCOMM根据协商的帧大小,把数据切成不超过帧大小的块。
  3. 每个块加上地址、控制、长度、FCS,组成UIH帧。
  4. UIH帧交给L2CAP,L2CAP根据MTU决定是否再分片。
  5. L2CAP包通过HCI传到控制器,发出去。

接收流程反过来:

  1. 控制器收到数据,通过HCI上传到Host。
  2. L2CAP重组分片,还原出RFCOMM帧。
  3. RFCOMM检查FCS,如果错就丢帧。
  4. 检查地址字段的DLCI,找到对应的数据通道。
  5. 把信息字段的内容放到接收缓冲区,通知应用读取。

这里有个流控问题。如果应用读得慢,接收缓冲区会满。RFCOMM支持两种流控:基于信用的流控和基于MSC的流控。基于信用的流控是:接收方给发送方一定数量的“信用”,发送方每发一帧信用减一,信用为0就停发,直到接收方再给信用。基于MSC的流控是用RTS/CTS信号:接收方拉低CTS,发送方就停发。两种方式可以单独用,也可以一起用。

实测中,基于信用的流控更可靠,因为它不依赖信号线的时序。但有些老设备只支持MSC流控,那就得用MSC。配置时要注意双方流控方式一致,否则会出现一方拼命发、另一方来不及收的情况。

4.4 拆链与异常断开的处理

正常拆链是发DISC,对端回UA,通道关闭。但实际中更多是异常断开:蓝牙链路断了、对端掉电、信号丢失。这时候RFCOMM层会收到L2CAP的断开通知,然后向上层报告通道断开。

异常断开时,发送缓冲区里没发完的数据会丢。如果应用要求可靠传输,得自己做重传或确认。RFCOMM本身不保证数据一定到达,它只保证帧的完整性(FCS校验),不保证送达。这一点跟TCP不同,TCP有重传和确认,RFCOMM没有。所以对可靠性要求高的场景,要么用上层协议补,要么用带确认的应用层协议。

注意:拆链时如果还有数据在缓冲区,最好先等数据发完再拆。有些实现会在DISC前发一个“排空”命令,但这不是标准。稳妥做法是应用层先停止写数据,等缓冲区空了再拆链。

5. 常见问题与排查技巧实录

5.1 建链失败:SABM没响应怎么办

建链失败是最常见的问题。现象是:L2CAP通道通了,但RFCOMM数据通道建不起来,应用层报“连接超时”。排查思路:

  • 先看SDP查询是否成功。如果SDP没查到服务记录,说明对端没注册SPP服务,或者UUID不对。用SDP工具查一下对端有哪些服务。
  • 再看L2CAP是否连上。如果L2CAP都没连上,可能是PSM不对,或者对端没监听。RFCOMM的PSM是0x0003,确认对端确实在这个PSM上监听。
  • 然后看SABM是否发出、是否有UA回来。用蓝牙抓包工具抓一下空口数据,看SABM发了没,对端回了什么。如果对端回DM,说明对端拒绝建链,可能是DLCI被占或参数不接受。
  • 最后看PN协商。如果SABM通了但PN失败,看PN响应里的参数,是不是帧大小或流控方式谈不拢。

我踩过的一个坑:对端的Server Channel是1,我这边却用DLCI 2去建链,结果对端回DM。原因是SDP记录里Server Channel是1,但RFCOMM建链时用的DLCI应该是Server Channel的值,不是随便选的。后来改成用SDP查到的通道号,就通了。

5.2 数据丢包:FCS错误和缓冲区溢出

数据丢包有两种常见原因:FCS错误和缓冲区溢出。FCS错误通常是传输干扰或帧边界错位。如果抓包看到大量FCS错误,检查一下空口质量,或者看看是不是有别的设备在干扰。缓冲区溢出则是接收方处理不过来,发送方还在发。解决办法是启用流控,让发送方知道接收方的缓冲情况。

还有一种隐蔽的丢包:帧大小不一致。发起方声明能收127字节,对端却发来200字节的帧,发起方直接丢。这种丢包在抓包工具里看是“帧长度超出预期”。解决办法是建链时把帧大小协商清楚,双方用同一个值。

5.3 延迟高:从帧大小到流控的调优

RFCOMM的延迟来源有几个:帧大小、流控、L2CAP分片、空口重传。帧太小,帧数就多,每帧都有头开销,有效载荷比例低,延迟自然高。帧太大,L2CAP可能分片,分片重组增加延迟。经验值是把帧大小设成L2CAP MTU减去头开销,这样一帧正好一个L2CAP包,不分片。

流控也会增加延迟。基于信用的流控如果信用给得少,发送方经常要等信用,延迟就上去了。可以适当增加初始信用,或者用MSC流控,让接收方用CTS信号实时控制。

空口重传是延迟的大头。如果信号不好,蓝牙基带会重传,延迟可能到几十毫秒甚至上百毫秒。这种延迟RFCOMM层控制不了,只能优化空口环境,比如缩短距离、减少干扰。

5.4 常见问题速查表

现象可能原因排查方法解决思路
建链超时SDP查不到服务用SDP工具查对端服务确认对端注册了SPP,UUID正确
建链超时L2CAP连不上检查PSM和监听状态确认对端在0x0003监听
建链超时SABM无响应抓包看SABM和UA检查DLCI是否被占,参数是否接受
数据丢包FCS错误抓包看FCS错误计数优化空口环境,检查帧边界
数据丢包缓冲区溢出看接收缓冲水位启用流控,增加缓冲
数据丢包帧大小不一致抓包看帧长度建链时协商帧大小
延迟高帧太小算有效载荷比例增大帧大小到L2CAP MTU
延迟高流控太严看信用或CTS增加初始信用,改用MSC
延迟高空口重传看基带重传计数优化空口环境
异常断开链路丢失看L2CAP断开原因应用层加重连和重传

6. 从RFCOMM延伸出去:它还能怎么用

RFCOMM虽然老,但生命力很强。除了传统的串口透传,它还在一些意想不到的地方发挥作用。比如有些音频设备用RFCOMM传控制命令,有些车载系统用RFCOMM传诊断数据,有些医疗设备用RFCOMM传实时波形。这些场景的共同点是:数据量不大,但对兼容性和可靠性要求高,RFCOMM正好合适。

如果你在做一个蓝牙项目,需要选传输协议,可以这样判断:如果数据是串口语义的,用RFCOMM;如果是文件传输,用OBEX;如果是音频流,用A2DP;如果是低功耗小数据,用GATT。RFCOMM的优势是成熟、兼容性好、开发资料多;劣势是功耗比BLE高,延迟比某些专用协议大。

后续如果想深入,可以研究RFCOMM和L2CAP的交互细节,比如L2CAP的分片重组怎么影响RFCOMM的帧边界,或者RFCOMM的流控怎么和L2CAP的流控配合。这些细节在调试复杂场景时很有用。

我个人在实际操作中的体会是:RFCOMM的坑大多在参数协商和流控上,把这两块搞明白,大部分问题都能解决。另外,抓包工具是必备的,没有抓包,排查全靠猜,效率太低。最后再分享一个小技巧:建链时把帧大小设成L2CAP MTU减去5(RFCOMM头4字节加FCS 1字节),这样一帧正好一个L2CAP包,不分片,延迟最低。这个值在不同平台上可能略有差异,实测几次就能找到最优值。

相关新闻

TensorFlow入门指南:从环境搭建到模型训练全流程

TensorFlow入门指南:从环境搭建到模型训练全流程

1. 从一个空项目正文说起:为什么“tensorflow”这四个字值得单独写一篇拿到这个标题的时候,项目正文是空的,关键词是空的,摘要也是空的。只有一个词:tensorflow。这种情况其实在技术社区里很常见——有人扔下一个框架名…

2026/10/20 18:01:01 阅读更多 →
基于腾讯云语音识别构建会议纪要助手:从录音到Markdown的完整实践

基于腾讯云语音识别构建会议纪要助手:从录音到Markdown的完整实践

前阵子我们团队开完周会,我盯着自己那页越写越乱的笔记发呆——需求记了半截,负责人记混了,散会十分钟后就被同事追问“刚才说的那个接口到底谁对接”。那段时间我一直在想,开会一小时,整理纪要两小时,信息…

2026/10/20 18:01:01 阅读更多 →
企业级AI落地重心转移:从模型能力到Agent与多模态输出

企业级AI落地重心转移:从模型能力到Agent与多模态输出

1. 从两条产品动态看企业级 AI 的落地重心转移1.1 这两条更新到底在说什么先把标题里的信息拆开看。第一条是某头部模型厂商推出了面向企业场景的 Agent 产品,第二条是另一家模型厂商在原有对话产品上新增了实时仪表盘和动画创作能力。两条动态放在同一天出现&#…

2026/10/20 18:01:01 阅读更多 →

最新新闻

pandas动态时间窗口实现多周期销量统计

pandas动态时间窗口实现多周期销量统计

1. 项目概述:为什么“近X天销量统计”是业务分析的起点而非终点在某电商公司做数据支持的那两年,我每天早上八点准时打开BI看板,第一眼不是看总GMV,而是盯着“近7天销量趋势”那个小卡片——它像血压计一样,能快速判断…

2026/10/20 19:20:37 阅读更多 →
YOLOv5/v8/v10离线训练工具:免环境、全链路、一键部署

YOLOv5/v8/v10离线训练工具:免环境、全链路、一键部署

简介:这是一套面向YOLO系列目标检测初学者与工程实践者的免环境训练工具集,专为解决深度学习环境配置复杂、标注效率低、模型版本兼容难等痛点而设计。资源共14个文件,包含4个说明类txt文档(含工具原理与使用引言)、4张…

2026/10/20 19:20:37 阅读更多 →
单片机一阶低通滤波位移法实现:原理、代码与实战优化

单片机一阶低通滤波位移法实现:原理、代码与实战优化

/* 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 19:20:37 阅读更多 →
ESP32S3入门不踩坑:选型对比、引脚接线到WiFi控制实战

ESP32S3入门不踩坑:选型对比、引脚接线到WiFi控制实战

/* 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 19:20:37 阅读更多 →
芯片研发中专家系统与大模型的协同:确定性正确与辅助效率的平衡

芯片研发中专家系统与大模型的协同:确定性正确与辅助效率的平衡

芯片研发圈最近有个话题挺热:大模型这么强了,以后芯片设计会不会被重写一遍?我的判断很明确——芯片研发大概率是专家系统打底,大模型在旁边做辅助。这不是保守,是跑了多个项目之后,被现实约束反复教育出来…

2026/10/20 19:20:37 阅读更多 →
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 19:19:32 阅读更多 →

日新闻

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实现详解

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

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

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

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

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

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

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在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 阅读更多 →