"""
#%TITLE%pace6000.mac
#$Revision: 1.6 $
#%NAME%
#Macromotor to control the PACE6000 K0443 Pressure Automated Calibration Equipment.
#%DESCRIPTION%
#Control of the PACE5000 single-channel or PACE6000 single/dual-channel Pressure Automated
#Calibration Equipment.
#%BR%Control via ethernet sockets.
#%BR%The macromotor controller to be used is 'pace6000'. Each controller
#must define the serial device index or the "adress:socket_number" as the address in config.
#Declare a %B%motor\0controller%B%:
#
#%PRE%
#MOTORS DEVICE ADDR <>MODE NUM <>TYPE
# YES pace6000 id09pace6000:5025 2 Macro Motors
#%PRE%
# and a macro motor:
#%BR% %BR%Unit is index num of controller, second is the %B%controller\0channel%B%
#as number 0 (zero) or 1 (one).
#%PRE%
#Number: <>Controller xx: MAC_MOT
#Unit/[Module/]Channel y/0
#Name pace
#Mnemonic pace
#Steps per degree/mm 10000
#Sign of user * dial 1
#Backlash [steps] 0
#Steady-state rate [Hz] 2000
#Base rate [Hz] 200
#Acceleration time [msec] 125
#Motor accumulator 362
#Restrictions <> NONE
#Dial = accumulator / steps
# High limit xxx.0000
# Current 0.0000
# Low limit 0.0100
#User = sign * dial + offset
# Offset 0.0000
# `High' limit xxx.0000
# Current 0.0000
# `Low' limit 0.0100
#%PRE%
#%BR%
# Then hit 'm' twice. Set the following for your motor:
#%PRE%
#Hardware read mode <> PR + AL + NQ
#%PRE%
#Please NOTE: When the controller is close to zero, it mightn`t return the
#second in-limit parameter as 1. This implies, that the pressure zero will
#not be reached and the controller will never signal it has reached the final
#destination. Solution is to set the lower limit to %B%0.1%B%.
#%END%
$Log: pace6000.mac,v $
Revision 1.6 2015/06/02 13:12:56 witsch
* macro pace6000_slewrate corrected to work with the controller's
pressure unit, but converted to units per minute.
* bug fix, macro pace6000_slewrate : one motor_par used a bad variable
as motor number.
* define macro pace6000_slewrate as pace_slewrate and pace6000_switch as
pace_switch to allow for pace5000 users not to be confused.
Revision 1.5 2015/05/29 15:21:47 witsch
* keep ping from talking.
* clarify message after ping failed
* check for controller state, before checking for motor state.
if output:state? is 0, return 0 and motor is then not moving.
Revision 1.4 2014/03/27 15:09:22 witsch
macro pace6000_switch was working on only first channel, as the channel
number had been omitted with the first documentation.
Added the treatment of channel for :OUTPUT[x]:STATE command.
Revision 1.3 2014/02/25 08:29:56 witsch
bug in pace6000_switch has been fixed.
some safety in pace6000_io and pace6000_switch and pace6000_slew to make sure,
they're not used with wrong motors.
Revision 1.2 2014/02/18 09:52:09 witsch
Added macro to change the slewrate.
"""
global __PACE6000
#%UU%
#%MDESC%toggle the debug mode
if (!(whatis("_pace6000_debug") & 2)) rdef _pace6000_debug \'#$*\'
def pace6000_debug '{
if ((whatis("_pace6000_debug")>>16) <= 3) { # macro length is 3 bytes: comment
rdef _pace6000_debug "eprint \">>> PACE6000 debug: \""
printf ("_pace6000 macro debug mode is ON\n")
} else {
rdef _pace6000_debug \'#\$*\'
printf ("_pace6000 macro debug mode is OFF\n")
}
}
'
# some programmer help
#%UU%
#%MDESC%toggle simulation mode for the present macros.
def pace6000_simul '{
if (__PACE6000["SIMUL"]) { # if present should be true
__PACE6000["SIMUL"] = 0
printf ("pace6000 simulation is OFF\n")
} else {
__PACE6000["SIMUL"] = 1
printf ("pace6000 simulation is ON\n")
}
}
'
#%IU%
#%MDESC%MACRO MOTOR:
# Called by spec after reading the config file
def pace6000_config(mne, type, unit, num_motors) '{
local dev
_pace6000_debug "config: ", mne, type, unit, num_motors
# called for each macro-hardware controller
# p1:unit p2: nbchane
if(type == "ctrl") {
local lcmd, dd, output
if (split(pace6000_ADDR, dd,":")) { # ethernet
lcmd = sprintf ("ping %s -c 3 >/dev/null 2>&1", dd[0])
if (unix(lcmd, output) != 0) {
eprintf ("PACE6000: Controller %s not responding, disabling controller.\n", dd[0])
return(".error.")
}
__PACE6000[unit]["type"] = "ethernet"
} else { # serial
__PACE6000[unit]["type"] = "serial"
}
__PACE6000[unit]["dev"] = pace6000_ADDR
_pace6000_debug " new controller ", _pace6000_io(unit, "*IDN?")
}
"""
else if (type == "mot") {
This didn`t work, it is precisely like described in the manual (4-46)
local chan, cmd
chan = motor_par(mne, "channel")
cmd = ":SENS" chan ":PRES:INL:time 1"
_pace6000_io(unit, cmd)
}
"""
}
'
"""
#%IU%
#%MDESC%
# MACRO MOTOR:
# Called by spec on motor operation. It manages:
#%BR%- position
#%BR%- start_one
#%BR%- get_status
"""
def pace6000_cmd(num,key,p1,p2) '{
_pace6000_debug "_cmd: ", num, key, p1, p2
local unit, chan, cmd, aux
if(num == "..") { return } # do nothing with controller
unit = motor_par(num, "unit")
chan = motor_par(num, "channel")
# controller uses 1 or 2, if empty, communicate empty string for channel
# so that would "" for channel 1 and 2 for channel 2 (for pace5000)
if (chan) chan += 1
else chan = ""
if (key == "start_one") {
# start a motion. p1: dial abs. pos., p2: dial rel. pos.
local currstate
cmd = ":OUTPut" chan ":STATe?"
currstate = _pace6000_io(unit, cmd) * 1
if (!currstate) {
eprint "PACE6000: Controller not on. Use macro pace6000_switch!"
return ".error."
}
cmd = ":SOURce" chan ":PRESsure " p1
_pace6000_io(unit, cmd)
if (_pace6000_report_error(unit) == ".error") {
_pace6000_debug "_cmd: --------------- reporting an .ERROR."
return ".error."
}
#returns nothing
}
else if (key == "position") {
# return the current pressure
cmd = ":SENSe" chan ":PRESsure?"
_pace6000_debug "_cmd: position", cmd
retval = _pace6000_io(unit, cmd) * 1
if (_pace6000_report_error(unit) == ".error") {
_pace6000_debug "_cmd: --------------- reporting an .ERROR."
return ".error."
}
else {
_pace6000_debug retval, "bar"
return retval
}
}
else if (key == "get_status") {
"""
return motor status
0x02: moving
0 : otherwise
Function: Query in-limits value
Response: First parameter - current pressure.
Second parameter - in limit:
0 = not in limits
1 = in limits
NOTE: When the controller is close to zero, it mightn`t give the second parameter as 1.
"""
local pressevent, aux[], pressure, currstate
cmd = ":OUTPut" chan ":STATe?"
currstate = _pace6000_io(unit, cmd) * 1
if (! currstate) {
return 0
}
cmd = ":SENS" chan ":PRES:INL?"
pressevent = _pace6000_io(unit, cmd)
if (_pace6000_report_error(unit) == ".error") {
_pace6000_debug "_cmd: --------------- reporting an .ERROR."
return ".error."
}
nb = split(pressevent, aux, ",")
pressevent = aux[1] * 1
if (pressevent) {
return 0 # and return zero to signal, we`re there!
}
else {
return 0x02
}
}
else if (key == "abort_one") {
"""
stop channel that is changing pressure
There seems to be no ABORT command in the controller. Read the pressure and send it
as set point instead.
"""
local pressure
# get the current pressure
cmd = ":SENSe" chan ":PRESsure?"
_pace6000_debug "_cmd: --------------------> abort_one", cmd
pressure = _pace6000_io(unit, cmd) * 1
cmd = ":SOURce" chan ":PRESsure " pressure
_pace6000_debug "_cmd: --------------------> abort_one", cmd
_pace6000_io(unit, cmd)
}
}'
#%IU%
#%MDESC%sends the string 'cmd' to controller.
#%BR%It ends the command with \\r and \\n for serial comm.
#%BR%There could be a GPIB connection, but it's not handled here.
def _pace6000_io(num, cmd) '{
local aux, retval, nb, rsvp
_pace6000_debug ">>> _pace6000_io " cmd
if (index( cmd, "?") ) { # is there an answer requested ?
_pace6000_debug "RSVP"
rsvp = 1
}
if (!__PACE6000["SIMUL"]) {
if (! __PACE6000[num]["dev"]) {
eprint "pace6000: Apparently the config didn`t work. Please reconfig!"
exit
}
if (__PACE6000[num]["type"] == "ethernet") {
sock_par(__PACE6000[num]["dev"], "flush") # clean trailing output
sock_put(__PACE6000[num]["dev"], sprintf("%s\n", cmd))
if (rsvp) {
retval = sock_get(__PACE6000[num]["dev"], "\n")
_pace6000_debug "raw data", retval
# the command is prepended to the answer :-(
nb = split(retval, aux, " ")
retval = aux[1]
if (nb > 1) {
local i
for (i=2; i<nb; i++)
retval = retval " " aux[i]
}
} else
return
} else if (__PACE6000[num]["type"] == "serial") {
cdef("cleanup_once", sprintf("_pace6000_flush %d;",num),"_pace6000")
ser_put(__PACE6000[num]["dev"], sprintf("%s\r\n", cmd))
if (rsvp) {
retval = ser_get(__PACE6000[num]["dev"], "\r")
nb = split(retval, aux, PACE5000[num]["split"])
if (nb > 1)
retval = aux[1]*1
} else
return
}
}
else { # simulation !
retval = "0.1"
}
_pace6000_debug ">>> _pace6000_io returns " retval
return retval
}
'
#%IU% ()
#%MDESC%get errors
#%BR%returns ".error." if there is an error
#%BR%returns 0 if no error
def _pace6000_report_error(unit) '{
local syserr, esr, osr, sre, str, errflag
if ((esr = _pace6000_io(unit, "*ESR?")*1) != 0) {
# if ((esr >> 5) & 1) str = str " Command error" # doubles syserr
if ((esr >> 4) & 1) str = str " Execution error"
if ((esr >> 2) & 1) str = str " Query errors"
eprint "PACE6000 ESR error:" str
errflag = 1
}
if ((sre = _pace6000_io(unit, "*STB?")*1) != 0) { # Status Register
if (sre & (1<<2)) # bit 2 ! ignore bit 4, which is just normal output
if ((syserr = _pace6000_io(unit, ":SYST:ERR?")) != "0, No error") {
local nb, aux
nb = split(syserr, aux, ",")
eprint "PACE6000 STB error:", aux[1]
errflag = 1
}
else if (sre & (1<<7)) # bit 7, Operation Status (16 bits wide)
if ((osr = _pace6000_io(unit, ":STATus:OPERation:CONDition?")*1) != 0) {
if ( osr & 1) str = str " Vent complete"
if ((osr >> 1) & 1) str = str " Range change complete"
if ((osr >> 2) & 1) str = str " In-limits reached"
if ((osr >> 3) & 1) str = str " Zero complete"
if ((osr >> 4) & 1) str = str " Auto-zero started"
if ((osr >> 5) & 1) str = str " Fill time, timed-out"
if ((osr >> 8) & 1) str = str " contacts changed state"
eprint "PACE6000 status error:" str
errflag = 1
}
}
if (errflag)
return ".error"
else
return ""
}
'
#%UU%<mnemonic> <on/off>
#%MDESC%switch controller on or off
def pace6000_switch '{
local unit, chan, onoff, currstate, answer, mnum, ctrl, cmd
# on and off are builtin functions, which cause an error with
# _check0. So if $1 is on or off, that`s wrong.
if (($# < 1) || ("$1" == "on") || ("$1" == "off")) {
print "Usage: pace6000_switch <mnemonic> [\"on/off\"]"
exit
}
mnum = $1 * 1
if (mnum != motor_num(mnum)) {
eprint "$0: Invalid motor name: $1"
exit
}
if ((ctrl = motor_par(mnum, "device_id")) != "pace6000") {
eprint "$0: this motor is not a controlled by a pace5000/6000!"
exit
}
unit = motor_par("$1", "unit")
chan = motor_par("$1", "channel") + 1
_pace6000_debug "Switch controller on/off - motor:", "$1", unit
cmd = ":OUTPut" chan ":STATe?"
currstate = _pace6000_io(unit, cmd) * 1
print "PACE controller output is", currstate ? "ON" : "OFF"
if ($# < 2) {
state = currstate ? 0 : 1
if (!yesno(sprintf("Do you want to change this to %s", state ? "ON" : "OFF"), 1)) {
exit
} else {
onoff = onoff ? 0 : 1
}
} else {
onoff = "$2"
if ( onoff == "ON" || onoff == "on" || onoff == "On") onoff = 1
else if ( onoff == "OFF" || onoff == "off" || onoff == "Off") onoff = 0
else {
print "Value", "$2", "is not allowed as second argument!"
exit
}
}
if (currstate != onoff) {
cmd = ":OUTPut" chan ":STATe " onoff
_pace6000_io(unit, cmd)
cmd = ":OUTPut" chan ":STATe?"
currstate = _pace6000_io(unit, cmd) * 1
print "and is now", currstate ? "ON" : "OFF"
}
}
'
def pace_switch 'pace6000_switch'
#%UU%mnemonic <slewrate>
#%MDESC%Set the rate at which the controller ramps pressure. Documentation says
#values can also be "max" or "min", but that didn't work for me.
def pace6000_slewrate '{
local unit, answer, cmd, slewrate
if ($# < 1) {
print "Usage: $0 mnemonic <slewrate>"
exit
}
_check0 # check motor
if ((ctrl = motor_par($1, "device_id")) != "pace6000") {
eprint "$0: this motor is not a controlled by a pace5000/6000!"
exit
}
unit = motor_par("$1", "unit")
chan = motor_par("$1", "channel") + 1
cmd = ":UNIT" chan ":PRESsure?"
instrunit = _pace6000_io(unit, cmd)
instrunit = substr(instrunit, 1, length(instrunit) - 2 )
cmd = ":SOURCE" chan ":PRESsure:SLEW?"
# :SOURCE[x][:PRESsure]:SLEW?
# where x = 1 or 2 is the module number (default - 1)
# Short form:
# :SOUR:SLEW?
# Function:
# Query rate value
# Response:
# Decimal number representing rate value in selected units/second.
# convert to unit / minute
slewrate = _pace6000_io(unit, cmd) * 1
print "PACE controller channel", chan, "slewrate was", slewrate, instrunit "/sec,", slewrate *60, instrunit "/min"
slewrate *= 60
if ($# < 2) {
slewrate = getval("Do you want to change this", slewrate, sprintf(" %s/min",instrunit))
} else {
slewrate = "$2" * 1.0
}
slewrate /= 60
cmd = ":SOURCE" chan ":PRESsure:SLEW " slewrate
_pace6000_io(unit, cmd)
cmd = ":SOURCE" chan ":PRESsure:SLEW?"
slewrate = _pace6000_io(unit, cmd) * 1
print "PACE controller channel", chan, "slewrate now is", slewrate, instrunit "/sec,", slewrate *60, instrunit "/min"
}
'
def pace_slewrate 'pace6000_slewrate'
#%MACROS%
#%IMACROS%
#%LOG%
#$Revision: 1.6 $, $Date: 2015/06/02 13:12:56 $
#
#%AUTHOR% mcd january 2011, hw - move to SCPI in Jan 2013
#%TOC%
|