第3章:Python与仪器通信:pyvisa库入门、SCPI指令基础、仪器资源管理与错误处理

做光模块测试这么多年,我最大的体会就是:不会跟仪器聊天,自动化就是空谈。你想想看,无论你的测试方案设计得多漂亮,如果Python连仪器都控制不了,那一切都是纸上谈兵。

这一章,我们就来聊聊怎么让Python和仪器「对上话」。我会从最基础的pyvisa库开始,带你一步步掌握SCPI指令、资源管理,还有那些让人头疼的错误处理。

3.1 pyvisa库:Python与仪器的「翻译官」

pyvisa是什么?说白了,它就是Python和仪器之间的桥梁。你的Python代码说「我要读电压」,pyvisa就把这句话翻译成仪器能听懂的电气信号,通过GPIB、USB、以太网这些物理接口传过去。

安装很简单,一行命令搞定:

pip install pyvisa pyvisa-py

我个人习惯用pyvisa-py作为后端,因为它不需要安装NI-VISA这种商业驱动,纯Python实现,部署起来特别方便。当然,如果你在产线上用,还是建议装NI-VISA,稳定性更好。

核心概念:pyvisa把仪器抽象成一个「资源对象」。你通过这个对象发送命令、读取数据,就像在操作一个文件一样简单。

3.2 SCPI指令基础:学会仪器的「方言」

SCPI(Standard Commands for Programmable Instruments)是仪器界的通用语言。但说实话,「通用」这个词有点理想化。不同厂家的仪器,对同一功能的SCPI指令往往有细微差别。

我在项目中遇到过最典型的例子:同样是设置直流电源的输出电压,Agilent的指令是VOLT 5.0,而Keithley的却是SOUR:VOLT 5.0。所以,拿到一台新仪器,第一件事就是去翻它的编程手册

SCPI指令的基本结构是这样的:

# 查询指令(带问号)
*IDN?
MEAS:VOLT:DC?

# 设置指令(不带问号)
VOLT 5.0
OUTP ON

# 复合指令(用冒号分隔层级)
SOUR:VOLT:LEV:IMM:AMPL 5.0

我的小技巧:调试SCPI指令时,先用仪器自带的「远程控制」软件(比如Keysight的IO Libraries)手动发一遍,确认指令正确了,再写到Python代码里。这样能省掉很多排查时间。

3.3 仪器资源管理:别让仪器「失联」

资源管理听起来高大上,其实就三件事:找到仪器、打开连接、关闭连接

先看怎么找到仪器:

import pyvisa

rm = pyvisa.ResourceManager()
resources = rm.list_resources()
print(resources)
# 输出示例:['USB0::0x2A8D::0x0101::MY12345678::INSTR', 'TCPIP0::192.168.1.100::inst0::INSTR']

找到资源地址后,打开连接:

inst = rm.open_resource('USB0::0x2A8D::0x0101::MY12345678::INSTR')
print(inst.query('*IDN?'))  # 查询仪器身份

嗯,这里要注意:用完一定要关闭连接。我曾经在产线上遇到过,因为程序异常退出没关连接,导致仪器一直处于「被占用」状态,后续所有测试脚本都连不上。那叫一个惨。

# 正确的关闭方式
inst.close()
rm.close()

避坑指南:我曾经在批量测试时,每测完一个模块就重新打开一次资源连接。结果测到第50个模块时,仪器直接卡死了。后来发现是资源泄漏——每次打开连接都会占用系统句柄,不释放就会耗尽。建议用with语句自动管理资源:

with rm.open_resource('USB0::...') as inst:
    # 在这里做测试
    pass  # 自动关闭

3.4 错误处理:让程序「扛得住」意外

自动化测试最怕什么?最怕程序跑着跑着突然崩了,然后你也不知道崩在哪一步。所以,健壮的错误处理是自动化脚本的「安全带」

常见的仪器通信错误有这几类:

错误类型 典型场景 处理方式
连接超时 仪器没开机、网线松了 重试3次,仍失败则报错
指令语法错误 SCPI指令写错了 捕获异常,打印指令内容
仪器忙 仪器正在执行其他操作 等待并重试
数据格式错误 返回的数据不是预期格式 解析前做格式校验

我一般这样写错误处理:

import pyvisa
import time

def safe_query(inst, command, retries=3):
    """带重试机制的查询函数"""
    for attempt in range(retries):
        try:
            response = inst.query(command)
            return response.strip()
        except pyvisa.errors.VisaIOError as e:
            print(f"第{attempt+1}次尝试失败: {e}")
            if attempt < retries - 1:
                time.sleep(1)  # 等1秒再重试
            else:
                raise  # 重试用完,抛出异常

# 使用示例
rm = pyvisa.ResourceManager()
try:
    inst = rm.open_resource('TCPIP0::192.168.1.100::inst0::INSTR')
    inst.timeout = 5000  # 设置超时5秒
    
    idn = safe_query(inst, '*IDN?')
    print(f"仪器识别: {idn}")
    
except Exception as e:
    print(f"通信失败: {e}")
finally:
    if 'inst' in locals():
        inst.close()
    rm.close()

我的经验:产线上经常有仪器因为静电干扰导致通信瞬间中断。所以,所有仪器通信操作都要加重试机制。我一般设3次重试,每次间隔1秒。如果3次都失败,那基本就是硬件问题了,该报修报修。

3.5 本章知识体系

为了让你更直观地理解这一章的内容,我画了一张流程图:

Python与仪器通信知识体系 Python测试脚本 pyvisa库 SCPI指令 测试仪器 资源管理 错误处理 核心流程:Python → pyvisa → SCPI → 仪器 资源管理和错误处理贯穿整个通信过程

这张图把整个通信流程串起来了。你写代码的时候,脑子里要有这个图:Python脚本通过pyvisa库发送SCPI指令给仪器,同时要做好资源管理和错误处理。这三块缺一不可。

好了,这一章的内容就到这里。记住我说的:多动手、多踩坑、多总结。仪器通信这块,光看是学不会的,一定要自己连上仪器跑一遍代码。哪怕只是读个*IDN?,也比看十遍教程强。

本章要点回顾:

  • pyvisa是Python与仪器通信的桥梁,安装pyvisapyvisa-py
  • SCPI指令分查询(带?)和设置(不带?)两类,不同厂家有差异
  • 资源管理三步骤:找到资源、打开连接、关闭连接
  • 所有通信操作都要加错误处理和重试机制

专注资料整理