416 lines
11 KiB
Tcl
416 lines
11 KiB
Tcl
namespace eval nvstep {
|
|
}
|
|
|
|
proc stdConfig::nvstep {args} {
|
|
variable name
|
|
|
|
controller syncedprot
|
|
pollperiod 1 1
|
|
|
|
obj NvStep wr
|
|
prop write nvstep::write
|
|
prop read nvstep::read
|
|
prop enum fixed=0,controlled=1,automatic=2,close=3,open=4
|
|
prop write nvstep::write
|
|
prop lastpulse 0
|
|
prop filter 0
|
|
prop closetest 0
|
|
prop amplitude 0
|
|
prop t_after_delay 0
|
|
prop fixed_to_auto 0
|
|
prop initialize 0
|
|
prop maxflow 0
|
|
default 0
|
|
|
|
set sensirion 0
|
|
foreach arg $args {
|
|
if {$arg eq "1"} {
|
|
set sensirion 1
|
|
}
|
|
}
|
|
|
|
kids "needle value" {
|
|
node flow upd
|
|
|
|
node motstat -text upd
|
|
|
|
node set out
|
|
default 2.5
|
|
prop check nvstep::checkset
|
|
prop write stdSct::complete
|
|
prop label "flow set"
|
|
|
|
node flowmax par 20
|
|
prop label "flow maximum"
|
|
|
|
node flowp upd
|
|
prop help "flow calculated from pressure before pump"
|
|
|
|
node use_pressure par -int [expr !$sensirion]
|
|
prop enum 1
|
|
prop help "use pressure instead of flow meter for control"
|
|
|
|
node ctrl -none
|
|
kids "control parameters" {
|
|
node prop par 10
|
|
prop help bigger means higher feedback
|
|
|
|
node int par 15
|
|
prop help bigger means reacting slower (unit: sec)
|
|
|
|
node delay par 5
|
|
prop help minimum time to wait before next motor step
|
|
|
|
node tol par 0.1
|
|
}
|
|
|
|
node autoflow -none
|
|
kids "autoflow control parameters" {
|
|
flow::make flow::tmts {result tt set/reg}
|
|
}
|
|
|
|
node calib -none
|
|
kids calib {
|
|
node ln_per_min_per_mbar par 0.9
|
|
node mbar_offset par 0.5
|
|
}
|
|
|
|
node initialize -int out
|
|
default 0
|
|
prop visible false
|
|
prop enum check=1,adjust=2,stop=3
|
|
prop label "limit switch"
|
|
prop write nvstep::startinit
|
|
|
|
node initstate -text upd
|
|
prop visible false
|
|
default ""
|
|
}
|
|
}
|
|
|
|
proc nvstep::checkset {} {
|
|
sct update [sct target]
|
|
set s [hvali [sct parent]]
|
|
if {[hvali /cc/fa] == 0 || ($s != 1 && $s != 2)} {
|
|
if {$s != 2} {
|
|
set s 1
|
|
}
|
|
hset [sct parent] $s
|
|
}
|
|
}
|
|
|
|
proc nvstep::write {} {
|
|
switch [sct target] {
|
|
3 {
|
|
sct rangeshift 0
|
|
if {[hvali [sct]/nvmot] > [hvali [sct]/nvmot/lowerlimit]} {
|
|
nvmot [hvali [sct]/nvmot/lowerlimit]
|
|
updateval [sct]/motstat closing
|
|
}
|
|
}
|
|
4 {
|
|
nvmot [hvali [sct]/nvmot/upperlimit]
|
|
updateval [sct]/motstat opening
|
|
}
|
|
2 {
|
|
hupdate [sct]/autoflow/suspended 0
|
|
}
|
|
}
|
|
sct fixed_to_auto 0
|
|
if {[sct target] == 0 || [sct target] > 2} {
|
|
logsetup [sct]/set clear
|
|
logsetup [sct]/autoflow/flowtarget clear
|
|
}
|
|
sct update [sct target]
|
|
return idle
|
|
}
|
|
|
|
proc nvstep::calcstep {from to prop} {
|
|
# for the decreasing step (to < from), we use a linear function above 20
|
|
foreach var {from to} {
|
|
if {[set $var] > 20 && $to < $from} {
|
|
set $var [expr 1.9 + 0.0025 * [set $var]]
|
|
} elseif {[set $var] > 1} {
|
|
set $var [expr 2 - 1.0 / [set $var]]
|
|
}
|
|
}
|
|
set res [expr ($to - $from) * $prop]
|
|
return $res
|
|
}
|
|
|
|
proc nvstep::poll {} {
|
|
set now [DoubleTime]
|
|
set mode [sctval [sct]]
|
|
if {$mode != 0} {
|
|
set encpos [hval [sct]/nvmot/encoder]
|
|
if {$encpos < [hval [sct]/nvmot/lowerlimit] - 15 ||
|
|
$encpos > [hval [sct]/nvmot/upperlimit] + 15} {
|
|
hsetprop [sct]/nvmot/encoder adjust_zero 1
|
|
return idle
|
|
}
|
|
}
|
|
# if {[silent 0 sct initialize] > 0} {
|
|
# return nvstep::init
|
|
# }
|
|
hset [sct]/nvmot/disablelimits 0
|
|
set umsg "automatic needle valve not activated - set temperature undefined"
|
|
switch -- $mode {
|
|
1 - 2 {
|
|
# pump_is_off is defined in startup/hepump.tcl
|
|
if {[info command pump_is_off] ne "" && [pump_is_off]} {
|
|
return idle
|
|
}
|
|
if {$mode == 1 || [sctval [sct]/autoflow/suspended]} {
|
|
set soll [hvali [sct]/set]
|
|
hupdate [sct]/autoflow/flowtarget $soll
|
|
} else {
|
|
if {$now > [silent 0 sct lastauto] + 4.7} {
|
|
sct lastauto $now
|
|
set script [hvali [sct]/autoflow/script]
|
|
set flowmax [hvali [sct]/flowmax]
|
|
if {$flowmax > 20} {
|
|
set flowmax 20
|
|
clientput "WARNING: reduced flowmax to $flowmax ln/min for less stress to the pump"
|
|
hupdate [sct]/flowmax $flowmax
|
|
}
|
|
$script [sct]/autoflow [hvali [sct]/set] $flowmax
|
|
}
|
|
set soll [hvali [sct]/autoflow/flowset]
|
|
if {[hgetpropval [sct]/autoflow/getTset t_set_undefined]} {
|
|
if {[hvali [sct]/status] ne $umsg} {
|
|
clientput "ERROR: $umsg"
|
|
}
|
|
hupdate [sct]/status $umsg
|
|
}
|
|
}
|
|
if {[hval [sct]/use_pressure]} {
|
|
set ist [hvali [sct]/flowp]
|
|
} else {
|
|
set ist [hvali [sct]/flow]
|
|
}
|
|
set tol [hvali [sct]/ctrl/tol]
|
|
set a [sct amplitude]
|
|
set t [sct t_after_delay]
|
|
if {$t != 0} {
|
|
set t [expr $now - $t]
|
|
}
|
|
set i [hvali [sct]/ctrl/int]
|
|
# lim is an exponential curve converging to soll.
|
|
# the range between lim and soll is a window shrinking with time
|
|
# before t_after_delay, the last 'ist' value is between lim and soll
|
|
# if the 'ist' value does not change it will reach lim at t_after_delay
|
|
set lim [expr $soll + $a * exp(-$t/double($i))]
|
|
# calculate expected limits for no further step needed
|
|
if {$lim > $soll} {
|
|
set uplim [expr $lim + $tol]
|
|
set lolim [expr $soll - $tol]
|
|
} else {
|
|
set uplim [expr $soll + $tol]
|
|
set lolim [expr $lim - $tol]
|
|
}
|
|
if {$ist > $uplim || $ist < $lolim} {
|
|
# we have to do a next step
|
|
set step [nvstep::calcstep $ist $soll [hvali [sct]/ctrl/prop]]
|
|
sct t_after_delay [expr $now + [hvali [sct]/ctrl/delay]]
|
|
sct amplitude [expr $ist - $soll]
|
|
set v [format %.2f [expr [hvali [sct]/nvmot] + $step]]
|
|
set u [hvali [sct]/nvmot/upperlimit]
|
|
set ll [hvali [sct]/nvmot/lowerlimit] ;# ll was 0 before!
|
|
if {$v > $u} {
|
|
set v $u
|
|
updateval [sct]/motstat opened
|
|
} elseif {$v < $ll} {
|
|
set v $ll
|
|
updateval [sct]/motstat closed
|
|
} elseif {$step > 0} {
|
|
updateval [sct]/motstat opening
|
|
} else {
|
|
updateval [sct]/motstat closing
|
|
}
|
|
#clientput "$step $v"
|
|
nvmot $v
|
|
} else {
|
|
# no step needed yet
|
|
updateval [sct]/motstat idle
|
|
if {$t > 0} {
|
|
if {$ist < $uplim - $tol && $ist > $lolim + $tol} {
|
|
# the ist value is making more progress then expected at worst
|
|
# so we narrow the window accordingly
|
|
sct amplitude [expr $ist - $soll]
|
|
sct t_after_delay $now
|
|
}
|
|
}
|
|
}
|
|
}
|
|
0 { # fixed
|
|
set cnt [sct fixed_to_auto]
|
|
if {[silent 0 hval [sct]/flow] > [hvali [sct]/flowmax] + 10} {
|
|
incr cnt
|
|
if {$cnt > 60} {
|
|
clientput "pressure high - switch to automatic mode"
|
|
hset [sct] 2
|
|
}
|
|
} else {
|
|
if {$cnt > 0} {
|
|
incr cnt -1
|
|
}
|
|
}
|
|
sct fixed_to_auto $cnt
|
|
switch [hvali [sct]/motstat] {
|
|
opening - closing {
|
|
if {[hgetpropval [sct]/nvmot status] ne "run"} {
|
|
updateval [sct]/motstat idle
|
|
}
|
|
}
|
|
}
|
|
}
|
|
3 { # close
|
|
set stat [hvali [sct]/motstat]
|
|
if {[hgetpropval [sct]/nvmot status] ne "run" && $stat eq "closing"} {
|
|
updateval [sct]/motstat closed
|
|
}
|
|
}
|
|
4 { # open
|
|
set stat [hvali [sct]/motstat]
|
|
if {[hgetpropval [sct]/nvmot status] ne "run" && $stat eq "opening"} {
|
|
updateval [sct]/motstat opened
|
|
}
|
|
}
|
|
}
|
|
if {[hvali [sct]/status] eq $umsg && \
|
|
([sctval [sct]] != 2 || [hgetpropval [sct]/autoflow/getTset t_set_undefined] == 0)} {
|
|
hsetprop [sct]/autoflow/getTset t_set_undefined 0
|
|
hupdate [sct]/status ""
|
|
}
|
|
return idle
|
|
}
|
|
|
|
proc nvstep::read {} {
|
|
hsetprop /cc/fa nvpath [sct]
|
|
_cc updatescript /cc/fa nvstep::updatemode
|
|
hsetprop /cc/f nvpath [sct]
|
|
hsetprop /cc/f nvctrl [sct controller]
|
|
hsetprop /cc/f flowsource pressure
|
|
_cc updatescript /cc/f nvstep::updateflow
|
|
catch {
|
|
hsetprop /nvflow flowsource flow
|
|
hsetprop /nvflow nvpath [sct]
|
|
hsetprop /nvflow nvctrl [sct controller]
|
|
_hemot updatescript /nvflow nvstep::updateflow
|
|
}
|
|
return unpoll
|
|
}
|
|
|
|
proc nvstep::updateflow {value} {
|
|
# flowsource:
|
|
# pressure: this is a pressure
|
|
# flow: this is a flow from a flowmeter
|
|
|
|
set source [silent pressure sct flowsource]
|
|
set filter [lrange "[silent $value sct filter] $value" end-9 10]
|
|
sct filter $filter
|
|
# filter out values which are within the 3 highest or 3 lowest values
|
|
# out of 10 last values (i.e. within 5 seconds)
|
|
set m 3
|
|
set filter [lsort -real $filter]
|
|
if {[llength $filter] < 10} {
|
|
set flow $value
|
|
} else {
|
|
set min [lindex $filter $m]
|
|
set max [lindex $filter end-$m]
|
|
set mean [expr double([join $filter +]) / [llength $filter]]
|
|
set flow [silent 0 sct filtered]
|
|
if {$max < $flow} {
|
|
set flow $max
|
|
} elseif {$min > $flow} {
|
|
set flow $min
|
|
} else {
|
|
set flow [expr $flow * 0.98 + $mean * 0.02]
|
|
}
|
|
}
|
|
sct filtered $flow
|
|
if {$source eq "flow"} {
|
|
updateval [sct nvpath]/flow $flow
|
|
} elseif {$source eq "pressure"} {
|
|
if {$flow < -50} {
|
|
set flow -62.5
|
|
} else {
|
|
set off [hval [sct nvpath]/calib/mbar_offset]
|
|
set fpm [hval [sct nvpath]/calib/ln_per_min_per_mbar]
|
|
set flow [expr ($flow - $off) * $fpm]
|
|
}
|
|
updateval_e [sct nvpath]/flowp $flow -62.5 no_sensor
|
|
} else {
|
|
error "[sct] illegal flowsource: $source"
|
|
}
|
|
[sct nvctrl] queue [sct nvpath] read nvstep::poll
|
|
}
|
|
|
|
proc nvstep::startinit {} {
|
|
set i [hgetpropval [sct parent] initialize]
|
|
switch [sct target] {
|
|
1 {
|
|
if {$i != 0} {
|
|
error "checking already"
|
|
}
|
|
# hsetprop [sct parent] initialize 10
|
|
hsetprop [sct parent] initialize 13
|
|
}
|
|
2 {
|
|
if {$i != 0} {
|
|
error "adjusting already"
|
|
}
|
|
hsetprop [sct parent] initialize 20
|
|
}
|
|
3 {
|
|
if {$i >= 10 && $i < 13} {
|
|
hsetprop [sct parent] initialize 13
|
|
} elseif {$i >= 20} {
|
|
hsetprop [sct parent] initialize 28
|
|
} else {
|
|
hsetprop [sct parent] initialize 29
|
|
}
|
|
}
|
|
}
|
|
sct update [sct target]
|
|
return idle
|
|
}
|
|
|
|
proc nvstep::ierror {msg} {
|
|
updateerror [sct]/initstate "$msg"
|
|
clientput "[sct]: $msg"
|
|
}
|
|
|
|
proc nvstep::imsg {msg} {
|
|
if {$msg ne [hvali [sct]/initstate]} {
|
|
hupdate [sct]/initstate $msg
|
|
clientput "[sct]: $msg"
|
|
catch {hdelprop [sct]/initstate geterror}
|
|
}
|
|
}
|
|
|
|
proc nvstep::init {} {
|
|
set now [DoubleTime]
|
|
if {[hgetpropval [sct]/nvmot status] eq "run"} {
|
|
return idle
|
|
}
|
|
set phase [sct initialize]
|
|
set pos [hvali [sct]/nvmot/encoder]
|
|
set goto ""
|
|
switch $phase {
|
|
10 { # start check
|
|
ierror "limit switch no longer supported"
|
|
}
|
|
20 { # start adjust
|
|
ierror "limit switch no longer supported"
|
|
}
|
|
}
|
|
if {$goto ne ""} {
|
|
sct goto $goto
|
|
clientput "goto $goto"
|
|
run [hgetpropval [sct]/nvmot sicsdev] $goto
|
|
}
|
|
sct initialize $phase
|
|
return idle
|
|
}
|