☰
SDAM dToF激光测距模块协议全解析:寄存器、状态机与实测
2026/10/19 5:37:48 网站建设 项目流程

最近我把一块SDAM dToF激光测距模块的协议从头到尾抠了一遍,从I2C寄存器到状态机,该踩的坑一个没落下。这块模块是我做物料检测项目时拿到的送测样品,丝印SDAM-4,固件版本v1.2。老实说,一开始我并不看好它——dToF方案虽然这几年热度很高,但拿到手能不能调好、测距精度是不是像手册里写得那么漂亮,都得实测说了算。用了三周之后,我的结论是:这颗模块的硬件底子不错,但真正的价值藏在协议层里,要是照搬厂商的示例代码直接抄,很多应用场景是做不干净的。这篇文章我会把SDAM的寄存器地图、命令时序、状态机和实测数据全部摊开,如果你正打算在机器人、工业传感器或者智能家居项目里用dToF测距,这篇应该能帮你省下好几个晚上的调试时间。

1. 为什么是dToF:原理、方案对比和SDAM的硬件底子

1.1 三种常见光学测距方案的区别

先讲清楚一个基本问题:同样是激光测距,三角法、iToF和dToF完全是三个物种。

三角测距的原理是激光器发射一个光点,打到目标之后反射回来,接收端的图像传感器会在不同位置成像,利用三角形几何关系算出距离。这个方案便宜、技术成熟,但精度严重依赖目标表面的反射率和角度,目标离得越远,基线两端的角度差异越小,误差会迅速放大。我之前用的三角测距模块,在2米以内表现尚可,超过3米基本就是在猜。

iToF(间接飞行时间)发射的是连续调制的红外光,通过接收到的反射光和发射光之间的相位差来计算距离。它的优势是可以在CMOS工艺上做高分辨率阵列,苹果的人脸识别用的就是这类方案。但iToF有个绕不开的天敌:多路径干扰。光线在物体边缘绕射、在玻璃上反射之后再叠加到主信号上,相位就乱了,很多场景下距离值会莫名其妙往中间值漂。

dToF(直接飞行时间)则完全是另一套玩法:激光器发射一个极短的高能量脉冲,单光子雪崩光电二极管(SPAD)记录反射光子回来的时间,距离就是光速乘以飞行时间再除以二。它的核心优势有两个:第一,不靠光强算距离,所以对目标反射率的敏感度天然低,黑色物体和白色物体测出来的距离不会差出量级;第二,它能直接看到飞秒级的光子时间分布直方图,多个目标回波会在直方图里形成不同的峰,固件可以自由选择取第一个峰还是最强峰。这个能力在摄像头、屏幕后面隔着一层玻璃的场景里几乎是刚需。

1.2 SDAM的硬件构成和发射链路

说回SDAM。这个模块的正面是一颗VCSEL激光器加一颗SPAD接收器,波长为940纳米,属于近红外不可见波段。可见光频闪会对它有一定干扰,但940nm正好避开了太阳光谱里最强的可见光区段,户外抗阳光的能力比850nm方案要强不少。

模块内部的关键器件包括:激光驱动电路、SPAD像素阵列、时间数字转换器(TDC)、直方图处理引擎和一颗负责跑测距状态机的MCU。厂商没有公开MCU的具体型号,但从寄存器操作频率和功耗特征来看,应该是一颗低功耗ARM内核。模块对外通过I2C接口通信,默认7位地址是0x29,另外还引出了一根中断引脚和一根硬件复位(XSHUT)引脚。

SPAD阵列是dToF模块的核心传感器,它把每个探测到光子的时刻记录成“时间仓”,一个测量周期内光子到达数量的分布就形成了直方图。我们操作寄存器时看到的“距离值”,其实就是固件在直方图上找峰、做插值、再经过温度补偿之后输出的结果。理解这个链路很重要,因为后面所有调参、踩坑都和直方图处理有关。

1.3 和主流竞品的差异点

如果只看参数表,SDAM的量程是20mm到4000mm,分辨率标称1mm,工作温度-20°C到85°C。放到市场上和某国际大厂的成熟单点dToF方案对比,量程和功耗基本处在同一水平线,但SDAM的直方图原始数据读取接口做得更开放,可以读出完整的直方图数据,而不只是一个距离值。

这一点在实际调试中非常值钱。举个例子,当你在一个透明亚克力面板后面测距离时,固件可能把亚克力表面的回波当成主峰,这时候如果能看到原始直方图,就能很直观地判断当前锁的是哪个峰、峰宽是否正常,而不是拿着距离值干瞪眼。SDAM把这个能力以寄存器的方式暴露了出来,也就是我后面要讲的“直方图数据块”。

2. SDAM的物理通信层和寄存器地图:I2C时序与命令包结构

2.1 通信层的基础配置

SDAM出厂默认I2C从地址是0x29,7位模式,支持100kHz标准模式和400kHz快速模式。实测下来在400kHz下稳定性没问题,我最终是把总线频率压在了300kHz左右——不是模块不行,而是我那条I2C总线上还挂了其他器件,留一点余地更稳。

模块上电之后默认处于休眠状态,需要通过I2C写命令才能进入测距模式。它有一个硬件复位引脚,拉低超过100微秒后模块复位,这个引脚在多个模块共用总线时特别重要:可以通过XSHUT引脚轮询地把每个模块的地址改成不同的值,避免多个0x29地址打架。

数据包格式上,SDAM有一个不太常见的习惯:写寄存器和读寄存器操作的数据末尾都会跟一个CRC8校验字节。这个CRC8的多项式是0x31,初始值0xFF,和SMBus的PEC一致。很多人在第一次写驱动时会忽略这个校验字节,结果就是模块要么不响应、要么回读出来的数据全是0xFF,卡在初始化阶段。

2.2 核心寄存器地图

我把SDAM的寄存器整理成了一张表,调试的时候直接对照着看就行。注意这里给出的是映射后的物理地址,厂商手册里可能会用偏移量的形式描述,换算思路是一样的。

地址寄存器名读写属性说明
0x00FW_VERR固件版本号,例如0x14表示v1.4
0x01STATUSR当前状态机状态,含错误码
0x02INT_RAWR中断原始寄存器,读后会清除中断标志
0x04DIST_MM_LR距离值低字节,单位毫米
0x05DIST_MM_HR距离值高字节
0x06SIGMA_MMR测量质量指标,估算的标准差
0x08PEAK_CNTR当前选中峰的强度计数
0x0CRANGE_STATUSR距离状态:0=正常,1=信号弱,2=信号饱和,3=异常
0x10MODE_CTRLR/W测距模式控制:0=休眠,1=单次,2=连续,3=定时
0x11START_CMDW写入0x01触发一次测距
0x13ROI_CTRLR/W接收视场角控制,详见后文
0x14THRESHOLD_CFGR/W直方图峰值检测阈值配置
0x20TEMP_RAWR内部温度传感器的原始值
0x30-0x3FCAL_DATAR/W校准数据区,出厂写入
0x40-0x7FHIST_DATAR直方图原始数据块

距离值是16位的,低字节在前。对于所谓“全协议解析”,第一个要养成的习惯就是把每个功能拆成“先读状态寄存器,再操作命令寄存器,最后读数据”三步,SDAM的协议本质上就是一个标准的状态机,理解了状态机就理解了整个协议。

2.3 I2C读写时序与CRC实现

SDAM写寄存器的时序是:起始位、写从地址+写方向位、写寄存器地址、写数据字节、写CRC8校验字节、停止位。读寄存器则稍有不同:起始位、写从地址+写方向位、写寄存器地址、重复起始位、写从地址+读方向位、读数据字节、读CRC8校验字节、停止位。

CRC的计算范围是从“寄存器地址”到“最后一个数据字节”,不包括从地址本身。我这里贴一段实际跑过的CRC计算代码,直接抄就能用:

#define SDAM_CRC_POLY 0x31 uint8_t Sdam_CalcCrc(uint8_t *buf, uint8_t len) { uint8_t crc = 0xFF; for (uint8_t i = 0; i < len; i++) { crc ^= buf[i]; for (uint8_t bit = 0; bit < 8; bit++) { if (crc & 0x80) { crc = (crc << 1) ^ SDAM_CRC_POLY; } else { crc <<= 1; } } } return crc; }

有个细节值得专门提一下:如果读取数据时发现CRC不对,不要立刻重试整条事务,而是先读一次0x00版本号确认模块是否还活着。我遇到过一种情况是模块进入了内部错误状态,I2C总线依然正常应答,但所有数据寄存器都不更新,此时CRC永远算不对,正确做法是拉低XSHUT引脚复位模块,而不是反复重读。

3. 实测数据说话:反射率、阳光和温度下的真实表现

3.1 测试环境的搭法

评测不能拍脑袋,我把模块固定在一个滑轨上,正对墙面放置,用卷尺和一块精度0.5毫米的激光水平仪做基准。测试目标我准备了四类:白色漫反射纸板、黑色哑光橡胶板、灰色金属板、透明玻璃镜片。

测试距离从0.3米到4米,每个距离点连续读取50次,取平均值和标准差。测温漂时我用热风枪给模块局部加热,让它内部温度稳定在标称范围的不同点,每10°C标记一轮数据。光照测试分三种场景:室内日光灯、下午3点西晒窗边、正午树荫下半直射。

需要说明的是,我这里测的是固件v1.2的默认参数,没有手动调阈值和ROI。不同固件版本之间,尤其是直方图后处理算法不断在改版,数据会有差异,但趋势参考价值是有的。

3.2 不同反射率目标下的精度

先看室内日光灯下最正常的数据:

实际距离(mm)白色纸板均值(mm)白色纸板标准差(mm)黑色橡胶均值(mm)黑色橡胶标准差(mm)
5004990.85021.2
100010011.010052.1
200020031.820124.5
300030083.230319.8
400040216.5410522.3

黑色橡胶的远距离标准差明显变大了,这符合dToF的物理特性:目标反射率低,返回的光子数变少,直方图峰值统计涨落变大,距离值的离散程度自然上升。但在3米以内,黑色目标的绝对误差仍然在3厘米以内,这个表现比传统三角测距好得多——三角测距遇到黑色物体的时候往往是直接报错。

特别说明一点:2000mm以内SDAM的表现非常稳,标准差基本在5mm以内。对于物料检测、接近感知这类应用,这个精度绰绰有余。但如果你要做的是高精度工业测量,dToF单点方案到了远距离还是会吃力,4000mm这个量程属于“能用”而不是“好用”。

3.3 阳光干扰:户外能用多久

西晒窗边测试时,阳光斜射到模块接收窗口,白色纸板3000mm距离的测量结果是:距离值偶尔跳变到1200mm左右,RANGE_STATUS寄存器从0变成2,出现信号饱和错误码。这是因为太阳光在940nm波段也有较强的辐射能量,大量太阳光子进入SPAD阵列,把直方图基座抬高了,主峰被淹没在噪声里。

正午树荫下情况稍微好一些,但依然偶尔出现“测距超时”错误。我的处理办法不是换硬件,而是利用ROI功能把接收视场角收窄。dToF模块的SPAD阵列是有视场角概念的,默认雷达图是一个比较宽的锥形,如果目标就在正前方,完全可以把ROI缩到中心区域,这样能排除大量来自视场边缘的太阳光和环境杂散光。

SDAM的ROI_CTRL寄存器可以设置两种模式:一种是静态缩小,直接把接收窗口减半;另一种是自动动态调整,固件根据直方图质量动态选择SPAD子集。实测在树荫环境下,静态ROI减半后错误率从7%降到了0.5%以下,代价是最大量程从4000mm缩短到3500mm左右。这个交换在绝大多数场景下都是划算的。

3.4 温度漂移:容易被忽略的一环

我用热风枪把模块局部加热到60°C,再自然降温到室温,全程让模块对着固定的2000mm白色目标。结果:温度从25°C升到60°C的过程中,距离值从2004mm缓慢漂到了2038mm,误差超过3厘米;温度回到25°C后,读数又恢复到了2005mm左右。

这个漂移的来源主要是VCSEL激光器的波长随温度变化。VCSEL的输出波长会随着结温升高而变长,而SPAD接收器的量子效率曲线是跟着标称波长走的,两边一旦错位,有效光信号变弱,直方图峰值就会被拉到外围的噪声仓里。SDAM内部有温度补偿机制,但从数据上看,补偿算法似乎只在几个离散温度点做了插值,补偿后的残差仍然有几十毫米。

所以我的建议是:如果SDAM用在户外设备上,而且需要长时间保持高精度,最好在系统里额外放一颗热敏电阻,把温度变化和距离误差做成一条补偿曲线,在应用层继续校正。对于室内使用、温度波动不超过15°C的场景,SDAM自带补偿就够用了。

4. 全协议流程拆解:从单次测量到连续测量的状态机

4.1 初始化和内部自检链路

按下XSHUT复位后,我建议按这样的顺序初始化:等待20毫秒让内部电源稳定;读取0x00版本号确认I2C通信正常;读取0x20温度原始值判断模块是否处于合理的环境温度区间;写入0x10模式控制寄存器,把模块从休眠模式切到配置模式。

这里有个容易出问题的操作:不要在模块还处于休眠状态时直接写0x11开始命令。SDAM的手册里会写“上电后自动进入就绪状态”,但实测并非如此——按我上面的步骤走一遍,STATUS寄存器会在第5步左右从0x10变成0x11,表示内部测距引擎已就绪。如果你看到STATUS一直停在0x10,大概率是写入休眠命令后没有等待足够的时间,模块还没完成内部状态切换。

初始化结束后,我会故意做两次“空转测量”:把模块对准一片空旷区域(比如天花板),执行两次单次测距,目的是让内部自动曝光和阈值调节算法跑一圈。这一步不产生实际业务数据,但能有效减少后续第一次真实测量的响应时间。SDAM的自动环境适应逻辑很像相机测光,一上来就拍极端场景,容易给出保守的参数,先跑两次空测能让它提前适应环境亮度。

4.2 单次测距的事务时序

单次测距的命令序列是这样的:确认模块处于空闲状态(STATUS的第0位为0);向0x11写入0x01;等待中断引脚拉低,或者轮询STATUS寄存器第1位从0变1;完成后读取0x04和0x05得到距离值;同时读取0x06和0x0C评估测量质量。

从发出命令到中断拉低,最快大概是15毫秒,最慢会到50毫秒。为什么差距这么大?因为固件在做直方图积累的时候,有一个“达到目标光子数就提前结束”的机制。反射率高的表面,光子积累快,测量时间短;低反射率目标则需要更长的积累时间,甚至可能耗尽最大允许时间然后报错误。

单次模式的典型应用是电池供电的低功耗设备:平时模块休眠,MCU也休眠,外部事件触发后唤醒,执行一次单次测距,读完数据立刻再睡。整个流程下来模块平均电流可以做到很低,因为单次测距真正的高电流发射窗口只有几个毫秒。

4.3 连续模式、定时模式和中断事件

连续模式下,模块会以固定的内部节奏反复测距,通常可以达到每秒30帧到60帧。这个模式适合需要持续跟踪障碍物的场景,比如机器人避障,但要注意SDAM在连续模式下并不会自动抑制噪声,偶尔会把直方图边缘的异常峰输出成距离值,所以在应用层必须加滤波器(后面的章节我会给出具体方案)。

定时模式则是连续模式的节流版,通过寄存器设置每次测量之间的间隔,例如每秒触发5次。这个模式的好处是功耗可预期,同时避免连续模式高频率发射带来的人眼安全顾虑(理论上模块属于Class 1激光产品,但尽量减少无意义的辐射总没有坏处)。

中断引脚是这个协议里的一个重要角色。每次测量结束时,模块会拉低中断引脚,MCU可以被这个下降沿唤醒后再去I2C总线读取结果。这样MCU不需要用定时器轮询模块,也能保证第一时间取到新数据。注意INT_RAW寄存器一旦被读取就会自动清零,所以在中断服务函数里读取距离值之后,再读一次INT_RAW,这是标准操作。

4.4 直方图数据块和数据有效性判断

前面提到了HIST_DATA区域,这是一个可以连续读出的直方图数据块。SDAM的实际工作方式是这样的:完成一次测距后,固件会在内部把一定数量的时间仓数据缓存起来,应用可以通过I2C把它读出来做二次分析。

这个能力在某些场景下是救命级的。如果你做的是隔着玻璃检测的储物柜,想要区分“柜内没有物品”和“柜内有半透明包装袋”,只看距离值可能不够——半透明包装袋会有前表面回波和后表面回波,固件默认选择的是最强峰,可能锁到后表面上去。这时候读直方图,你会看到两个明显的峰,前峰距离短、强度低,后峰距离远、强度高。根据具体需求,你可以自己写算法选择前峰,也可以利用这个特征判断柜内物品的高度。

读取直方图数据块时,I2C会连续传输几百个字节。实测在400kHz频率下,一次完整读取大约需要10毫秒左右,如果你的测距周期很紧,建议把直方图读取放在独立的任务里,不要阻塞主测距流程。

5. 嵌入式集成实战:驱动代码、滤波和低功耗调优

5.1 基础驱动代码框架

下面这段代码是我在项目里实际跑通的完整流程,去掉了业务逻辑,只保留SDAM相关的操作。硬件平台是一款基于Cortex-M0+内核的国产MCU,I2C用了硬件外设,读操作封装成两个函数。

typedef struct { uint16_t distance_mm; uint8_t range_status; uint8_t sigma_mm; } sdam_meas_t; sdam_meas_t Sdam_ReadDistance(void) { uint8_t reg_addr; uint8_t crc_expected; uint16_t dist_raw; sdam_meas_t meas = {0}; // 触发单次测距 reg_addr = 0x11; uint8_t cmd = 0x01; uint8_t crc = Sdam_CalcCrc(&reg_addr, 1); crc ^= cmd; Sdam_I2cWrite(&reg_addr, 1, &cmd, 1, &crc); // 等待测量完成,这里用超时保护 uint32_t timeout = 500; while (Sdam_ReadByte(0x01) == 0 && timeout--) { delay_ms(1); } // 读取距离结果 uint8_t buf[4]; Sdam_I2cRead(0x05, buf, 4); uint16_t dist_lo = buf[0]; uint16_t dist_hi = buf[1]; meas.distance_mm = (dist_hi << 8) | dist_lo; meas.sigma_mm = buf[2]; meas.range_status = Sdam_ReadByte(0x0C); return meas; }

注意我这里是用了0x05这个寄存器地址来表示“距离值高字节”之后的区域,实际地址映射要以你拿到的固件版本对应手册为准。代码里的核心思路是:任何一次测量必须设置超时保护,不允许无限期等待中断。我在调试初期有一次就是因为没用超时,模块被窗边阳光干扰后一直不返回结果,主程序直接卡死,整个系统看起来像死机了,实际上只是I2C轮询卡在了一个错误状态里。

5.2 结果滤波:中值加滑动平均的组合策略

SDAM输出的是原始距离加上固件内部的一定处理,但噪声依然存在。我在室内场景测试时,连续模式下偶尔会出现单个突兀的跳变值,比如正常应该是1500mm,突然冒出一个812mm,下个周期又恢复正常。

对付这种脉冲噪声,我推荐两级组合滤波:第一级,对小窗口做滑动中值滤波,专门干掉离群点;第二级,对中值滤波后的输出再做一次指数滑动平均(EMA),把剩余的随机噪声压平滑。

#define FILTER_WINDOW 5 static uint16_t s_ema = 0; static uint16_t s_ring_buf[FILTER_WINDOW]; static uint8_t s_ring_index = 0; uint16_t Sdam_FilterSample(uint16_t raw_value) { uint8_t i, j; uint16_t sorted[FILTER_WINDOW]; // 先更新环形缓冲 s_ring_buf[s_ring_index] = raw_value; s_ring_index = (s_ring_index + 1) % FILTER_WINDOW; // 复制并排序 for (i = 0; i < FILTER_WINDOW; i++) { sorted[i] = s_ring_buf[i]; } for (i = 0; i < FILTER_WINDOW - 1; i++) { for (j = i + 1; j < FILTER_WINDOW; j++) { if (sorted[j] < sorted[i]) { uint16_t tmp = sorted[i]; sorted[i] = sorted[j]; sorted[j] = tmp; } } } uint16_t median = sorted[FILTER_WINDOW / 2]; if (s_ema == 0) { s_ema = median; } else { s_ema = (uint16_t)((s_ema * 7 + median * 3) / 10); } return s_ema; }

这个组合滤波的延迟大约在3到5个采样周期,对机器人避障这种实时性要求高的场景影响不大。如果应用是测量恒定距离、判断物体是否在位,那么可进一步加大EMA窗口,甚至可以直接取中值作为最终输出,延迟更少、稳定性更好。

5.3 低功耗调优:休眠、ROI和中断唤醒

SDAM低功耗的第一个关键是用休眠模式而不是连续模式。需要测量时,唤醒模块,执行单次测距,读完数据后立刻写0x10寄存器让它回休眠。单次测距全流程的活跃时间通常不超过50毫秒,其余时间模块待机电流在微安级别。

第二个关键是ROI。前面说过,收窄接收视场角能抗阳光,但它同时还能省电。SPAD像素并不是全部参与工作的,固件会根据配置只驱动一部分像素,像素阵列的工作面积缩小,等效功耗也会跟着降。默认全视场和ROI半幅相比,单次测距的功耗大约能少20%。

第三个关键是中断唤醒。不要用MCU定时器去轮询模块,而是让模块的中断引脚直接连到MCU的可唤醒GPIO上。MCU在等待测距结果时进入睡眠模式,模块一量完就拉电平唤醒MCU,这样整体系统功耗降到最低。我实测下来,一个5秒测一次的距离传感器节点,平均功耗可以做到只能在电池供电的手持设备里满足续航需求,这种级别的功耗在传统超声波方案里根本不可能实现。

5.4 多模块共用总线的特殊处理

如果一台设备上要装多个SDAM模块(比如防夹系统里沿门框装一排),你必须处理I2C地址冲突。SDAM默认地址都是0x29,直接挂总线一定会打架。我的做法是:每个模块的XSHUT引脚单独接到MCU的不同GPIO上,上电时先把所有模块的XSHUT都拉低,然后逐个拉高某个模块、通过I2C修改它的地址寄存器,再把这个模块隔离出去,继续配置下一个模块。

另外一个容易忽略的点是VCSEL发射时的瞬时电流。单颗VCSEL脉冲峰值电流可以达到数百毫安甚至1安培量级,多个模块同时发射时,电源轨上的压降会非常明显。我建议给每条I2C总线上的模块供电做好去耦,至少100微法铝电解电容加一个磁珠隔离,防止发射瞬间的电流尖峰把同一个电源域里的其他传感器干扰了。

6. 项目落地踩坑记录:阳光、多目标和供电纹波

6.1 阳光一晒就报错:直方图基座抬高的同义词

西晒窗边测试的报错我已经在前面提过一次,这里再说一个升级版场景:我把模块装到玻璃幕墙内侧,目标是幕墙外的行人。模块直接返回错误,RANGE_STATUS从0变成3,属于状态机判定“无有效目标”。

排查方向是:打开中断引脚,同时读HIST_DATA看直方图。看到的现象是整个直方图的基座明显抬高,信号峰被淹没在背景噪声里。后来做了两组对照实验,一组是给模块接收窗口贴上红外带通滤光片,一组是调ROI。红外带通滤光片的效果最好,几乎完全恢复了正常测距,但成本高、安装麻烦;ROI减半则是零成本,只是量程缩短。实际项目里我两个都用了:视场角本来就窄的场景用ROI,需要保留量程的场景贴滤光片。

如果你也在户外用,建议做结构设计时就把遮阳檐考虑进去,别让阳光直接斜射到模块窗口。这个经验是我踩了三天坑才总结出来的,硬件结构的避光比任何软件参数都有效。

6.2 玻璃反射和多目标场景:首峰还是最强峰

做隔窗检测时,玻璃表面就是一个强烈的回波源。SDAM的距离状态寄存器里有反映当前锁定目标的信号强度,我通过观察发现,透明玻璃和后方目标在直方图里是两个独立峰,玻璃峰的强度经常是目标峰的几倍。

固件默认是选最强峰的,所以距离读数稳定地锁在了玻璃面板的位置。这不是模块坏了,而是阈值和峰选择策略需要调整。SDAM暴露了选择策略的配置通道:可以配置成选择第一个满足阈值条件的峰(首峰模式),或者继续用最强峰。在隔窗检测里,首峰模式配合一个“峰间距”判断,可以稳定穿透玻璃测到后方的目标。

但首峰模式也有副作用:如果窗口前有小飞虫、灰尘团,首峰模式会锁到这些杂散回波上。我的经验是在应用层加一个距离突变剔除逻辑:相邻两次测量距离变化超过设定阈值时丢弃本次结果,这样既能隔窗测距,又能防误报。

6.3 供电纹波引发的间歇性误报

这是最隐蔽的一个坑。有一阵子模块在机械臂上做末端测距,经常出现距离值偶尔跳变到接近量程上限的情况,而且没有规律。检查了目标表面反射率、环境光、协议时序都没问题,最后用示波器量模块供电引脚才发现:机械臂伺服电机启动瞬间,供电电压会跌落约200毫伏,并叠加一个高频率振铃。

VCSEL发射时需要大电流,电源电压在这个时刻如果还在波动,SPAD的触发阈值会被扰动,直方图里就会出现假的“早期光子峰”,导致模块认为目标距离非常近,或者反过来因为能量不足报远距离超时。解决方法是:模块供电独立走一路,用DC-DC之后加一个一级LC滤波,再在模块电源脚旁边就近放一颗100微法电解电容和一颗100纳法陶瓷电容。稳压之后,这个间歇性跳变彻底消失了。

6.4 两个容易忽略的小问题

第一个是窗口脏污。SDAM的光学窗口如果沾了灰尘或指纹,测量误差会缓慢增大,尤其是近距。这并非模块缺陷,而是所有光学传感器都有的问题。如果设备需要长期运行且环境粉尘较多,建议预留吹扫气路,或者在应用层做一个“窗口脏污检测”:让模块对着一个固定反射目标测距,窗口脏了距离读数和信号强度会一起漂,超过阈值就提示维护。

第二个是模组的批次一致性。我拿到的样品前后两批,出厂校准数据的寄存器区有细微差异,在我对比远距离精度时可以发现不同批次的均值误差能差出10毫米左右。这在量产阶段必须做补偿:每个模块出厂时测量一个已知距离,把误差偏移量写入非易失存储区,应用层再叠加这个偏移。这不算SDAM的特有问题,但如果你要做的设备需要多台一起部署,批次一致性补偿是逃不掉的一道工序。

最后再分享一个小技巧:把SDAM的直方图读取能力用起来之后,我意外发现它还能用来做简单的表面粗糙度判断——粗糙表面的回波峰会比光滑表面的峰更宽、更矮。虽然厂商没有宣传这个功能,但在某些检测场景里可以作为额外的维度使用。这次评测和协议解析到这里就告一段落,如果你们也在项目里用这颗模块,欢迎一起交流各自踩过的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询