利用python进行仪器控制【转载】

我只用过通过RS232串口、GPIB并口、网口、usb口通信的仪器。其中,RS232串口、GPIB并口非常非常简单,网口我没咋用过,应该也不难。最麻烦的是usb口通讯,比如newport的光学延迟线,这个得看说明书,一般是厂家给你一个动态链接库xxx.dll,通过调用dll中的函数去控制仪器。其实,我只用过labview去封装dll里的函数(labview用了好多年,奈何它不是开源的),用python封装应该也不难,百度一下就能知道(有时间的话,我会替大家百度)。

这篇文章只适合需要自己diy简单测量系统的穷逼搬砖狗。

仪器控制常用的python包
pyvisa:这个要先安装ni-visa,visa是对串口、GPIB、网口等通讯接口的封装,很常用。

serial:不想用visa进行串口通讯,可以用serial这个包。

pymeasure:这个包对测量过程和一些常用仪器进行了进一步的封装,具体可以去看它的文档。这个包不建议新手用,虽然它可以很方便的写出边测量边画图的程序,新手还是建议老老实实写简单的测量程序。别人写的复杂的包虽好,如果文档读的不好,很容易出错。测量嘛,程序越简单越不容易出错,要做到:只要电脑不死机,测量好几天都不能出错。

time:这个包用来设置时间延迟,比如:执行写入电流命令之后,等多少秒,再执行读取电压命令。

numpy:这个就不说了,太常用了。

matplotlib:用来画图。

至于python软件,建议直接安装Anaconda或者Miniconda,界面我用的Jupyter(并不好用),建议直接用Spyder。

测量之前,查看已连接仪器的程序
python程序代码:

import pyvisa #visa一般能看所有接口的仪器
import serial #我比较喜欢用serial控制有串口仪器,不喜欢用visa
import serial.tools.list_ports #用来列出说有串口
rm = pyvisa.ResourceManager() #得到visa的ResourceManage
port_list = list(serial.tools.list_ports.comports()) #得到所有串口
print(rm.list_resources()) #打印所有visa封装的接口(一般会包含下面的串口,只不过名字不太一样)
if len(port_list) == 0:
print(‘无可用串口’)
else:
for i in range(0,len(port_list)):
print(port_list[i]) #打印所有的串口
输出(我这台电脑只有12个串口):

(‘ASRL1::INSTR’, ‘ASRL2::INSTR’, ‘ASRL3::INSTR’, ‘ASRL4::INSTR’, ‘ASRL5::INSTR’, ‘ASRL6::INSTR’, ‘ASRL7::INSTR’, ‘ASRL8::INSTR’, ‘ASRL9::INSTR’, ‘ASRL10::INSTR’, ‘ASRL14::INSTR’, ‘ASRL19::INSTR’)
COM10 - USB Serial Port (COM10)
COM14 - USB-SERIAL CH340 (COM14)
COM1 - 通信端口 (COM1)
COM2 - 通信端口 (COM2)
COM3 - 通信端口 (COM3)
COM4 - 通信端口 (COM4)
COM5 - 通信端口 (COM5)
COM6 - 通信端口 (COM6)
COM8 - ADLINK CPL64 Port 0 (COM8)
COM9 - ADLINK CPL64 Port 1 (COM9)
COM7 - Intel® Active Management Technology - SOL (COM7)
COM19 - Prolific USB-to-Serial Comm Port (COM19)
简单控制程序之——两路串口继电器控制(只有写,没有读)
继电器淘宝链接:【淘宝】https://m.tb.cn/h.UAHwoOY?tk=ysh4dr9Hcec CZ0001 「LCUS型 USB继电器模块 电脑串口控制开关 PC智能控制器」 点击链接直接打开 或者 淘宝搜索直接打开

这个继电器的用途是:对于穷逼实验室,买不起双极性电源给电磁铁(穷逼可以自己绕电磁铁)供电,可以买个好一点的线性直流电源,配合这个继电器给电流换向,实现双极性电源的功能。这样就可以实现加正负磁场的测量。

python程序代码:

#继电器控制
import serial #我比较喜欢用serial控制有串口仪器,不喜欢用visa
from time import sleep #控制延时
on1=bytes.fromhex(‘A001 01A2’) #第一路开命令,命令可从淘宝链接查询
on2=bytes.fromhex(‘A002 01A3’) #第二路开命令
off1=bytes.fromhex(‘A001 00A1’) #第一路关命令
off2=bytes.fromhex(‘A002 00A2’) #第二路关命令

def relayon(): #继电器全开的函数,这个继电器是usb转串口,用的CH340芯片,串口号是COM14
relay=serial.Serial(‘COM14’,9600) #打开COM14这个串口,波特率是9600
relay.write(on1) #写命令,开第一路
sleep(0.02) #延时0.02s
relay.write(on2) #写命令,开第二路
sleep(0.02)
relay.close() #用完之后,关闭串口

def relayoff(): #继电器全关的函数,同上,不在注释
relay=serial.Serial(‘COM14’,9600)
#十六进制的发送
relay.write(off1)#写数据
sleep(0.02)
relay.write(off2)#写数据
sleep(0.02)
relay.close()#关闭串口

relayon() #两路继电器全开,此函数无输出
简单控制程序之——线性直流电源的控制(也是只有写,没有读,这个电源可以读,但是读它的信息没啥用)
电源淘宝链接:【淘宝】https://m.tb.cn/h.UzDRFtk?tk=2F8mdr9BrVi CZ0001 「同门可编程直流稳压电源30V60V150V25A高精度线性实验测试供应器」 点击链接直接打开 或者 淘宝搜索直接打开

这个电源可以给简易的电磁铁供电,配合上面的两路继电器可以实现双极性电源的功能,怎么接线大家自己想吧,很简单,画图太麻烦了,我就不画接线图了。同门电源的精度其实挺高的,有一款设置精度是0.1mA(跟2400肯定没法比),对于我绕的磁铁可以理论上可以实现0.1 Oe的磁场精度。

python程序代码:

#电源控制
import serial #我比较喜欢用serial控制有串口仪器,不喜欢用visa
def power_source_write(cmd: bytes): #电源写入函数:就是对写串口函数封装一下
power_source = serial.Serial(‘COM6’,9600) #我这里电源的串口号是COM6,波特率是9600
power_source.write(cmd)
power_source.close()

def power_source_on(): #电源输出开,函数
power_source_write(b’:OUTP ON\r\n’) #命令可以去同门电源的说明书里查询

def power_source_off(): #电源输出关,函数
power_source_write(b’:OUTP OFF\r\n’)

def power_source_setvolt(volt: float): #设置电压函数
if abs(volt) <= 20.0: #设置了个电压上限,太高了怕把自己绕的磁铁铜线烧坏
power_source_write(b’:VOLT %.4f\r\n’% volt)

def power_source_setcurr(curr: float): #设置电流函数
if abs(curr) <= 4.0: #设置了个电流上限
if curr >= 0: #配合继电器实现电流换向,继电器程序在上一小节
relayon() #电流大于等于0,继电器全开,把电流换向
power_source_write(b’:CURR %.4f\r\n’% abs(curr))
else:
relayoff() #电流小于0,继电器全关,电流不换向(因为继电器上电默认是关)
power_source_write(b’:CURR %.4f\r\n’% abs(curr))

#以下程序,设置电源输出,电流为-1A,电压为10V
current = -1 # A
power_source_off()
sleep(0.5)
power_source_setvolt(10.0)
power_source_setcurr(current)
sleep(0.5)
power_source_on()
#函数都没有写输出
简单控制程序之——闭环57步进电机控制(既有写,也有读,终于有读了)
张大头闭环57步进电机驱动模块:【淘宝】https://m.tb.cn/h.UAtgLyU?tk=4gEsdrk4VlP CZ0001 「张大头57步进闭环电机驱动模块3D打印机驱动器FOC超静音RS485 CAN」 点击链接直接打开 或者 淘宝搜索直接打开

57步进电机带磁柱:【淘宝】https://m.tb.cn/h.UBQK5s0?tk=V0LAdrkVlrd CZ3457 「张大头 57步进电机马达带磁柱孔高精密大扭矩 雕刻机长度41/70/76」 点击链接直接打开 或者 淘宝搜索直接打开

这个57步进电机套装可以实现简单的转动功能。比如电磁铁的旋转,我是把电磁铁放在一个8寸分度盘上(【淘宝】https://m.tb.cn/h.UBQtKgD?tk=zUf2drkhrvA CZ0001 「HV-8铣床卧式分度盘铣床旋转台分割器分度头立式两用手动简易转盘」 点击链接直接打开 或者 淘宝搜索直接打开),精加工一个转接件,把分度盘的手摇杆换成这个电机就行了。这个57电机控制简单,力矩很大,极力推荐!这个分度盘是1:90的,配合这个电机,角度控制精度应该还可以,普通的转角测量完全够用了。但是这个分度盘正转之后再反转,有零点几度的回程差,我的测量对精度要求不高,可以接受。

淘宝有卖自己改造的电动分度盘的,和我上面的方案一模一样:8寸分度盘+自己画的转接件+一个联轴器+57电机套装。我这一套成本一共1500不到,他好像卖3000多,做这个生意能赚一半,但估计也没多少需求。

python程序代码:

电机控制

import serial #我比较喜欢用serial控制有串口仪器,不喜欢用visa
from time import sleep
def motor_write(cmd: bytes): # 电机写入函数:就是对写串口函数封装一下
#十六进制的发送
motor = serial.Serial(‘COM3’,115200) #电机串口号在我电脑上是COM3,波特率设置的115200
motor.write(cmd)
sleep(0.1)
motor.close()

def motor_read(cmd: bytes, length: int): # 电机读取函数:就是对读串口函数封装一下
#十六进制的发送
motor = serial.Serial(‘COM3’,115200)
motor.write(cmd) #注意:读都是先写再读!你得告诉电机,我要读你
sleep(0.1)
read = motor.read(length) #读出字节长度要合适,返回多少字节就读多少字节。某个命令返回几个字节,可以看张大头的说明书,也可以自己试出来。
sleep(0.1)
motor.close()
return read

#以下用到的具体的命令,可以去张大头说明书里查
def motor_en(en: int): # 电机使能,函数
if en == 0:
motor_write(bytes.fromhex(‘01 F3 AB 00 00 6B’))
elif en == 1:
motor_write(bytes.fromhex(‘01 F3 AB 01 00 6B’))

def motor_read_en(): # 读使能状态,函数
en = motor_read(bytes.fromhex(‘013A6B’), 3)
en = int.from_bytes(en[2:4], byteorder=‘big’) & 0x01
return en

def motor_read_angle(): # 读角度函数,angle指是电机角度!
angle = motor_read(bytes.fromhex(‘01366B’), 8)
if int.from_bytes(angle[2:3], byteorder=‘big’,signed=True) == 1:
angle = -int.from_bytes(angle[3:7], byteorder=‘big’,signed=True)/10
else:
angle = int.from_bytes(angle[3:7], byteorder=‘big’,signed=True)/10
return angle

def motor_stop(): #急停函数
motor_write(bytes.fromhex(‘01 FE 98 00 6B’))

def motor_move(speed:float,angle:float): # 相对运动函数,speed(0-60)angle(0-720),angle指是分度盘的角度!
angle_motor = angle90
if angle>0:
cw = 0
else:
cw = 1
angle_motor_cmd = int(round(abs(angle_motor),1)10)
speed_cmd = int(round(abs(speed),1)10)
if (cw0 or cw1) and 0<=speed_cmd<=60
10 and 0<=angle_motor_cmd<=720
90
10:
para1 = ((cw).to_bytes(1, byteorder=‘big’)).hex()
para2 = ((speed_cmd).to_bytes(2, byteorder=‘big’)).hex()
para3 = ((angle_motor_cmd).to_bytes(4, byteorder=‘big’)).hex()
motor_write(bytes.fromhex(‘01FB’+para1+para2+para3+‘00’+‘006B’))

def motor_set_zero(): # 设置当前位置为零点
motor_write(bytes.fromhex(‘01 0A 6D 6B’))

def motor_move_abs(speed:float,angle:float): # 绝对运动,speed(0-60)angle(0-720),angle指是分度盘的角度!
angle_motor = angle90
if angle>0:
cw = 0
else:
cw = 1
angle_motor_cmd = int(round(abs(angle_motor),1)10)
speed_cmd = int(round(abs(speed),1)10)
if (cw0 or cw1) and 0<=speed_cmd<=60
10 and 0<=angle_motor_cmd<=720
90
10:
para1 = ((cw).to_bytes(1, byteorder=‘big’)).hex()
para2 = ((speed_cmd).to_bytes(2, byteorder=‘big’)).hex()
para3 = ((angle_motor_cmd).to_bytes(4, byteorder=‘big’)).hex()
motor_write(bytes.fromhex(‘01FB’+para1+para2+para3+‘01’+‘006B’))

#用之前先使能电机
motor_en(1)
motor_read_en()

使能成功,返回1

下面是用上面的函数,控制电机转动负90度,并实时显示已转过角度的一个例子:

电机转动程序,这里用的是相对运动函数,也可以用绝对运动,注意:掉电的话,绝对运动的零点会变成当前位置

move_angle = -90 #设置转动角度为负90度,设置的是分度盘角度,电机角度是分度盘角度的90倍,因为分度盘是1:90的
current_angle = motor_read_angle()/90 #读取当前分度盘角度
motor_move(15, move_angle) #执行相对转动负90度,speed(范围0-60):15对应分度盘速度1度/s; angle(范围0-720)
while 1: # 循环条件为1必定成立,这一段实时显示转过的角度
angle = motor_read_angle()/90
print(‘\r’+str(angle), end=’ ‘)
if abs(abs(angle-current_angle)-abs(move_angle))<0.1:
sleep(1)
print(’\r’+str(motor_read_angle()/90), end=’ ')
break
当前角度读取程序:

angle_current = motor_read_angle()/90
print(angle_current)
回到角度0程序:

这里用的是相对运动函数,也可以用绝对运动函数

angle_current = motor_read_angle()/90
motor_move(15,-angle_current)
print(motor_read_angle()/90)
电机紧急停止:

motor_stop()
简单测量程序之——2400_IV曲线测量(终于到了具体实验了,要实现边测量边画图)
2400大家都知道,用GPIB控制相当简单,买个二手的ni-usb-GPIB,接上就行。

python程序代码:

import pyvisa #visa一般能看所有接口的仪器
import numpy as np
from time import sleep
from matplotlib import pyplot as plt #用matplotlib包画图
%matplotlib qt5 #jupyter用qt5才会更新图像

#连接2400
rm = pyvisa.ResourceManager() #得到visa的ResourceManage
keithley2400 = rm.open_resource(‘GPIB0::1::INSTR’) #我这台2400设置的GPIB地址是1

#设置测量参数(下面是从-1mA到1mA,测量100个点)
min_current=-1e-3
max_current=1e-3
data_points=100
wait_time=0.5

#初始化2400
keithley2400.write(‘*RST’)
keithley2400.write(‘:sour:curr:rang 100e-3’) # Sets the source current range to 100 mA
keithley2400.write(‘:volt:prot:lev 10’) # Sets the compliance voltage to 10 V
keithley2400.write(‘:sour:func curr’) # 选择电流源功能
keithley2400.write(‘:sens:func ‘volt’’) #选择电压测量功能
keithley2400.write(‘:FORM:ELEM VOLT’) #只测量电压
keithley2400.write(‘:sour:curr:lev %f’%min_current) # Sets the source current to min_current
keithley2400.write(‘:outp on’)
sleep(0.5) # wait here to give the instrument time to react

#测量并实时画图
currents = np.linspace(min_current,max_current,data_points) #生成电流数组
voltages = np.zeros(len(currents)) #生成电压数组
figure, ax = plt.subplots(figsize=(8,6))
for i in range(len(currents)):
keithley2400.write(‘:sour:curr:lev %f’%currents[i]) #加电流
sleep(wait_time)
keithley2400.write(‘:read?’) #注意:读都是先写再读!
voltages[i] = float(keithley2400.read()) #测电压
ax.clear()
ax.plot(currents[:i],voltages[:i])
figure.canvas.draw()
figure.canvas.flush_events()

#储存数据为txt格式
np.savetxt(r’XXX.txt’,np.array([currents,voltages]).T)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值