diff --git a/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_mercury.tcl b/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_mercury.tcl new file mode 100644 index 00000000..62cdcd10 --- /dev/null +++ b/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_mercury.tcl @@ -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