#%TITLE% kepco_bop_mm.mac
#$Revision: 1.8 $
#%NAME% Macros for a the use of a KEPCO,BOP 1000W 100-10 powersuppy
#%DESCRIPTION%
# The intrument pool power supply is a KEPCO,BOP 1000W 100-10 08/04/08 ,A98599,1.61b
#%BR%
# the string it answers is : KEPCO,BOP1KW 100-10 ,A98599, 2.04
#%BR%
# ID18`s power supply answers: KEPCO,BOP1KW 20-50 10-15-2009 ,E157846, 3.04
#%BR%
#Kepco's auto-crossover digital supplies can operate in either voltage mode with current limit, or
#current mode with voltage limit. The operating mode is determined by the voltage and current
#commands received, as well as the load. Each time voltage and current commands are
#received, the unit must evaluate the commands aand the load conditions to determine the necessary
#operating mode. Reducing the number of times this evaluation must be made is desirable
#because Kepco's digital auto-crossover supplies employ two separate feedback loops. Each
#time there is a potential mode change, there is always an uncontrolled period of a few milliseconds
#while the two feedback loops compete for control of the output. By changing only the
#active parameter (e.g., voltage for voltage mode), there is no doubt as to what the operating
#mode will be, so the unit is never uncontrolled, response is quick and no transients are possible
#%BR% %BR%
# To define a macro motor controller you must define
# a kepco motor controller in config, ADDR is the GPIB address.
# %BR%
#%PRE%
#\0\0\0MOTORS\0\0\0\0\0\0\0DEVICE\0\0\0\0ADDR\0\0\0<>MODE\0\0\0\0\0\0NUM\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<>TYPE
#\0\0\0\0\0\0YES\0\0\0\0\0\0\0kepco\0\0\0\0\0\00:6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01\0\0\0\0\0\0\0\0\0Macro\0Motors
#%PRE%
# %BR% %BR%
# Then declare a motor with that controller.
# %BR% %BR%
#%PRE%
#Number:\0<>Controller\0\0\0\0\0\0\0\00:\0MAC_MOT
#Unit/[Module/]Channel\0\0\0\0\0\0\0\0\0\0\0\0\0\00/1
#Name\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Kepco\0Curr
#Mnemonic\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0curr
#Steps\0per\0degree/mm\0\0\0\0\0\0\0\0\0\0\0\0\0\010000
#Sign\0of\0user\0*\0dial\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#Backlash\0[steps]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00
#Steady-state\0rate\0[Hz]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#Base\0rate\0[Hz]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#Acceleration\0time\0[msec]\0\0\0\0\0\0\0\0\0\0\0\0\01
#Motor\0accumulator\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00
#Restrictions\0<>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0NONE
#
#Dial\0=\0accumulator\0/\0steps
#\0\0High\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01.6000
#\0\0Current\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000
#\0\0Low\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-1.6000
#User\0=\0sign\0*\0dial\0+\0offset
#\0\0Offset\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000
#\0\0`High'\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01.6000
#\0\0Current\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000
#\0\0`Low'\0limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-1.6000
#%PRE%
## hit `m` twice to move to the third motor config screen
#%PRE%
#Number:\0<>Controller\0\0\0\0\0\0\0\00:\0MAC_MOT
#Unit/[Module/]Channel\0\0\0\0\0\0\0\0\0\0\0\0\0\00/1
#Name\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Kepco\0Curr
#Mnemonic\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0curr
#
#Encoder\0steps\0per\0deg/mm
#Step\0mode\0(0=full,1=half)
#Linear/Rotary\0(1=rotary)
#Disable\0limit\0checks
#Readback\0slop\0[steps]\0\0\0\0\0\0\0\0\0\0\0\0\0\0100
#Hardware\0read\0mode\0<>\0\0\0\0\0PR\0+\0AL\0+\0NQ
#
#%PRE%
#%BR%
#%END%
#NOTES:
#%PRE%
#*IDN? works fine.
#*RST resets power to 0, rather not!
#OUTP ON will switch the PS to a usable state.
#*OPC? operation completed ? should be used for error catching. then ask the status registers.
#we want to work in current mode. The voltage is kept constant by the power supply and limited to a maximum/minimum.
#Marcin says: he wants to work at 10 V and vary the current.
#Switch to current mode with FUNC:MODE CURR/VOLT for voltage mode.
#Then protect the ps and the magnet with a VOLT:PROT 10 (10 volt is max/min). One can set the minimum separately, but we should use both + and -.
#$Log: kepco_bop_mm.mac,v $
#Revision 1.8 2016/01/05 16:14:44 guilloud
#fix wrong chars --> "1"
#
#Revision 1.7 2011/02/03 10:48:06 witsch
#only cosmetical changes --> help local kepco_bop_mm.mac
#
#Revision 1.6 2010/09/10 15:16:14 witsch
#some corrections for the variable KEPCO_ADDR, which seemed to be invalid
#for the KEPCO_cmd and KEPCO_par functions. Read the address with
#motor_par(mnum, "address")
#
#Revision 1.5 2010/05/03 12:34:42 witsch
#lock device from being used, when power was cycled. This might happen, when
#sensor connection was opened. Cycling power is necessary to achieve this.
#
#The check is done by asking the device for the source mode (current or
#voltage). As ID18 will use it in current mode only and voltage is the
#default, we check if device is in voltage mode and if so, refuse all
#commands.
#
#Revision 1.4 2010/04/21 14:10:28 witsch
#some better error handling. Basically Spec will stop working with the device
#if an error occurs. Some more cosmetics for the startup in fresh mode.
#
#Revision 1.2 2010/01/13 14:25:25 witsch
#new version, now no longer based on tango server, but direct access
#via gpib builtin spec support.
#Slightly modified in _io_ function for error reporting and
#lower protection voltage for new power supply.
#
#added function for voltage change.
#
if (!(whatis("__kepco_debug") & 2)) rdef __kepco_debug \'#$*\'
#%UU%
#%MDESC% toggle debug mode for the present macros.
def kepco_debug '{
if ((whatis("__kepco_debug")>>16) <= 4) { # just a # sign -> off
rdef __kepco_debug "eprint"
print "kepco debug is ON"
} else {
rdef __kepco_debug \'#$*\'
print "kepco debug is OFF"
}
}
'
#%IU%(mnum, type, unit, mod, chan)
#%MDESC%
# Called by spec
def KEPCO_config(mnum, type, unit, mod, chan) '{
__kepco_debug "KEPCO config", mnum, type, unit, mod, chan
global __KEPCO[]
__KEPCO["active"] = "CURR"
__KEPCO["complm"] = "VOLT"
__KEPCO["PROT"] = 20 # whatever the unit :-)
delete __KEPCO["error"]
local answer, ident
if (mnum == "..") {
if ((answer = __kepco_io(KEPCO_ADDR, "*IDN?")) == "") {
eprint "No connection with the Kepco power supply!"
return(".error.")
}
ident = "KEPCO,BOP1KW 100-10 "
if (substr(ident, answer) != ident) {
print "The interface does not answer the correct identification string!"
print "Are the interface informations correct?"
return(".error.")
}
# OUTP ON Turns the output on.
__kepco_put(KEPCO_ADDR, "OUTP ON")
# Activate
__kepco_put(KEPCO_ADDR, "*OPC")
__kepco_put(KEPCO_ADDR, "OUTPUT:MODE ACTIVE")
}
else {
motor_par(mnum, "mode", chan)
motor_par(mnum, "prot", __KEPCO["PROT"])
__KEPCO["SLOP"] = motor_par(mnum, "slop") / motor_par(mnum, "step_size")
local aux[], pos, str, addr
addr = motor_par(mnum, "address")
str = "*wai;meas:" __KEPCO["active"] "?;*wai;*OPC?"
answer = __kepco_io(addr, str)
split(answer, aux, ";")
answer = aux[0]
__KEPCO["pos"] = answer
}
}
'
#%IU%(mnum, key, p1, p2, p3)
#%MDESC%
# Called by spec
def KEPCO_cmd(mnum, key, p1, p2, p3) '{
__kepco_debug "KEPCO command", mnum, key, p1, p2, p3
if (mnum == "..") {
return
}
if (!__KEPCO["active"]) {
return
}
if ( ! motor_par(mnum, "mode") ) {
eprint "Kepco Power supply: Did you cycle power ? Please reconfig!"
return(".error.")
}
local str, addr
addr = motor_par(mnum, "address")
if (key == "position") {
local str, answer
#[VOLT|CURR]? Returns programmed output
str = "*wai;meas:" __KEPCO["active"] "?;*wai;*OPC?"
answer = __kepco_io(addr, str)
# with "*OPC?" outputs curr;1, but spec seems to cope,
# so no treatment of output
# print answer
return(answer)
} else
# if (key == "magnitude") {
# print "magnitude", p1, p1 * .5, __KEPCO["SLOP"]
# if (__KEPCO["SLOP"] > p1 *.5)
# __KEPCO["SLOP"] = p1 * .5
# } else
if (key == "get_status") {
local answer, aux[], pos
str = "*wai;meas:" __KEPCO["active"] "?;*wai;*OPC?"
answer = __kepco_io(addr, str)
split(answer, aux, ";")
answer = aux[0]
pos = __KEPCO["pos"]
__kepco_debug "pos", pos, "answer", answer, "diff", pos - answer, "fabs", fabs(pos - answer), "slop", __KEPCO["SLOP"]
if (fabs(pos - answer) > __KEPCO["SLOP"]) {
return(2)
}
return(0)
} else
if (key == "start_one") {
__KEPCO["pos"] = p1
str = __KEPCO["active"] " " p1 ";*wai"
# output is unused
return(__kepco_io(addr, str))
}
}
'
#%IU%(mnum, key, action, p1, p2)
#%MDESC%
# Called by spec
def KEPCO_par(mnum, key, action, p1, p2) '{
__kepco_debug "* kepco parameters", mnum, key, action, p1, p2, KEPCO_ADDR
local str, answer, addr
addr = motor_par(mnum, "address")
__kepco_debug "addr", addr
if (key == "prot") { # set protection limits
__kepco_debug "* kepco prot"
if (action == "set") {
__KEPCO["PROT"] = p1
str = __KEPCO["complm"] ":PROT " __KEPCO["PROT"]
answer = __kepco_put(addr, str)
# if (__kepco_opc(addr) == 0) {
# eprint "Kepco: ERROR ! Operation", str, "NOT complete!"
# return(".error.")
# }
return(answer)
}
else if (action == "get") {
str = __KEPCO["complm"] ":PROT?"
answer = __kepco_io(addr, str)
__kepco_debug "get prot", str, answer
return answer
}
}
else if (key == "mode") { # set current or voltage mode as active mode
__kepco_debug "* kepco mode"
# motor_par only allow numerical values for p1 --->
# use 0 for voltage mode and 1 for current mode, which are the values the
# system wil answer, if asked "func:mode?"
if (action == "set") {
if (p1 == 0) {
__KEPCO["active"] = "VOLT"
__KEPCO["complm"] = "CURR"
} else {
__KEPCO["active"] = "CURR"
__KEPCO["complm"] = "VOLT"
}
str = "FUNC:MODE " __KEPCO["active"]
answer = __kepco_put(addr, str)
if (answer == ".error.") {
return(answer)
}
if (__kepco_opc(addr) == 0) {
eprint "Kepco: ERROR ! Operation", str, "NOT complete!"
return(".error.")
}
return 0
# can we set the protection from here ?
motor_par(mnum, "prot", __KEPCO["PROT"])
}
else if (action == "get") {
str = "func:mode?"
answer = __kepco_io(addr, str)
__kepco_debug "get mode", str, answer, answer ? "curr" : "volt"
return answer
}
}
}
'
#%PRE%
# Copy of the oepration manual
# OPERATION COMPLETE QUERY *OPC?
#Syntax: *OPC?
#Return value: <1 or 0> (ASCII)
#0 placed in output queue if power supply has not completed operation after prior *OPC command.
#1 placed in output queue when power supply has completed operation.
#Description: Indicates when pending operations have been completed. *OPC command must be sent to first to
#clear status bit 0 (Operation Complete). *OPC? will return "0" until all pending operations are complete
#(all previous commands have been executed and changes in output level have been completed) At
#that time *OPC? will return "1". Unlike the *WAI command (see PAR. A.18), subsequent commands
#are not inhibited while status bit 0 is "0". *OPC? is intended to be used at the end of a command line
#so that the application program can monitor the bus for data until it receives "1" from the power
#supply Output Queue
#%PRE%
#%IU%(addr, cmd)
#%MDESC% Called by spec, write command to controller and read answer.
def __kepco_io(addr, cmd) '{
__kepco_debug "__kepco_io(\"" addr "\", \"" cmd "\")"
if (__kepco_put(addr, cmd) == ".error.") {
return(".error.")
}
local i, x, str, answer, error, aux[]
answer = gpib_get(addr, "\n")
# the answer can sometimes be
# \0000,"no error". Of course with the \0 at the beginning, the string
# becomes empty in the sense of spec.
if (__kepco_put(addr, "SYSTem:ERRor?") == ".error.") {
return(".error.")
}
errors = gpib_get(addr, "\n")
if (split(errors, aux, ",") == 2) {
if (aux[0] != 0) {
eprint "Kepco PS ERROR:", aux[1]
__KEPCO["error"] = aux[0]
return(".error.")
}
}
__kepco_debug answer
return(answer)
}
'
#%IU%(addr, cmd)
#%MDESC% Called by spec, write command to controller, no answer expected.
def __kepco_put(addr, cmd) '{
local str
str = cmd "\r\n"
__kepco_debug "__kepco_put(\"" addr "\", \"" cmd "\")"
if ((answ = gpib_put(addr, str)) == -1) {
return(".error.")
}
return 0
}
'
#%IU%(addr, cmd)
#%MDESC% Called by spec, here check if command complete
def __kepco_opc(addr) '{
__kepco_debug "__kepco_opc(" addr ")"
return __kepco_io(addr, "*OPC?")
}
'
#%UU% motor protection_voltage
#%MDESC% read or set the protection voltage
def kepco_prot '{
if ($# == 0) {
eprint "Please give motor mnummonic as first argument!"
exit
}
local aux[], answer
answer = motor_par($1, "prot")
split(answer, aux, ",")
print "Kepco power supply protection voltage is", aux[1]
if ($# > 1) {
print "Set protection to:", $2
motor_par($1, "prot", $2)
local aux[], answer
answer = motor_par($1, "prot")
if (answer == "0") {
exit
}
split(answer, aux, ",")
print "Kepco power supply protection voltage is", aux[1]
}
}
'
# this is an attempt to come around the problem with the macro motor macros
# being loaded at the end of the config/setup, thus not executing the
# KEPCO_config function. Variable remain uninitialised. We need a reconfig
if (!whatis("__KEPCO")) {
eprint "\n\n\n"
eprint "***************************************************************"
eprint "Make sure to do a reconfig for the KEPCO power supply macros!!!"
eprint "***************************************************************"
eprint "\n\n\n"
}
#%MACROS%
#%IMACROS%
#%END%
#%BUGS% Bugs ? What bugs ??
#%AUTHOR%
#Holger (BLISS) for ID18.
#%TOC%
|