
实验室里堆了示波器、程控电源、频谱仪、温箱每一台都有自己的上位机软件每个软件的操作逻辑还不一样。每次要做一组测试就得来回切换界面手动记录数据整理半天再作图。这种状态维持了快两年直到我把 openrig 引入到测试流程里才算是把这一摊子事理顺了。openrig 是一个开源的测试台架管理平台核心就做三件事统一接入不同厂商的仪器设备、自动化执行测试流程、集中采集和存储数据。它把底层那些乱七八糟的通信协议和厂商 SDK 全部封住对外暴露一套简洁的 Python API让我可以用几百行脚本替代以前一整天的手工操作。这篇文章适合谁看如果你正在被多台仪器协同测试折磨或者你接了项目要做产线级的自动化老化测试又或者你单纯不想再被某家厂商的商业软件绑住openrig 都值得你花半小时了解一下。我会从设计思路、设备接入原理、实际部署过程到排坑经验一次性讲完全部基于我这两个月真刀真枪的实际使用。1. 项目背景与核心设计思路1.1 传统仪器控制的三大痛点接触 openrig 之前我处理过的仪器控制方式基本分成三种各有各的烦。第一种是厂商自带的上位机软件。功能齐全但只兼容自家设备。测试工程师最痛苦的不是不会用这些软件而是要在好几套软件之间反复切换。做完一组温度特性测试可能需要同时盯着温箱软件、万用表软件和计算机软件数据格式还各不相同后处理全靠手动复制粘贴到 Excel。第二种是租用商业化的测试管理平台。这种平台确实能统一管理多品牌仪器但授权费用按仪器节点数计算一台仪器一个授权几百上千个点的产线光授权费就够买两台仪器了。而且商业平台的脚本语言通常是私有化的掌握这些技能换到另一家公司就完全用不上。第三种是纯手动编写脚本直接通过 SCPI 命令控制仪器。这种方式最灵活但问题在于每写一台新仪器的控制脚本都要重新啃一遍这台仪器的编程手册。SCPI 命令虽然号称标准化但每个厂商都有一套自己的方言导致代码里充满了各种 if-elif 的厂家分支维护成本极高。1.2 openrig 的解决方法抽象层与插件化openrig 解决这个问题的思路说白了就是标准接口 插件适配。它把仪器抽象成几个大类电源类Powersupply、测量类DMM、示波器类Scope、信号源类Generator、电子负载类Load每一类定义一套统一的操作 API。比如不管是什么型号的程控电源都有 set_voltage() 和 set_current() 这两个方法不管什么品牌的示波器都能通过 capture_waveform() 拿到波形数据。至于不同设备之间通信协议和指令集的差异全部由对应的 adapter 插件来处理。你接入新设备时只需要安装这个设备的 adapter 插件openrig 会自动把统一 API 调用翻译成设备能听懂的原生命令。这和我之前用过的很多工具思路完全不同它不再是以设备为中心——每个设备一个控制脚本而是以测试任务为中心——只需要关心我要做什么不用关心设备是谁家的。这个设计带来的直接好处有两个。第一测试脚本与具体设备解耦。同一套老化测试脚本换一台不同品牌的电源也能跑只是需要在配置里改一下设备标识。第二测试代码可以跨项目复用。以前写过的测试逻辑封装成 openrig 里的 task 模块后新项目直接调用就行。1.3 为什么不选现成的商业方案我知道肯定有人会问市面上的 LabVIEW、TestStand 不是也能做这些事吗我只能说工具本身没有优劣关键看使用场景是不是匹配。如果你所在的团队本身就是 NI 生态的重度用户PLC 或者数据采集卡全是 NI 的那 LabVIEW 自然是顺理成章的选择。但我的情况是团队里仪器品牌很杂有是德、泰克、固纬、普源还有几台很老的 Agilent统一迁移到某个商业生态的成本太高。openrig 可以逐步接入今天先接电源和数字万用表下周再加示波器不用一次性替换所有东西这个渐进式迁移的体验确实舒服。还有一点让我下决心选它是开源的。实验室的测试需求永远是动态变化的商业软件遇到不满足的场景只能提工单等版本更新。但 openrig 我可以直接看源码改出符合自己需求的逻辑分支自己改完自己用这种工具完全可控的感觉是做项目最需要的底气。2. 核心功能与设备接入逻辑2.1 整体架构三层模型openrig 的逻辑架构可以简单分成三层我在实际看源码的时候把它的调用链理顺了大致如下应用层用户写测试脚本、定义测试流程、调用 API 获取结果。这一层只和抽象接口打交道。核心层负责设备发现、会话管理、任务调度、数据缓存。设备之间怎么协同工作由这一层统一调度。适配层不同的 adapter 插件负责把标准 API 映射到具体仪器的通信协议。这个分层和日常软件开发里的接口与实现分离是一样的。核心层定义好 API 规范适配层负责实现规范。我后来给一台老旧的国产电源写 adapter 插件时只需要实现标准接口里定义的那十几个方法不用关心 openrig 其他部分是怎么运转的这种低耦合的设计对新接入设备特别友好。一个关键的细节是设备注册表。openrig 启动时会扫描配置文件里声明的设备连接成功后把这些设备放到一个全局的寄存器里。后面的脚本可以通过设备名直接引用比如 get_device(psu_main) 拿到电源实例。如果连接失败设备会被标记为异常状态但不会阻塞其他设备的初始化。这个设计让我在做长时间老化测试时非常安心即使中间有台仪器掉线了也不影响整体任务继续运行。2.2 设备发现与连接管理openrig 支持三种设备连接方式VISAGPIB/LXI/USB、Modbus TCP、串口。对于支持 VISA 的仪器openrig 会通过 VISA 资源管理器自动发现仪器并读取设备的 IDN 字符串来识别型号。比如识别出是 KEYSIGHT TECHNOLOGIES,E3648A就会自动加载对应的 keysight_e36xx adapter。如果你用的是串口设备需要在设备配置里手动指定串口号和波特率。这里有个容易踩坑的地方很多国产仪器的串口实现并不完全遵循标准可能需要调整 data bits、stop bits、parity 等参数才能正常通信。我后面会在排坑章节专门讲这个问题。连接管理的核心是一个会话池。因为多台仪器共享同一个 USB 总线或者 GPIB 总线时不能同时收发数据所以 openrig 为每个物理接口维护一个互斥锁。当脚本里同时控制示波器和电源时对串口的读写会被自动排队避免指令交叉导致仪器响应错乱。这个细节帮我解决了很多莫名奇妙的通信时序问题。2.3 数据采集管线与格式标准化仪器控制搞定之后第二个核心问题就是数据。openrig 的数据采集管线是采集-解析-标准化-存储四步。先说采集。不同类型的设备返回的原始数据格式差异很大万用表返回一个浮点数示波器返回一串二进制波形点温度计可能返回字符串。openrig 在采集层拿到这些数据后会交给对应 adapter 里的解析器转成统一的 Python 数据类型标量、数组或者 DataFrame。再说存储。openrig 支持把数据写入 SQLite、CSV 文件或者通过 MQTT 转发到外部数据库。我个人的习惯是测试过程中先把原始数据写到 SQLite写入快不会丢数据等测试结束后再导出成 CSV 做分析。SQLite 的单文件特性也方便做数据归档一个测试项目就是一个文件拷走就能复现。还有个值得提的功能是数据时间戳对齐。多台仪器同时采集时如果每台仪器的时钟不一致数据对不上时间轴就废了。openrig 会给每个采样点打上统一的 UTC 时间戳并且在测试任务开始时会执行一次所有设备的时钟同步校准。这样示波器抓到的波形和电源记录的电压电流才能在同一个时间基准下对比。2.4 任务编排与自动重试机制自动化测试的本质是把设定参数-执行操作-读取数据-判断结果这些步骤串成一个流程并且要能无人值守地循环运行。openrig 的任务编排引擎支持定义多步骤的 test plan每个步骤可以是指定设备的操作也可以是等待延时。在我做 48 小时高温老化测试时用到了它的自动重试机制。比如给温箱发送温度设定指令后温箱实际达到目标温度需要时间。openrig 支持为每个步骤设置超时时间和重试次数超时后可以自动重发指令。我还给每个步骤写了断言逻辑如果设备回读的数据超出预设范围任务会按预案执行——可以是暂停、跳过或者直接 terminate 并触发报警。这套机制让我真正实现了一个人在工位上几十台设备在隔壁实验室自己跑测试。每天晚上去收一次数据就行再也不用熬夜盯着温度曲线手动调整了。3. 实操部署与配置全流程3.1 环境准备与最小安装openrig 的部署方式很简单官方推荐通过 pip 安装Python 版本要求 3.9 以上。我在一台 Ubuntu 20.04 的工控机上做的部署命令如下sudo apt update sudo apt install -y python3-pip python3-venv libusb-1.0-0-dev python3 -m venv venv source venv/bin/activate pip install openrig如果仪器是通过 USB 连接的记得把当前用户加入 dialout 组否则没有串口权限sudo usermod -aG dialout $USER安装完成后用 openrig doctor 命令检查一下环境是否就绪。这个命令会逐项检查 Python 版本、VISA 库、串口权限、设备接入状态并给出具体的修改建议。我强烈建议新人在正式配置设备前先跑一遍这个检查能省下很多排查环境问题的时间。3.2 配置文件编写与设备接入实操openrig 的配置文件采用 YAML 格式一份标准的配置长这样devices: - name: psu_main type: powersupply interface: visa resource: USB0::0x2A8D::0x1102::MY59001234::0::INSTR adapter: keysight_e36xx options: timeout: 5000 read_termination: \n - name: dmm_temp type: dmm interface: visa resource: GPIB0::22::INSTR adapter: agilent_34401a options: timeout: 3000 - name: chamber_1 type: temperature_chamber interface: modbus host: 192.168.1.100 port: 502 unit_id: 1 adapter: generic_modbus_temp第一台设备接入的时候我用到了 openrig 自带的设备探测工具。跑openrig scan命令它会列出所有通过 VISA 能访问到的仪器资源并尝试读取 IDN 字符串。比如输出显示USB0::0x2A8D::...对应的 IDN 是 KEYSIGHT TECHNOLOGIES,E3648A我就能直接确定这台设备对应 keysight_e36xx 这个 adapter并把资源地址填到配置文件里。这里有一个很多新手容易栽的坑read_termination 必须和仪器实际返回的结束符一致。默认是\n但有的仪器用\r\n有的甚至用\r。如果设置不对openrig 读回的数据会带上一堆乱码或者直接超时。我是通过抓取串口裸数据确认这台电源的终止符是\n之后才填入配置的。配置写好之后启动 openrig service 服务。日志输出里会看到每台设备的连接状态比如 SUCCESS: psu_main is online 这种信息。连接成功后在另一个终端跑openrig list就能看到当前在线设备和它们的健康状态。确认所有设备都 online 后这一步就算完整走通了。3.3 第一个自动化测试脚本设备接入成功后我写了一个最简单的自动化测试脚本功能是让电源输出 5V然后用万用表回读电压值判断漂移是否在允许范围内。import openrig # 1. 建立服务连接 rig openrig.connect(config/etc/openrig/config.yaml) # 2. 获取设备实例 psu rig.get_device(psu_main) dmm rig.get_device(dmm_temp) # 3. 设置电源输出 psu.set_voltage(5.0) psu.set_current(0.5) psu.output(True) # 4. 等待稳定 rig.wait(2.0) # 5. 回读实际电压 actual dmm.measure_voltage() print(f实际输出电压: {actual:.6f} V) # 6. 判断是否在范围内 tolerance 0.01 if abs(actual - 5.0) tolerance: print(PASS: 电压在允许范围内) else: print(FAIL: 电压漂移超限) # 7. 关闭输出 psu.output(False)这个脚本看起来很简单但我实际调试时遇到两个值得说明白的问题。第一个是电源输出前需要先设置电流限制否则负载短路时电源会处于过流保护状态。这个习惯我在用 openrig 之前就有了但 openrig 的 API 设计里把 set_current 单独列出来也是在提示使用者注意这一步。第二个是测量前加了一个 2 秒的等待。这是因为电源的输出电压建立需要时间尤其是容性负载比较大的情况下上电瞬间会有过冲和振铃。如果一设置完电压马上就去量读到的值和稳态值可能差不少。在自动化测试脚本里这种延时用的是一种保险但要注意别滥用不然整个测试时长会被拉长。我在做循环测试时会把延时压到尽量短只在关键节点保留等待。3.4 跑一个循环老化任务单步操作跑通之后我很快就把它扩展成了一个完整的循环老化测试任务。任务核心是让电源循环输出不同电压每个电压点停留一定时间同时用万用表和示波器持续采集数据。import openrig import time rig openrig.connect(...) psu rig.get_device(psu_main) dmm rig.get_device(dmm_temp) scope rig.get_device(scope_1) # 配置测试参数 voltage_profile [3.3, 5.0, 12.0] dwell_time 30 # 每个电压点停留 30 秒 sample_interval 1 # 每秒采样一次 results [] for cycle in range(100): for v in voltage_profile: psu.set_voltage(v) psu.output(True) rig.wait(0.5) # 等待输出稳定 # 按固定间隔采样 for _ in range(int(dwell_time / sample_interval)): v_measured dmm.measure_voltage() i_measured dmm.measure_current() timestamp time.time() results.append({ cycle: cycle, target: v, measured_v: v_measured, measured_i: i_measured, ts: timestamp }) rig.wait(sample_interval) psu.output(False) rig.wait(2.0) # 每个电压点之间断电休息 2 秒 # 测试结束保存数据 rig.export_csv(results, /data/aging_test_cycle.csv)这个脚本在 openrig 里跑起来非常平稳但有一个细节我研究了很久示波器采集和万用表采样的同步。如果只是简单地把两者读到的时间戳拿来对齐因为采样时刻并不完全一致对数次波形对比时会出现相位差。后来我改成了用 openrig 的硬件触发同步功能让示波器在电源输出稳定的瞬间触发采集才解决了这个问题。这个功能在文档里叫 hardware_trigger_sync需要示波器支持外部触发输入我的电流探头夹在电源输出线上触发信号就从电流探头接入示波器的触发通道。这样每次电压切换时示波器都能自动抓到对应波形数据的时间基准完全对齐。3.5 参数计算过程采样间隔的确定安排采样间隔的时候我做了个简单的计算。万用表的最大采样速率是 50 kSa/s但实际的测量精度会随着采样速率上升而下降。在 5 位半精度模式下它的有效采样率只有大约每秒 15 次。我设置 1 秒采样一次远低于仪器的物理上限留出了充裕的通信余量。这样设定既保证了数据的独立性相邻样本之间不因为仪器 ADC 的连续采样而产生相关又不会给总线通信造成过大的负担。示波器的采样率设置则完全是另一套计算逻辑。我要抓的是电源切换瞬间的过冲波形开关时间大约在微秒级所以把示波器采样率设为 250 MSa/s采集长度 1 ms这样能捕获 250,000 个点足够完整地看到过冲波形和振铃细节。数了下我需要的波形细节长度50 ns 左右的毛刺至少要保证 5 个采样点才能还原按照这个反推出来的采样率就是 250 MSa/s 以上。4. 常见问题与排查技巧实录4.1 采集数据全是乱码或者超时这是接入串口仪器时最常遇到的问题。我排查了几台设备后总结了一个统一的分析路径。第一步先用串口调试工具直接和设备通信发送*IDN?指令看返回结果。如果返回的字符串里能正常看到设备型号说明串口参数基本正确。如果返回乱码大概率是波特率不匹配。如果完全没有返回则要检查接线和串口映射。第二步如果乱码但波特率没错就逐个尝试 data bits、stop bits、parity 的组合。很多国产仪器出厂默认是 8N18 数据位、无校验、1 停止位但也有相当一部分设备是 7E1 或者 8O1。openrig 的串口配置里可以直接指定这些参数。第三步确认终止符。这也是最容易忽略的一步。厂家手册里写的是\n但实际通过串口抓包发现发回来的是\r\n。这种情况下程序会读到一堆看似乱码的字符串其实是尾部多了\r导致的内容错位。在 openrig 配置里把 read_termination 改成\r\n问题立刻消失。我在排查这个问题的时候还用了 openrig 的 debug 模式日志里会把采集的原始字节流打印出来对比原始数据后就基本锁定问题所在了。这里建议你遇到问题别急着改代码先打开 debug 日志看一眼最原始的通信内容定位效率会高很多。4.2 设备时而识别时而识别不了这个问题多出现在 USB 接口的设备上我一开始以为是硬件连接不稳定直到打开系统日志才发现是 USB 设备的权限和电源管理问题。Linux 下 USB 设备默认有 autosuspend 机制如果一段时间没有通信USB 接口会进入挂起状态仪器再发数据时接口无法正常唤醒导致 openrig 误判设备掉线。解决办法是在 udev 规则里禁用该 USB 端口的自动挂起echo SUBSYSTEMusb, ATTR{power/autosuspend}-1 | sudo tee /etc/udev/rules.d/99-usb-power.rules sudo udevadm control --reload-rules还有一种情况是台式机前置 USB 口供电不足示波器这种功耗稍大的设备会间歇性掉线。建议把示波器这类高功耗设备接在机箱后置 USB 口或者带外部供电的 USB HUB 上问题会缓解很多。顺便说一句如果设备老是无规律掉线先看电源指示灯如果设备本身显示正常但系统里掉了90% 是和 USB 电源管理有关。别一上来就怀疑 openrig 的问题。4.3 SCPI 指令语法差异导致的兼容性问题即使 adapter 已经封装好了接口有时候你也会遇到一些比较老的仪器它的 SCPI 实现和标准不一致。比如某台老电源IEEE 标准里规定的:VOLT 5.0在它上面就是不被识别必须写成VOLT 5.0不带冒号否则返回错误。遇到这种情况openrig 提供了一层指令过滤器机制。在 adapter 的配置里可以指定 pre_translate_rules把统一 API 的指令转换成这台设备能懂的原始命令。我举个例子adapter: custom_psu_parser options: pre_translate_rules: - pattern: :VOLT replacement: VOLT这个机制解决了我手里那台老电源 80% 的兼容问题。剩下 20% 是因为一些命令的参数格式也不一致比如有的设备要求浮点数必须带后缀单位有的则不允许带。这些就需要你在 adapter 里实现对应设备的专属逻辑了。4.4 长时间运行后数据漂移或丢失我在做 48 小时连续老化测试时发现一个隐蔽的问题运行到约 30 小时之后部分采样数据的时间戳明显跳动间隔从 1 秒变成了 3 秒甚至 5 秒而且偶尔出现重复采样的数据。排查了半天最后定位到问题是 USB 总线的调度延迟。当多台仪器同时通过 USB 通信时系统级联的带宽会变得紧张部分设备的采样请求被延迟处理。openrig 默认的采样方式是单线程顺序执行一台设备卡住后面的采样任务就会积压。我的解决方案是调整脚本的并发模型把不同设备的采样放到独立的多线程任务中每个线程独立处理单一设备的数据。改完之后即使一台设备因为总线仲裁延迟了也不会阻塞其他设备的数据采集。如果延时超过一定阈值openrig 还会自动丢弃这个迟到的采样点避免脏数据进入结果集。另外一个容易被忽略的问题是内存泄漏。如果采样周期太短数据量较大长期运行会导致内存逐渐增大。我给自己的脚本里加了定期 flush 机制每 10 分钟把结果写入一次 SQLite 并清空内存中的累积数据。实践下来内存占用一直平稳。4.5 常见问题速查表我把这段时间遇到的主要问题和解决思路整理成了下面这个表格后续做项目时可以直接按图索骥。现象可能原因排查方向设备连接失败串口被占用、权限不足、资源地址错误openrig doctor 检查lsof 查看串口占用核对配置文件数据返回乱码波特率不匹配、校验位错误、终止符不一致串口调试工具裸调调整通信参数逐项排除设备间歇性掉线USB autosuspend、供电不足禁用 USB 自动挂起更换后置 USB 口SCPI 指令报错老设备指令方言差异启用 pre_translate_rules 做指令翻译长时间运行数据漂移USB 调度延迟、线程阻塞改为多线程独立采样增加数据 flush 策略时间戳不齐设备时钟不同步、采样时刻不一致使用硬件触发同步开启时钟校准5. 实操心得与更多扩展方向在分享最后一批心得体会之前我想说一个从这两个月里反复验证出来的核心认知一套工具真正的价值不在于功能列表有多少项而在于它能不能贴合你的实际工作流让你把精力留给测试设计本身。openrig 对我来说最大的收获是让我从一个每台设备的临时工变成了测试流程的设计者。以前我花大量时间在仪器之间来回切换、处理数据格式现在我只需要把注意力放在测试方案是否合理、数据边界是否靠谱这类真正重要的问题上。有几个实操上的小经验供你们参考。第一配置文件的版本管理一定要做。openrig 的 YAML 配置不算复杂但设备多了之后微调一个参数就可能影响全局。我建议把配置文件纳入 git 管理每次变更都写清楚 commit message这样出了问题可以快速回滚到能跑的版本。第二adapter 插件尽量自己维护。就算某个设备的官方 adapter 已经很好用了我还是建议你 fork 一份自己留着。因为你永远不知道你手里的设备固件版本和官方修的是不是同一个问题自己维护的 adapter 即使出问题也能快速定位。第三善用 openrig 的离线模拟模式。如果某台仪器不在手边又想开发调试脚本可以用它的 mock driver完全模拟一台设备的行为。这个方法帮助我在出差途中把新项目的脚本提前写完回实验室一接上设备就能跑省了整整一天的调试时间。至于后续可以怎么扩展我自己已经在尝试的方向是把 openrig 和时序数据库打通把历史测试数据直接写入 InfluxDB再做可视化看板。另一个方向是把它接进公司的工单系统测试任务完成后自动生成测试报告并推送到相关人员。这些扩展本质上都是因为 openrig 把最麻烦的设备控制层拆干净了上层才容易长出自己的业务逻辑。如果你也被多设备协同测试折磨或者你正在准备一套自动化产线测试方案我真心建议你花一个下午把 openrig 跑起来接上你手头最常用的两三台仪器按照本文的步骤搭一个小 demo。上手之后你会很快感受到测试工作终于可以把重心从拧螺丝挪到设计试验上了。