Module hvps_lib
Expand source code
# py-hvps-interface GUI of the Project Peta-pico-Voltron
# petapicovoltron.com
# Copyright 2017-2020 Samuel Rosset
# Distributed under the terms of the GNU General Public License GNU GPLv3
# This file is part of py-hvps-interface.
# py-hvps-interface is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# py-hvps-interface is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with py-hvps-interface. If not, see <http://www.gnu.org/licenses/>
try:
import serial
except ImportError:
serial = None
print("Serial library missing. You need to install pySerial")
exit()
import serial.tools.list_ports
from time import sleep
from math import sin
from math import pi
EMUL = False # Set to True to test the library without a connected HVPS
DEBUG = False
LIB_VER = "2.9" # Version of this library (matches the Labview Library number)
FIRM_VER = 9 # Firmware version That this library expects to run on the HVPS
# S witching mode constants: off=0, on-DC=1, on-Switching=2, on-waveform=3
SWMODE_OFF = 0
SWMODE_DC = 1
SWMODE_SW = 2
SWMODE_WFRM = 3
# Switching source constants: Timer=0,External=1, Button=2,
SWSRC_TMR = 0
SWSRC_EXT = 1
SWSRC_BTTN = 2
# Voltage control mode constants: Regulated=0, External=1, Open loop=2
VMODE_R = 0
VMODE_EXT = 1
VMODE_O = 2
# Stroboscobic illumination mode: Off=0 Fixed position=1, sweeping mode=2
STMODE_OFF = 0
STMODE_FIXED = 1
STMODE_SWEEP = 2
# Standard user-defined functions
FUNC_SINE = 0 # sine + offset
FUNC_TRI = 1 # Triangle
FUNC_TRAP = 2 # Trapezoid
FUNC_CSTM = 3 # Custom waveform (read from file)
# Error bits
ERR_FIRM = 0b1 # Incompatibility between python library and Firmware running on HVPS
ERR_TYPE = 0b10 # The connected arduino is not a single channel HVPS
ERR_JACK = 0b100 # The power Jack is not plugged
ERR_COM = 0b1000 # Communication error: The arduino is detected but cannot talk to it. Is arduino running the shvps
# firmware?
ERR_CONF = 0b10000 # Configuration error: the HVPS running the hvps software, but appears to be unconfigured
ERR_PORT = 0b100000 # port cannot be open. Used by another process
class HVPS:
""" Class to control a petapicovoltron HVPS
The class implements the functions from https://petapicovoltron.com/software/direct-communication-with-the-hvps/
for easy communication with the HVPS. In addition, a few higher-level functions are provided, especially
for the user-defined waveform."""
# ====Communication functions and class constructor====
def __init__(self, port):
""" Initialises a HVPS object: dev = HVPS('/path/to/serial/port').
Input: COM port to which the HVPS is connected. You can use /dev/null if using in emulator mode (EMUL = True)"""
self.name = ''
self.i2c = ''
self.vmax = 0
self.swmode = 0
self.vset = 0
self.vnow = 0
self.f = 0
self.cycles = 0
self.cycle_n = 0 # the current cycle number
self.swsrc = 0
self.vmode = 0
self.latch = 0 # latching behaviour of the button
self.err = 0
self.stmode = 0 # Strobe mode
self.stpos = 0 # Strobe position
self.stdur = 0 # strobe duration
self.stsweep = 5000 # Strobe sweep time (default when HVPS starts)
self.config = 0 # 0 0=HVPS powered with external power_supply 1=HVPS integrated with touchscreen (standalone mode)
self.listen = 0 # in touchscreen + battery mode, listen=1 if interface must listen on Pi's serial port
# for incoming commands
self.ser = serial.Serial() # the serial connection to the HVPS
self.waveform_pts = [] # list to store the set points of the custom waveform
self.waveform_meas = [] # list to store the measured points of the custom waveform.
if not EMUL:
try:
self.ser = serial.Serial(port, 115200, timeout=1)
except serial.SerialException:
self.err = self.err | ERR_PORT
if DEBUG:
print("Cannot connect to serial port. Probably busy.")
else:
self.ser.reset_input_buffer()
if DEBUG:
text = "connecting to " + port
print(text)
print("Serial port open")
self.ser.write(b'QVer\r') # We send a command to see if board answers
sleep(0.1)
if self.ser.in_waiting == 0: # if no reply then the connected board is not running a HVPS firmware
self.err = self.err | ERR_COM
else: # communication is established and board replies to commands
self.ser.reset_input_buffer()
if self.q_type() != "slave": # check that the HVPS connected is a SHVPS
self.err = self.err | ERR_TYPE
else:
self.name = self.q_name() # reads the name of the board
if self.name == b'': # empty name is taken to mean that the board is un-configured
self.err = self.err | ERR_CONF
else:
if self.q_ver() != FIRM_VER: # HVPs not running the correct firmware version
self.err = self.err | ERR_FIRM
if not self.q_jack() and self.q_power_jack(): # We don't check for presence of power jack
# if HVPS powered via 5V pin (and not jack). self.config cannot be used at this time as
# not initialised
self.err = self.err | ERR_JACK
self._initialise() # initialise the board (note that ERR_FIRM and ERR_JACK
# lead to initialisation
def close(self): # closes connection with the HVPS
"""Closes the connection to the HVPS. Sets voltage to 0 if board was connected"""
if not EMUL:
if self.ser.is_open:
if not (self.err & ERR_COM): # if connected board is not running the firmware, do not send command
self.s_vset(0) # set the voltage to 0 as a safety measure
self.ser.close()
if DEBUG:
print("Serial port closed")
def transmit(self, x): # transmits a command directly to the HVPS
"""Sends a direct command to the HVPS
Sends a command to the HVPS. List of commands:
https://petapicovoltron.com/software/direct-communication-with-the-hvps/
This function is used by the main() functions in case this file is run as a script
and provides an interactive terminal session with the HVPS. However, when using
the library, the specific functions provided by the library should be used instead\n
input: x: a string to send to the HVPS\n
output: The reply from the HVPS (string)"""
if EMUL:
z = b'null\r\n'
else:
self.ser.write(x)
z = self._readline2()
if DEBUG:
print(x)
print(z)
return z
def _readline(self): # reads a line on the serial port and removes the end of line characters
line = self._readline2()
line = line[:-2] # removes the last 2 elements of the array because it is \r\n
return bytes(line)
def _readline2(self): # reads a line on the serial port
eol = b'\r\n' # Arduino println command adds \r\n at the end of lines
leneol = len(eol)
line = bytearray()
while True:
c = self.ser.read(1)
if c:
line += c
if line[-leneol:] == eol:
break
else:
break
return bytes(line)
def _initialise(self):
self.vmax = self.q_vmax()
self.i2c = self.q_i2c()
self.f = self.q_f()
self.config = not self.q_power_jack() # get the configuration of the HVPS (1= touchscreen + battery).
self.latch = self.q_latch_mode()
self.stmode = self.q_st_mode() # Strobe mode is not saved in memory. But it is not necessarily 0,
# if the interface was closed, but the HVPS not unplugged
self.stpos = self.q_st_pos()
self.stdur = self.q_st_dur()
self.stsweep = self.s_st_sweep(self.stsweep)
if self.config == 0: # if HVPS connected via USB
self.vset = self.s_vset(0)
self.swmode = self.s_sw_mode(SWMODE_DC)
self.swsrc = self.s_sw_src(SWSRC_TMR)
self.vmode = self.s_v_mode(VMODE_R)
self.cycles = self.s_cycle(0)
else: # if in touchscreen housing, then we use the current parameters (i.e. memory if just
# started or last params if interface is restarted)
self.vset = self.q_vset() # initialises the info structure with the current parameters of the HVPS
self.swmode = self.q_sw_mode()
self.swsrc = self.q_sw_src()
self.vmode = self.q_v_mode()
s = self.q_cycle()
self.cycles = int(s[1])
if DEBUG:
print("Bord initialised")
# ====Commands related to voltage and frequency====
def s_vset(self, x): # sets the output voltage
""" Sets the output voltage of the HVPS
input: x: voltage set point (int)\n
output: voltage set point accepted by HVPS\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
Although this command can be used at any time, it is mainly useful when the HVPS voltage control mode is
internal regulator (VMODE_R); see s_vmode() command."""
if EMUL:
z = x
else:
x = constrain(x, 0, self.vmax)
string = 'SVset '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_vset(" + str(x) + ") -> " + str(z)
print(y)
self.vset = z
return z
def q_vset(self): # queries the voltage setpoint
"""Queries the voltage set point. The returned value is in volts."""
if EMUL:
z = 0
else:
self.ser.write(b'QVset\r')
z = int(self._readline())
if DEBUG:
y = "q_vset -> " + str(z)
print(y)
self.vset = z
return z
def q_vnow(self): # queries the voltage output
"""Queries the current feedback voltage of the HVPS.
The returned value is in volts.
Note that it is not necessarily the voltage at the output of the HVPS, which also depends on the
switching mode (whether the HVPS is off, in DC mode, or switching)."""
if EMUL:
z = 0
else:
self.ser.write(b'QVnow\r')
try:
z = int(self._readline())
except ValueError:
z = 0
if DEBUG:
y = "q_vnow -> " + str(z)
print(y)
self.vnow = z
return z
def s_pwm(self, x): # sets the pwm value
""" Set the voltage output as a PWM value
Defines the functioning set point of the HV programmable source as a 10-bit (0-1023) raw PWM value.
Although this command can be used at any time, it mainly useful when the HVPS voltage control mode is
internal openloop, VMODE_O (see set_vmode() command).\n
input: x: PWM set point (0-1023)\n
output: PWM set point accepted by HVPS"""
if EMUL:
z = 0
else:
x = constrain(x, 0, 1023)
string = 'SPWM '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_pwm -> " + str(z)
print(y)
return z
def q_pwm(self): # queries the pwm setting
"""Queries the current HVPS set point as a raw PWM value. returns value between 0 and 1023"""
if EMUL:
z = 0
else:
self.ser.write(b'QPWM\r')
z = int(self._readline())
if DEBUG:
y = "q_pwm -> " + str(z)
print(y)
return z
def s_f(self, x): # sets the frequency
"""Sets the frequency of the signal
Sets the frequency of the signal when the HVPS is in switching mode (SWMODE_SW).\n
The value returned is the new frequency, taking quantification into account.\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
input: x: frequency in Hz between 0.001 and 1000\n
output: frequency accepted by HVPS"""
if EMUL:
z = 1
else:
x = constrain(x, 0.001, 1000.0)
string = 'SF '
string = string + f"{x:.3f}" + '\r'
string = string.encode()
self.ser.write(string)
z = float(self._readline())
if DEBUG:
y = "s_f(" + str(x) + ") -> " + str(z)
print(y)
self.f = z
return z
def q_f(self): # queries the frequency
"""Queries the switching frequency. The returned value is in Hz."""
if EMUL:
z = 1
else:
self.ser.write(b'QF\r')
z = float(self._readline())
if DEBUG:
y = "q_f -> " + str(z)
print(y)
self.f = z
return z
def s_cycle(self, x): # sets the number of cycles
"""Sets the number of switching cycles
Sets the number of switching cycles to perform when the HVPS is in switching mode.
The maximum value is 65535. A value of 0 means continuous switching (unlimited number of cycles).
For any value other than 0, the HVPS will change to switching mode 0 (HVPS off, SWMODE_OFF, after the desired
number of cycles is reached. A new series of switching cycles can be can be initiated by placing the HVPS
back in switching mode (SWMODE_SW). When you call s_cycle(), the cycle counter is reset to 0.
Example: s_cycle(1000) to switch 1000 times at the selected frequency and then stop.
Note that s_cycles configures the HVPS to switch for a limited number of time. If the HVPS is in switching
mode (SWMODE_SW), then the cycles will start at once. If the HVPS is in off mode (SWMODE_OFF) or in
DC mode (SWMODE_DC), the cycles will start once the HVPS is put in Switching mode with s_sw_mode(SWMODE_SW).\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
input: x: number of cycles (0 to 65535)\n
output: number of cycles accepted by HVPS"""
if EMUL:
z = x
else:
x = constrain(x, 0, 65535)
string = 'SCycle '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_cycle(" + str(x) + ") -> " + str(z)
print(y)
self.cycles = z
return z
def q_cycle(self): # queries the number of cycles returns a list. Element 0 is the current cycle number.
# Element 1 is the total number of cycles in the series.
"""Queries the number of cycles.
Queries the number of cycles. The returned value is a list z, with z[0] being the current cycle
number and z[1] the total number of cycles to make. Once the total number of cycles is reached,
the output is turned off (SWMODE_OFF), and q_cycle() returns [0,XXX] with XXX the number of cycles to make
(XXX=0 in case of continuous cycles)."""
if EMUL:
z = "0/0"
else:
self.ser.write(b'QCycle\r')
z = self._readline()
z = z.decode("utf-8")
if DEBUG:
y = "q_cycle -> " + z
print(y)
s = z.split("/")
self.cycles = s[1]
self.cycle_n = s[0]
return s
# Commands to change the voltage control and switching behaviour
def s_sw_mode(self, x): # sets the switching mode
"""Sets the switching mode of the HVPS.
Sets the switching mode of the HVPS. Four possible values: SWMODE_OFF: HVPS is off (0 V output irrespective
of voltage set point), SWMODE_DC: the HVPS is in DC mode with a constant output voltage at the desired
set point, SWMODE_SW: the HVPS is switching at the desired frequency between 0V and Vset, and SWMODE_WFRM:
the HVPS is in user-defined waveform mode. Setting the switching mode is only effective if the switching
source is SWSRC_TMR (onboard timer switching).\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
input: x: SWMODE_OFF, SWMODE_DC, SWMODE_SW, or SWMODE_WFRM\n
output: Switching mode set by the HVPS"""
if EMUL:
z = x
else:
if x > SWMODE_WFRM:
x = SWMODE_OFF
string = 'SSwMode '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_sw_mode(" + str(x) + ") -> " + str(z)
print(y)
self.swmode = z
return z
def q_sw_mode(self): # queries the switching mode
"""Queries the switching mode of the HVPS.
Queries the switching mode of the HVPS. Output is either SWMODE_OFF: HVPS is off (0 V output irrespective
of voltage setpoint), SWMODE_DC the HVPS is in DC mode with a constant output voltage at the desired
set point, SWMODE_SW: the HVPS is switching at the desired frequency between 0V and Vset, or SWMODE_WFRM:
the HVPS is in user-defined waveform mode."""
if EMUL:
z = 1
else:
self.ser.write(b'QSwMode\r')
z = int(self._readline())
if DEBUG:
y = "q_sw_mode -> " + str(z)
print(y)
self.swmode = z
return z
def s_sw_src(self, x): # sets the switching source
"""Sets the source of the switching signal.
Sets the source of the switching signal. Accepted values are: SWSRC_TMR for onboard switching
(from internal clock of the board), SWSRC_EXT for external switching via pin 6 (Ext.F) on the board main
connector, or SWSRC_BTTN for the push button. Example: s_sw_src(SWSRC_EXT) to use the external signal to
switch the source on/off. Note that this setting is useful only if the jumper on header H2 is set to
“onboard control”, else the jumper setting defines the source of the switching signal.\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
input: x: SWSRC_TMR, or SWSRC_EXT, or SWSRC_BTTN"""
if EMUL:
z = x
else:
if x > SWSRC_BTTN:
x = SWSRC_TMR
string = 'SSwSrc '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_sw_src(" + str(x) + ") -> " + str(z)
print(y)
self.swsrc = z
return z
def q_sw_src(self): # queries the switching source
"""Queries the source of the switching signal.
Queries the source of the switching signal. Output is SWSRC_TMR for onboard switching
(from internal clock of the board), SWSRC_EXT for external switching via pin 6 (Ext.F) on the board main
connector, or SWSRC_BTTN for the push button. Example: s_sw_src(SWSRC_EXT) to use the external signal to
switch the source on/off. Note that this setting is useful only if the jumper on header H2 is set to
“onboard control”, else the jumper setting defines the source of the switching signal."""
if EMUL:
z = 1
else:
self.ser.write(b'QSwSrc\r')
z = int(self._readline())
if DEBUG:
y = "q_sw_src -> " + str(z)
print(y)
self.swsrc = z
return z
def s_latch_mode(self, x): # sets the latch mode of the push button
"""Defines the behaviour of the push button
Defines the behaviour of the push button, when the switching source of the HVPS is set to the push button
(SWSRC_BTTN, c.f. s_sw_src() command above). Accepted values are 0 and 1: 0 for a push button behaviour
(i.e. the high voltage is turned on as long as the button is pressed),
and 1 for a latching switch behaviour (i.e. press once to turn the high voltage on, and press a second time
to turn it off).\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
input: x: 0 or 1\n
output: latching mode as understood by the HVPS"""
if EMUL:
z = x
else:
if x > 1:
x = 1
string = 'SLatchMode '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_latch_mode(" + str(x) + ") -> " + str(z)
print(y)
self.latch = z
return z
def q_latch_mode(self): # queries the latch mode of the push button
"""Queries whether the push button is configured to act as a push button (o) or a latching switch (1)."""
if EMUL:
z = 1
else:
self.ser.write(b'QLatchMode\r')
z = int(self._readline())
if DEBUG:
y = "q_latch_mode -> " + str(z)
print(y)
self.latch = z
return z
def s_v_mode(self, x): # sets the voltage control mode
"""Sets the voltage control mode
Sets the voltage control mode (i.e. how is the value of the output voltage controlled):\n
VMODE_R for internal voltage regulator (regulates the voltage to the value defined with the Vset command).\n
SMODE_EXT external voltage control (sets the output voltage according to the control voltage applied on pin 5
(Ext.V) of the main connector of the board. The input voltage range is 0 to 5V.\n
VMODE_O (that's an O like in open) internal open loop control (on-board regulator disconnected).\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
input: x: VMODE_R, VMODE_EXT, VMODE_O\n
Output: Voltage control mode accepted by the HVPS"""
if EMUL:
z = x
else:
if x > VMODE_O:
x = VMODE_R
string = 'SVMode '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_v_mode(" + str(x) + ") -> " + str(z)
print(y)
self.vmode = z
return z
def q_v_mode(self): # queries the switching source
"""Queries the voltage control mode:
Queries the voltage control mode:\n
VMODE_R internal voltage regulator, VMODE_EXT external voltage control. VMODE_O internal open loop control
(on-board regulator disconnected)."""
if EMUL:
z = 1
else:
self.ser.write(b'QVMode\r')
z = int(self._readline())
if DEBUG:
y = "q_v_mode -> " + str(z)
print(y)
self.vmode = z
return z
# ====User Waveform Functions====
def clear_waveform(self): # clear the stored waveform
"""Clear the current user-defined waveform
Clear the current user-defined waveform from the HVPS memory."""
if EMUL:
z = 0 # clear waveform returns 0
else:
self.ser.write(b'SP X\r')
z = int(self._readline())
if DEBUG:
y = "clear_waveform -> " + str(z)
print(y)
return z
def q_waveform_num_pts(self): # queries the number of points saved for the waveform
"""Queries how many data point are currently stored in the waveform"""
if EMUL:
z = 0 # returns 0 points
else:
self.ser.write(b'QPtot\r')
z = int(self._readline())
if DEBUG:
y = "q_waveform_num_pts -> " + str(z)
print(y)
return z
def s_waveform_point(self, x): # Add a point to the waveform
"""Add a point to the user waveform.
Add a point to the user waveform. Usage: s_waveform_point(xxx), with xxx between 0 and 255 representing
0 to 100% of the voltage setpoint.\n
A new waveform is defined by issuing clear_waveform() (to clear the previous waveform), followed by a series of
s_waveform_point(xxx) to define the points of the new waveform. The maximal number of allowed points is 255.
This is a low-level function provided to match the 'SP' command of the HVPS communication protocol. However,
It is easier to use upload_waveform() to upload a complete waveform to the HVPS in one go, or to use
upload_std_waveform() to upload some customisable standard waveforms.\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
input: x: set point to add to the current waveform. 0-255 representing 0-100% of voltage set point.\n
output: accepted set point (or -1 if waveform full)"""
s = [-1, -1]
x = constrain(x, 0, 255)
if EMUL:
z = x
else:
num_pts = self.q_waveform_num_pts() # queries how many points currently saved in memory
if num_pts < 255: # can only add a point if less than 255 points currently saved
string = 'SP '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = self._readline()
z = z.decode("utf-8")
s = z.split(",")
z = s[1]
else:
z = -1
if DEBUG:
y = "s_waveform_point(" + str(x) + ") -> " + str(s[0]) + "," + str(s[1])
print(y)
return z
def q_waveform_set_pts(self, x): # queries the the xth point of the waveform (x starts at 0)
"""queries the waveform set point number x
queries the waveform set point number x (0<=x<=255) returns a value between 0 and 255 representing 0 to 100%
of current voltage set point. This is a low-level function provided to match the QP command of the HVPS
communication protocol. It is easier to use download_waveform_set_pts() to download the whole waveform from
the HVPS"""
if EMUL:
z = x
else:
string = 'QP '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "q_waveform_set_point(" + str(x) + ") -> " + str(z)
print(y)
return z
def q_waveform_meas_pts(self, x): # queries the the measured voltage of the xth point of the
# waveform (x starts at 0)
"""queries the waveform measured point number x
queries the waveform measured point number x. Same as q_waveform_set_pts(), but instead of returning the set
point value, it returns the voltage value read by the SHVPS internally. In order for QR to return meaningful
values, the SHVPS must have been in Waveform mode (SWMODE_WFRM) for at least one cycle.\n
Queries the waveform point number x (0<=x<=255). returns a value between 0 and 255 representing 0 to 100%
of current voltage set point. This is a low-level function provided to match the QR command of the HVPS
communication protocol. It is easier to use download_waveform_meas_pts() to download the whole waveform from
the HVPS"""
if EMUL:
z = x
else:
string = 'QR '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "q_waveform_meas_point(" + str(x) + ") -> " + str(z)
print(y)
return z
def upload_waveform(self, x): # upload a list (x) of waveform set points to the HVPS
"""upload a user-defined waveform to the HVPS
upload a user-defined waveform to the HVPS. It starts by clearing the current waveform and then it upload
an new list of points. It also updates the member variable self.waveform_pts with the new list of points.\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n
input: x: [p1, p2, p3, ..., pn] where pn is the nth point of the waveform, between 0 and 255, representing 0 to
100% of the current voltage set point. n is limited to 255.\n
output: none"""
self.clear_waveform() # starts by clearing the waveform
self.waveform_pts.clear() # empty the current list of point of the local copy
if len(x) > 255: # waveform limited to 255 points
x = x[:255]
for point in x:
point = constrain(point, 0, 255)
self.waveform_pts.append(self.s_waveform_point(point)) # upload the point and add it to the local copy
def download_waveform_set_pts(self): # download the waveform set points stored in the HVPS
"""Download the current waveform from the HVPS
Download the current waveform from the HVPS. The output is a list of set points between 0 and 255 representing
0 to 100% of the voltage set point. the downloaded points are stored in the member list waveform_pts"""
self.waveform_pts.clear() # empty the current list of point of the local copy
num_points = self.q_waveform_num_pts()
for i in range(num_points):
self.waveform_pts.append(self.q_waveform_set_pts(i)) # download the point +add it to the local copy
def download_waveform_meas_pts(self): # download the waveform set points stored in the HVPS
"""Download the measured waveform (last performed cycle) from the HVPS
Download the current waveform from the HVPS. The output is a list of set points between 0 and 255 representing
0 to 100% of the voltage set point. the SHVPS must have been in Waveform mode (SWMODE_WFRM) for at least one
cycle to obtain meaningful values. member list waveform_meas"""
self.waveform_meas.clear() # empty the current list of point of the local copy
num_points = self.q_waveform_num_pts()
for i in range(num_points):
self.waveform_meas.append(self.q_waveform_meas_pts(i)) # download the point +add it to the local copy
def upload_std_waveform(self, func=FUNC_SINE, sr=False, n=100, b=0.15):
"""Upload a customisable standard waveform to the HVPS
inputs:\n
func: FUNC_SINE (a sine wave with an offset to be between 0 and Voltage set point), FUNC_TRI
(a triangle function), FUNC_TRAP (a Trapezoid function), FUNC_CSTM (a custom waveform. Points (a maximum number
of 255 points) should be defined in a file named waveform.txt located alongside this library. There should be
1 point per line, each point between 0 and 1, representing 0 to 100% of the voltage set point)\n
sr: (square root) True or False. In case the HVPS is used to drive dielectric elastomer actuators, there is
a quadratic relationship between voltage and actuation strain. True: a square root correction is applied so
that the actuation strain will roughly have the chosen profile. False: No correction applied/n
n: number of point in the waveform. Max is 255. It depends on the frequency at which the waveform will be
produced, For a 1Hz signal, 100 points are adequate. Reduce the number of points for higher frequencies
b: This applies only for the FUNC_TRAP function and defines the percentage of the period that the raising
(and falling) edge should take. The value should be smaller than 0.5 (at which point the waveform becomes a
triangle).\n
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the
save() command enables to save this parameter in memory\n"""
pts = []
n = constrain(n, 1, 255) # n must be between 1 and 255 points
b = constrain(b, 0, 0.5) # b must be between 0 and 0.5
if sr: # if we want the square root of the signal (because of the quadratic relationship between voltage
# and strain for DEAs)
power = 0.5
else:
power = 1.0
if func == FUNC_CSTM: # custom user waveform
try:
fp = open('./waveform.txt', 'r')
except FileNotFoundError:
if DEBUG:
print("Custom waveform must be in ./waveform.txt, but file is not found")
fp = 0
if fp:
list_of_points = fp.readlines()
for point in list_of_points:
try:
point = int(255*(float(point) ** power))
except ValueError:
point = 0
if DEBUG:
print("Error when reading point for custom waveform. Each line in the file ./waveform.txt "
"must contain a single floating point number")
point = constrain(point, 0, 255) # points should be between 0 and 255
pts.append(point)
fp.close()
else: # if other standard functions are chosen
for i in range(n):
p = 0 # p is between 0 to 1 representing percentage of voltage set point
if func == FUNC_SINE: # Sine + offset waveform
p = (0.5+0.5*sin(2*pi/n*i)) ** power
elif func == FUNC_TRAP: # trapeze waveform
if i <= b*n: # the ramp up of the trapeze
p = (i/b/n) ** power
elif i <= n/2: # holding time
p = 1
elif i <= (n/2 + b*n): # ramp down
p = (1-(i - n/2) / b / n) ** power
else:
p = 0
elif func == FUNC_TRI:
if i <= n/2: # Raising edge
p = (2/n*i) ** power
else:
p = (1 - 2 / n * (i - n / 2)) ** power
p = int(p*255)
pts.append(p)
self.upload_waveform(pts) # uploads the waveform to the HVPS
# ====Trigger / Strobe pulse functions====
def s_st_mode(self, x): # sets the strobe mode
"""Sets the strobe mode.
Sets the strobe mode. Usage: s_st_mode(X), with X being\n
STMODE_OFF: trigger/strobe pulse off: no signal is generated.\n
STMODE_FIXED: fixed position: a trigger/strobe signal is generated at a fixed position, with a fixed duration.
By default, the pulse is synchronized with the HV switching signal, but the position and duration of the pulse
can be defined by the user (see next s_st_pos()).\n
STMODE_SWEEP: sweep mode: the position of the trigger/strobe pulse is shifted along the HV signal at a
user-defined speed. The HVPS must be in switching mode (SWMODE_SW) for the trigger pulse to be generated.
The trigger pulse is generated on pin T of the multi-purpose 10-pins header on the HVPS board.\n
input: x: STMODE_OFF or STMODE_FIXED, or STMODE_SWEEP\n
output: strobe mode as understood by HVPS"""
if EMUL:
z = x
else:
if x > STMODE_SWEEP:
x = STMODE_OFF
string = 'SStMode '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_st_mode(" + str(x) + ") -> " + str(z)
print(y)
self.stmode = z
return z
def q_st_mode(self): # queries the strobe mode
"""Queries the current strobe mode.
Queries the current strobe mode. 0: Off, 1: Fixed position, 2: Sweep mode.\n
STMODE_OFF: trigger/strobe pulse off: no signal is generated.\n
STMODE_FIXED: fixed position: a trigger/strobe signal is generated at a fixed position, with a fixed duration.
By default, the pulse is synchronized with the HV switching signal, but the position and duration of the pulse
can be defined by the user (see next s_st_pos()).\n
STMODE_SWEEP: sweep mode: the position of the trigger/strobe pulse is shifted along the HV signal at a
user-defined speed."""
if EMUL:
z = 1
else:
self.ser.write(b'QStMode\r')
z = int(self._readline())
if DEBUG:
y = "q_st_mode -> " + str(z)
print(y)
self.stmode = z
return z
def s_st_pos(self, x): # sets the position of the strobe pulse
"""Sets the position of the rising edge of the strobe pulse with respect to the HV output.
Sets the position of the rising edge of the strobe pulse with respect to the HV output.
Usage: s_st_pos(xxx), with xxx a value between 0 and 255, representing the position of the rising edge of the
trigger pulse as a fraction of the period T of the HV signal. A value of 0 means that the rising edge of the
trigger pulse is coincident with the rising edge of the HV output.\n
A value of 127 means that the rising edge of the trigger pulse is coincident with the falling edge of the HV
output. The position of the pulse is only used when the strobe pulse mode is STMODE_FIXED (fixed position).\n
input: x: position of the trigger pulse (0 to 255)\n
output: position of the trigger pulse accepted by the HVPS"""
if EMUL:
z = x
else:
x = constrain(x, 0, 255)
string = 'SStPos '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_st_pos(" + str(x) + ") -> " + str(z)
print(y)
self.stpos = z
return z
def q_st_pos(self): # queries the the position of the strobe pulse
"""Queries the current position of the rising edge of the strobe/trigger pulse.
Queries the current position of the rising edge of the strobe/trigger pulse. The returned value is
between 0 and 255, and represents a fraction of the period of the HV output, with 0
being the rising edge of the HV signal."""
if EMUL:
z = 1
else:
self.ser.write(b'QStPos\r')
z = int(self._readline())
if DEBUG:
y = "q_st_pos -> " + str(z)
print(y)
self.stpos = z
return z
def s_st_dur(self, x): # sets the duration of the strobe pulse
"""Sets the duration of the strobe/trigger pulse as a fraction of the period of the HV output.
Sets the duration of the strobe/trigger pulse as a fraction of the period of the HV output.
Usage: s_st_dur(xxx), with xxx being the fraction of the period of the HV output during which the
strobe/trigger pulse must remain high
(0: constantly off, 127: on during 50% of the period, and 255: constantly on).\n
The duration of the pulse is used in strobe mode ST_MODE_FIXED (fixed position) and STMODE_SWEEP (sweep mode)\n
input: x: duration of the strobe pulse (0-255, representing 0 to 100% duty cycle)\n
output: pulse duration accepted by the HVPS"""
if EMUL:
z = x
else:
x = constrain(x, 0, 255)
string = 'SStDur '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_st_dur(" + str(x) + ") -> " + str(z)
print(y)
self.stdur = z
return z
def q_st_dur(self): # queries the the duration of the strobe pulse
"""Queries the current duration of the strobe/trigger pulse.
Queries the current duration of the strobe/trigger pulse. Returns a value between 0 and 255 representing
the fraction of the period of the HV signal during which the strobe/trigger signal remains high
(0: constantly off, 127: on during 50% of the period, and 255: constantly on)."""
if EMUL:
z = 1
else:
self.ser.write(b'QStDur\r')
z = int(self._readline())
if DEBUG:
y = "q_st_dur -> " + str(z)
print(y)
self.stdur = z
return z
def s_st_sweep(self, x): # sets the sweep period (im ms) when in sweep mode
"""sets the sweep time in ms.
sets the sweep time in ms. Usage s_st_sweep(xxx), where xxx is the time (in ms) that it takes to sweep the
strobe/trigger pulse over a complete period of the HV output. This parameter is only used in strobe mode
STMODE_SWEEP (sweep mode). If the pulse is used to drive a strobe LED, the sweep time defines the apparent
period of the motion. Logically, the period set with s_st_sweep much be considerably longer than the period
of the HV signal.\n
input: x: period of the sweep duration in ms\n
output: sweep duration accepted by HVPS"""
if EMUL:
z = x
else:
x = constrain(x, 0, 65535)
string = 'SStSw '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_st_sweep(" + str(x) + ") -> " + str(z)
print(y)
self.stsweep = z
return z
# Miscellaneous functions
def save(self): # save current HVPS parameters into the memory
"""save current HVPS parameters into the memory
This command saves the following parameters in EEPROM: Voltage setpoint, Frequency, Frequency divider,
Source of switching signal (external, internal, button), Switching mode (off, DC output, switching output),
Voltage mode (internal voltage regulator or following external signal), and number of switching cycles.
It also saves the user-defined waveform into the EEPROM. This is useful so that it is not necessary to
reconfigure the HVPS for the desired behavior every time it is powered up, for example when the HVPS is
meant to be used without computer (when connected to a demo device). Note that when the HVPS is used with a
computer, it is safer to save a voltage setpoint of 0V (and/or a switching mode 0 (box off)) so as to be sure
that no high voltage is present at the output when the board is powered up (and before the computer has the
time to initialise it to 0V output)."""
if EMUL:
z = 1
else:
self.ser.write(b'Save\r')
z = int(self._readline())
if DEBUG:
y = "save -> " + str(z)
print(y)
return z
def q_mem(self): # queries the content of the memory
"""queries the content of the memory
Queries the content of the memory (when the box is powered up, it will use the settings stored in memory,
which allows using the board without a computer).
This commands returns a string of parameters separated by commas: Voltage, Frequency, Switching source,
Switching mode, Voltage mode, Regulator gain P, Regulator gain I, Regulator gain D ,
Voltage Calibration factor 0, Voltage Calibration factor 1, Voltage Calibration factor 2,
number of switching cycles, button latching mode.\n
input: none\n
output: a HVPSMem object with the values of the different parameters."""
mem = HVPSMem()
if not EMUL:
self.ser.write(b'QMem\r')
z = self._readline()
z = z.decode("utf-8")
s = z.split(",")
mem.vset = int(s[0])
mem.f = float(s[1])
mem.swsrc = int(s[2])
mem.swmode = int(s[3])
mem.vmode = int(s[4])
mem.kp = float(s[5])
mem.ki = float(s[6])
mem.kd = float(s[7])
mem.c0 = float(s[8])
mem.c1 = float(s[9])
mem.c2 = float(s[10])
mem.cycles = int(s[11])
mem.latch = int(s[12])
else:
z = 'empty memory'
if DEBUG:
y = "q_mem -> " + z
print(y)
return mem
def q_ver(self): # queries the firmware version
"""returns the current version of the firmware running on the board."""
if EMUL:
z = 7
else:
self.ser.write(b'QVer\r')
s = self._readline() # returns a string in the form of "slave X" need to get the value of X
s = s.decode("utf-8")
z1 = s.split(" ")
z = int(z1[1])
if DEBUG:
y = "q_ver -> " + str(z)
print(y)
return z
def q_jack(self): # queries whether power Jack is plugged in.
"""returns 1 if the power adapter is plugged in the Jack socket J1, and 0 if it is not."""
if EMUL:
z = 1
else:
self.ser.write(b'QJack\r')
z = int(self._readline())
if DEBUG:
y = "q_jack -> " + str(z)
print(y)
return z
# Configuration functions
def conf(self, x): # performs initial configuration of the board
"""Performs the initial configuration of a board
Performs the initial configuration of a board (instead of using commands below separately).
Usage: conf(xxx), where XXX is the voltage rating of one of the 5 standard configurations
(i.e. 5000, 3000, 2000, 1200, and 500). Initialises Vmax to the value of XXX, and C0, C1, C2, Kp, Ki, and Kd
to the default values for each voltage rating.\n
input: x: board voltage rating (5000, 3000, 2000, 1200, or 500)
output: 1 in case of success, 0 in case of failure"""
if EMUL:
z = 1 # this emulate success
else:
if x == 5000 or x == 3000 or x == 2000 or x == 1200 or x == 500:
string = 'Conf '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline()) > 0
self._initialise() # initialises the board now that it has been configured
else:
z = 0 # 0 indicates failure (in that case entered voltage not one of the HVPS std voltages
if DEBUG:
y = "conf(" + str(x) + ") -> " + str(z)
print(y)
return z
def s_i2c(self, x): # sets the I2C address
"""sets the I2C address of the board. Only useful if board to be used in multichannel configuration
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n
input: x: I2C address to assign"""
if EMUL:
z = 12 # random returned i2c value in case we emulate the presence of a board
else:
x = constrain(x, 0, 127)
string = 'SI2C '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_I2C(" + str(x) + ") -> " + str(z)
print(y)
self.i2c = z
return z
def q_i2c(self): # queries the i2c address of the board
"""queries the I2C address of the board."""
if EMUL:
z = 12
else:
self.ser.write(b'QI2C\r')
z = int(self._readline())
if DEBUG:
y = "q_I2C -> " + str(z)
print(y)
self.i2c = z
return z
def s_vmax(self, x): # sets the maximum voltage rating of the board
"""sets the voltage rating of the SHVPS.
sets the voltage rating of the SHVPS. Must match the EMCO DC/DC converter rating.\n
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n
input: x:voltage rating of HVPS in Volt"""
if EMUL:
z = x
else:
x = constrain(x, 0, 10000)
string = 'SVmax '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_vmax(" + str(x) + ") -> " + str(z)
print(y)
self.vmax = z
return z
def q_vmax(self): # queries the voltage rating of the board
"""Queries the maximal voltage of the board. The returned value is in volts."""
if EMUL:
z = 5000
else:
self.ser.write(b'QVmax\r')
z = int(self._readline())
if DEBUG:
y = "q_vmax -> " + str(z)
print(y)
self.vmax = z
return z
def s_c0(self, x): # sets the calibration constant c0
"""sets the calibration constant c0
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n"""
if EMUL:
z = x
else:
string = 'SC0 '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = float(self._readline())
if DEBUG:
y = "s_c0(" + str(x) + ") -> " + str(z)
print(y)
return z
def q_c0(self): # queries the calibration constant c0
"""queries the calibration constant c0"""
if EMUL:
z = 0
else:
self.ser.write(b'QC0\r')
z = float(self._readline())
if DEBUG:
y = "q_c0 -> " + str(z)
print(y)
return z
def s_c1(self, x): # sets the calibration constant c1
"""sets the calibration constant c1
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n"""
if EMUL:
z = x
else:
string = 'SC1 '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = float(self._readline())
if DEBUG:
y = "s_c1(" + str(x) + ") -> " + str(z)
print(y)
return z
def q_c1(self): # queries the calibration constant c1
"""queries the calibration constant c1"""
if EMUL:
z = 0
else:
self.ser.write(b'QC1\r')
z = float(self._readline())
if DEBUG:
y = "q_c1 -> " + str(z)
print(y)
return z
def s_c2(self, x): # sets the calibration constant c2
"""sets the calibration constant c2
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n"""
if EMUL:
z = x
else:
string = 'SC2 '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = float(self._readline())
if DEBUG:
y = "s_c2(" + str(x) + ") -> " + str(z)
print(y)
return z
def q_c2(self): # queries the calibration constant c2
"""queries the calibration constant c2"""
if EMUL:
z = 0
else:
self.ser.write(b'QC2\r')
z = float(self._readline())
if DEBUG:
y = "q_c2 -> " + str(z)
print(y)
return z
def s_kp(self, x): # sets the PID gain Kp
"""sets parameters Kp of the PID regulator.
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n"""
if EMUL:
z = x
else:
string = 'SKp '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = float(self._readline())
if DEBUG:
y = "s_kp(" + str(x) + ") -> " + str(z)
print(y)
return z
def q_kp(self): # queries the PID gain Kp
"""Query the value of parameter Kp of the PID regulator"""
if EMUL:
z = 0
else:
self.ser.write(b'QKp\r')
z = float(self._readline())
if DEBUG:
y = "q_kp -> " + str(z)
print(y)
return z
def s_ki(self, x): # sets the PID gain Ki
"""""sets parameters Ki of the PID regulator.
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n"""
if EMUL:
z = x
else:
string = 'SKi '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = float(self._readline())
if DEBUG:
y = "s_ki(" + str(x) + ") -> " + str(z)
print(y)
return z
def q_ki(self): # queries the PID gain Ki
"""Query the value of parameter Ki of the PID regulator"""
if EMUL:
z = 0
else:
self.ser.write(b'QKi\r')
z = float(self._readline())
if DEBUG:
y = "q_ki -> " + str(z)
print(y)
return z
def s_kd(self, x): # sets the PID gain Kd
"""sets parameters Kd of the PID regulator.
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n"""
if EMUL:
z = x
else:
string = 'SKd '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = float(self._readline())
if DEBUG:
y = "s_kd(" + str(x) + ") -> " + str(z)
print(y)
return z
def q_kd(self): # queries the PID gain Kd
"""Query the value of parameter Kd of the PID regulator"""
if EMUL:
z = 0
else:
self.ser.write(b'QKd\r')
z = float(self._readline())
if DEBUG:
y = "q_kp -> " + str(z)
print(y)
return z
def s_name(self, x): # set the name of the HVPS
"""Sets the name of the HVPS.
Sets the name of the HVPS. 20 characters maximum\n
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n
input: x=Name of the HVPS
output: name accepted by HVPS"""
if EMUL:
z = x
elif len(x) < 21:
string = 'SName '
string = string + x + '\r'
string = string.encode()
self.ser.write(string)
z = self._readline()
else:
z = 'too long'
if DEBUG:
y = "s_kd(" + str(x) + ") -> " + str(z)
print(y)
return z
def q_name(self): # queries the name of the board
"""queries the name of the board"""
if EMUL:
z = "Emulator"
else:
self.ser.write(b'QName\r')
z = self._readline()
if DEBUG:
y = "q_name -> " + str(z)
print(y)
self.name = z
return z
def q_type(self): # queries the type (master (multi-channel), slave (single channel))
"""queries the type (master (multi-channel), slave (single channel))"""
if EMUL:
z = "slave"
else:
self.ser.write(b'QVer\r')
s = self._readline() # returns a string in the form of "slave X" need to get slave
s = s.decode("utf-8")
z1 = s.split(" ")
z = z1[0]
if DEBUG:
y = "q_ver -> " + str(z)
print(y)
return z
def s_power_jack(self, x): # sets the configuration of the HVPS (whether power comes from power jack)
"""Defines if power if provided by the power jack.
Defines if power if provided by the power jack, s_power_jack(1) (default), or through 5V pin, s_power_jack(0).
As the default is power jack 1, You only need the use this command with SPowJack 0 if you wish to use the HVPS
in the standalone configuration with touchscreen and battery, or in the multichannel configuration.\n
<b>This command automatically saves the parameter in the HVPS EEPROM</b>\n
input: x: 0 or 1
output: power jack mode accepted by HVPS"""
if EMUL:
z = x
else:
if x > 1:
x = 1
string = 'SPowJack '
string = string + str(x) + '\r'
string = string.encode()
self.ser.write(string)
z = int(self._readline())
if DEBUG:
y = "s_power_jack(" + str(x) + ") -> " + str(z)
print(y)
self.config = not z # updates the configuration status of the HVPS
return z
def q_power_jack(self): # queries whether power is supposed to come from Power Jack.
# (0 if in touchscreen + battery configuration)
"""Queries the power jack setting.
Queries the power jack setting. 1 when HVPS expects to receive power from power jack, and 0 when power
comes from 5 V pin."""
if EMUL:
z = 1
else:
self.ser.write(b'QPowJack\r')
z = int(self._readline())
if DEBUG:
y = "q_power_jack -> " + str(z)
print(y)
return z
class HVPSMem: # structure to store the memory information of the HVPS
def __init__(self):
self.vset = 0
self.f = 0
self.swsrc = 0
self.swmode = 0
self.vmode = 0
self.kp = 0
self.ki = 0
self.kd = 0
self.c0 = 0
self.c1 = 0
self.c2 = 0
self.cycles = 0
self.latch = 0
self.vmax = 0 # Vmax, ver and i2c address are not returned by the q_mem function, because they have dedicated
# query function. They are added to the structure so that all information regarding the configuration of the
# board can be grouped in a single variable. (Name should be added)
self.i2c = 0
self.ver = 0
def list_hvps(list_all=False):
"""list the arduinos and serial to usb converter connected to PC in a dictionary.
The key is the name of the HVPS, and the parameter it the associated serial port
list arduinos connected to PC in an array. It also list the generic usb to serial controller used in the
touchscreen configuration.
input:
list_all: if True list all connected HVPS.
if list_all is false, it will only list device that are configured. Using True enable to list unconfigured
devices and give the opportunity to configure them"""
arduino_ports = [ # creates a list with all of the arduino connected to the computer
p.device
for p in serial.tools.list_ports.comports()
if ('Arduino' in p.description or 'Serial' in p.description)
]
dict_hvps = {}
i = 0
for port in arduino_ports:
dev = HVPS(port) # Attempts to connect to HVPS
if not dev.err or dev.err & ERR_FIRM or dev.err & ERR_JACK: # No error (Firmware mismatch or absence of
# Power jack OK): looks to be a HVPS to which we can connect
dict_hvps[dev.name.decode("utf-8")] = port # add an entry in the dictionary with the name of the
# HVPS and the port
elif list_all and not (dev.err & ERR_PORT) and not (dev.err & ERR_COM): # Also list unconfigured boards
name = 'Noname' + str(i)
i = i+1
dict_hvps[name] = port
dev.close()
return dict_hvps
def interactive(dev):
"""provides a terminal for direct communication with a HVPS
provides a terminal for direct communication with a HVPS\n
input: dev: a HVPS object with which to communicate"""
print("entering interactive mode. Enter commands to send to HVPS. type exit to quit")
stop = False
while not stop:
data_str = input()
if data_str == "exit":
stop = True
else:
data_str = data_str + "\r"
data_str = data_str.encode()
hvps_answer = dev.transmit(data_str) # forwards commands to HVPS
hvps_answer = hvps_answer[:-2] # removes the last 2 elements of the array because it is \r\n
print(hvps_answer.decode('utf-8')) # to remove the b prefix
def main():
cont = False # flag to decide whether to continue the programme or close the COM port
dev = None
if EMUL:
dev = HVPS('/dev/NULL')
else:
ports = list_hvps(list_all=True)
keys = list(ports.keys())
if len(ports) == 0:
print("No HVPS connected to the device. Terminating programme")
exit()
elif len(ports) == 1:
dev = HVPS(ports[keys[0]]) # connects to the only available HVPS
else:
print("List of connected HVPS:")
for i in range(len(ports)):
print(str(i) + ": " + keys[i])
print("Enter the number of the board you want to connect to")
connect_to = 0
try:
connect_to = int(input())
except ValueError:
print("Invalid entry. Terminating programme")
exit()
if connect_to >= len(ports):
print("Invalid entry. Terminating programme")
exit()
else:
dev = HVPS(ports[keys[connect_to]])
error = dev.err
if error & ERR_PORT:
print("Cannot open COM port. Probably busy with another process. Terminating Programme")
if error & ERR_COM:
print("Cannot communicate with HVPS. Is it loaded with the shvps firmware?. Terminating programme")
if error & ERR_TYPE:
print("Multi chanel HVPS not supported. Connect a single channel HVPS. Terminating programme")
if error & ERR_CONF:
print("HVPS appears not to be configured. Do you want to configure board? Y/N")
if input() == 'Y':
print("Enter HVPS voltage rating (5000, 3000, 2000, 1200, or 500)")
answer = int(input())
if answer == 5000 or answer == 3000 or answer == 2000 or answer == 1200 or answer == 500:
if dev.conf(answer): # config function returns 1 if successful
print("Configuration successful, continuing")
cont = True # We are good to continue
else:
print("Configuration failed. Terminating programme")
else:
print("Wrong voltage value entered. Terminating programme")
else:
print("HVPS left unconfigured. Terminating programme")
if error & ERR_JACK:
print("Warning: Power Jack not connected. Connect HVPS to power")
cont = True
if error & ERR_FIRM:
print("Warning: HVPS firmware incompatible with this library. You should upgrade you HVPS")
cont = True
if error == 0:
cont = True
if cont:
interactive(dev)
dev.close()
def constrain(val, min_val, max_val):
"""A simple implementation to constrain a value between two boundaries"""
return min(max_val, max(min_val, val))
if __name__ == "__main__": # if the library is executed as the main programme
main()
Functions
def constrain(val, min_val, max_val)
-
A simple implementation to constrain a value between two boundaries
Expand source code
def constrain(val, min_val, max_val): """A simple implementation to constrain a value between two boundaries""" return min(max_val, max(min_val, val))
def interactive(dev)
-
provides a terminal for direct communication with a HVPS
provides a terminal for direct communication with a HVPS
input: dev: a HVPS object with which to communicate
Expand source code
def interactive(dev): """provides a terminal for direct communication with a HVPS provides a terminal for direct communication with a HVPS\n input: dev: a HVPS object with which to communicate""" print("entering interactive mode. Enter commands to send to HVPS. type exit to quit") stop = False while not stop: data_str = input() if data_str == "exit": stop = True else: data_str = data_str + "\r" data_str = data_str.encode() hvps_answer = dev.transmit(data_str) # forwards commands to HVPS hvps_answer = hvps_answer[:-2] # removes the last 2 elements of the array because it is \r\n print(hvps_answer.decode('utf-8')) # to remove the b prefix
def list_hvps(list_all=False)
-
list the arduinos and serial to usb converter connected to PC in a dictionary.
The key is the name of the HVPS, and the parameter it the associated serial port list arduinos connected to PC in an array. It also list the generic usb to serial controller used in the touchscreen configuration. input: list_all: if True list all connected HVPS. if list_all is false, it will only list device that are configured. Using True enable to list unconfigured devices and give the opportunity to configure them
Expand source code
def list_hvps(list_all=False): """list the arduinos and serial to usb converter connected to PC in a dictionary. The key is the name of the HVPS, and the parameter it the associated serial port list arduinos connected to PC in an array. It also list the generic usb to serial controller used in the touchscreen configuration. input: list_all: if True list all connected HVPS. if list_all is false, it will only list device that are configured. Using True enable to list unconfigured devices and give the opportunity to configure them""" arduino_ports = [ # creates a list with all of the arduino connected to the computer p.device for p in serial.tools.list_ports.comports() if ('Arduino' in p.description or 'Serial' in p.description) ] dict_hvps = {} i = 0 for port in arduino_ports: dev = HVPS(port) # Attempts to connect to HVPS if not dev.err or dev.err & ERR_FIRM or dev.err & ERR_JACK: # No error (Firmware mismatch or absence of # Power jack OK): looks to be a HVPS to which we can connect dict_hvps[dev.name.decode("utf-8")] = port # add an entry in the dictionary with the name of the # HVPS and the port elif list_all and not (dev.err & ERR_PORT) and not (dev.err & ERR_COM): # Also list unconfigured boards name = 'Noname' + str(i) i = i+1 dict_hvps[name] = port dev.close() return dict_hvps
def main()
-
Expand source code
def main(): cont = False # flag to decide whether to continue the programme or close the COM port dev = None if EMUL: dev = HVPS('/dev/NULL') else: ports = list_hvps(list_all=True) keys = list(ports.keys()) if len(ports) == 0: print("No HVPS connected to the device. Terminating programme") exit() elif len(ports) == 1: dev = HVPS(ports[keys[0]]) # connects to the only available HVPS else: print("List of connected HVPS:") for i in range(len(ports)): print(str(i) + ": " + keys[i]) print("Enter the number of the board you want to connect to") connect_to = 0 try: connect_to = int(input()) except ValueError: print("Invalid entry. Terminating programme") exit() if connect_to >= len(ports): print("Invalid entry. Terminating programme") exit() else: dev = HVPS(ports[keys[connect_to]]) error = dev.err if error & ERR_PORT: print("Cannot open COM port. Probably busy with another process. Terminating Programme") if error & ERR_COM: print("Cannot communicate with HVPS. Is it loaded with the shvps firmware?. Terminating programme") if error & ERR_TYPE: print("Multi chanel HVPS not supported. Connect a single channel HVPS. Terminating programme") if error & ERR_CONF: print("HVPS appears not to be configured. Do you want to configure board? Y/N") if input() == 'Y': print("Enter HVPS voltage rating (5000, 3000, 2000, 1200, or 500)") answer = int(input()) if answer == 5000 or answer == 3000 or answer == 2000 or answer == 1200 or answer == 500: if dev.conf(answer): # config function returns 1 if successful print("Configuration successful, continuing") cont = True # We are good to continue else: print("Configuration failed. Terminating programme") else: print("Wrong voltage value entered. Terminating programme") else: print("HVPS left unconfigured. Terminating programme") if error & ERR_JACK: print("Warning: Power Jack not connected. Connect HVPS to power") cont = True if error & ERR_FIRM: print("Warning: HVPS firmware incompatible with this library. You should upgrade you HVPS") cont = True if error == 0: cont = True if cont: interactive(dev) dev.close()
Classes
class HVPS (port)
-
Class to control a petapicovoltron HVPS
The class implements the functions from https://petapicovoltron.com/software/direct-communication-with-the-hvps/ for easy communication with the HVPS. In addition, a few higher-level functions are provided, especially for the user-defined waveform.
Initialises a HVPS object: dev = HVPS('/path/to/serial/port').
Input: COM port to which the HVPS is connected. You can use /dev/null if using in emulator mode (EMUL = True)
Expand source code
class HVPS: """ Class to control a petapicovoltron HVPS The class implements the functions from https://petapicovoltron.com/software/direct-communication-with-the-hvps/ for easy communication with the HVPS. In addition, a few higher-level functions are provided, especially for the user-defined waveform.""" # ====Communication functions and class constructor==== def __init__(self, port): """ Initialises a HVPS object: dev = HVPS('/path/to/serial/port'). Input: COM port to which the HVPS is connected. You can use /dev/null if using in emulator mode (EMUL = True)""" self.name = '' self.i2c = '' self.vmax = 0 self.swmode = 0 self.vset = 0 self.vnow = 0 self.f = 0 self.cycles = 0 self.cycle_n = 0 # the current cycle number self.swsrc = 0 self.vmode = 0 self.latch = 0 # latching behaviour of the button self.err = 0 self.stmode = 0 # Strobe mode self.stpos = 0 # Strobe position self.stdur = 0 # strobe duration self.stsweep = 5000 # Strobe sweep time (default when HVPS starts) self.config = 0 # 0 0=HVPS powered with external power_supply 1=HVPS integrated with touchscreen (standalone mode) self.listen = 0 # in touchscreen + battery mode, listen=1 if interface must listen on Pi's serial port # for incoming commands self.ser = serial.Serial() # the serial connection to the HVPS self.waveform_pts = [] # list to store the set points of the custom waveform self.waveform_meas = [] # list to store the measured points of the custom waveform. if not EMUL: try: self.ser = serial.Serial(port, 115200, timeout=1) except serial.SerialException: self.err = self.err | ERR_PORT if DEBUG: print("Cannot connect to serial port. Probably busy.") else: self.ser.reset_input_buffer() if DEBUG: text = "connecting to " + port print(text) print("Serial port open") self.ser.write(b'QVer\r') # We send a command to see if board answers sleep(0.1) if self.ser.in_waiting == 0: # if no reply then the connected board is not running a HVPS firmware self.err = self.err | ERR_COM else: # communication is established and board replies to commands self.ser.reset_input_buffer() if self.q_type() != "slave": # check that the HVPS connected is a SHVPS self.err = self.err | ERR_TYPE else: self.name = self.q_name() # reads the name of the board if self.name == b'': # empty name is taken to mean that the board is un-configured self.err = self.err | ERR_CONF else: if self.q_ver() != FIRM_VER: # HVPs not running the correct firmware version self.err = self.err | ERR_FIRM if not self.q_jack() and self.q_power_jack(): # We don't check for presence of power jack # if HVPS powered via 5V pin (and not jack). self.config cannot be used at this time as # not initialised self.err = self.err | ERR_JACK self._initialise() # initialise the board (note that ERR_FIRM and ERR_JACK # lead to initialisation def close(self): # closes connection with the HVPS """Closes the connection to the HVPS. Sets voltage to 0 if board was connected""" if not EMUL: if self.ser.is_open: if not (self.err & ERR_COM): # if connected board is not running the firmware, do not send command self.s_vset(0) # set the voltage to 0 as a safety measure self.ser.close() if DEBUG: print("Serial port closed") def transmit(self, x): # transmits a command directly to the HVPS """Sends a direct command to the HVPS Sends a command to the HVPS. List of commands: https://petapicovoltron.com/software/direct-communication-with-the-hvps/ This function is used by the main() functions in case this file is run as a script and provides an interactive terminal session with the HVPS. However, when using the library, the specific functions provided by the library should be used instead\n input: x: a string to send to the HVPS\n output: The reply from the HVPS (string)""" if EMUL: z = b'null\r\n' else: self.ser.write(x) z = self._readline2() if DEBUG: print(x) print(z) return z def _readline(self): # reads a line on the serial port and removes the end of line characters line = self._readline2() line = line[:-2] # removes the last 2 elements of the array because it is \r\n return bytes(line) def _readline2(self): # reads a line on the serial port eol = b'\r\n' # Arduino println command adds \r\n at the end of lines leneol = len(eol) line = bytearray() while True: c = self.ser.read(1) if c: line += c if line[-leneol:] == eol: break else: break return bytes(line) def _initialise(self): self.vmax = self.q_vmax() self.i2c = self.q_i2c() self.f = self.q_f() self.config = not self.q_power_jack() # get the configuration of the HVPS (1= touchscreen + battery). self.latch = self.q_latch_mode() self.stmode = self.q_st_mode() # Strobe mode is not saved in memory. But it is not necessarily 0, # if the interface was closed, but the HVPS not unplugged self.stpos = self.q_st_pos() self.stdur = self.q_st_dur() self.stsweep = self.s_st_sweep(self.stsweep) if self.config == 0: # if HVPS connected via USB self.vset = self.s_vset(0) self.swmode = self.s_sw_mode(SWMODE_DC) self.swsrc = self.s_sw_src(SWSRC_TMR) self.vmode = self.s_v_mode(VMODE_R) self.cycles = self.s_cycle(0) else: # if in touchscreen housing, then we use the current parameters (i.e. memory if just # started or last params if interface is restarted) self.vset = self.q_vset() # initialises the info structure with the current parameters of the HVPS self.swmode = self.q_sw_mode() self.swsrc = self.q_sw_src() self.vmode = self.q_v_mode() s = self.q_cycle() self.cycles = int(s[1]) if DEBUG: print("Bord initialised") # ====Commands related to voltage and frequency==== def s_vset(self, x): # sets the output voltage """ Sets the output voltage of the HVPS input: x: voltage set point (int)\n output: voltage set point accepted by HVPS\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n Although this command can be used at any time, it is mainly useful when the HVPS voltage control mode is internal regulator (VMODE_R); see s_vmode() command.""" if EMUL: z = x else: x = constrain(x, 0, self.vmax) string = 'SVset ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_vset(" + str(x) + ") -> " + str(z) print(y) self.vset = z return z def q_vset(self): # queries the voltage setpoint """Queries the voltage set point. The returned value is in volts.""" if EMUL: z = 0 else: self.ser.write(b'QVset\r') z = int(self._readline()) if DEBUG: y = "q_vset -> " + str(z) print(y) self.vset = z return z def q_vnow(self): # queries the voltage output """Queries the current feedback voltage of the HVPS. The returned value is in volts. Note that it is not necessarily the voltage at the output of the HVPS, which also depends on the switching mode (whether the HVPS is off, in DC mode, or switching).""" if EMUL: z = 0 else: self.ser.write(b'QVnow\r') try: z = int(self._readline()) except ValueError: z = 0 if DEBUG: y = "q_vnow -> " + str(z) print(y) self.vnow = z return z def s_pwm(self, x): # sets the pwm value """ Set the voltage output as a PWM value Defines the functioning set point of the HV programmable source as a 10-bit (0-1023) raw PWM value. Although this command can be used at any time, it mainly useful when the HVPS voltage control mode is internal openloop, VMODE_O (see set_vmode() command).\n input: x: PWM set point (0-1023)\n output: PWM set point accepted by HVPS""" if EMUL: z = 0 else: x = constrain(x, 0, 1023) string = 'SPWM ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_pwm -> " + str(z) print(y) return z def q_pwm(self): # queries the pwm setting """Queries the current HVPS set point as a raw PWM value. returns value between 0 and 1023""" if EMUL: z = 0 else: self.ser.write(b'QPWM\r') z = int(self._readline()) if DEBUG: y = "q_pwm -> " + str(z) print(y) return z def s_f(self, x): # sets the frequency """Sets the frequency of the signal Sets the frequency of the signal when the HVPS is in switching mode (SWMODE_SW).\n The value returned is the new frequency, taking quantification into account.\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: frequency in Hz between 0.001 and 1000\n output: frequency accepted by HVPS""" if EMUL: z = 1 else: x = constrain(x, 0.001, 1000.0) string = 'SF ' string = string + f"{x:.3f}" + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_f(" + str(x) + ") -> " + str(z) print(y) self.f = z return z def q_f(self): # queries the frequency """Queries the switching frequency. The returned value is in Hz.""" if EMUL: z = 1 else: self.ser.write(b'QF\r') z = float(self._readline()) if DEBUG: y = "q_f -> " + str(z) print(y) self.f = z return z def s_cycle(self, x): # sets the number of cycles """Sets the number of switching cycles Sets the number of switching cycles to perform when the HVPS is in switching mode. The maximum value is 65535. A value of 0 means continuous switching (unlimited number of cycles). For any value other than 0, the HVPS will change to switching mode 0 (HVPS off, SWMODE_OFF, after the desired number of cycles is reached. A new series of switching cycles can be can be initiated by placing the HVPS back in switching mode (SWMODE_SW). When you call s_cycle(), the cycle counter is reset to 0. Example: s_cycle(1000) to switch 1000 times at the selected frequency and then stop. Note that s_cycles configures the HVPS to switch for a limited number of time. If the HVPS is in switching mode (SWMODE_SW), then the cycles will start at once. If the HVPS is in off mode (SWMODE_OFF) or in DC mode (SWMODE_DC), the cycles will start once the HVPS is put in Switching mode with s_sw_mode(SWMODE_SW).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: number of cycles (0 to 65535)\n output: number of cycles accepted by HVPS""" if EMUL: z = x else: x = constrain(x, 0, 65535) string = 'SCycle ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_cycle(" + str(x) + ") -> " + str(z) print(y) self.cycles = z return z def q_cycle(self): # queries the number of cycles returns a list. Element 0 is the current cycle number. # Element 1 is the total number of cycles in the series. """Queries the number of cycles. Queries the number of cycles. The returned value is a list z, with z[0] being the current cycle number and z[1] the total number of cycles to make. Once the total number of cycles is reached, the output is turned off (SWMODE_OFF), and q_cycle() returns [0,XXX] with XXX the number of cycles to make (XXX=0 in case of continuous cycles).""" if EMUL: z = "0/0" else: self.ser.write(b'QCycle\r') z = self._readline() z = z.decode("utf-8") if DEBUG: y = "q_cycle -> " + z print(y) s = z.split("/") self.cycles = s[1] self.cycle_n = s[0] return s # Commands to change the voltage control and switching behaviour def s_sw_mode(self, x): # sets the switching mode """Sets the switching mode of the HVPS. Sets the switching mode of the HVPS. Four possible values: SWMODE_OFF: HVPS is off (0 V output irrespective of voltage set point), SWMODE_DC: the HVPS is in DC mode with a constant output voltage at the desired set point, SWMODE_SW: the HVPS is switching at the desired frequency between 0V and Vset, and SWMODE_WFRM: the HVPS is in user-defined waveform mode. Setting the switching mode is only effective if the switching source is SWSRC_TMR (onboard timer switching).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: SWMODE_OFF, SWMODE_DC, SWMODE_SW, or SWMODE_WFRM\n output: Switching mode set by the HVPS""" if EMUL: z = x else: if x > SWMODE_WFRM: x = SWMODE_OFF string = 'SSwMode ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_sw_mode(" + str(x) + ") -> " + str(z) print(y) self.swmode = z return z def q_sw_mode(self): # queries the switching mode """Queries the switching mode of the HVPS. Queries the switching mode of the HVPS. Output is either SWMODE_OFF: HVPS is off (0 V output irrespective of voltage setpoint), SWMODE_DC the HVPS is in DC mode with a constant output voltage at the desired set point, SWMODE_SW: the HVPS is switching at the desired frequency between 0V and Vset, or SWMODE_WFRM: the HVPS is in user-defined waveform mode.""" if EMUL: z = 1 else: self.ser.write(b'QSwMode\r') z = int(self._readline()) if DEBUG: y = "q_sw_mode -> " + str(z) print(y) self.swmode = z return z def s_sw_src(self, x): # sets the switching source """Sets the source of the switching signal. Sets the source of the switching signal. Accepted values are: SWSRC_TMR for onboard switching (from internal clock of the board), SWSRC_EXT for external switching via pin 6 (Ext.F) on the board main connector, or SWSRC_BTTN for the push button. Example: s_sw_src(SWSRC_EXT) to use the external signal to switch the source on/off. Note that this setting is useful only if the jumper on header H2 is set to “onboard control”, else the jumper setting defines the source of the switching signal.\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: SWSRC_TMR, or SWSRC_EXT, or SWSRC_BTTN""" if EMUL: z = x else: if x > SWSRC_BTTN: x = SWSRC_TMR string = 'SSwSrc ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_sw_src(" + str(x) + ") -> " + str(z) print(y) self.swsrc = z return z def q_sw_src(self): # queries the switching source """Queries the source of the switching signal. Queries the source of the switching signal. Output is SWSRC_TMR for onboard switching (from internal clock of the board), SWSRC_EXT for external switching via pin 6 (Ext.F) on the board main connector, or SWSRC_BTTN for the push button. Example: s_sw_src(SWSRC_EXT) to use the external signal to switch the source on/off. Note that this setting is useful only if the jumper on header H2 is set to “onboard control”, else the jumper setting defines the source of the switching signal.""" if EMUL: z = 1 else: self.ser.write(b'QSwSrc\r') z = int(self._readline()) if DEBUG: y = "q_sw_src -> " + str(z) print(y) self.swsrc = z return z def s_latch_mode(self, x): # sets the latch mode of the push button """Defines the behaviour of the push button Defines the behaviour of the push button, when the switching source of the HVPS is set to the push button (SWSRC_BTTN, c.f. s_sw_src() command above). Accepted values are 0 and 1: 0 for a push button behaviour (i.e. the high voltage is turned on as long as the button is pressed), and 1 for a latching switch behaviour (i.e. press once to turn the high voltage on, and press a second time to turn it off).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: 0 or 1\n output: latching mode as understood by the HVPS""" if EMUL: z = x else: if x > 1: x = 1 string = 'SLatchMode ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_latch_mode(" + str(x) + ") -> " + str(z) print(y) self.latch = z return z def q_latch_mode(self): # queries the latch mode of the push button """Queries whether the push button is configured to act as a push button (o) or a latching switch (1).""" if EMUL: z = 1 else: self.ser.write(b'QLatchMode\r') z = int(self._readline()) if DEBUG: y = "q_latch_mode -> " + str(z) print(y) self.latch = z return z def s_v_mode(self, x): # sets the voltage control mode """Sets the voltage control mode Sets the voltage control mode (i.e. how is the value of the output voltage controlled):\n VMODE_R for internal voltage regulator (regulates the voltage to the value defined with the Vset command).\n SMODE_EXT external voltage control (sets the output voltage according to the control voltage applied on pin 5 (Ext.V) of the main connector of the board. The input voltage range is 0 to 5V.\n VMODE_O (that's an O like in open) internal open loop control (on-board regulator disconnected).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: VMODE_R, VMODE_EXT, VMODE_O\n Output: Voltage control mode accepted by the HVPS""" if EMUL: z = x else: if x > VMODE_O: x = VMODE_R string = 'SVMode ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_v_mode(" + str(x) + ") -> " + str(z) print(y) self.vmode = z return z def q_v_mode(self): # queries the switching source """Queries the voltage control mode: Queries the voltage control mode:\n VMODE_R internal voltage regulator, VMODE_EXT external voltage control. VMODE_O internal open loop control (on-board regulator disconnected).""" if EMUL: z = 1 else: self.ser.write(b'QVMode\r') z = int(self._readline()) if DEBUG: y = "q_v_mode -> " + str(z) print(y) self.vmode = z return z # ====User Waveform Functions==== def clear_waveform(self): # clear the stored waveform """Clear the current user-defined waveform Clear the current user-defined waveform from the HVPS memory.""" if EMUL: z = 0 # clear waveform returns 0 else: self.ser.write(b'SP X\r') z = int(self._readline()) if DEBUG: y = "clear_waveform -> " + str(z) print(y) return z def q_waveform_num_pts(self): # queries the number of points saved for the waveform """Queries how many data point are currently stored in the waveform""" if EMUL: z = 0 # returns 0 points else: self.ser.write(b'QPtot\r') z = int(self._readline()) if DEBUG: y = "q_waveform_num_pts -> " + str(z) print(y) return z def s_waveform_point(self, x): # Add a point to the waveform """Add a point to the user waveform. Add a point to the user waveform. Usage: s_waveform_point(xxx), with xxx between 0 and 255 representing 0 to 100% of the voltage setpoint.\n A new waveform is defined by issuing clear_waveform() (to clear the previous waveform), followed by a series of s_waveform_point(xxx) to define the points of the new waveform. The maximal number of allowed points is 255. This is a low-level function provided to match the 'SP' command of the HVPS communication protocol. However, It is easier to use upload_waveform() to upload a complete waveform to the HVPS in one go, or to use upload_std_waveform() to upload some customisable standard waveforms.\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: set point to add to the current waveform. 0-255 representing 0-100% of voltage set point.\n output: accepted set point (or -1 if waveform full)""" s = [-1, -1] x = constrain(x, 0, 255) if EMUL: z = x else: num_pts = self.q_waveform_num_pts() # queries how many points currently saved in memory if num_pts < 255: # can only add a point if less than 255 points currently saved string = 'SP ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = self._readline() z = z.decode("utf-8") s = z.split(",") z = s[1] else: z = -1 if DEBUG: y = "s_waveform_point(" + str(x) + ") -> " + str(s[0]) + "," + str(s[1]) print(y) return z def q_waveform_set_pts(self, x): # queries the the xth point of the waveform (x starts at 0) """queries the waveform set point number x queries the waveform set point number x (0<=x<=255) returns a value between 0 and 255 representing 0 to 100% of current voltage set point. This is a low-level function provided to match the QP command of the HVPS communication protocol. It is easier to use download_waveform_set_pts() to download the whole waveform from the HVPS""" if EMUL: z = x else: string = 'QP ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "q_waveform_set_point(" + str(x) + ") -> " + str(z) print(y) return z def q_waveform_meas_pts(self, x): # queries the the measured voltage of the xth point of the # waveform (x starts at 0) """queries the waveform measured point number x queries the waveform measured point number x. Same as q_waveform_set_pts(), but instead of returning the set point value, it returns the voltage value read by the SHVPS internally. In order for QR to return meaningful values, the SHVPS must have been in Waveform mode (SWMODE_WFRM) for at least one cycle.\n Queries the waveform point number x (0<=x<=255). returns a value between 0 and 255 representing 0 to 100% of current voltage set point. This is a low-level function provided to match the QR command of the HVPS communication protocol. It is easier to use download_waveform_meas_pts() to download the whole waveform from the HVPS""" if EMUL: z = x else: string = 'QR ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "q_waveform_meas_point(" + str(x) + ") -> " + str(z) print(y) return z def upload_waveform(self, x): # upload a list (x) of waveform set points to the HVPS """upload a user-defined waveform to the HVPS upload a user-defined waveform to the HVPS. It starts by clearing the current waveform and then it upload an new list of points. It also updates the member variable self.waveform_pts with the new list of points.\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: [p1, p2, p3, ..., pn] where pn is the nth point of the waveform, between 0 and 255, representing 0 to 100% of the current voltage set point. n is limited to 255.\n output: none""" self.clear_waveform() # starts by clearing the waveform self.waveform_pts.clear() # empty the current list of point of the local copy if len(x) > 255: # waveform limited to 255 points x = x[:255] for point in x: point = constrain(point, 0, 255) self.waveform_pts.append(self.s_waveform_point(point)) # upload the point and add it to the local copy def download_waveform_set_pts(self): # download the waveform set points stored in the HVPS """Download the current waveform from the HVPS Download the current waveform from the HVPS. The output is a list of set points between 0 and 255 representing 0 to 100% of the voltage set point. the downloaded points are stored in the member list waveform_pts""" self.waveform_pts.clear() # empty the current list of point of the local copy num_points = self.q_waveform_num_pts() for i in range(num_points): self.waveform_pts.append(self.q_waveform_set_pts(i)) # download the point +add it to the local copy def download_waveform_meas_pts(self): # download the waveform set points stored in the HVPS """Download the measured waveform (last performed cycle) from the HVPS Download the current waveform from the HVPS. The output is a list of set points between 0 and 255 representing 0 to 100% of the voltage set point. the SHVPS must have been in Waveform mode (SWMODE_WFRM) for at least one cycle to obtain meaningful values. member list waveform_meas""" self.waveform_meas.clear() # empty the current list of point of the local copy num_points = self.q_waveform_num_pts() for i in range(num_points): self.waveform_meas.append(self.q_waveform_meas_pts(i)) # download the point +add it to the local copy def upload_std_waveform(self, func=FUNC_SINE, sr=False, n=100, b=0.15): """Upload a customisable standard waveform to the HVPS inputs:\n func: FUNC_SINE (a sine wave with an offset to be between 0 and Voltage set point), FUNC_TRI (a triangle function), FUNC_TRAP (a Trapezoid function), FUNC_CSTM (a custom waveform. Points (a maximum number of 255 points) should be defined in a file named waveform.txt located alongside this library. There should be 1 point per line, each point between 0 and 1, representing 0 to 100% of the voltage set point)\n sr: (square root) True or False. In case the HVPS is used to drive dielectric elastomer actuators, there is a quadratic relationship between voltage and actuation strain. True: a square root correction is applied so that the actuation strain will roughly have the chosen profile. False: No correction applied/n n: number of point in the waveform. Max is 255. It depends on the frequency at which the waveform will be produced, For a 1Hz signal, 100 points are adequate. Reduce the number of points for higher frequencies b: This applies only for the FUNC_TRAP function and defines the percentage of the period that the raising (and falling) edge should take. The value should be smaller than 0.5 (at which point the waveform becomes a triangle).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n""" pts = [] n = constrain(n, 1, 255) # n must be between 1 and 255 points b = constrain(b, 0, 0.5) # b must be between 0 and 0.5 if sr: # if we want the square root of the signal (because of the quadratic relationship between voltage # and strain for DEAs) power = 0.5 else: power = 1.0 if func == FUNC_CSTM: # custom user waveform try: fp = open('./waveform.txt', 'r') except FileNotFoundError: if DEBUG: print("Custom waveform must be in ./waveform.txt, but file is not found") fp = 0 if fp: list_of_points = fp.readlines() for point in list_of_points: try: point = int(255*(float(point) ** power)) except ValueError: point = 0 if DEBUG: print("Error when reading point for custom waveform. Each line in the file ./waveform.txt " "must contain a single floating point number") point = constrain(point, 0, 255) # points should be between 0 and 255 pts.append(point) fp.close() else: # if other standard functions are chosen for i in range(n): p = 0 # p is between 0 to 1 representing percentage of voltage set point if func == FUNC_SINE: # Sine + offset waveform p = (0.5+0.5*sin(2*pi/n*i)) ** power elif func == FUNC_TRAP: # trapeze waveform if i <= b*n: # the ramp up of the trapeze p = (i/b/n) ** power elif i <= n/2: # holding time p = 1 elif i <= (n/2 + b*n): # ramp down p = (1-(i - n/2) / b / n) ** power else: p = 0 elif func == FUNC_TRI: if i <= n/2: # Raising edge p = (2/n*i) ** power else: p = (1 - 2 / n * (i - n / 2)) ** power p = int(p*255) pts.append(p) self.upload_waveform(pts) # uploads the waveform to the HVPS # ====Trigger / Strobe pulse functions==== def s_st_mode(self, x): # sets the strobe mode """Sets the strobe mode. Sets the strobe mode. Usage: s_st_mode(X), with X being\n STMODE_OFF: trigger/strobe pulse off: no signal is generated.\n STMODE_FIXED: fixed position: a trigger/strobe signal is generated at a fixed position, with a fixed duration. By default, the pulse is synchronized with the HV switching signal, but the position and duration of the pulse can be defined by the user (see next s_st_pos()).\n STMODE_SWEEP: sweep mode: the position of the trigger/strobe pulse is shifted along the HV signal at a user-defined speed. The HVPS must be in switching mode (SWMODE_SW) for the trigger pulse to be generated. The trigger pulse is generated on pin T of the multi-purpose 10-pins header on the HVPS board.\n input: x: STMODE_OFF or STMODE_FIXED, or STMODE_SWEEP\n output: strobe mode as understood by HVPS""" if EMUL: z = x else: if x > STMODE_SWEEP: x = STMODE_OFF string = 'SStMode ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_st_mode(" + str(x) + ") -> " + str(z) print(y) self.stmode = z return z def q_st_mode(self): # queries the strobe mode """Queries the current strobe mode. Queries the current strobe mode. 0: Off, 1: Fixed position, 2: Sweep mode.\n STMODE_OFF: trigger/strobe pulse off: no signal is generated.\n STMODE_FIXED: fixed position: a trigger/strobe signal is generated at a fixed position, with a fixed duration. By default, the pulse is synchronized with the HV switching signal, but the position and duration of the pulse can be defined by the user (see next s_st_pos()).\n STMODE_SWEEP: sweep mode: the position of the trigger/strobe pulse is shifted along the HV signal at a user-defined speed.""" if EMUL: z = 1 else: self.ser.write(b'QStMode\r') z = int(self._readline()) if DEBUG: y = "q_st_mode -> " + str(z) print(y) self.stmode = z return z def s_st_pos(self, x): # sets the position of the strobe pulse """Sets the position of the rising edge of the strobe pulse with respect to the HV output. Sets the position of the rising edge of the strobe pulse with respect to the HV output. Usage: s_st_pos(xxx), with xxx a value between 0 and 255, representing the position of the rising edge of the trigger pulse as a fraction of the period T of the HV signal. A value of 0 means that the rising edge of the trigger pulse is coincident with the rising edge of the HV output.\n A value of 127 means that the rising edge of the trigger pulse is coincident with the falling edge of the HV output. The position of the pulse is only used when the strobe pulse mode is STMODE_FIXED (fixed position).\n input: x: position of the trigger pulse (0 to 255)\n output: position of the trigger pulse accepted by the HVPS""" if EMUL: z = x else: x = constrain(x, 0, 255) string = 'SStPos ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_st_pos(" + str(x) + ") -> " + str(z) print(y) self.stpos = z return z def q_st_pos(self): # queries the the position of the strobe pulse """Queries the current position of the rising edge of the strobe/trigger pulse. Queries the current position of the rising edge of the strobe/trigger pulse. The returned value is between 0 and 255, and represents a fraction of the period of the HV output, with 0 being the rising edge of the HV signal.""" if EMUL: z = 1 else: self.ser.write(b'QStPos\r') z = int(self._readline()) if DEBUG: y = "q_st_pos -> " + str(z) print(y) self.stpos = z return z def s_st_dur(self, x): # sets the duration of the strobe pulse """Sets the duration of the strobe/trigger pulse as a fraction of the period of the HV output. Sets the duration of the strobe/trigger pulse as a fraction of the period of the HV output. Usage: s_st_dur(xxx), with xxx being the fraction of the period of the HV output during which the strobe/trigger pulse must remain high (0: constantly off, 127: on during 50% of the period, and 255: constantly on).\n The duration of the pulse is used in strobe mode ST_MODE_FIXED (fixed position) and STMODE_SWEEP (sweep mode)\n input: x: duration of the strobe pulse (0-255, representing 0 to 100% duty cycle)\n output: pulse duration accepted by the HVPS""" if EMUL: z = x else: x = constrain(x, 0, 255) string = 'SStDur ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_st_dur(" + str(x) + ") -> " + str(z) print(y) self.stdur = z return z def q_st_dur(self): # queries the the duration of the strobe pulse """Queries the current duration of the strobe/trigger pulse. Queries the current duration of the strobe/trigger pulse. Returns a value between 0 and 255 representing the fraction of the period of the HV signal during which the strobe/trigger signal remains high (0: constantly off, 127: on during 50% of the period, and 255: constantly on).""" if EMUL: z = 1 else: self.ser.write(b'QStDur\r') z = int(self._readline()) if DEBUG: y = "q_st_dur -> " + str(z) print(y) self.stdur = z return z def s_st_sweep(self, x): # sets the sweep period (im ms) when in sweep mode """sets the sweep time in ms. sets the sweep time in ms. Usage s_st_sweep(xxx), where xxx is the time (in ms) that it takes to sweep the strobe/trigger pulse over a complete period of the HV output. This parameter is only used in strobe mode STMODE_SWEEP (sweep mode). If the pulse is used to drive a strobe LED, the sweep time defines the apparent period of the motion. Logically, the period set with s_st_sweep much be considerably longer than the period of the HV signal.\n input: x: period of the sweep duration in ms\n output: sweep duration accepted by HVPS""" if EMUL: z = x else: x = constrain(x, 0, 65535) string = 'SStSw ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_st_sweep(" + str(x) + ") -> " + str(z) print(y) self.stsweep = z return z # Miscellaneous functions def save(self): # save current HVPS parameters into the memory """save current HVPS parameters into the memory This command saves the following parameters in EEPROM: Voltage setpoint, Frequency, Frequency divider, Source of switching signal (external, internal, button), Switching mode (off, DC output, switching output), Voltage mode (internal voltage regulator or following external signal), and number of switching cycles. It also saves the user-defined waveform into the EEPROM. This is useful so that it is not necessary to reconfigure the HVPS for the desired behavior every time it is powered up, for example when the HVPS is meant to be used without computer (when connected to a demo device). Note that when the HVPS is used with a computer, it is safer to save a voltage setpoint of 0V (and/or a switching mode 0 (box off)) so as to be sure that no high voltage is present at the output when the board is powered up (and before the computer has the time to initialise it to 0V output).""" if EMUL: z = 1 else: self.ser.write(b'Save\r') z = int(self._readline()) if DEBUG: y = "save -> " + str(z) print(y) return z def q_mem(self): # queries the content of the memory """queries the content of the memory Queries the content of the memory (when the box is powered up, it will use the settings stored in memory, which allows using the board without a computer). This commands returns a string of parameters separated by commas: Voltage, Frequency, Switching source, Switching mode, Voltage mode, Regulator gain P, Regulator gain I, Regulator gain D , Voltage Calibration factor 0, Voltage Calibration factor 1, Voltage Calibration factor 2, number of switching cycles, button latching mode.\n input: none\n output: a HVPSMem object with the values of the different parameters.""" mem = HVPSMem() if not EMUL: self.ser.write(b'QMem\r') z = self._readline() z = z.decode("utf-8") s = z.split(",") mem.vset = int(s[0]) mem.f = float(s[1]) mem.swsrc = int(s[2]) mem.swmode = int(s[3]) mem.vmode = int(s[4]) mem.kp = float(s[5]) mem.ki = float(s[6]) mem.kd = float(s[7]) mem.c0 = float(s[8]) mem.c1 = float(s[9]) mem.c2 = float(s[10]) mem.cycles = int(s[11]) mem.latch = int(s[12]) else: z = 'empty memory' if DEBUG: y = "q_mem -> " + z print(y) return mem def q_ver(self): # queries the firmware version """returns the current version of the firmware running on the board.""" if EMUL: z = 7 else: self.ser.write(b'QVer\r') s = self._readline() # returns a string in the form of "slave X" need to get the value of X s = s.decode("utf-8") z1 = s.split(" ") z = int(z1[1]) if DEBUG: y = "q_ver -> " + str(z) print(y) return z def q_jack(self): # queries whether power Jack is plugged in. """returns 1 if the power adapter is plugged in the Jack socket J1, and 0 if it is not.""" if EMUL: z = 1 else: self.ser.write(b'QJack\r') z = int(self._readline()) if DEBUG: y = "q_jack -> " + str(z) print(y) return z # Configuration functions def conf(self, x): # performs initial configuration of the board """Performs the initial configuration of a board Performs the initial configuration of a board (instead of using commands below separately). Usage: conf(xxx), where XXX is the voltage rating of one of the 5 standard configurations (i.e. 5000, 3000, 2000, 1200, and 500). Initialises Vmax to the value of XXX, and C0, C1, C2, Kp, Ki, and Kd to the default values for each voltage rating.\n input: x: board voltage rating (5000, 3000, 2000, 1200, or 500) output: 1 in case of success, 0 in case of failure""" if EMUL: z = 1 # this emulate success else: if x == 5000 or x == 3000 or x == 2000 or x == 1200 or x == 500: string = 'Conf ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) > 0 self._initialise() # initialises the board now that it has been configured else: z = 0 # 0 indicates failure (in that case entered voltage not one of the HVPS std voltages if DEBUG: y = "conf(" + str(x) + ") -> " + str(z) print(y) return z def s_i2c(self, x): # sets the I2C address """sets the I2C address of the board. Only useful if board to be used in multichannel configuration <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n input: x: I2C address to assign""" if EMUL: z = 12 # random returned i2c value in case we emulate the presence of a board else: x = constrain(x, 0, 127) string = 'SI2C ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_I2C(" + str(x) + ") -> " + str(z) print(y) self.i2c = z return z def q_i2c(self): # queries the i2c address of the board """queries the I2C address of the board.""" if EMUL: z = 12 else: self.ser.write(b'QI2C\r') z = int(self._readline()) if DEBUG: y = "q_I2C -> " + str(z) print(y) self.i2c = z return z def s_vmax(self, x): # sets the maximum voltage rating of the board """sets the voltage rating of the SHVPS. sets the voltage rating of the SHVPS. Must match the EMCO DC/DC converter rating.\n <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n input: x:voltage rating of HVPS in Volt""" if EMUL: z = x else: x = constrain(x, 0, 10000) string = 'SVmax ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_vmax(" + str(x) + ") -> " + str(z) print(y) self.vmax = z return z def q_vmax(self): # queries the voltage rating of the board """Queries the maximal voltage of the board. The returned value is in volts.""" if EMUL: z = 5000 else: self.ser.write(b'QVmax\r') z = int(self._readline()) if DEBUG: y = "q_vmax -> " + str(z) print(y) self.vmax = z return z def s_c0(self, x): # sets the calibration constant c0 """sets the calibration constant c0 <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SC0 ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_c0(" + str(x) + ") -> " + str(z) print(y) return z def q_c0(self): # queries the calibration constant c0 """queries the calibration constant c0""" if EMUL: z = 0 else: self.ser.write(b'QC0\r') z = float(self._readline()) if DEBUG: y = "q_c0 -> " + str(z) print(y) return z def s_c1(self, x): # sets the calibration constant c1 """sets the calibration constant c1 <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SC1 ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_c1(" + str(x) + ") -> " + str(z) print(y) return z def q_c1(self): # queries the calibration constant c1 """queries the calibration constant c1""" if EMUL: z = 0 else: self.ser.write(b'QC1\r') z = float(self._readline()) if DEBUG: y = "q_c1 -> " + str(z) print(y) return z def s_c2(self, x): # sets the calibration constant c2 """sets the calibration constant c2 <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SC2 ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_c2(" + str(x) + ") -> " + str(z) print(y) return z def q_c2(self): # queries the calibration constant c2 """queries the calibration constant c2""" if EMUL: z = 0 else: self.ser.write(b'QC2\r') z = float(self._readline()) if DEBUG: y = "q_c2 -> " + str(z) print(y) return z def s_kp(self, x): # sets the PID gain Kp """sets parameters Kp of the PID regulator. <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SKp ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_kp(" + str(x) + ") -> " + str(z) print(y) return z def q_kp(self): # queries the PID gain Kp """Query the value of parameter Kp of the PID regulator""" if EMUL: z = 0 else: self.ser.write(b'QKp\r') z = float(self._readline()) if DEBUG: y = "q_kp -> " + str(z) print(y) return z def s_ki(self, x): # sets the PID gain Ki """""sets parameters Ki of the PID regulator. <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SKi ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_ki(" + str(x) + ") -> " + str(z) print(y) return z def q_ki(self): # queries the PID gain Ki """Query the value of parameter Ki of the PID regulator""" if EMUL: z = 0 else: self.ser.write(b'QKi\r') z = float(self._readline()) if DEBUG: y = "q_ki -> " + str(z) print(y) return z def s_kd(self, x): # sets the PID gain Kd """sets parameters Kd of the PID regulator. <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SKd ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_kd(" + str(x) + ") -> " + str(z) print(y) return z def q_kd(self): # queries the PID gain Kd """Query the value of parameter Kd of the PID regulator""" if EMUL: z = 0 else: self.ser.write(b'QKd\r') z = float(self._readline()) if DEBUG: y = "q_kp -> " + str(z) print(y) return z def s_name(self, x): # set the name of the HVPS """Sets the name of the HVPS. Sets the name of the HVPS. 20 characters maximum\n <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n input: x=Name of the HVPS output: name accepted by HVPS""" if EMUL: z = x elif len(x) < 21: string = 'SName ' string = string + x + '\r' string = string.encode() self.ser.write(string) z = self._readline() else: z = 'too long' if DEBUG: y = "s_kd(" + str(x) + ") -> " + str(z) print(y) return z def q_name(self): # queries the name of the board """queries the name of the board""" if EMUL: z = "Emulator" else: self.ser.write(b'QName\r') z = self._readline() if DEBUG: y = "q_name -> " + str(z) print(y) self.name = z return z def q_type(self): # queries the type (master (multi-channel), slave (single channel)) """queries the type (master (multi-channel), slave (single channel))""" if EMUL: z = "slave" else: self.ser.write(b'QVer\r') s = self._readline() # returns a string in the form of "slave X" need to get slave s = s.decode("utf-8") z1 = s.split(" ") z = z1[0] if DEBUG: y = "q_ver -> " + str(z) print(y) return z def s_power_jack(self, x): # sets the configuration of the HVPS (whether power comes from power jack) """Defines if power if provided by the power jack. Defines if power if provided by the power jack, s_power_jack(1) (default), or through 5V pin, s_power_jack(0). As the default is power jack 1, You only need the use this command with SPowJack 0 if you wish to use the HVPS in the standalone configuration with touchscreen and battery, or in the multichannel configuration.\n <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n input: x: 0 or 1 output: power jack mode accepted by HVPS""" if EMUL: z = x else: if x > 1: x = 1 string = 'SPowJack ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_power_jack(" + str(x) + ") -> " + str(z) print(y) self.config = not z # updates the configuration status of the HVPS return z def q_power_jack(self): # queries whether power is supposed to come from Power Jack. # (0 if in touchscreen + battery configuration) """Queries the power jack setting. Queries the power jack setting. 1 when HVPS expects to receive power from power jack, and 0 when power comes from 5 V pin.""" if EMUL: z = 1 else: self.ser.write(b'QPowJack\r') z = int(self._readline()) if DEBUG: y = "q_power_jack -> " + str(z) print(y) return z
Methods
def clear_waveform(self)
-
Clear the current user-defined waveform
Clear the current user-defined waveform from the HVPS memory.
Expand source code
def clear_waveform(self): # clear the stored waveform """Clear the current user-defined waveform Clear the current user-defined waveform from the HVPS memory.""" if EMUL: z = 0 # clear waveform returns 0 else: self.ser.write(b'SP X\r') z = int(self._readline()) if DEBUG: y = "clear_waveform -> " + str(z) print(y) return z
def close(self)
-
Closes the connection to the HVPS. Sets voltage to 0 if board was connected
Expand source code
def close(self): # closes connection with the HVPS """Closes the connection to the HVPS. Sets voltage to 0 if board was connected""" if not EMUL: if self.ser.is_open: if not (self.err & ERR_COM): # if connected board is not running the firmware, do not send command self.s_vset(0) # set the voltage to 0 as a safety measure self.ser.close() if DEBUG: print("Serial port closed")
def conf(self, x)
-
Performs the initial configuration of a board
Performs the initial configuration of a board (instead of using commands below separately). Usage: conf(xxx), where XXX is the voltage rating of one of the 5 standard configurations (i.e. 5000, 3000, 2000, 1200, and 500). Initialises Vmax to the value of XXX, and C0, C1, C2, Kp, Ki, and Kd to the default values for each voltage rating.
input: x: board voltage rating (5000, 3000, 2000, 1200, or 500) output: 1 in case of success, 0 in case of failure
Expand source code
def conf(self, x): # performs initial configuration of the board """Performs the initial configuration of a board Performs the initial configuration of a board (instead of using commands below separately). Usage: conf(xxx), where XXX is the voltage rating of one of the 5 standard configurations (i.e. 5000, 3000, 2000, 1200, and 500). Initialises Vmax to the value of XXX, and C0, C1, C2, Kp, Ki, and Kd to the default values for each voltage rating.\n input: x: board voltage rating (5000, 3000, 2000, 1200, or 500) output: 1 in case of success, 0 in case of failure""" if EMUL: z = 1 # this emulate success else: if x == 5000 or x == 3000 or x == 2000 or x == 1200 or x == 500: string = 'Conf ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) > 0 self._initialise() # initialises the board now that it has been configured else: z = 0 # 0 indicates failure (in that case entered voltage not one of the HVPS std voltages if DEBUG: y = "conf(" + str(x) + ") -> " + str(z) print(y) return z
def download_waveform_meas_pts(self)
-
Download the measured waveform (last performed cycle) from the HVPS
Download the current waveform from the HVPS. The output is a list of set points between 0 and 255 representing 0 to 100% of the voltage set point. the SHVPS must have been in Waveform mode (SWMODE_WFRM) for at least one cycle to obtain meaningful values. member list waveform_meas
Expand source code
def download_waveform_meas_pts(self): # download the waveform set points stored in the HVPS """Download the measured waveform (last performed cycle) from the HVPS Download the current waveform from the HVPS. The output is a list of set points between 0 and 255 representing 0 to 100% of the voltage set point. the SHVPS must have been in Waveform mode (SWMODE_WFRM) for at least one cycle to obtain meaningful values. member list waveform_meas""" self.waveform_meas.clear() # empty the current list of point of the local copy num_points = self.q_waveform_num_pts() for i in range(num_points): self.waveform_meas.append(self.q_waveform_meas_pts(i)) # download the point +add it to the local copy
def download_waveform_set_pts(self)
-
Download the current waveform from the HVPS
Download the current waveform from the HVPS. The output is a list of set points between 0 and 255 representing 0 to 100% of the voltage set point. the downloaded points are stored in the member list waveform_pts
Expand source code
def download_waveform_set_pts(self): # download the waveform set points stored in the HVPS """Download the current waveform from the HVPS Download the current waveform from the HVPS. The output is a list of set points between 0 and 255 representing 0 to 100% of the voltage set point. the downloaded points are stored in the member list waveform_pts""" self.waveform_pts.clear() # empty the current list of point of the local copy num_points = self.q_waveform_num_pts() for i in range(num_points): self.waveform_pts.append(self.q_waveform_set_pts(i)) # download the point +add it to the local copy
def q_c0(self)
-
queries the calibration constant c0
Expand source code
def q_c0(self): # queries the calibration constant c0 """queries the calibration constant c0""" if EMUL: z = 0 else: self.ser.write(b'QC0\r') z = float(self._readline()) if DEBUG: y = "q_c0 -> " + str(z) print(y) return z
def q_c1(self)
-
queries the calibration constant c1
Expand source code
def q_c1(self): # queries the calibration constant c1 """queries the calibration constant c1""" if EMUL: z = 0 else: self.ser.write(b'QC1\r') z = float(self._readline()) if DEBUG: y = "q_c1 -> " + str(z) print(y) return z
def q_c2(self)
-
queries the calibration constant c2
Expand source code
def q_c2(self): # queries the calibration constant c2 """queries the calibration constant c2""" if EMUL: z = 0 else: self.ser.write(b'QC2\r') z = float(self._readline()) if DEBUG: y = "q_c2 -> " + str(z) print(y) return z
def q_cycle(self)
-
Queries the number of cycles.
Queries the number of cycles. The returned value is a list z, with z[0] being the current cycle number and z[1] the total number of cycles to make. Once the total number of cycles is reached, the output is turned off (SWMODE_OFF), and q_cycle() returns [0,XXX] with XXX the number of cycles to make (XXX=0 in case of continuous cycles).
Expand source code
def q_cycle(self): # queries the number of cycles returns a list. Element 0 is the current cycle number. # Element 1 is the total number of cycles in the series. """Queries the number of cycles. Queries the number of cycles. The returned value is a list z, with z[0] being the current cycle number and z[1] the total number of cycles to make. Once the total number of cycles is reached, the output is turned off (SWMODE_OFF), and q_cycle() returns [0,XXX] with XXX the number of cycles to make (XXX=0 in case of continuous cycles).""" if EMUL: z = "0/0" else: self.ser.write(b'QCycle\r') z = self._readline() z = z.decode("utf-8") if DEBUG: y = "q_cycle -> " + z print(y) s = z.split("/") self.cycles = s[1] self.cycle_n = s[0] return s
def q_f(self)
-
Queries the switching frequency. The returned value is in Hz.
Expand source code
def q_f(self): # queries the frequency """Queries the switching frequency. The returned value is in Hz.""" if EMUL: z = 1 else: self.ser.write(b'QF\r') z = float(self._readline()) if DEBUG: y = "q_f -> " + str(z) print(y) self.f = z return z
def q_i2c(self)
-
queries the I2C address of the board.
Expand source code
def q_i2c(self): # queries the i2c address of the board """queries the I2C address of the board.""" if EMUL: z = 12 else: self.ser.write(b'QI2C\r') z = int(self._readline()) if DEBUG: y = "q_I2C -> " + str(z) print(y) self.i2c = z return z
def q_jack(self)
-
returns 1 if the power adapter is plugged in the Jack socket J1, and 0 if it is not.
Expand source code
def q_jack(self): # queries whether power Jack is plugged in. """returns 1 if the power adapter is plugged in the Jack socket J1, and 0 if it is not.""" if EMUL: z = 1 else: self.ser.write(b'QJack\r') z = int(self._readline()) if DEBUG: y = "q_jack -> " + str(z) print(y) return z
def q_kd(self)
-
Query the value of parameter Kd of the PID regulator
Expand source code
def q_kd(self): # queries the PID gain Kd """Query the value of parameter Kd of the PID regulator""" if EMUL: z = 0 else: self.ser.write(b'QKd\r') z = float(self._readline()) if DEBUG: y = "q_kp -> " + str(z) print(y) return z
def q_ki(self)
-
Query the value of parameter Ki of the PID regulator
Expand source code
def q_ki(self): # queries the PID gain Ki """Query the value of parameter Ki of the PID regulator""" if EMUL: z = 0 else: self.ser.write(b'QKi\r') z = float(self._readline()) if DEBUG: y = "q_ki -> " + str(z) print(y) return z
def q_kp(self)
-
Query the value of parameter Kp of the PID regulator
Expand source code
def q_kp(self): # queries the PID gain Kp """Query the value of parameter Kp of the PID regulator""" if EMUL: z = 0 else: self.ser.write(b'QKp\r') z = float(self._readline()) if DEBUG: y = "q_kp -> " + str(z) print(y) return z
def q_latch_mode(self)
-
Queries whether the push button is configured to act as a push button (o) or a latching switch (1).
Expand source code
def q_latch_mode(self): # queries the latch mode of the push button """Queries whether the push button is configured to act as a push button (o) or a latching switch (1).""" if EMUL: z = 1 else: self.ser.write(b'QLatchMode\r') z = int(self._readline()) if DEBUG: y = "q_latch_mode -> " + str(z) print(y) self.latch = z return z
def q_mem(self)
-
queries the content of the memory
Queries the content of the memory (when the box is powered up, it will use the settings stored in memory, which allows using the board without a computer). This commands returns a string of parameters separated by commas: Voltage, Frequency, Switching source, Switching mode, Voltage mode, Regulator gain P, Regulator gain I, Regulator gain D , Voltage Calibration factor 0, Voltage Calibration factor 1, Voltage Calibration factor 2, number of switching cycles, button latching mode.
input: none
output: a HVPSMem object with the values of the different parameters.
Expand source code
def q_mem(self): # queries the content of the memory """queries the content of the memory Queries the content of the memory (when the box is powered up, it will use the settings stored in memory, which allows using the board without a computer). This commands returns a string of parameters separated by commas: Voltage, Frequency, Switching source, Switching mode, Voltage mode, Regulator gain P, Regulator gain I, Regulator gain D , Voltage Calibration factor 0, Voltage Calibration factor 1, Voltage Calibration factor 2, number of switching cycles, button latching mode.\n input: none\n output: a HVPSMem object with the values of the different parameters.""" mem = HVPSMem() if not EMUL: self.ser.write(b'QMem\r') z = self._readline() z = z.decode("utf-8") s = z.split(",") mem.vset = int(s[0]) mem.f = float(s[1]) mem.swsrc = int(s[2]) mem.swmode = int(s[3]) mem.vmode = int(s[4]) mem.kp = float(s[5]) mem.ki = float(s[6]) mem.kd = float(s[7]) mem.c0 = float(s[8]) mem.c1 = float(s[9]) mem.c2 = float(s[10]) mem.cycles = int(s[11]) mem.latch = int(s[12]) else: z = 'empty memory' if DEBUG: y = "q_mem -> " + z print(y) return mem
def q_name(self)
-
queries the name of the board
Expand source code
def q_name(self): # queries the name of the board """queries the name of the board""" if EMUL: z = "Emulator" else: self.ser.write(b'QName\r') z = self._readline() if DEBUG: y = "q_name -> " + str(z) print(y) self.name = z return z
def q_power_jack(self)
-
Queries the power jack setting.
Queries the power jack setting. 1 when HVPS expects to receive power from power jack, and 0 when power comes from 5 V pin.
Expand source code
def q_power_jack(self): # queries whether power is supposed to come from Power Jack. # (0 if in touchscreen + battery configuration) """Queries the power jack setting. Queries the power jack setting. 1 when HVPS expects to receive power from power jack, and 0 when power comes from 5 V pin.""" if EMUL: z = 1 else: self.ser.write(b'QPowJack\r') z = int(self._readline()) if DEBUG: y = "q_power_jack -> " + str(z) print(y) return z
def q_pwm(self)
-
Queries the current HVPS set point as a raw PWM value. returns value between 0 and 1023
Expand source code
def q_pwm(self): # queries the pwm setting """Queries the current HVPS set point as a raw PWM value. returns value between 0 and 1023""" if EMUL: z = 0 else: self.ser.write(b'QPWM\r') z = int(self._readline()) if DEBUG: y = "q_pwm -> " + str(z) print(y) return z
def q_st_dur(self)
-
Queries the current duration of the strobe/trigger pulse.
Queries the current duration of the strobe/trigger pulse. Returns a value between 0 and 255 representing the fraction of the period of the HV signal during which the strobe/trigger signal remains high (0: constantly off, 127: on during 50% of the period, and 255: constantly on).
Expand source code
def q_st_dur(self): # queries the the duration of the strobe pulse """Queries the current duration of the strobe/trigger pulse. Queries the current duration of the strobe/trigger pulse. Returns a value between 0 and 255 representing the fraction of the period of the HV signal during which the strobe/trigger signal remains high (0: constantly off, 127: on during 50% of the period, and 255: constantly on).""" if EMUL: z = 1 else: self.ser.write(b'QStDur\r') z = int(self._readline()) if DEBUG: y = "q_st_dur -> " + str(z) print(y) self.stdur = z return z
def q_st_mode(self)
-
Queries the current strobe mode.
Queries the current strobe mode. 0: Off, 1: Fixed position, 2: Sweep mode.
STMODE_OFF: trigger/strobe pulse off: no signal is generated.
STMODE_FIXED: fixed position: a trigger/strobe signal is generated at a fixed position, with a fixed duration. By default, the pulse is synchronized with the HV switching signal, but the position and duration of the pulse can be defined by the user (see next s_st_pos()).
STMODE_SWEEP: sweep mode: the position of the trigger/strobe pulse is shifted along the HV signal at a user-defined speed.
Expand source code
def q_st_mode(self): # queries the strobe mode """Queries the current strobe mode. Queries the current strobe mode. 0: Off, 1: Fixed position, 2: Sweep mode.\n STMODE_OFF: trigger/strobe pulse off: no signal is generated.\n STMODE_FIXED: fixed position: a trigger/strobe signal is generated at a fixed position, with a fixed duration. By default, the pulse is synchronized with the HV switching signal, but the position and duration of the pulse can be defined by the user (see next s_st_pos()).\n STMODE_SWEEP: sweep mode: the position of the trigger/strobe pulse is shifted along the HV signal at a user-defined speed.""" if EMUL: z = 1 else: self.ser.write(b'QStMode\r') z = int(self._readline()) if DEBUG: y = "q_st_mode -> " + str(z) print(y) self.stmode = z return z
def q_st_pos(self)
-
Queries the current position of the rising edge of the strobe/trigger pulse.
Queries the current position of the rising edge of the strobe/trigger pulse. The returned value is between 0 and 255, and represents a fraction of the period of the HV output, with 0 being the rising edge of the HV signal.
Expand source code
def q_st_pos(self): # queries the the position of the strobe pulse """Queries the current position of the rising edge of the strobe/trigger pulse. Queries the current position of the rising edge of the strobe/trigger pulse. The returned value is between 0 and 255, and represents a fraction of the period of the HV output, with 0 being the rising edge of the HV signal.""" if EMUL: z = 1 else: self.ser.write(b'QStPos\r') z = int(self._readline()) if DEBUG: y = "q_st_pos -> " + str(z) print(y) self.stpos = z return z
def q_sw_mode(self)
-
Queries the switching mode of the HVPS.
Queries the switching mode of the HVPS. Output is either SWMODE_OFF: HVPS is off (0 V output irrespective of voltage setpoint), SWMODE_DC the HVPS is in DC mode with a constant output voltage at the desired set point, SWMODE_SW: the HVPS is switching at the desired frequency between 0V and Vset, or SWMODE_WFRM: the HVPS is in user-defined waveform mode.
Expand source code
def q_sw_mode(self): # queries the switching mode """Queries the switching mode of the HVPS. Queries the switching mode of the HVPS. Output is either SWMODE_OFF: HVPS is off (0 V output irrespective of voltage setpoint), SWMODE_DC the HVPS is in DC mode with a constant output voltage at the desired set point, SWMODE_SW: the HVPS is switching at the desired frequency between 0V and Vset, or SWMODE_WFRM: the HVPS is in user-defined waveform mode.""" if EMUL: z = 1 else: self.ser.write(b'QSwMode\r') z = int(self._readline()) if DEBUG: y = "q_sw_mode -> " + str(z) print(y) self.swmode = z return z
def q_sw_src(self)
-
Queries the source of the switching signal.
Queries the source of the switching signal. Output is SWSRC_TMR for onboard switching (from internal clock of the board), SWSRC_EXT for external switching via pin 6 (Ext.F) on the board main connector, or SWSRC_BTTN for the push button. Example: s_sw_src(SWSRC_EXT) to use the external signal to switch the source on/off. Note that this setting is useful only if the jumper on header H2 is set to “onboard control”, else the jumper setting defines the source of the switching signal.
Expand source code
def q_sw_src(self): # queries the switching source """Queries the source of the switching signal. Queries the source of the switching signal. Output is SWSRC_TMR for onboard switching (from internal clock of the board), SWSRC_EXT for external switching via pin 6 (Ext.F) on the board main connector, or SWSRC_BTTN for the push button. Example: s_sw_src(SWSRC_EXT) to use the external signal to switch the source on/off. Note that this setting is useful only if the jumper on header H2 is set to “onboard control”, else the jumper setting defines the source of the switching signal.""" if EMUL: z = 1 else: self.ser.write(b'QSwSrc\r') z = int(self._readline()) if DEBUG: y = "q_sw_src -> " + str(z) print(y) self.swsrc = z return z
def q_type(self)
-
queries the type (master (multi-channel), slave (single channel))
Expand source code
def q_type(self): # queries the type (master (multi-channel), slave (single channel)) """queries the type (master (multi-channel), slave (single channel))""" if EMUL: z = "slave" else: self.ser.write(b'QVer\r') s = self._readline() # returns a string in the form of "slave X" need to get slave s = s.decode("utf-8") z1 = s.split(" ") z = z1[0] if DEBUG: y = "q_ver -> " + str(z) print(y) return z
def q_v_mode(self)
-
Queries the voltage control mode:
Queries the voltage control mode:
VMODE_R internal voltage regulator, VMODE_EXT external voltage control. VMODE_O internal open loop control (on-board regulator disconnected).
Expand source code
def q_v_mode(self): # queries the switching source """Queries the voltage control mode: Queries the voltage control mode:\n VMODE_R internal voltage regulator, VMODE_EXT external voltage control. VMODE_O internal open loop control (on-board regulator disconnected).""" if EMUL: z = 1 else: self.ser.write(b'QVMode\r') z = int(self._readline()) if DEBUG: y = "q_v_mode -> " + str(z) print(y) self.vmode = z return z
def q_ver(self)
-
returns the current version of the firmware running on the board.
Expand source code
def q_ver(self): # queries the firmware version """returns the current version of the firmware running on the board.""" if EMUL: z = 7 else: self.ser.write(b'QVer\r') s = self._readline() # returns a string in the form of "slave X" need to get the value of X s = s.decode("utf-8") z1 = s.split(" ") z = int(z1[1]) if DEBUG: y = "q_ver -> " + str(z) print(y) return z
def q_vmax(self)
-
Queries the maximal voltage of the board. The returned value is in volts.
Expand source code
def q_vmax(self): # queries the voltage rating of the board """Queries the maximal voltage of the board. The returned value is in volts.""" if EMUL: z = 5000 else: self.ser.write(b'QVmax\r') z = int(self._readline()) if DEBUG: y = "q_vmax -> " + str(z) print(y) self.vmax = z return z
def q_vnow(self)
-
Queries the current feedback voltage of the HVPS.
The returned value is in volts. Note that it is not necessarily the voltage at the output of the HVPS, which also depends on the switching mode (whether the HVPS is off, in DC mode, or switching).
Expand source code
def q_vnow(self): # queries the voltage output """Queries the current feedback voltage of the HVPS. The returned value is in volts. Note that it is not necessarily the voltage at the output of the HVPS, which also depends on the switching mode (whether the HVPS is off, in DC mode, or switching).""" if EMUL: z = 0 else: self.ser.write(b'QVnow\r') try: z = int(self._readline()) except ValueError: z = 0 if DEBUG: y = "q_vnow -> " + str(z) print(y) self.vnow = z return z
def q_vset(self)
-
Queries the voltage set point. The returned value is in volts.
Expand source code
def q_vset(self): # queries the voltage setpoint """Queries the voltage set point. The returned value is in volts.""" if EMUL: z = 0 else: self.ser.write(b'QVset\r') z = int(self._readline()) if DEBUG: y = "q_vset -> " + str(z) print(y) self.vset = z return z
def q_waveform_meas_pts(self, x)
-
queries the waveform measured point number x
queries the waveform measured point number x. Same as q_waveform_set_pts(), but instead of returning the set point value, it returns the voltage value read by the SHVPS internally. In order for QR to return meaningful values, the SHVPS must have been in Waveform mode (SWMODE_WFRM) for at least one cycle.
Queries the waveform point number x (0<=x<=255). returns a value between 0 and 255 representing 0 to 100% of current voltage set point. This is a low-level function provided to match the QR command of the HVPS communication protocol. It is easier to use download_waveform_meas_pts() to download the whole waveform from the HVPS
Expand source code
def q_waveform_meas_pts(self, x): # queries the the measured voltage of the xth point of the # waveform (x starts at 0) """queries the waveform measured point number x queries the waveform measured point number x. Same as q_waveform_set_pts(), but instead of returning the set point value, it returns the voltage value read by the SHVPS internally. In order for QR to return meaningful values, the SHVPS must have been in Waveform mode (SWMODE_WFRM) for at least one cycle.\n Queries the waveform point number x (0<=x<=255). returns a value between 0 and 255 representing 0 to 100% of current voltage set point. This is a low-level function provided to match the QR command of the HVPS communication protocol. It is easier to use download_waveform_meas_pts() to download the whole waveform from the HVPS""" if EMUL: z = x else: string = 'QR ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "q_waveform_meas_point(" + str(x) + ") -> " + str(z) print(y) return z
def q_waveform_num_pts(self)
-
Queries how many data point are currently stored in the waveform
Expand source code
def q_waveform_num_pts(self): # queries the number of points saved for the waveform """Queries how many data point are currently stored in the waveform""" if EMUL: z = 0 # returns 0 points else: self.ser.write(b'QPtot\r') z = int(self._readline()) if DEBUG: y = "q_waveform_num_pts -> " + str(z) print(y) return z
def q_waveform_set_pts(self, x)
-
queries the waveform set point number x
queries the waveform set point number x (0<=x<=255) returns a value between 0 and 255 representing 0 to 100% of current voltage set point. This is a low-level function provided to match the QP command of the HVPS communication protocol. It is easier to use download_waveform_set_pts() to download the whole waveform from the HVPS
Expand source code
def q_waveform_set_pts(self, x): # queries the the xth point of the waveform (x starts at 0) """queries the waveform set point number x queries the waveform set point number x (0<=x<=255) returns a value between 0 and 255 representing 0 to 100% of current voltage set point. This is a low-level function provided to match the QP command of the HVPS communication protocol. It is easier to use download_waveform_set_pts() to download the whole waveform from the HVPS""" if EMUL: z = x else: string = 'QP ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "q_waveform_set_point(" + str(x) + ") -> " + str(z) print(y) return z
def s_c0(self, x)
-
sets the calibration constant c0
This command automatically saves the parameter in the HVPS EEPROM
Expand source code
def s_c0(self, x): # sets the calibration constant c0 """sets the calibration constant c0 <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SC0 ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_c0(" + str(x) + ") -> " + str(z) print(y) return z
def s_c1(self, x)
-
sets the calibration constant c1
This command automatically saves the parameter in the HVPS EEPROM
Expand source code
def s_c1(self, x): # sets the calibration constant c1 """sets the calibration constant c1 <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SC1 ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_c1(" + str(x) + ") -> " + str(z) print(y) return z
def s_c2(self, x)
-
sets the calibration constant c2
This command automatically saves the parameter in the HVPS EEPROM
Expand source code
def s_c2(self, x): # sets the calibration constant c2 """sets the calibration constant c2 <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SC2 ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_c2(" + str(x) + ") -> " + str(z) print(y) return z
def s_cycle(self, x)
-
Sets the number of switching cycles
Sets the number of switching cycles to perform when the HVPS is in switching mode. The maximum value is 65535. A value of 0 means continuous switching (unlimited number of cycles). For any value other than 0, the HVPS will change to switching mode 0 (HVPS off, SWMODE_OFF, after the desired number of cycles is reached. A new series of switching cycles can be can be initiated by placing the HVPS back in switching mode (SWMODE_SW). When you call s_cycle(), the cycle counter is reset to 0. Example: s_cycle(1000) to switch 1000 times at the selected frequency and then stop. Note that s_cycles configures the HVPS to switch for a limited number of time. If the HVPS is in switching mode (SWMODE_SW), then the cycles will start at once. If the HVPS is in off mode (SWMODE_OFF) or in DC mode (SWMODE_DC), the cycles will start once the HVPS is put in Switching mode with s_sw_mode(SWMODE_SW).
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
input: x: number of cycles (0 to 65535)
output: number of cycles accepted by HVPS
Expand source code
def s_cycle(self, x): # sets the number of cycles """Sets the number of switching cycles Sets the number of switching cycles to perform when the HVPS is in switching mode. The maximum value is 65535. A value of 0 means continuous switching (unlimited number of cycles). For any value other than 0, the HVPS will change to switching mode 0 (HVPS off, SWMODE_OFF, after the desired number of cycles is reached. A new series of switching cycles can be can be initiated by placing the HVPS back in switching mode (SWMODE_SW). When you call s_cycle(), the cycle counter is reset to 0. Example: s_cycle(1000) to switch 1000 times at the selected frequency and then stop. Note that s_cycles configures the HVPS to switch for a limited number of time. If the HVPS is in switching mode (SWMODE_SW), then the cycles will start at once. If the HVPS is in off mode (SWMODE_OFF) or in DC mode (SWMODE_DC), the cycles will start once the HVPS is put in Switching mode with s_sw_mode(SWMODE_SW).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: number of cycles (0 to 65535)\n output: number of cycles accepted by HVPS""" if EMUL: z = x else: x = constrain(x, 0, 65535) string = 'SCycle ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_cycle(" + str(x) + ") -> " + str(z) print(y) self.cycles = z return z
def s_f(self, x)
-
Sets the frequency of the signal
Sets the frequency of the signal when the HVPS is in switching mode (SWMODE_SW).
The value returned is the new frequency, taking quantification into account.
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
input: x: frequency in Hz between 0.001 and 1000
output: frequency accepted by HVPS
Expand source code
def s_f(self, x): # sets the frequency """Sets the frequency of the signal Sets the frequency of the signal when the HVPS is in switching mode (SWMODE_SW).\n The value returned is the new frequency, taking quantification into account.\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: frequency in Hz between 0.001 and 1000\n output: frequency accepted by HVPS""" if EMUL: z = 1 else: x = constrain(x, 0.001, 1000.0) string = 'SF ' string = string + f"{x:.3f}" + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_f(" + str(x) + ") -> " + str(z) print(y) self.f = z return z
def s_i2c(self, x)
-
sets the I2C address of the board. Only useful if board to be used in multichannel configuration
This command automatically saves the parameter in the HVPS EEPROM
input: x: I2C address to assign
Expand source code
def s_i2c(self, x): # sets the I2C address """sets the I2C address of the board. Only useful if board to be used in multichannel configuration <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n input: x: I2C address to assign""" if EMUL: z = 12 # random returned i2c value in case we emulate the presence of a board else: x = constrain(x, 0, 127) string = 'SI2C ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_I2C(" + str(x) + ") -> " + str(z) print(y) self.i2c = z return z
def s_kd(self, x)
-
sets parameters Kd of the PID regulator.
This command automatically saves the parameter in the HVPS EEPROM
Expand source code
def s_kd(self, x): # sets the PID gain Kd """sets parameters Kd of the PID regulator. <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SKd ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_kd(" + str(x) + ") -> " + str(z) print(y) return z
def s_ki(self, x)
-
""sets parameters Ki of the PID regulator.
This command automatically saves the parameter in the HVPS EEPROM
Expand source code
def s_ki(self, x): # sets the PID gain Ki """""sets parameters Ki of the PID regulator. <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SKi ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_ki(" + str(x) + ") -> " + str(z) print(y) return z
def s_kp(self, x)
-
sets parameters Kp of the PID regulator.
This command automatically saves the parameter in the HVPS EEPROM
Expand source code
def s_kp(self, x): # sets the PID gain Kp """sets parameters Kp of the PID regulator. <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n""" if EMUL: z = x else: string = 'SKp ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = float(self._readline()) if DEBUG: y = "s_kp(" + str(x) + ") -> " + str(z) print(y) return z
def s_latch_mode(self, x)
-
Defines the behaviour of the push button
Defines the behaviour of the push button, when the switching source of the HVPS is set to the push button (SWSRC_BTTN, c.f. s_sw_src() command above). Accepted values are 0 and 1: 0 for a push button behaviour (i.e. the high voltage is turned on as long as the button is pressed), and 1 for a latching switch behaviour (i.e. press once to turn the high voltage on, and press a second time to turn it off).
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
input: x: 0 or 1
output: latching mode as understood by the HVPS
Expand source code
def s_latch_mode(self, x): # sets the latch mode of the push button """Defines the behaviour of the push button Defines the behaviour of the push button, when the switching source of the HVPS is set to the push button (SWSRC_BTTN, c.f. s_sw_src() command above). Accepted values are 0 and 1: 0 for a push button behaviour (i.e. the high voltage is turned on as long as the button is pressed), and 1 for a latching switch behaviour (i.e. press once to turn the high voltage on, and press a second time to turn it off).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: 0 or 1\n output: latching mode as understood by the HVPS""" if EMUL: z = x else: if x > 1: x = 1 string = 'SLatchMode ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_latch_mode(" + str(x) + ") -> " + str(z) print(y) self.latch = z return z
def s_name(self, x)
-
Sets the name of the HVPS.
Sets the name of the HVPS. 20 characters maximum
This command automatically saves the parameter in the HVPS EEPROM
input: x=Name of the HVPS output: name accepted by HVPS
Expand source code
def s_name(self, x): # set the name of the HVPS """Sets the name of the HVPS. Sets the name of the HVPS. 20 characters maximum\n <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n input: x=Name of the HVPS output: name accepted by HVPS""" if EMUL: z = x elif len(x) < 21: string = 'SName ' string = string + x + '\r' string = string.encode() self.ser.write(string) z = self._readline() else: z = 'too long' if DEBUG: y = "s_kd(" + str(x) + ") -> " + str(z) print(y) return z
def s_power_jack(self, x)
-
Defines if power if provided by the power jack.
Defines if power if provided by the power jack, s_power_jack(1) (default), or through 5V pin, s_power_jack(0). As the default is power jack 1, You only need the use this command with SPowJack 0 if you wish to use the HVPS in the standalone configuration with touchscreen and battery, or in the multichannel configuration.
This command automatically saves the parameter in the HVPS EEPROM
input: x: 0 or 1 output: power jack mode accepted by HVPS
Expand source code
def s_power_jack(self, x): # sets the configuration of the HVPS (whether power comes from power jack) """Defines if power if provided by the power jack. Defines if power if provided by the power jack, s_power_jack(1) (default), or through 5V pin, s_power_jack(0). As the default is power jack 1, You only need the use this command with SPowJack 0 if you wish to use the HVPS in the standalone configuration with touchscreen and battery, or in the multichannel configuration.\n <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n input: x: 0 or 1 output: power jack mode accepted by HVPS""" if EMUL: z = x else: if x > 1: x = 1 string = 'SPowJack ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_power_jack(" + str(x) + ") -> " + str(z) print(y) self.config = not z # updates the configuration status of the HVPS return z
def s_pwm(self, x)
-
Set the voltage output as a PWM value
Defines the functioning set point of the HV programmable source as a 10-bit (0-1023) raw PWM value. Although this command can be used at any time, it mainly useful when the HVPS voltage control mode is internal openloop, VMODE_O (see set_vmode() command).
input: x: PWM set point (0-1023)
output: PWM set point accepted by HVPS
Expand source code
def s_pwm(self, x): # sets the pwm value """ Set the voltage output as a PWM value Defines the functioning set point of the HV programmable source as a 10-bit (0-1023) raw PWM value. Although this command can be used at any time, it mainly useful when the HVPS voltage control mode is internal openloop, VMODE_O (see set_vmode() command).\n input: x: PWM set point (0-1023)\n output: PWM set point accepted by HVPS""" if EMUL: z = 0 else: x = constrain(x, 0, 1023) string = 'SPWM ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_pwm -> " + str(z) print(y) return z
def s_st_dur(self, x)
-
Sets the duration of the strobe/trigger pulse as a fraction of the period of the HV output.
Sets the duration of the strobe/trigger pulse as a fraction of the period of the HV output. Usage: s_st_dur(xxx), with xxx being the fraction of the period of the HV output during which the strobe/trigger pulse must remain high (0: constantly off, 127: on during 50% of the period, and 255: constantly on).
The duration of the pulse is used in strobe mode ST_MODE_FIXED (fixed position) and STMODE_SWEEP (sweep mode)
input: x: duration of the strobe pulse (0-255, representing 0 to 100% duty cycle)
output: pulse duration accepted by the HVPS
Expand source code
def s_st_dur(self, x): # sets the duration of the strobe pulse """Sets the duration of the strobe/trigger pulse as a fraction of the period of the HV output. Sets the duration of the strobe/trigger pulse as a fraction of the period of the HV output. Usage: s_st_dur(xxx), with xxx being the fraction of the period of the HV output during which the strobe/trigger pulse must remain high (0: constantly off, 127: on during 50% of the period, and 255: constantly on).\n The duration of the pulse is used in strobe mode ST_MODE_FIXED (fixed position) and STMODE_SWEEP (sweep mode)\n input: x: duration of the strobe pulse (0-255, representing 0 to 100% duty cycle)\n output: pulse duration accepted by the HVPS""" if EMUL: z = x else: x = constrain(x, 0, 255) string = 'SStDur ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_st_dur(" + str(x) + ") -> " + str(z) print(y) self.stdur = z return z
def s_st_mode(self, x)
-
Sets the strobe mode.
Sets the strobe mode. Usage: s_st_mode(X), with X being
STMODE_OFF: trigger/strobe pulse off: no signal is generated.
STMODE_FIXED: fixed position: a trigger/strobe signal is generated at a fixed position, with a fixed duration. By default, the pulse is synchronized with the HV switching signal, but the position and duration of the pulse can be defined by the user (see next s_st_pos()).
STMODE_SWEEP: sweep mode: the position of the trigger/strobe pulse is shifted along the HV signal at a user-defined speed. The HVPS must be in switching mode (SWMODE_SW) for the trigger pulse to be generated. The trigger pulse is generated on pin T of the multi-purpose 10-pins header on the HVPS board.
input: x: STMODE_OFF or STMODE_FIXED, or STMODE_SWEEP
output: strobe mode as understood by HVPS
Expand source code
def s_st_mode(self, x): # sets the strobe mode """Sets the strobe mode. Sets the strobe mode. Usage: s_st_mode(X), with X being\n STMODE_OFF: trigger/strobe pulse off: no signal is generated.\n STMODE_FIXED: fixed position: a trigger/strobe signal is generated at a fixed position, with a fixed duration. By default, the pulse is synchronized with the HV switching signal, but the position and duration of the pulse can be defined by the user (see next s_st_pos()).\n STMODE_SWEEP: sweep mode: the position of the trigger/strobe pulse is shifted along the HV signal at a user-defined speed. The HVPS must be in switching mode (SWMODE_SW) for the trigger pulse to be generated. The trigger pulse is generated on pin T of the multi-purpose 10-pins header on the HVPS board.\n input: x: STMODE_OFF or STMODE_FIXED, or STMODE_SWEEP\n output: strobe mode as understood by HVPS""" if EMUL: z = x else: if x > STMODE_SWEEP: x = STMODE_OFF string = 'SStMode ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_st_mode(" + str(x) + ") -> " + str(z) print(y) self.stmode = z return z
def s_st_pos(self, x)
-
Sets the position of the rising edge of the strobe pulse with respect to the HV output.
Sets the position of the rising edge of the strobe pulse with respect to the HV output. Usage: s_st_pos(xxx), with xxx a value between 0 and 255, representing the position of the rising edge of the trigger pulse as a fraction of the period T of the HV signal. A value of 0 means that the rising edge of the trigger pulse is coincident with the rising edge of the HV output.
A value of 127 means that the rising edge of the trigger pulse is coincident with the falling edge of the HV output. The position of the pulse is only used when the strobe pulse mode is STMODE_FIXED (fixed position).
input: x: position of the trigger pulse (0 to 255)
output: position of the trigger pulse accepted by the HVPS
Expand source code
def s_st_pos(self, x): # sets the position of the strobe pulse """Sets the position of the rising edge of the strobe pulse with respect to the HV output. Sets the position of the rising edge of the strobe pulse with respect to the HV output. Usage: s_st_pos(xxx), with xxx a value between 0 and 255, representing the position of the rising edge of the trigger pulse as a fraction of the period T of the HV signal. A value of 0 means that the rising edge of the trigger pulse is coincident with the rising edge of the HV output.\n A value of 127 means that the rising edge of the trigger pulse is coincident with the falling edge of the HV output. The position of the pulse is only used when the strobe pulse mode is STMODE_FIXED (fixed position).\n input: x: position of the trigger pulse (0 to 255)\n output: position of the trigger pulse accepted by the HVPS""" if EMUL: z = x else: x = constrain(x, 0, 255) string = 'SStPos ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_st_pos(" + str(x) + ") -> " + str(z) print(y) self.stpos = z return z
def s_st_sweep(self, x)
-
sets the sweep time in ms.
sets the sweep time in ms. Usage s_st_sweep(xxx), where xxx is the time (in ms) that it takes to sweep the strobe/trigger pulse over a complete period of the HV output. This parameter is only used in strobe mode STMODE_SWEEP (sweep mode). If the pulse is used to drive a strobe LED, the sweep time defines the apparent period of the motion. Logically, the period set with s_st_sweep much be considerably longer than the period of the HV signal.
input: x: period of the sweep duration in ms
output: sweep duration accepted by HVPS
Expand source code
def s_st_sweep(self, x): # sets the sweep period (im ms) when in sweep mode """sets the sweep time in ms. sets the sweep time in ms. Usage s_st_sweep(xxx), where xxx is the time (in ms) that it takes to sweep the strobe/trigger pulse over a complete period of the HV output. This parameter is only used in strobe mode STMODE_SWEEP (sweep mode). If the pulse is used to drive a strobe LED, the sweep time defines the apparent period of the motion. Logically, the period set with s_st_sweep much be considerably longer than the period of the HV signal.\n input: x: period of the sweep duration in ms\n output: sweep duration accepted by HVPS""" if EMUL: z = x else: x = constrain(x, 0, 65535) string = 'SStSw ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_st_sweep(" + str(x) + ") -> " + str(z) print(y) self.stsweep = z return z
def s_sw_mode(self, x)
-
Sets the switching mode of the HVPS.
Sets the switching mode of the HVPS. Four possible values: SWMODE_OFF: HVPS is off (0 V output irrespective of voltage set point), SWMODE_DC: the HVPS is in DC mode with a constant output voltage at the desired set point, SWMODE_SW: the HVPS is switching at the desired frequency between 0V and Vset, and SWMODE_WFRM: the HVPS is in user-defined waveform mode. Setting the switching mode is only effective if the switching source is SWSRC_TMR (onboard timer switching).
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
input: x: SWMODE_OFF, SWMODE_DC, SWMODE_SW, or SWMODE_WFRM
output: Switching mode set by the HVPS
Expand source code
def s_sw_mode(self, x): # sets the switching mode """Sets the switching mode of the HVPS. Sets the switching mode of the HVPS. Four possible values: SWMODE_OFF: HVPS is off (0 V output irrespective of voltage set point), SWMODE_DC: the HVPS is in DC mode with a constant output voltage at the desired set point, SWMODE_SW: the HVPS is switching at the desired frequency between 0V and Vset, and SWMODE_WFRM: the HVPS is in user-defined waveform mode. Setting the switching mode is only effective if the switching source is SWSRC_TMR (onboard timer switching).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: SWMODE_OFF, SWMODE_DC, SWMODE_SW, or SWMODE_WFRM\n output: Switching mode set by the HVPS""" if EMUL: z = x else: if x > SWMODE_WFRM: x = SWMODE_OFF string = 'SSwMode ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_sw_mode(" + str(x) + ") -> " + str(z) print(y) self.swmode = z return z
def s_sw_src(self, x)
-
Sets the source of the switching signal.
Sets the source of the switching signal. Accepted values are: SWSRC_TMR for onboard switching (from internal clock of the board), SWSRC_EXT for external switching via pin 6 (Ext.F) on the board main connector, or SWSRC_BTTN for the push button. Example: s_sw_src(SWSRC_EXT) to use the external signal to switch the source on/off. Note that this setting is useful only if the jumper on header H2 is set to “onboard control”, else the jumper setting defines the source of the switching signal.
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
input: x: SWSRC_TMR, or SWSRC_EXT, or SWSRC_BTTN
Expand source code
def s_sw_src(self, x): # sets the switching source """Sets the source of the switching signal. Sets the source of the switching signal. Accepted values are: SWSRC_TMR for onboard switching (from internal clock of the board), SWSRC_EXT for external switching via pin 6 (Ext.F) on the board main connector, or SWSRC_BTTN for the push button. Example: s_sw_src(SWSRC_EXT) to use the external signal to switch the source on/off. Note that this setting is useful only if the jumper on header H2 is set to “onboard control”, else the jumper setting defines the source of the switching signal.\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: SWSRC_TMR, or SWSRC_EXT, or SWSRC_BTTN""" if EMUL: z = x else: if x > SWSRC_BTTN: x = SWSRC_TMR string = 'SSwSrc ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_sw_src(" + str(x) + ") -> " + str(z) print(y) self.swsrc = z return z
def s_v_mode(self, x)
-
Sets the voltage control mode
Sets the voltage control mode (i.e. how is the value of the output voltage controlled):
VMODE_R for internal voltage regulator (regulates the voltage to the value defined with the Vset command).
SMODE_EXT external voltage control (sets the output voltage according to the control voltage applied on pin 5 (Ext.V) of the main connector of the board. The input voltage range is 0 to 5V.
VMODE_O (that's an O like in open) internal open loop control (on-board regulator disconnected).
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
input: x: VMODE_R, VMODE_EXT, VMODE_O
Output: Voltage control mode accepted by the HVPS
Expand source code
def s_v_mode(self, x): # sets the voltage control mode """Sets the voltage control mode Sets the voltage control mode (i.e. how is the value of the output voltage controlled):\n VMODE_R for internal voltage regulator (regulates the voltage to the value defined with the Vset command).\n SMODE_EXT external voltage control (sets the output voltage according to the control voltage applied on pin 5 (Ext.V) of the main connector of the board. The input voltage range is 0 to 5V.\n VMODE_O (that's an O like in open) internal open loop control (on-board regulator disconnected).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: VMODE_R, VMODE_EXT, VMODE_O\n Output: Voltage control mode accepted by the HVPS""" if EMUL: z = x else: if x > VMODE_O: x = VMODE_R string = 'SVMode ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_v_mode(" + str(x) + ") -> " + str(z) print(y) self.vmode = z return z
def s_vmax(self, x)
-
sets the voltage rating of the SHVPS.
sets the voltage rating of the SHVPS. Must match the EMCO DC/DC converter rating.
This command automatically saves the parameter in the HVPS EEPROM
input: x:voltage rating of HVPS in Volt
Expand source code
def s_vmax(self, x): # sets the maximum voltage rating of the board """sets the voltage rating of the SHVPS. sets the voltage rating of the SHVPS. Must match the EMCO DC/DC converter rating.\n <b>This command automatically saves the parameter in the HVPS EEPROM</b>\n input: x:voltage rating of HVPS in Volt""" if EMUL: z = x else: x = constrain(x, 0, 10000) string = 'SVmax ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_vmax(" + str(x) + ") -> " + str(z) print(y) self.vmax = z return z
def s_vset(self, x)
-
Sets the output voltage of the HVPS
input: x: voltage set point (int)
output: voltage set point accepted by HVPS
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
Although this command can be used at any time, it is mainly useful when the HVPS voltage control mode is internal regulator (VMODE_R); see s_vmode() command.
Expand source code
def s_vset(self, x): # sets the output voltage """ Sets the output voltage of the HVPS input: x: voltage set point (int)\n output: voltage set point accepted by HVPS\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n Although this command can be used at any time, it is mainly useful when the HVPS voltage control mode is internal regulator (VMODE_R); see s_vmode() command.""" if EMUL: z = x else: x = constrain(x, 0, self.vmax) string = 'SVset ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = int(self._readline()) if DEBUG: y = "s_vset(" + str(x) + ") -> " + str(z) print(y) self.vset = z return z
def s_waveform_point(self, x)
-
Add a point to the user waveform.
Add a point to the user waveform. Usage: s_waveform_point(xxx), with xxx between 0 and 255 representing 0 to 100% of the voltage setpoint.
A new waveform is defined by issuing clear_waveform() (to clear the previous waveform), followed by a series of s_waveform_point(xxx) to define the points of the new waveform. The maximal number of allowed points is 255. This is a low-level function provided to match the 'SP' command of the HVPS communication protocol. However, It is easier to use upload_waveform() to upload a complete waveform to the HVPS in one go, or to use upload_std_waveform() to upload some customisable standard waveforms.
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
input: x: set point to add to the current waveform. 0-255 representing 0-100% of voltage set point.
output: accepted set point (or -1 if waveform full)
Expand source code
def s_waveform_point(self, x): # Add a point to the waveform """Add a point to the user waveform. Add a point to the user waveform. Usage: s_waveform_point(xxx), with xxx between 0 and 255 representing 0 to 100% of the voltage setpoint.\n A new waveform is defined by issuing clear_waveform() (to clear the previous waveform), followed by a series of s_waveform_point(xxx) to define the points of the new waveform. The maximal number of allowed points is 255. This is a low-level function provided to match the 'SP' command of the HVPS communication protocol. However, It is easier to use upload_waveform() to upload a complete waveform to the HVPS in one go, or to use upload_std_waveform() to upload some customisable standard waveforms.\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: set point to add to the current waveform. 0-255 representing 0-100% of voltage set point.\n output: accepted set point (or -1 if waveform full)""" s = [-1, -1] x = constrain(x, 0, 255) if EMUL: z = x else: num_pts = self.q_waveform_num_pts() # queries how many points currently saved in memory if num_pts < 255: # can only add a point if less than 255 points currently saved string = 'SP ' string = string + str(x) + '\r' string = string.encode() self.ser.write(string) z = self._readline() z = z.decode("utf-8") s = z.split(",") z = s[1] else: z = -1 if DEBUG: y = "s_waveform_point(" + str(x) + ") -> " + str(s[0]) + "," + str(s[1]) print(y) return z
def save(self)
-
save current HVPS parameters into the memory
This command saves the following parameters in EEPROM: Voltage setpoint, Frequency, Frequency divider, Source of switching signal (external, internal, button), Switching mode (off, DC output, switching output), Voltage mode (internal voltage regulator or following external signal), and number of switching cycles. It also saves the user-defined waveform into the EEPROM. This is useful so that it is not necessary to reconfigure the HVPS for the desired behavior every time it is powered up, for example when the HVPS is meant to be used without computer (when connected to a demo device). Note that when the HVPS is used with a computer, it is safer to save a voltage setpoint of 0V (and/or a switching mode 0 (box off)) so as to be sure that no high voltage is present at the output when the board is powered up (and before the computer has the time to initialise it to 0V output).
Expand source code
def save(self): # save current HVPS parameters into the memory """save current HVPS parameters into the memory This command saves the following parameters in EEPROM: Voltage setpoint, Frequency, Frequency divider, Source of switching signal (external, internal, button), Switching mode (off, DC output, switching output), Voltage mode (internal voltage regulator or following external signal), and number of switching cycles. It also saves the user-defined waveform into the EEPROM. This is useful so that it is not necessary to reconfigure the HVPS for the desired behavior every time it is powered up, for example when the HVPS is meant to be used without computer (when connected to a demo device). Note that when the HVPS is used with a computer, it is safer to save a voltage setpoint of 0V (and/or a switching mode 0 (box off)) so as to be sure that no high voltage is present at the output when the board is powered up (and before the computer has the time to initialise it to 0V output).""" if EMUL: z = 1 else: self.ser.write(b'Save\r') z = int(self._readline()) if DEBUG: y = "save -> " + str(z) print(y) return z
def transmit(self, x)
-
Sends a direct command to the HVPS
Sends a command to the HVPS. List of commands: https://petapicovoltron.com/software/direct-communication-with-the-hvps/ This function is used by the main() functions in case this file is run as a script and provides an interactive terminal session with the HVPS. However, when using the library, the specific functions provided by the library should be used instead
input: x: a string to send to the HVPS
output: The reply from the HVPS (string)
Expand source code
def transmit(self, x): # transmits a command directly to the HVPS """Sends a direct command to the HVPS Sends a command to the HVPS. List of commands: https://petapicovoltron.com/software/direct-communication-with-the-hvps/ This function is used by the main() functions in case this file is run as a script and provides an interactive terminal session with the HVPS. However, when using the library, the specific functions provided by the library should be used instead\n input: x: a string to send to the HVPS\n output: The reply from the HVPS (string)""" if EMUL: z = b'null\r\n' else: self.ser.write(x) z = self._readline2() if DEBUG: print(x) print(z) return z
def upload_std_waveform(self, func=0, sr=False, n=100, b=0.15)
-
Upload a customisable standard waveform to the HVPS
inputs:
func: FUNC_SINE (a sine wave with an offset to be between 0 and Voltage set point), FUNC_TRI (a triangle function), FUNC_TRAP (a Trapezoid function), FUNC_CSTM (a custom waveform. Points (a maximum number of 255 points) should be defined in a file named waveform.txt located alongside this library. There should be 1 point per line, each point between 0 and 1, representing 0 to 100% of the voltage set point)
sr: (square root) True or False. In case the HVPS is used to drive dielectric elastomer actuators, there is a quadratic relationship between voltage and actuation strain. True: a square root correction is applied so that the actuation strain will roughly have the chosen profile. False: No correction applied/n n: number of point in the waveform. Max is 255. It depends on the frequency at which the waveform will be produced, For a 1Hz signal, 100 points are adequate. Reduce the number of points for higher frequencies b: This applies only for the FUNC_TRAP function and defines the percentage of the period that the raising (and falling) edge should take. The value should be smaller than 0.5 (at which point the waveform becomes a triangle).
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
Expand source code
def upload_std_waveform(self, func=FUNC_SINE, sr=False, n=100, b=0.15): """Upload a customisable standard waveform to the HVPS inputs:\n func: FUNC_SINE (a sine wave with an offset to be between 0 and Voltage set point), FUNC_TRI (a triangle function), FUNC_TRAP (a Trapezoid function), FUNC_CSTM (a custom waveform. Points (a maximum number of 255 points) should be defined in a file named waveform.txt located alongside this library. There should be 1 point per line, each point between 0 and 1, representing 0 to 100% of the voltage set point)\n sr: (square root) True or False. In case the HVPS is used to drive dielectric elastomer actuators, there is a quadratic relationship between voltage and actuation strain. True: a square root correction is applied so that the actuation strain will roughly have the chosen profile. False: No correction applied/n n: number of point in the waveform. Max is 255. It depends on the frequency at which the waveform will be produced, For a 1Hz signal, 100 points are adequate. Reduce the number of points for higher frequencies b: This applies only for the FUNC_TRAP function and defines the percentage of the period that the raising (and falling) edge should take. The value should be smaller than 0.5 (at which point the waveform becomes a triangle).\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n""" pts = [] n = constrain(n, 1, 255) # n must be between 1 and 255 points b = constrain(b, 0, 0.5) # b must be between 0 and 0.5 if sr: # if we want the square root of the signal (because of the quadratic relationship between voltage # and strain for DEAs) power = 0.5 else: power = 1.0 if func == FUNC_CSTM: # custom user waveform try: fp = open('./waveform.txt', 'r') except FileNotFoundError: if DEBUG: print("Custom waveform must be in ./waveform.txt, but file is not found") fp = 0 if fp: list_of_points = fp.readlines() for point in list_of_points: try: point = int(255*(float(point) ** power)) except ValueError: point = 0 if DEBUG: print("Error when reading point for custom waveform. Each line in the file ./waveform.txt " "must contain a single floating point number") point = constrain(point, 0, 255) # points should be between 0 and 255 pts.append(point) fp.close() else: # if other standard functions are chosen for i in range(n): p = 0 # p is between 0 to 1 representing percentage of voltage set point if func == FUNC_SINE: # Sine + offset waveform p = (0.5+0.5*sin(2*pi/n*i)) ** power elif func == FUNC_TRAP: # trapeze waveform if i <= b*n: # the ramp up of the trapeze p = (i/b/n) ** power elif i <= n/2: # holding time p = 1 elif i <= (n/2 + b*n): # ramp down p = (1-(i - n/2) / b / n) ** power else: p = 0 elif func == FUNC_TRI: if i <= n/2: # Raising edge p = (2/n*i) ** power else: p = (1 - 2 / n * (i - n / 2)) ** power p = int(p*255) pts.append(p) self.upload_waveform(pts) # uploads the waveform to the HVPS
def upload_waveform(self, x)
-
upload a user-defined waveform to the HVPS
upload a user-defined waveform to the HVPS. It starts by clearing the current waveform and then it upload an new list of points. It also updates the member variable self.waveform_pts with the new list of points.
The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory
input: x: [p1, p2, p3, …, pn] where pn is the nth point of the waveform, between 0 and 255, representing 0 to 100% of the current voltage set point. n is limited to 255.
output: none
Expand source code
def upload_waveform(self, x): # upload a list (x) of waveform set points to the HVPS """upload a user-defined waveform to the HVPS upload a user-defined waveform to the HVPS. It starts by clearing the current waveform and then it upload an new list of points. It also updates the member variable self.waveform_pts with the new list of points.\n The new parameter remains valid until a new call to this command, or when the HVPS is powered off. Using the save() command enables to save this parameter in memory\n input: x: [p1, p2, p3, ..., pn] where pn is the nth point of the waveform, between 0 and 255, representing 0 to 100% of the current voltage set point. n is limited to 255.\n output: none""" self.clear_waveform() # starts by clearing the waveform self.waveform_pts.clear() # empty the current list of point of the local copy if len(x) > 255: # waveform limited to 255 points x = x[:255] for point in x: point = constrain(point, 0, 255) self.waveform_pts.append(self.s_waveform_point(point)) # upload the point and add it to the local copy
class HVPSMem
-
Expand source code
class HVPSMem: # structure to store the memory information of the HVPS def __init__(self): self.vset = 0 self.f = 0 self.swsrc = 0 self.swmode = 0 self.vmode = 0 self.kp = 0 self.ki = 0 self.kd = 0 self.c0 = 0 self.c1 = 0 self.c2 = 0 self.cycles = 0 self.latch = 0 self.vmax = 0 # Vmax, ver and i2c address are not returned by the q_mem function, because they have dedicated # query function. They are added to the structure so that all information regarding the configuration of the # board can be grouped in a single variable. (Name should be added) self.i2c = 0 self.ver = 0