Created
December 29, 2019 10:21
-
-
Save nmz787/9ef47851c79d84f4d05aabc2c4d282e6 to your computer and use it in GitHub Desktop.
work in progress MKS 901P vacuum transducer sensor library and command-line program.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
usage: mks_901p.py [-h] [--find_baud] [--baud BAUD] [-unit] serial_port | |
positional arguments: | |
serial_port the Windows COM port or path to a linux serial port | |
optional arguments: | |
-h, --help show this help message and exit | |
--find_baud tries to access the sensor over all supported baud rates, | |
prints which is successful | |
--baud BAUD baud rate to connect with, defaults to 9600 (901p factory | |
default) | |
-unit print pressure unit with each reading | |
""" | |
# xxx = Transducer communication address (001 to 253. Broadcast addresses: 254, 255) | |
baud_supported = [4800, 9600, 19200, 38400, 57600, 115200, 230400] | |
commands = { | |
'Communication information': { | |
'get_baud_rate': { | |
'Command': '@{}BR?;FF', | |
'Response': '@xxxACK9600;FF', | |
'Explanation': 'Communication baud rate (4800, 9600, 19200, 38400, 57600, 115200,230400)' | |
}, | |
'get_address': { | |
'Command': '@{}AD?;FF', | |
'Response': '@xxxACK253;FF', | |
'Explanation': 'Transducer communication address (001 to 253)' | |
}, | |
'get_comms_delay': { | |
'Command': '@{}RSD?;FF', | |
'Response': '@xxxACKON;FF', | |
'Explanation': 'Communication delay between receive and transmit sequence.' | |
} | |
}, | |
'Pressure reading': { | |
'pirani': { | |
'Command': '@{}PR1?;FF', | |
'Response': '@xxxACK1.23E-3;FF', | |
'Explanation': 'MicroPirani sensor pressure as 3 digit floating point value.'}, | |
'piezo': { | |
'Command': '@{}PR2?;FF', | |
'Response': '@xxxACK-7.60E+2;FF', | |
'Explanation': 'Piezo differential sensor pressure as 3 digit floating point value.'}, | |
'combined_3_digit': { | |
'Command': '@{}PR3?;FF', | |
'Response': '@xxxACK1.23E-3;FF', | |
'Explanation': 'Combined reading as 3 digit floating point value.'}, | |
'combined_4_digit': { | |
'Command': '@{}PR4?;FF', | |
'Response': '@xxxACK1.234E-3;FF', | |
'Explanation': 'Combined reading as 4 digit floating point value.'} | |
}, | |
'Setpoint information': { | |
'get_setpoint_1_status': { | |
'Command': '@{}SS1?;FF', | |
'Response': '@xxxACKSET;FF', | |
'Explanation': 'Set point relay 1-3 status (SET=Relay energized / CLEAR=Relay deenergized'}, | |
'get_setpoint_2_status': { | |
'Command': '@{}SS2?;FF', | |
'Response': '@xxxACKSET;FF', | |
'Explanation': 'Set point relay 1-3 status (SET=Relay energized / CLEAR=Relay deenergized'}, | |
'get_setpoint_3_status': { | |
'Command': '@{}SS3?;FF', | |
'Response': '@xxxACKSET;FF', | |
'Explanation': 'Set point relay 1-3 status (SET=Relay energized / CLEAR=Relay deenergized'}, | |
'get_setpoint_1': { | |
'Command': '@{}SP1?;FF', | |
'Response': '@xxxACK1.00E-2;FF', | |
'Explanation': 'Set point 1-3 switch value.'}, | |
'get_setpoint_2': { | |
'Command': '@{}SP2?;FF', | |
'Response': '@xxxACK1.00E-2;FF', | |
'Explanation': 'Set point 1-3 switch value.'}, | |
'get_setpoint_3': { | |
'Command': '@{}SP3?;FF', | |
'Response': '@xxxACK1.00E-2;FF', | |
'Explanation': 'Set point 1-3 switch value.'}, | |
'get_hysteresis_1': { | |
'Command': '@{}SH1?;FF', | |
'Response': '@xxxACK1.10E-2;FF', | |
'Explanation': 'Set point 1-3 hystereses switch value.'}, | |
'get_hysteresis_2': { | |
'Command': '@{}SH2?;FF', | |
'Response': '@xxxACK1.10E-2;FF', | |
'Explanation': 'Set point 1-3 hystereses switch value.'}, | |
'get_hysteresis_3': { | |
'Command': '@{}SH3?;FF', | |
'Response': '@xxxACK1.10E-2;FF', | |
'Explanation': 'Set point 1-3 hystereses switch value.'}, | |
'get_setpoint_1_enabled': { | |
'Command': '@{}EN1?;FF', | |
'Response': '@xxxACKDIFF;FF', | |
'Explanation': 'Set point 1-3 enable status ( OFF, DIFF=Piezo differential or ABS=Absolute Piezo)'}, | |
'get_setpoint_2_enabled': { | |
'Command': '@{}EN2?;FF', | |
'Response': '@xxxACKDIFF;FF', | |
'Explanation': 'Set point 1-3 enable status ( OFF, DIFF=Piezo differential or ABS=Absolute Piezo)'}, | |
'get_setpoint_3_enabled': { | |
'Command': '@{}EN3?;FF', | |
'Response': '@xxxACKDIFF;FF', | |
'Explanation': 'Set point 1-3 enable status ( OFF, DIFF=Piezo differential or ABS=Absolute Piezo)'}, | |
'get_setpoint1_relay_direction': { | |
'Command': '@{}SD1?;FF', | |
'Response': '@xxxACKBELOW;FF', | |
'Explanation': 'Set point relay direction (ABOVE or BELOW) If set to above relay will be energized above setpoint value. If set to below relay will be energized below setpoint value.'}, | |
'get_setpoint2_relay_direction': { | |
'Command': '@{}SD2?;FF', | |
'Response': '@xxxACKBELOW;FF', | |
'Explanation': 'Set point relay direction (ABOVE or BELOW) If set to above relay will be energized above setpoint value. If set to below relay will be energized below setpoint value.'}, | |
'get_setpoint3_relay_direction': { | |
'Command': '@{}SD3?;FF', | |
'Response': '@xxxACKBELOW;FF', | |
'Explanation': 'Set point relay direction (ABOVE or BELOW) If set to above relay will be energized above setpoint value. If set to below relay will be energized below setpoint value.'}, | |
'get_setpoint_safety_delay': { | |
'Command': '@{}SPD?;FF', | |
'Response': '@xxxACKON;FF', | |
'Explanation': 'Setpoint safety delay'} | |
}, | |
'Transducer information': { | |
'get_model': { | |
'Command': '@{}MD?;FF', | |
'Response': '@xxxACK901P;FF', | |
'Explanation': 'Model number (901P)'}, | |
'get_devicetype': { | |
'Command': '@{}DT?;FF', | |
'Response': '@xxxACKLoadlock;FF', | |
'Explanation': 'Device type name (MicroPirani)'}, | |
'get_mfg': { | |
'Command': '@{}MF?;FF', | |
'Response': '@xxxACKMKS;FF', | |
'Explanation': 'Manufacturer name (MKS)'}, | |
'get_hw_version': { | |
'Command': '@{}HV?;FF', | |
'Response': '@xxxACKA;FF', | |
'Explanation': 'Hardware version'}, | |
'get_fw_version': { | |
'Command': '@{}FV?;FF', | |
'Response': '@xxxACK1.00;FF', | |
'Explanation': 'Firmware version'}, | |
'get_serial_num': { | |
'Command': '@{}SN?;FF', | |
'Response': '@xxxACK08350123456;FF', | |
'Explanation': 'Serial number'}, | |
'get_switch': { | |
'Command': '@{}SW?;FF', | |
'Response': '@xxxACKON;FF', | |
'Explanation': 'Switch enable'}, | |
'get_time_on': { | |
'Command': '@{}TIM?;FF', | |
'Response': '@xxxACK12345;FF', | |
'Explanation': 'Time on (hours of operation )'}, | |
'get_pirani_temp': { | |
'Command': '@{}TEM?;FF', | |
'Response': '@xxxACK2.50E+1;FF', | |
'Explanation': 'MicroPirani sensor temperature'}, | |
'get_usertext': { | |
'Command': '@{}UT?;FF', | |
'Response': '@xxxACKVACUUM1;FF', | |
'Explanation': 'User programmed text string'}, | |
'get_status': { | |
'Command': '@{}T?;FF', | |
'Response': '@xxxACKO;FF', | |
'Explanation': 'Transducer status check'} | |
}, | |
'Calibration and adjustment information': { | |
'get_pressure_unit': { | |
'Command': '@{}U?;FF', | |
'Response': '@xxxACKTORR;FF', | |
'Explanation': 'Pressure unit setup (Torr, mbar or Pascal)'}, | |
'get_calibration_gas': { | |
'Command': '@{}GT?;FF', | |
'Response': '@xxxACKNITROGEN;FF', | |
'Explanation': 'MicroPirani sensor calibration gas (Nitrogen, Air, Argon, Helium, Hydrogen, H2O, Neon, CO2, Xenon)'}, | |
'get_factory_diff_zero_point': { | |
'Command': '@{}VAC?;FF', | |
'Response': '@xxxACK5.12E-5;FF', | |
'Explanation': 'Provides delta pressure value between current vacuum zero adjustment and factory calibration.'}, | |
'get_factory_diff_atmosphere': { | |
'Command': '@{}ATM?;FF', | |
'Response': '@xxxACK1.22E+1;FF', | |
'Explanation': 'Provides delta pressure value between current atmospheric adjustment and factory calibration.'}, | |
'get_analog_out_1': { | |
'Command': '@{}AO1?;FF', | |
'Response': '@xxxACK10;FF', | |
'Explanation': 'Analog voltage output 1: Pressure assignment and calibration. (first digit is pressure assignment, second and third digit is calibration)'}, | |
'get_analog_out_2': { | |
'Command': '@{}AO2?;FF', | |
'Response': '@xxxACK10;FF', | |
'Explanation': 'Analog voltage output 2: Pressure assignment and calibration. (first digit is pressure assignment, second and third digit is calibration)'} | |
}, | |
'Setpoint setup and configuration': { | |
'set_setpoint_1':{ | |
'Command': '@{}SP1!2.00E+1;FF', | |
'Response': '@xxxACK2.00E+1;FF', | |
'Explanation': 'Set point 1-3 switch value.'}, | |
'set_setpoint_2':{ | |
'Command': '@{}SP2!2.00E+1;FF', | |
'Response': '@xxxACK2.00E+1;FF', | |
'Explanation': 'Set point 1-3 switch value.'}, | |
'set_setpoint_3':{ | |
'Command': '@{}SP3!2.00E+1;FF', | |
'Response': '@xxxACK2.00E+1;FF', | |
'Explanation': 'Set point 1-3 switch value.'}, | |
'set_hysteresis_1':{ | |
'Command': '@{}SH1!5.00E+1;FF', | |
'Response': '@xxxACK5.00E+1;FF', | |
'Explanation': 'Set point 1-3 hysteresis switch value.'}, | |
'set_hysteresis_2':{ | |
'Command': '@{}SH2!5.00E+1;FF', | |
'Response': '@xxxACK5.00E+1;FF', | |
'Explanation': 'Set point 1-3 hysteresis switch value.'}, | |
'set_hysteresis_3':{ | |
'Command': '@{}SH3!5.00E+1;FF', | |
'Response': '@xxxACK5.00E+1;FF', | |
'Explanation': 'Set point 1-3 hysteresis switch value.'}, | |
'enable_setpoint_1':{ | |
'Command': '@{}EN1!ON;FF', | |
'Response': '@xxxACKON;FF', | |
'Explanantion': 'Set point 1-3 enable status (ON or OFF)'}, | |
'enable_setpoint_2':{ | |
'Command': '@{}EN2!ON;FF', | |
'Response': '@xxxACKON;FF', | |
'Explanantion': 'Set point 1-3 enable status (ON or OFF)'}, | |
'enable_setpoint_3':{ | |
'Command': '@{}EN3!ON;FF', | |
'Response': '@xxxACKON;FF', | |
'Explanantion': 'Set point 1-3 enable status (ON or OFF)'}, | |
'set_setpoint1_relay_direction':{ | |
'Command': '@{}SD1!BELOW;FF', | |
'Response': '@xxxACKBELOW;FF', | |
'Explanation': 'Set point relay direction (ABOVE or BELOW). If set to above relay will be energized above setpoint value. If set to below relay will be energized below setpoint value.'}, | |
'set_setpoint2_relay_direction':{ | |
'Command': '@{}SD2!BELOW;FF', | |
'Response': '@xxxACKBELOW;FF', | |
'Explanation': 'Set point relay direction (ABOVE or BELOW). If set to above relay will be energized above setpoint value. If set to below relay will be energized below setpoint value.'}, | |
'set_setpoint3_relay_direction':{ | |
'Command': '@{}SD3!BELOW;FF', | |
'Response': '@xxxACKBELOW;FF', | |
'Explanation': 'Set point relay direction (ABOVE or BELOW). If set to above relay will be energized above setpoint value. If set to below relay will be energized below setpoint value.'}, | |
'set_setpoint_safety_delay':{ | |
'Command': '@{}SPD!ON;FF', | |
'Response': '@xxxACKON;FF', | |
'Explanation': 'Setpoint safety delay (prevent pulse trig of setpoint)'} | |
}, | |
'Communication setup': { | |
'set_baud_rate': { | |
'Command': '@{}BR!19200;FF', | |
'Response': '@xxxACK19200;FF', | |
'Explanation': 'Set communication Baud rate (4800, 9600, 19200, 38400, 57600, 115200, 230400)'}, | |
'set_address': { | |
'Command': '@{}AD!123;FF', | |
'Response': '@xxxACK123;FF', | |
'Explanation': 'Set Transducer communication address (001 to 253)'}, | |
'set_comms_delay': { | |
'Command': '@{}RSD!OFF;FF', | |
'Response': '@xxxACKOFF;FF', | |
'Explanation': 'Turn on or off communication delay between receive and transmit sequence.'} | |
}, | |
'Calibration and adjustment': { | |
'set_pressure_unit': { | |
'Command': '@{}U!MBAR;FF', | |
'Response': '@xxxACKMBAR;FF', | |
'Explanation': 'Set pressure unit setup (Torr, mbar, Pascal)'}, | |
'set_calibration_gas': { | |
'Command': '@{}GT!ARGON;FF', | |
'Response': '@xxxACKARGON;FF', | |
'Explanation': 'Set MicroPirani sensor calibration gas. (Nitrogen, Air, Argon, Helium, Hydrogen, H2O, Neon, CO2, Xenon)'}, | |
'perform_pirani_zero_adjustment': { | |
'Command': '@{}VAC!;FF', | |
'Response': '@xxxACK;FF', | |
'Explanation': 'Executes MicroPirani zero adjustment'}, | |
'perform_pirani_atmosphere_adjustment': { | |
'Command': '@{}ATM!7.60E+2;FF', | |
'Response': '@xxxACK;FF', | |
'Explanation': 'Executes MicroPirani full scale atmospheric adjustment.'}, | |
'perform_piezo_absolute_adjustment': { | |
'Command': '@{}ATD!7.60E+2;FF', | |
'Response': '@xxxACK;FF', | |
'Explanation': 'Executes Piezo absolute reading at zero differential pressure.'}, | |
'perform_piezo_differential_adjustment': { | |
'Command': '@{}ATZ;FF', | |
'Response': '@xxxACK;FF', | |
'Explanation': 'Executes Piezo differential zero adjustment'}, | |
'set_analog_out_1': { | |
'Command': '@{}AO1!10;FF', | |
'Response': '@xxxACK10;FF', | |
'Explanation': 'Set analog voltage output 1 calibration.'}, | |
'set_analog_out_2': { | |
'Command': '@{}AO1!10;FF', | |
'Response': '@xxxACK10;FF', | |
'Explanation': 'Set analog voltage output 2 calibration.'} | |
}, | |
'Information setup': { | |
'set_user_tag':{ | |
'Command': '@{}UT!LOADLOCK;FF', | |
'Response': '@xxxACKLOADLOCK;FF', | |
'Explanation': 'Set transducer user tag' | |
} | |
}, | |
'User Switch': { | |
'set_userswitch_on_off': { | |
'Command': '@{}SW!ON;FF', | |
'Response': '@xxxACKON;FF', | |
'Explanation': 'Enable / disable user switch' | |
} | |
} | |
} | |
error_responses = [ | |
['NAK Code', 'Error', 'description'], | |
['8', 'Zero adjustment at too high pressure', '@253VAC!;FF'], | |
['9', 'Atmospheric adjustment at too low pressure', '@253ATM!7.60;FF'], | |
['160', 'Unrecognized message', '@253S%;FF'], | |
['169', 'Invalid argument', '@253EN1!of;FF'], | |
['172', 'Value out of range', '@253SP1!5.00E+9;FF'], | |
['175', 'Command/query character invalid', '@253FV!;FF'], | |
['180', 'Not in setup mode (locked)', '-'], | |
] | |
# xxx = Transducer communication address (001 to 253. Broadcast addresses: 254, 255) | |
broadcast_address_1 = 254 # 254 WILL cause any listening sensors to reply | |
broadcast_address_2 = 255 # 255 will NOT cause any listening sensors to reply | |
DEBUG = False | |
import serial | |
class Mks901P(object): | |
def __init__(self, com_port_name, baud=9600): | |
self.com_port_name = com_port_name | |
if DEBUG: | |
print('creating new MKS 901p object with baud of {}'.format(baud)) | |
self.serial_port = serial.Serial(com_port_name, baudrate=baud) | |
#self.serial_port.read() | |
self.pressure_unit = None | |
def get_pressure_unit(self, address=broadcast_address_1): | |
cmd = commands['Calibration and adjustment information']['get_pressure_unit'] | |
expect = cmd['Response'] | |
cmd = cmd['Command'] | |
output = self.send_cmd(cmd, expect, address) | |
if output: | |
self.pressure_unit = output[1] | |
return self.pressure_unit | |
def get_pressure_combined_4_digit(self, address=broadcast_address_1, return_address=False): | |
cmd = commands['Pressure reading']['combined_4_digit']['Command'] | |
expect = commands['Pressure reading']['combined_4_digit']['Response'] | |
output = self.send_cmd(cmd, expect, address) | |
if output and not return_address: | |
return output[1] | |
return output | |
def send_cmd(self, cmd, expected_response, address): | |
cmd = cmd.format(address) | |
self.serial_port.write(bytes(cmd.encode())) | |
raw_data = self.serial_port.read(len(expected_response)) | |
data = raw_data.decode() | |
if 'ACK' in data: | |
addr = data[data.index('@')+len('@'):data.index('ACK')] | |
value = data[data.index('ACK')+len('ACK'):].split(';')[0] | |
return (addr,value) | |
else: | |
if DEBUG: | |
print('no ACK received from cmd') | |
return None | |
import os | |
import sys | |
import time | |
this_files_path = os.path.abspath(__file__) | |
if __name__ == '__main__': | |
import argparse | |
parser = argparse.ArgumentParser() | |
parser.add_argument("serial_port", help='the Windows COM port or path to a linux serial port') | |
parser.add_argument("--find_baud", help='tries to access the sensor over all supported baud rates, prints which is successful', action="store_true") | |
parser.add_argument("--baud", help='baud rate to connect with, defaults to 9600 (901p factory default)', type=int) | |
parser.add_argument("-unit", help='print pressure unit with each reading', action="store_true") | |
args = parser.parse_args() | |
com_port = args.serial_port | |
if args.find_baud and not args.baud: | |
from subprocess import STDOUT, check_output, TimeoutExpired | |
for baud in baud_supported: | |
print("attempting to ask MKS 901p for it's baudrate using baudrate of {}".format(baud)) | |
cmd = [sys.executable, this_files_path, com_port, '--find_baud', '--baud={}'.format(baud)] | |
try: | |
output = check_output(cmd, stderr=STDOUT, timeout=1) | |
if output: | |
output = output.decode().split(',') | |
output = [o.strip("() '\n") for o in output] | |
print('sensor ({}) replied with baudrate of ({})'.format(output[0], output[1])) | |
break | |
except TimeoutExpired: | |
pass | |
elif args.find_baud and args.baud: | |
if DEBUG: | |
print('setting up connection using baudrate of: {}'.format(args.baud)) | |
m = Mks901P(com_port, args.baud) | |
cmd = commands['Communication information']['get_baud_rate']['Command'] | |
expect = commands['Communication information']['get_baud_rate']['Response'] | |
print(m.send_cmd(cmd, expect, broadcast_address_1)) | |
else: | |
if args.baud: | |
m = Mks901P(com_port, args.baud) | |
else: | |
m = Mks901P(com_port) | |
unit = '' | |
if args.unit: | |
unit = ' {}'.format(m.get_pressure_unit()) | |
while True: | |
print('{}{}'.format(m.get_pressure_combined_4_digit(), unit)) | |
time.sleep(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment