Andrew Kerrigan's sct driver for the Pfeiffer pressure gauge and Oxford Mercury

This commit is contained in:
Douglas Clowes
2013-06-21 13:39:13 +10:00
parent 95d8a565e3
commit 3dce7feb8e

View File

@@ -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