Andrew Kerrigan's sct driver for the Pfeiffer pressure gauge and Oxford Mercury
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
# Andrew Kerrigan
|
||||
# andrewk@ansto.gov.au / u4673036@anu.edu.au
|
||||
#
|
||||
# Driver to control the pressure inside the 12T magnet using a pfeiffer pressure gauge as a pressure readout and the needle valve on the magnet as a pressure/flow control
|
||||
#
|
||||
# PID parameters:
|
||||
# setPoint/control Kp Proportionate control constant
|
||||
# setPoint/control Ki Integral control constant
|
||||
# setPoint/control Kd Derivative control constant
|
||||
# setPoint/control period Period of control loop in seconds
|
||||
#
|
||||
# Kp is in units of %/mbar, Ki and Kd follow from that.
|
||||
#
|
||||
# Usage:
|
||||
# add_mercury name IP_mercury Port_mercury IP_pfeiffer Port_pfeiffer filename
|
||||
# IP_mercury IP address of the mercury iTC on the moxabox
|
||||
# Port_mercury Port of the mercury iTC on the moxabox
|
||||
# IP_pfeiffer IP address of the pfeiffer on the moxabox
|
||||
# Port_pfeiffer Port of the pfeiffer on the moxabox
|
||||
# filename Name and location of the log file
|
||||
#
|
||||
# Example:
|
||||
# add_mercury mercury 137.157.202.78 4004 137.157.202.78 4002 /home/nbi/AndrewKSICS/MercuryPLoop.txt
|
||||
#
|
||||
# The commands to read and set the needle pressure are specific to the setup on the mercury
|
||||
|
||||
namespace eval ::scobj::mercurycontrol {
|
||||
proc getValue {id type signal nextState path} {
|
||||
if [hpropexists [sct] geterror] {
|
||||
hdelprop [sct] geterror
|
||||
}
|
||||
sct send "READ:DEV:DB4.G1:AUX:SIG:OPEN"
|
||||
return $nextState
|
||||
}
|
||||
|
||||
proc readValue {path} {
|
||||
set data [sct result]
|
||||
switch -glob -- $data {
|
||||
"ASCERR:*" {
|
||||
sct geterror $data
|
||||
set nextState idle
|
||||
}
|
||||
default {
|
||||
set val [string range $data 29 34]
|
||||
set oldval [hgetpropval ${path}/sensor/value oldval]
|
||||
set nextstate idle
|
||||
if {$val != $oldval} {
|
||||
sct update $val
|
||||
sct utime readtime
|
||||
}
|
||||
hsetprop ${path}/sensor/value oldval $val
|
||||
if {[string equal "true" [hgetpropval ${path}/setPoint isSet]]} {
|
||||
set nextstate controlValve
|
||||
}
|
||||
if {[hgetpropval $path/currentPressure logging] = 1} {
|
||||
set floc [hval ${path}/filename]
|
||||
set fn [open $floc a+]
|
||||
set valvepos [hval ${path}/sensor/value]
|
||||
set pressure [hval ${path}/currentPressure]
|
||||
set setpoint [hval ${path}/setPoint]
|
||||
set statustext [hgetpropval ${path}/currentPressure statusText]
|
||||
set curtime [hgetpropval ${path}/sensor/value readtime]
|
||||
puts $fn "$curtime, $pressure, $setpoint, $valvepos, $statusText"
|
||||
close $fn
|
||||
}
|
||||
}
|
||||
return $nextstate
|
||||
}
|
||||
|
||||
proc controlValve {path} {
|
||||
set currentTime [clock seconds]
|
||||
set prevTime [hgetpropval $path/setPoint updateTime]
|
||||
set elapsed [expr $currentTime - $prevTime]
|
||||
set period [expr [hgetpropval $path/setPoint/control period]]
|
||||
|
||||
set controlling 1
|
||||
#30 second update frequency - the needle valve is fairly slow
|
||||
if {$elapsed < $period} {
|
||||
return idle
|
||||
} else {
|
||||
hsetprop $path/setPoint updateTime [clock seconds]
|
||||
}
|
||||
|
||||
set Kp [hgetpropval $path/setPoint/control Kp]
|
||||
set Ki [hgetpropval $path/setPoint/control Ki]
|
||||
set Kd [hgetpropval $path/setPoint/control Kd]
|
||||
set currentError [hgetpropval $path/setPoint/control currentError]
|
||||
hsetprop $path/setPoint/control prevError $currentError
|
||||
set currentPressure [expr [hval $path/currentPressure]]
|
||||
set currentError [expr [hval $path/setPoint] - $currentPressure]
|
||||
set currentPos [expr [hval $path/sensor/value]]
|
||||
hsetprop $path/setPoint/control currentError $currentError
|
||||
set oldIntControl [hgetpropval $path/setPoint/control integralControl]
|
||||
set integralControl [expr $oldIntControl + $Ki * $currentError]
|
||||
hsetprop $path/setPoint/control integralControl $integralControl
|
||||
|
||||
set proportionateControl [expr $Kp * $currentError]
|
||||
set differentialControl [expr $Kd * $currentError - $Kd * $prevError]
|
||||
set newPos [expr $currentPos + $proportionateControl + $integralControl + $differentialControl]
|
||||
|
||||
if {$controlling} { # Control range is [0.0 - 100.0], the valve won't move if it is set outside this range
|
||||
if {$newPos > 100} {
|
||||
set outPos 100.0
|
||||
} elseif {$newPos < 0} {
|
||||
set outPos 0.0
|
||||
} else {
|
||||
set outPos $newPos
|
||||
}
|
||||
sct_mercury send "SET:DEV:MB1.T1:TEMP:LOOP:FSET:${outPos}"
|
||||
}
|
||||
return idle
|
||||
}
|
||||
|
||||
proc sendPR1 {par nextState} {
|
||||
if [hpropexists [sct] geterror] {
|
||||
hdelprop [sct] geterror
|
||||
}
|
||||
sct send "$par"
|
||||
return $nextState
|
||||
}
|
||||
|
||||
proc isReady {nextState} {
|
||||
set data [sct result]
|
||||
switch -glob -- $data {
|
||||
"ASCERR:*" {
|
||||
sct geterror $data
|
||||
set nextState idle
|
||||
}
|
||||
default {
|
||||
if {$data == "\x06"} {
|
||||
sct send "\x05"
|
||||
}
|
||||
}
|
||||
}
|
||||
return $nextState
|
||||
}
|
||||
|
||||
proc getPR1 {path nextState} {
|
||||
set data [sct result]
|
||||
switch -glob -- $data {
|
||||
"ASCERR:*" {
|
||||
sct geterror $data
|
||||
set nextState idle
|
||||
}
|
||||
default {
|
||||
set val [string range $data 3 12]
|
||||
set status [string range $data 0 0]
|
||||
sct update $val
|
||||
hsetprop ${path}/currentPressure status $status
|
||||
sct utime readtime
|
||||
set nextState statusUpdate
|
||||
}
|
||||
return $nextState
|
||||
}
|
||||
}
|
||||
|
||||
proc statusUpdate {path} {
|
||||
set status [hgetpropval $path/currentPressure status]
|
||||
switch $status {
|
||||
0 { set text "Sensor OK" }
|
||||
1 { set text "Sensor underrange" }
|
||||
2 { set text "Sensor overrange" }
|
||||
3 { set text "Sensor error" }
|
||||
4 { set text "Sensor off" }
|
||||
5 { set text "No sensor" }
|
||||
6 { set text "Identification error" }
|
||||
default { set text "Status unreadable" }
|
||||
}
|
||||
hsetprop $path/currentPressure statusText $text
|
||||
return idle
|
||||
}
|
||||
|
||||
proc mk_mercury_itc {name sct_mercury sct_pfeiffer klass filename} {
|
||||
|
||||
makesicsobj $name SCT_OBJECT
|
||||
sicslist setatt $name klass $klass
|
||||
sicslist setatt $name long_name $name
|
||||
|
||||
set scobj_hpath /sics/$name
|
||||
set ns ::scobj::mercurycontrol
|
||||
|
||||
hfactory ${scobj_hpath}/sensor plain user none
|
||||
|
||||
hfactory ${scobj_hpath}/sensor/value plain user float
|
||||
hsetprop ${scobj_hpath}/sensor/value read ${ns}::getValue readValue $scobj_hpath
|
||||
hsetprop ${scobj_hpath}/sensor/value readValue ${ns}::readValue $scobj_hpath
|
||||
hsetprop ${scobj_hpath}/sensor/value controlValve ${ns}::controlValve $scobj_hpath
|
||||
hsetprop ${scobj_hpath}/sensor/value oldval -1.0
|
||||
|
||||
hfactory ${scobj_hpath}/setPoint plain user float
|
||||
hsetprop ${scobj_hpath}/setPoint isSet "false"
|
||||
hsetprop ${scobj_hpath}/setPoint updateTime 0
|
||||
|
||||
hfactory ${scobj_hpath}/setPoint/control plain user none
|
||||
hsetprop ${scobj_hpath}/setPoint/control Kp 33.0
|
||||
hsetprop ${scobj_hpath}/setPoint/control Ki 0.0
|
||||
hsetprop ${scobj_hpath}/setPoint/control Kd 0.0
|
||||
hsetprop ${scobj_hpath}/setPoint/control currentError UNKNOWN
|
||||
hsetprop ${scobj_hpath}/setPoint/control prevError UNKNOWN
|
||||
hsetprop ${scobj_hpath}/setPoint/control integralControl 0.0
|
||||
hsetprop ${scobj_hpath}/setPoint/control period 30
|
||||
|
||||
hfactory ${scobj_hpath}/currentPressure plain user float
|
||||
hsetprop ${scobj_hpath}/currentPressure read ${ns}::sendPR1 "PR1" isReady
|
||||
hsetprop ${scobj_hpath}/currentPressure isReady ${ns}::isReady getPR1
|
||||
hsetprop ${scobj_hpath}/currentPressure getPR1 ${ns}::getPR1 $scobj_hpath statusUpdate
|
||||
hsetprop ${scobj_hpath}/currentPressure statusUpdate ${ns}::statusUpdate $scobj_hpath
|
||||
hsetprop ${scobj_hpath}/currentPressure status 0
|
||||
hsetprop ${scobj_hpath}/currentPressure statusText UNKNOWN
|
||||
hsetprop ${scobj_hpath}/currentPressure readtime UNKNOWN
|
||||
|
||||
hfactory ${scobj_hpath}/filename plain user text
|
||||
hset ${scobj_hpath}/filename $filename
|
||||
if {$filename = "noFile"} {
|
||||
hsetprop ${scobj_hpath}/currentPressure logging 0
|
||||
} else {
|
||||
hsetprop ${scobj_hpath}/currentPressure logging 1
|
||||
set floc $filename
|
||||
set fn [open $floc a+]
|
||||
puts $fn "Time (s), Pressure (mbar), Setpoint (mbar), Valve Pos (%), Gauge Status"
|
||||
close $fn
|
||||
}
|
||||
|
||||
::scobj::hinitprops $name
|
||||
::scobj::set_required_props $scobj_hpath
|
||||
|
||||
if {[SplitReply [environment_simulation]]=="false"} {
|
||||
$sct_mercury poll ${scobj_hpath}/sensor/value 1 read read
|
||||
$sct_pfeiffer poll ${scobj_hpath}/currentPressure 1 read read
|
||||
}
|
||||
}
|
||||
namespace export mk_mercury_itc
|
||||
}
|
||||
namespace import ::scobj::mercurycontrol::*
|
||||
proc add_mercury {name IP_mercury port_mercury IP_pfeiffer port_pfeiffer {filename "noFile"}} {
|
||||
if {[SplitReply [environment_simulation]]=="false"} {
|
||||
makesctcontroller sct_mercury std ${IP_mercury}:$port_mercury
|
||||
makesctcontroller sct_pfeiffer std ${IP_pfeiffer}:$port_pfeiffer
|
||||
}
|
||||
mk_mercury_itc $name sct_mercury sct_pfeiffer environment $filename
|
||||
}
|
||||
|
||||
# add_mercury mercury 137.157.202.78 4004 137.157.202.78 4002 /home/nbi/AndrewKSICS/MercuryPLoop.txt
|
||||
Reference in New Issue
Block a user