Files
sea/tcl/drivers/loop.tcl
2022-08-18 15:04:28 +02:00

179 lines
4.0 KiB
Tcl

# software pi loop
namespace eval loop {
}
if {![namespace exists trun]} {
source drivers/trun.tcl
}
proc stdConfig::loop args {
variable name
variable path
variable node
scanargs $args var -invar -outvar -outmin 0 -outmax 1 -prop 1 -int 1 -maxdelta 60 -precision 0.001 -mindelta 0
variable hostport none
controller syncedprot
obj loop -drive out
prop lastinput 0
kids "$name control parameters" {
node mode -int out
default 0
prop enum off,on,manual
prop check loop::checkmode
prop write stdSct::completeUpdate
node output out
default $outmin
prop check loop::checkoutput
prop write stdSct::completeUpdate
node invar -text out
default 0
prop check loop::setinvar
prop write stdSct::completeUpdate
prop visible false
node outvar -text par $outvar
prop visible false
node pollinput rd
prop read stdSct::complete
node prop par $prop
prop help "the bigger, the less sensible"
node int par $int
node outmin par $outmin
node outmax par $outmax
node precision par $precision
prop label "output precision"
node maxdelta par $maxdelta
node mindelta par $mindelta
}
stdConfig::tdrive "$name control parameters" self loop::settarget
# hset $path/setcmd loop::settarget
hset $path/invar $invar
}
proc loop::checkmode {} {
if {[sct target] == 0} {
set output [hvali [sct parent]/outmin]
hset [sct parent]/output $output
}
}
proc loop::updateinput {value} {
set prop [hvali [sct]/prop]
set int [hvali [sct]/int]
set outmin [hvali [sct]/outmin]
set outmax [hvali [sct]/outmax]
set span [expr double($outmax - $outmin)]
set maxdelta [hvali [sct]/maxdelta]
set mindelta [hvali [sct]/mindelta]
set precision [hvali [sct]/precision]
set input $value
set effoutput [eval "result [hvali [sct]/outvar]"]
if {[hvali [sct]/mode] == 2} {
return idle
}
if {[hvali [sct]/mode] == 0} {
# to be put into write script of ../mode
if {$effoutput > $outmin} {
eval "[hvali [sct]/outvar] $outmin"
}
return idle
}
set output [hvali [sct]/output]
if {abs($effoutput - $output) > $precision} {
clientput "$output -> $effoutput"
set output $effoutput
}
set now [clock seconds]
if {[sct lastinput] == 0} {
set deltat 1
} else {
set deltat [expr $now - [sct lastinput]]
if {$deltat < $mindelta} {
return idle
}
if {$deltat > $maxdelta} {
set deltat $maxdelta
}
}
sct lastinput $now
set lastdif [silent 0 sct lastdif]
set dif [expr double([hvali [sct]/set] - $input)]
set output [expr $output + $span/$prop \
* (($dif - $lastdif) * $deltat + $dif / $int)]
sct lastdif $dif
if {$outmax > $outmin} {
if {$output > $outmax} {
set output $outmax
} elseif {$output < $outmin} {
set output $outmin
}
} else {
if {$output < $outmax} {
set output $outmax
} elseif {$output > $outmin} {
set output $outmin
}
}
hset [sct]/output $output
return idle
}
# updatescript on the remote input node
proc loop::updateinput1 {value} {
set loopobj [sct loopobj]
if {[silent 0 sct geterror] eq "0"} {
updateval $loopobj $value
}
return
}
proc loop::setinvar {} {
if {[silent none hgetprop [sct target] sicscommand] eq "none"} {
set t [sct parent]/pollinput
sct target [sct parent]/pollinput
# clientput "Tp $t"
} else {
set t [sct target]
# clientput "Tt $t"
}
[sct controllerName] updatescript [sct parent] loop::updateinput
[sct controllerName] updatescript $t loop::updateinput1
hsetprop $t loopobj [sct parent]
hsetprop $t read loop::pollinput
return
}
proc loop::pollinput {} {
catch {sct update [result [hval [sct parent]/invar]]}
return idle
}
proc loop::settarget {target} {
updateval [sct]/mode 1
sct print "[sct]/set = $target"
return idle
}
proc loop::updtarget {} {
sct print "[sct]/set = [sct target]"
return idle
}
proc loop::checkoutput {} {
eval "[hvali [sct parent]/outvar] [sct target]"
}