ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深视智能SR系列3D相机SDK四种取数模式详解与选型指南

深视智能SR系列3D相机SDK四种取数模式详解与选型指南 简介深视智能SR系列3D相机SDK程序文件是一套官方二次开发例程主要面向需要对该系列3D相机进行底层数据采集与控制的软件工程师、视觉集成方案开发者和高校研究人员。针对不同项目需求SDK提供了四种可灵活切换的采集模式一次回调模式设定15000行以内一次性将采集数据全部返回是官方推荐的常规模式阻塞模式同样单次返回数据但采集期间进程阻塞适合强实时同步流程无限循环模式不限制批处理行数按固定时间窗口循环取数适合长时间连续检测2.5D模式则返回单条轮廓需提前在EdgeImaging软件中开启并关闭批处理。配套例程包含了各模式的基本调用方式开发者按照这些模板即可快速切入二次开发理解模式差异、数据返回时机和缓存处理要点减少底层协议与API的摸索成本。资源包为zip压缩包大小约18.01MB下载后解压可直接查看例程。目前已有446人学习/下载适合正在选型或已经使用深视智能SR系列相机的开发者作为参考。1. 深视智能SR系列3D相机SDK四种取数模式决定你后面三个月的工作量拿到深视智能SR系列3D相机的SDK程序文件包我建议你先别急着把demo跑起来。这个SDK和普通工业相机SDK最大的不同是它把取数方式分成了四种一次回调、阻塞、无限循环、2.5D。选错模式轻则采集线程被卡住重则控制器15000行缓存溢出轮廓数据丢得无声无息测量结果全不可信。很多做3D结构光相机的厂商都会随设备给一套SDK但深视智能这套把缓存边界暴露给了开发者理解它比多抄几个API重要。这篇内容写给视觉工程师和自动化上位机开发也适合正在把3D相机接进产线的人。下面不贴手册直接讲模式怎么选、代码怎么写、坑怎么填。2. 四种取数模式的运行机制与选型依据3D相机和2D相机最大的区别在于输出的是轮廓行而不是完整帧。每一条轮廓都对应一行激光或结构光只有连续多行拼起来才有测量意义。所以SDK必须站在批处理角度设计四种模式本质上是对“什么时候把多少行交给你”的不同回答。2.1 一次回调模式为什么官方建议二次开发优先用它一次回调模式的核心约束是设定采集行数不超过15000行SDK把这15000行内的全部轮廓装进一个数据块一次性回调给应用层。对开发者来说拿到的是一个完整批次的轮廓数组可以在回调函数里直接做滤波、找特征、算高度差不需要自己拼接不同时间片的数据。为什么官方把它列为“二次开发最建议使用模式”因为数据完整、时机明确回调触发时这一批数据已经齐了。工程上需要先算清楚“15000行到底覆盖多少物理长度”。比如相机行频是10kHz传送带速度是500mm/s那么15000行对应1.5秒覆盖750mm的物料。计算公式是有效行程除以每毫米行数每毫米行数由运动速度和行频决定。如果单个产品尺寸超过这个覆盖范围一次回调就装不下只能在触发策略上分段或者改用无限循环模式拼接。我的选型判断顺序是单次检测需要的轮廓行数是否稳定小于15000。如果是无脑选一次回调如果不是看数据能不能分段不能分段就切到无限循环模式。这里要注意“一次性返回”不代表没有延迟数据封装、DMA搬运和回调分发都会带来毫秒级延迟飞拍场景要把这部分计入节拍。和康耐视、海康威视相机的SDK一样拿到手的程序文件包里通常有头文件、库、samples但深视这边要先定模式再看demo。2.2 阻塞模式与一次回调的差异只在“阻塞”阻塞模式在一次回调模式基础上把“回调通知”换成了“调用线程等待”。同样是设定采集行数小于等于15000同样一次性返回全部数据但函数调用会阻塞直到采集完成后才把数据写到输出缓冲区。输出数据结构和一次回调几乎一样只是获取方式从异步回调变成了同步返回。这个模式适合调试。比如你要验证相机能不能触发、轮廓有没有输出用阻塞模式写一个几千行的测试程序逻辑非常直白不牵扯线程。但它不适合放到UI线程或节拍要求高的工位阻塞期间线程什么都干不了界面会卡死运动控制卡也无法及时响应。如果项目里已经有实时任务必须把阻塞调用放进独立工作线程。一个容易忽略的点阻塞模式在采集过程中如果遇到外部触发信号中断或者相机掉线阻塞可能超时或永久卡住。生产代码里要给阻塞调用加超时保护比如用额外线程等待退出信号或者SDK有超时参数就显式设置。不要依赖操作系统默认的无限等待我在一个项目里就因为没处理超时导致上位机在相机断网后再也没恢复过。2.3 无限循环模式15000行缓存是硬约束无限循环模式是四种模式里唯一不限批处理行数的模式但它要求先把控制器切到循环模式然后SDK固定时间返回一次数据。这里的关键是“控制器有15000行的缓存数据数据要及时取出”。也就是说硬件侧只给你一个15000行深度的环形缓存无论业务上需要多少行软件取出数据的速度必须跟上写入速度。判断是否跟得上的标准不是平均速度而是峰值速度。比如平均行频5kHz但每次触发瞬间可能冲到8kHz如果消费线程在取数时做解包、转float、分配内存滞后期就会出现。缓存一旦写满后面的轮廓会被丢弃或导致采集停摆。SDK不一定抛异常但你会看到轮廓行数变少或者相邻两次返回的数据时间戳不连续。所以无限循环模式的设计重点不是调用API而是消费链路。我一般会在取数回调里只做一件事把数据从SDK缓冲区拷贝到自己的队列立刻返回后续的滤波、测量、存储全在另一个线程做。这个模式还需要处理“固定时间返回一次数据”的节奏如果算法处理时间超过这个固定间隔就必须用双缓冲而不是单缓冲。2.4 2.5D模式单条轮廓不是“小数据”2.5D模式返回的是单条轮廓而不是一整段。启动有前提需要在EdgeImaging软件里打开2.5D模式并且批处理要处于OFF状态实时显示开启。也就是说这个模式本质上是把相机当作在线轮廓传感器用SDK每次拿到当前这一条轮廓的高度数据适合做对位引导、焊缝跟踪、边缘定位这类逐行处理场景。这里要区分“2.5D”和“2D”2D相机拿到的是灰度图SR系列3D相机在2.5D模式下输出的是轮廓高度序列可能还带强度信息。虽然单条轮廓数据量不大但处理频率很高逐条语义对时序要求更严格这一条和下一条之间如果漏了产品表面形状就断了。因此应用2.5D模式时我通常会在数据里保留轮廓序号和时间戳方便在测量侧做重排。另外2.5D模式要求软件端先打开对应开关这一步最容易忘。很多人代码里设置了模式但相机不返回数据排查半天发现是EdgeImaging里批处理还开着SDK和软件抢了控制权。把这一项写进部署检查清单能省一个下午。这四种模式之间不是版本差异而是硬件缓存和应用场景的平衡结果。最后给一张快速对照表方便在方案阶段直接拍板模式最大行数返回方式是否阻塞典型场景一次回调15000一次性回调否批量测量官方首选阻塞15000同步返回是调试、联调无限循环不限制固定时间返回否长物料、连续检测2.5D单条轮廓逐条返回否在线轮廓定位、跟踪3. C示例把四种模式从SDK手册搬到工程里在写任何取数逻辑前先决定SDK程序文件怎么放。我见过太多次因为路径问题导致初始化失败所以项目里我固定用一套目录结构include放头文件lib放导入库bin放动态库和依赖的运行组件。所有demo例程都从bin目录启动不要把dll散在C盘Windows目录里。这样做的好处是换一台机器部署时整个SDK目录直接拷贝过去就能跑不会出现“开发机正常、产线机报错”的鬼问题。3.1 连接相机与通用参数配置先完成SDK初始化和相机连接。下面以C为例具体函数名以SDK头文件为准我在这里只展示调用关系避免你对着手册找不到同名函数时发蒙。#include SRCameraApi.h SR_HANDLE handle SR_OpenCamera(0); if (!handle) { // 检查相机IP、USB连接和EdgeImaging是否占用 return -1; } SR_SetTriggerMode(handle, SR_TRIGGER_ENCODER); SR_SetProfileCount(handle, 8000); // 一次回调/阻塞模式下使用 SR_SetCallbackBufferSize(handle, 32); // 回调缓冲数量逻辑说明SR_OpenCamera返回设备句柄参数0是相机序号如果相机被EdgeImaging软件独占这一步会失败。SR_SetTriggerMode设置触发方式为编码器触发实际项目中还有外部硬触发和软触发两种。SR_SetProfileCount设置一次采集的行数这里设为8000低于15000上限如果你的产品需要12000行就设为12000。SR_SetCallbackBufferSize设置内部缓冲个数较大可以抗瞬时抖动但占用内存也多。参数说明行数设置不是越大越好因为一次回调拿到的数据块要分配连续内存超过15000时SDK会直接报错。缓冲个数建议不小于4否则回调还没消费完下一批数据就把缓冲占满。这个参数在无限循环模式下同样生效因为控制器只有15000行缓存缓冲个数实际是给上层消化的余量。3.2 一次回调模式实现一次回调模式的核心是注册一个回调函数SDK在数据收齐后调用它。我一般会在回调里拷贝数据而不直接做测量避免拖慢采集。void onProfileData(SR_ProfileBatch* batch, void* user) { auto* ctx static_castContext*(user); ctx-queue.Push(batch); // 只做浅拷贝把指针交给业务线程 } SR_RegisterProfileCallback(handle, onProfileData, ctx); SR_StartGrabbing(handle);这里onProfileData的batch里包含轮廓条数、每条轮廓的光点数据和状态位。回调里queue.Push把整个batch交给消费队列业务线程再Pop出来做计算。注意batch内存由SDK管理回调返回后可能被复用所以队列必须深拷贝或者显式标记“使用完毕”。我倾向于在队列里存结构体数组而不是裸指针。参数说明SR_RegisterProfileCallback的user参数可以传入上下文对象方便在回调里访问队列、日志和统计变量。SR_StartGrabbing是异步开始采集返回值不代表数据已经有效真正可用的信号是回调触发。如果你需要等待一帧完成可以配合信号量做同步。3.3 无限循环模式切换模式与及时消费无限循环模式需要先切换控制器模式再循环取数。注意切换顺序先停止当前采集再设置循环模式否则模式切换可能失败。SR_StopGrabbing(handle); SR_SetWorkMode(handle, SR_MODE_LOOP); // 切到循环模式 SR_StartGrabbing(handle); while (running) { SR_ProfileBatch* batch SR_WaitProfile(handle, 1000); // 等待一批数据 if (batch) { memcpy(myData[batch-seq % MAX], batch-points, batch-count * sizeof(SR_Point)); SR_ReleaseProfile(handle, batch); } }这个代码演示了“等一批拿一批”的消费模型。SR_WaitProfile会阻塞最多1000毫秒有数据就返回没有数据返回空指针避免纯忙等。拿到batch后立即拷贝到自己的数组然后调用SR_ReleaseProfile释放SDK内部引用。这里MAX是你本地环形缓冲的槽位数应根据最大轮廓数和测量耗时来定。参数说明batch-seq是轮廓批次序号如果发现相邻两次seq不连续说明中间丢数据了。SR_ReleaseProfile被很多人漏掉它占用15000行缓存的一个槽位不及时释放会让缓存越积越多最后表现为取数越来越慢甚至停采。把释放操作放在拷贝之后、计算之前是循环模式最稳的写法。3.4 2.5D模式的开启流程2.5D模式的代码层面和其他模式类似但前提是EdgeImaging软件端已经开启2.5D模式并将批处理置为OFF。代码侧通常只需要设置取数类型和回调模式。SR_SetWorkMode(handle, SR_MODE_2_5D); SR_SetBatchMode(handle, OFF); // 批处理关闭逐条输出 SR_RegisterProfileCallback(handle, onSingleProfile, ctx); SR_StartGrabbing(handle);注意SR_MODE_2_5D的名字不一定与手册完全一致但含义就是返回单条轮廓。SR_SetBatchMode(handle, OFF)对应批处理关闭如果批处理没有关闭SDK可能还是按批次返回单条轮廓的语义就不成立。开启后回调里每触发一次只拿到当前这一条轮廓可以直接和上一帧做位置差或高度差值计算。另外提醒一句2.5D模式需要实时显示EdgeImaging里如果开了批量输出或离线分析SDK端就进不了这个模式。我在现场遇到过一次相机在EdgeImaging里能出图但SDK一直没回调最后发现是实时显示没勾选导致SDK始终进入不了单条输出状态。4. 高频踩坑与排查缓存溢出、模式切换失败、双端抢连接4.1 15000行缓存溢出的真实表现无限循环模式最容易出现溢出。现象是程序跑几分钟后返回的行数变少或者轮廓序号跳跃。原因是取出速度小于写入速度当缓存写满控制器直接丢弃新轮廓。判断方法很简单在取数时记录batch-seqif (batch-seq ! expectedSeq) { printf(lost data: expect %d, got %d\n, expectedSeq, batch-seq); } expectedSeq batch-seq 1;这是排查丢行最直接的手段。出现丢失后不要急着加内存先看消费线程里有没有在取数路径上做重活把数据解析、图像处理、日志写入全部移到另一个线程。如果丢行只发生在设备启动后的前几秒说明边缘时刻SDK还没有把内部缓冲初始化好可以在SR_StartGrabbing之后先抛掉前5批数据再开始统计。4.2 模式切换前必须先停止采集一次回调、阻塞、无限循环、2.5D这几种模式之间切换必须在停止采集状态下进行。直接调用SR_SetWorkMode而没先SR_StopGrabbing常见结果是返回成功但实际模式没变导致后续取数行为还是旧模式。最坑的是这类错误不会报异常只在数据里表现异常。我一般会在每次切换前写一个工具函数先停采再置位再停100毫秒最后读回模式确认。读回模式这一步很关键SDK支持查询当前模式切完不验证等于白切。另外从无限循环切到一次回调时缓存里可能残留旧数据切换后第一次回调的数据不要直接用于测量先丢弃一批。提示模式切换后读回模式再采数是最稳妥的防御性做法。4.3 EdgeImaging软件独占设备SDK连不上和很多相机SDK类似深视智能的相机会被EdgeImaging软件独占。如果软件开着实时取流SDK调用SR_OpenCamera会返回设备忙或者打开后拿不到数据。现场联调最常遇到的情况是软件没关SDK程序一启动就报错或者软件和SDK都打开了但两边抢触发导致数据混乱。解决办法是约定一个原则调试阶段用EdgeImaging看实时轮廓联调阶段关掉软件只让SDK控制相机。如果必须同时在线查看需要把SDK和软件理解为主从关系优先保证一边。另外2.5D模式本身要求EdgeImaging打开对应开关这种情况属于例外但也要确保只有一边执行采集命令。4.4 回调函数里不能做耗时操作这条看起来是老生常谈但在3D相机高行频下尤其严重。一次回调模式虽然数据是整体返回但如果你在回调里做大量浮点计算、写日志、打印调试信息回调执行时间会超过下一个数据块的到达间隔于是SDK内部缓冲被占满后续数据被迫丢弃。正确的做法是回调里只入队计算放到消费者线程。如果你的业务确实需要实时处理那就用2.5D模式逐条处理而不是在高吞吐模式下硬扛。排查时可以先在回调里加一个执行耗时统计超过10毫秒就打印立刻能定位到瓶颈。4.5 程序文件路径和运行库缺失导致SDK初始化失败最后说一个和模式无关但最常见的初始化问题。深视智能SR系列的SDK程序文件包里除了头文件和库通常还带运行组件。有人把SRCameraApi.h和lib拷到工程目录就完事运行时却报“找不到动态库”或初始化返回错误码往往是没有把SDK目录加到程序文件搜索路径或者缺少依赖的运行库。我在Windows下一般这样处理把SDK的bin目录复制到exe同级目录并且把包含路径、库路径、动态库路径统一指向同一个SDK根目录。这样换电脑部署时不用装额外环境程序文件包直接拷贝就能跑。如果还是初始化失败用依赖查看工具检查DLL加载链比盲改代码有效得多。4.6 多台相机同时取数时的模式策略项目里有多台SR系列相机时取数模式必须按工位独立配置。常见的错误是给所有相机套同一个配置结果缓存容量和取数线程互相抢占。如果两台相机共用一台工控机我建议把高行频的那台用无限循环模式并单独绑一个CPU核心另一台用一次回调模式。两种模式分别在各自线程里消费避免无限循环的固定返回间隔拖拽一次回调的实时性。如果现场出现过数据错乱优先排查取数线程是否绑了同一个核心以及SDK回调是否在不同相机间共享了同一个队列。5. 把无限循环模式调稳环形队列和双消费线程无限循环模式的瓶颈不在SDK而在应用层消费速度。我常用的做法是自建一个固定容量的环形队列每个槽位预分配足够大的内存取数线程只负责把SDK数据整块拷贝进槽位测量线程按序取走并解包。这样即使测量线程偶发抖动取数线程也不会阻塞。队列槽位大小按下式计算最大轮廓点数乘以最大行数。如果相机参数是每行3200点、每批3000行一个槽位就是3200×3000×2字节float高度强度约18MB。环形队列设4个槽总内存约72MB在工控机上完全可以接受。代码结构类似struct Slot { std::vectorfloat height; std::vectorfloat intensity; uint32_t seq; uint32_t count; }; std::vectorSlot ring(4); size_t writeIdx 0, readIdx 0; // 取数线程 ring[writeIdx].seq batch-seq; memcpy(ring[writeIdx].height.data(), batch-height, batch-count * sizeof(float)); writeIdx (writeIdx 1) % ring.size(); // 测量线程 while (readIdx ! writeIdx) { ProcessSlot(ring[readIdx]); readIdx (readIdx 1) % ring.size(); }这里有两个关键点。一是写索引和读索引都只在各自线程内修改避免加锁堵塞取数读线程追上写索引说明消费不过来此时可以报警而不是覆盖数据。二是槽位内存预先分配不要在取数路径上触发堆申请Windows下频繁 new/delete 会造成隐性延迟而3D相机的数据量足够让堆碎片化延迟会越来越不稳定。验证方法跑满行频连续观察一小时的batch-seq连续性同时记录最大写读间隔。如果间隔越来越大说明消费速度跟不上如果稳定再加大行频直到丢数据为止这个临界点就是你的系统吞吐上界。把结果写进项目记录后续换相机或改分辨率时可以直接对比。环形队列的容量不是越大越好过大会让延迟变高产品缺陷不能及时反馈给PLC。你需要根据产线节拍换算允许的最大延迟再反推队列深度。一个收尾技巧2.5D模式也可以套用这个环形队列只是槽位容量从“一批轮廓”缩成“一条轮廓”队列深度建议设为4096保证高速运行时小轮廓不丢失。这样无论你切到哪种模式消费模型都保持统一排查问题时也会省很多事。本文还有配套的精品资源点击获取
返回列表