Files
sics/site_ansto/instrument/pelican/config/chopper/fermimot.tcl
2013-03-14 15:29:31 +11:00

389 lines
11 KiB
Tcl

# Table Source Document: 998-0234-004 Rev A.doc
# Speed (RPM) {veto {KpCW KpCCW} {KiCW KiCCW} {KthCW KthCCW}
# NOTE: You can use the motor direction register value to lookup the gains because motdir=0 is CW and motdir=1 is CCW
namespace eval ::chopper {
variable ch1_gains
variable ch2_gains
variable ch3_gains
variable speedMult
variable CW 0 CCW 1
variable PROPGAIN 1 INTGAIN 2 PHGAIN 3
variable POSDIR
set POSDIR $CCW
array set ch1_gains {
24000 { 350 { 10 10 } { 10 10 } { 2.33 2.33 } }
21000 { 400 { 10 15 } { 10 13 } { 2.33 13 } }
18000 { 450 { 10 10 } { 10 10 } { 2.33 2.33 } }
15000 { 550 { 10 10 } { 10 10 } { 2.33 2.33 } }
12000 { 650 { 12 12 } { 10 10 } { 10 10 } }
9000 { 950 { 10 10 } { 10 10 } { 10 10 } }
6000 { 1350 { 10 10 } { 10 10 } { 10 10 } }
3600 { 2310 { 5 5 } { 5 5 } { 5 5 } }
3000 { 2750 { 5 5 } { 5 5 } { 2.33 2.33 } }
}
array set ch2_gains {
24000 { 350 { 15 15 } { 13 13 } { 13 13 } }
21000 { 400 { 15 15 } { 13 13 } { 13 13 } }
18000 { 450 { 15 15 } { 13 13 } { 13 13 } }
15000 { 550 { 15 15 } { 13 13 } { 13 13 } }
12000 { 650 { 10 10 } { 10 10 } { 2.33 2.33 } }
9000 { 950 { 10 10 } { 10 10 } { 2.33 2.33 } }
6000 { 1350 { 10 10 } { 10 10 } { 2.33 2.33 } }
3000 { 2750 { 5 5 } { 5 5 } { 2 2 } }
}
array set ch3_gains {
24000 { 350 { 15 10 } { 13 10 } { 13 2.33 } }
21000 { 400 { 15 10 } { 13 10 } { 13 2.33 } }
18000 { 450 { 15 10 } { 13 10 } { 13 2.33 } }
15000 { 550 { 10 10 } { 10 10 } { 2.33 2.33 } }
12000 { 650 { 10 10 } { 10 10 } { 2.33 2.33 } }
9000 { 950 { 10 10 } { 10 10 } { 2.33 2.33 } }
6000 { 1350 { 10 10 } { 10 10 } { 2.33 2.33 } }
3000 { 2750 { 5 5 } { 5 5 } { 2 2 } }
}
foreach mult {
1.0/12 1.0/11 1.0/10 1.0/9 1.0/8
1.0/7 1.0/6 1.0/5 1.0/4 1.0/3
1.0/2 1 1.5 2 2.5
3 3.5 4 4.5 5
5.5 6 6.5 7 7.5
8 8.5 9 9.5 10
10.5 11 11.5 12 12.5
13 13.5 14 14.5 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
} {
lappend speedMult [expr double($mult)]
}
##
# Echeck_SpeedMult: Checks that speed is an allowed multiple of the reference signal
# refFreq: Reference signal frequency (Hz)
# speed: Requested chopper speed (RPM)
proc Echeck_SpeedMult {refFreq speed} {
variable speedMult
set refRPM [expr 60 * $refFreq]
foreach mult $speedMult {
if { [expr $mult * $refRPM] == $speed} {return}
}
return -code error "Speed ($speed) is not an allowed multiple of the reference signal"
}
proc Echeck_ChSpeed {ch speed} {
set minSpeed 3000
array set vetoRange {min 9000 max 11000}
if {$ch != 1 && $ch != 2 && $ch != 3} {
return -code error "Chopper number ($ch) must be 1, 2, or 3"
}
if { ![string is double $speed] } {
return -code error "Speed ($speed) is not a valid number"
} elseif {$speed < $minSpeed} {
return -code error "Speed ($speed) should be >= $minSpeed"
} elseif {$speed >= $vetoRange(min) && $speed <= $vetoRange(max)} {
return -code error "Speed ($speed) is in the vetoed range: $vetoRange(min), $vetoRange(max)"
}
}
proc Echeck_gainDir {gain dir} {
variable CW
variable CCW
variable PROPGAIN
variable INTGAIN
variable PHGAIN
if {$gain != $INTGAIN && $gain != $PROPGAIN && $gain != $PHGAIN} {
return -code error "gain identifier ($gain) should be $PROPGAIN (PROPGAIN), $INTGAIN (INTGAIN), or $PHGAIN (PHGAIN)"
}
if {$dir != $CW && $dir != $CCW} {
return -code error "direction identifier ($dir) should be $CW {CW} or $CCW {CCW}"
}
}
proc getVetoWin {ch speed} {
variable ch1_gains
variable ch2_gains
variable ch3_gains
# Check argument and return error otherwise return veto window
set catch_status [ catch {
Echeck_ChSpeed $ch $speed
set speed [expr int($speed)]
set ch [expr int($ch)]
switch $ch {
1 { set gainTable ch1_gains }
2 { set gainTable ch2_gains }
3 { set gainTable ch3_gains }
}
foreach sp [lsort -integer -decreasing [array names $gainTable]] {
if {$sp <= $speed} {
return [lindex [set ${gainTable}($sp)] 0]
}
}
error "Failed when looking up veto window for speed $speed"
} message ]
handle_exception $catch_status $message
}
proc getGain {gain ch speed dir} {
variable ch1_gains
variable ch2_gains
variable ch3_gains
variable CW
variable CCW
variable INTGAIN
variable PROPGAIN
variable PHGAIN
set catch_status [ catch {
Echeck_ChSpeed $ch $speed
Echeck_gainDir $gain $dir
set gain [expr int($gain)]
set dir [expr int($dir)]
set speed [expr int($speed)]
set ch [expr int($ch)]
switch $ch {
1 { set gainTable ch1_gains }
2 { set gainTable ch2_gains }
3 { set gainTable ch3_gains }
}
foreach sp [lsort -integer -decreasing [array names $gainTable]] {
if {$sp <= $speed} {
return [lindex [set ${gainTable}($sp)] $gain $dir]
}
}
error "Failed when looking up integral gain for speed $speed"
} message ]
handle_exception $catch_status $message
}
##
# setSpeed
# ch: Chopper number
# refFreq: The reference frequency in Hz
# dir: Chopper direction CW or CCW
# speed: The chopper speed in RPM
proc setSpeed {ch refFreq dir speed} {
set catch_status [ catch {
Echeck_SpeedMult $refFreq $speed
} message ]
handle_exception $catch_status $message
}
#TODO Define a run function which looks up parameters from hdb tree and calls the setSpeed function
# pDriv->GetPosition = GetTclPos;
# pDriv->RunTo = TclRun;
# pDriv->GetStatus = TclStat;
# pDriv->GetError = TclError;
# pDriv->TryAndFixIt = TclFix;
# pDriv->SetDriverPar = TclSetPar;
# pDriv->GetDriverPar = TclGetPar;
# pDriv->Halt = TclHalt;
# pDriv->KillPrivate = KillTCL;
variable chPath "/instrument/fermi_chopper"
proc getSpeed {ch} {
variable chPath
set rSpeed [hval $chPath/$ch/rotation_speed]
return $rSpeed
}
##
# Implement speed and phase motor objects
proc SGetPos {hpath node addr name} {
global SCode
variable CW
variable CCW
variable POSDIR
set chpath ${hpath}/$node/rotation_speed
set speed [hval $chpath]
broadcast [info level 0]: chpath=$chpath, speed = $speed
if {[hval $hpath/$node/motdir] == $POSDIR} {
return $speed
} else {
return -$speed
}
}
proc SRun {hpath node addr name target} {
global SCode
variable CW
variable CCW
# broadcast [info level 0]
if {$target >= 0} {
set dir $CW
} else {
set dir $CCW
}
set speed [expr abs($target)]
getVetoWin $addr $speed
broadcast TODO: hset $hpath/$node/control/set_rotspeed $speed
# hset $hpath/$node/control/set_rotspeed $speed
return $SCode(OKOK)
}
proc SStatus {hpath node addr name} {
global SCode
return $SCode(HWIdle)
}
proc SHalt {hpath node addr name} {
global SCode
}
proc SGetError {hpath node addr name} {
global SCode
return "[info level 0]: TODO error message"
}
proc SFixit {hpath node addr name icode fVal} {
global SCode
return $SCode(MOTOK)
}
# Implementation of phase motor interface
proc PhGetPos {hpath node addr name} {
global SCode
return 0
}
proc PhRun {hpath node addr name target} {
global SCode
return $SCode(OKOK)
}
proc PhStatus {hpath node addr name} {
global SCode
return $SCode(HWIdle)
}
proc PhHalt {hpath node addr name} {
global SCode
}
proc PhGetError {hpath node addr name} {
global SCode
return "[info level 0]: TODO error message"
}
proc PhFixit {hpath node addr name icode fVal} {
global SCode
return $SCode(MOTOK)
}
}
# TEST
global SCode
array set SCode {
OKOK 1
HWIdle 2
HWBusy 3
HWFault 4
HWPosFault 5
HWCrash 6
NOMEMORY 7
HWNoBeam 8
HWPause 9
HWWarn 10
HWRedo 11
}
proc handle_exception {status message args} {
switch $status {
0 {
# TCL_OK, This is raised when you just drop out of the
# bottom of a 'catch' command.
return -code ok
}
1 {
# TCL_ERROR
return -code error "([info level -1]) $message: $args"
}
2 {
# TCL_RETURN
return -code return "$message"
}
3 {
# TCL_BREAK
return -code break
}
4 {
# TCL_CONTINUE
return -code continue
}
default {
# Propogate user defined return codes with message
return -code $status "$message"
}
}
}
proc mkFSpeedMot {fmot hdbroot chnode addr lowlim uplim} {
Motor $fmot tclmot [params\
getpos "::chopper::SGetPos $hdbroot $chnode $addr"\
run "::chopper::SRun $hdbroot $chnode $addr"\
status "::chopper::SStatus $hdbroot $chnode $addr"\
halt "::chopper::SHalt $hdbroot $chnode $addr"\
geterror "::chopper::SGetError $hdbroot $chnode $addr"\
fixit "::chopper::SFixit $hdbroot $chnode $addr"
]
$fmot hardlowerlim $lowlim
$fmot hardupperlim $uplim
$fmot softlowerlim $lowlim
$fmot softupperlim $uplim
sicslist setatt $fmot units rpm
sicslist setatt $fmot klass fermi_chopper
sicslist setatt $fmot long_name $fmot
}
proc mkFPhaseMot {fmot hdbroot chnode addr lowlim uplim} {
Motor $fmot tclmot [params\
getpos "::chopper::PhGetPos $hdbroot $chnode $addr"\
run "::chopper::PhRun $hdbroot $chnode $addr"\
status "::chopper::PhStatus $hdbroot $chnode $addr"\
halt "::chopper::PhHalt $hdbroot $chnode $addr"\
geterror "::chopper::PhGetError $hdbroot $chnode $addr"\
fixit "::chopper::PhFixit $hdbroot $chnode $addr"
]
$fmot hardlowerlim $lowlim
$fmot hardupperlim $uplim
$fmot softlowerlim $lowlim
$fmot softupperlim $uplim
sicslist setatt $fmot units degrees
sicslist setatt $fmot klass fermi_chopper
sicslist setatt $fmot long_name $fmot
}
##
# @brief Make the fermichopper driver and speed and phase motors for the master and
# slave choppers.
#
# @param mSpdmot, Name of master chopper speed motor
# @param sSpdmot, Name of slave chopper speed motor
# @param sPhmot, Name of slave chopper phase motor
# @param master, Master chopper hdb node name
# @param maddr, Master chopper modbus address
# @param slave, Slave chopper hdb node name
# @param saddr, Slave chopper modbus address
proc mkFermiMotors {mSpdmot sSpdmot sPhmot master maddr slave saddr} {
set hdbPath [mkChoppers " $master $maddr $slave $saddr"]
# Create Master Chopper Speed motor object
mkFSpeedMot $mSpdmot $hdbPath $master $maddr -24000 24000
mkFSpeedMot $sSpdmot $hdbPath $slave $saddr -24000 24000
mkFPhaseMot $sPhmot $hdbPath $slave $saddr 0 180
}
mkFermiMotors mchs schs schp mch 1 sch 2