# global bank 2 usage # persistent: # 0 zero # 1 id # 2 lower limit # 3 upper limit # 4 precision # 6 feedback available # 8 pump number # 9 hysteresis # non-persistent: # 255 init (0/1) namespace eval trinamic {} { variable cmds set cmds(motor_stop) 3 set cmds(move_to_pos) 4 set cmds(set_axis_par) 5 set cmds(get_axis_par) 6 set cmds(save_axis_par) 7 set cmds(load_axis_par) 8 set cmds(set_glob_par) 9 set cmds(get_glob_par) 10 set cmds(save_glob_par) 11 set cmds(load_glob_par) 12 set cmds(set_io) 14 set cmds(get_io) 15 # command numbers are translated 1:1 # foreach key [array names cmds] { # set val $cmds($key) # set cmds($val) $val # } } proc stdConfig::trinamic {{usage undefined} {sensirion 0}} { # bin controller bin chksum-crc 1 2 prop write trinamic::write prop read trinamic::read prop complete trinamic::complete prop update trinamic::update variable node set node $node/tasks set tasknode $node # prop start trinamic::startCmd prop startcmd "str1 n int 10 / str9" pollperiod 5 5 set f [expr 256 / 1.8] # set f 1 obj trinamic -drive out prop status idle prop check trinamic::setpos prop write trinamic::runmsg prop halt trinamic::halt prop fact $f prop usezero 1 prop cormode 0 prop @due 0 prop runlabel pos hsetprop $tasknode objectnode $node kids "trinamic stepper motor" { node pos rd prop adr axis_par 1 prop fact $f prop usezero 1 prop update trinamic::updatePos node encoder rd prop adr axis_par 209 prop fact $f prop usezero 1 node zero wr prop fact $f prop write trinamic::writezero prop read trinamic::readzero prop eeprom 1 prop adr glob_par 0 2 default -999 node lowerlimit wr prop adr glob_par 2 2 prop eeprom 1 prop fact $f node upperlimit wr prop adr glob_par 3 2 prop eeprom 1 prop fact $f node disablelimits par 0 prop enum 1 node verbose par 0 prop enum 1 node target rd prop adr axis_par 0 prop fact $f prop usezero 1 node runstate upd prop enum idle,running,finished,error # node targetreached rd 5 slow # prop adr axis_par 8 # prop update trinamic::updateTargetReached # prop enum idle,running,finished node precision wr default 0.9 prop fact $f prop eeprom 1 prop adr glob_par 5 2 node maxencdif wr default 1.8 prop fact $f prop eeprom 1 prop adr axis_par 212 # node blindrun wr 0 # prop eeprom 1 # prop adr glob_par 8 2 # prop enum 1 node id wr 0 prop eeprom 1 prop adr glob_par 1 2 if {$usage eq "hepump"} { node pump_number wr 0 prop eeprom 1 prop adr glob_par 8 2 } node init wr 0 prop adr glob_par 255 2 # node currentspeed rd # prop adr axis_par 3 # prop read trinamic::read_when_running # prop update trinamic::updateCurrentSpeed # prop running_time 0 # prop fast 0 node maxspeed wr prop adr axis_par 4 prop eeprom 1 node acceleration wr prop adr axis_par 5 prop eeprom 1 node maxcurrent wr prop adr axis_par 6 prop eeprom 1 node standbycurrent wr prop adr axis_par 7 prop eeprom 1 node freewheeling wr prop adr axis_par 204 prop eeprom 1 prop enum 1 node output0 wr prop adr io 0 2 prop enum 1 node output1 wr prop adr io 1 2 prop enum 1 node input3 rd prop adr io 3 0 prop enum 1 prop update trinamic::updateInput3 # node input0 rd # prop adr io 0 1 # prop fact 30 # prop offset 1.1 # prop update trinamic::updateInput0 # prop last 0 # prop old 0 # prop perform_calib 0 # node input0raw upd node pullup wr prop adr io 0 0 if {$sensirion} { node flow rd prop read stdSct::read prop update trinamic::updateFlow prop readcmd "str1 ? / str18" node flowstddev upd # ?_ nsample=160: <~= 1 sec, nsample=800: <~= 5 sec node flowsamples -int out prop write stdSct::write prop complete trinamic::updatecalib prop writecmd "str8 n%6dr / str18" node flowoffset wr prop check trinamic::checkCalib prop read stdSct::read prop write stdSct::write prop update trinamic::updateCalib prop complete trinamic::updateCalib prop readcmd "str1 r / str18" prop writecmd "str8 t%6.3fr / str18" node flowscale out prop check trinamic::checkCalib prop write stdSct::write prop complete trinamic::updateCalib prop writecmd "str8 g%6.3fr / str18" node flowsave out prop enum 1 prop write trinamic::saveCalib prop help "unchecked: current calib is not saved. set checked: save calib" } # node hysteresis wr # prop fact $f # prop eeprom 1 # prop adr glob_par 9 2 if {$usage eq "hepump"} { node nopumpfeedback wr prop eeprom 1 prop adr glob_par 6 2 prop enum 1 } # node stopstatus rd # prop adr axis_par 207 # prop update trinamic::updateStopstatus node eeprom out default 1 prop enum ok,dirty,save,load prop write trinamic::eewrite prop label "eeprom status" node customadr out -text default "axis_par 209" prop check trinamic::setcustom prop write stdSct::complete node custompar wr prop adr axis_par 209 } variable ctrl variable path # load # $ctrl queue $path start trinamic::init # read zero first (global bank2 parameter 0) $ctrl queue $path/zero progress trinamic::readzero } proc trinamic::updateFlow {} { lassign [sct result] flow stddev sct update $flow updateval [sct parent]/flowstddev $stddev return idle } proc trinamic::currentCalib {} { return [format {%.4f %.4f} [sctval [sct parent]/flowoffset] [sctval [sct parent]/flowscale]] } proc trinamic::updateCalib {} { lassign [sct result] offset scale updateval [sct parent]/flowoffset $offset updateval [sct parent]/flowscale $scale set node [sct parent]/flowsave if {[silent -1 hgetpropval $node saved] == -1} { hsetprop $node saved [currentCalib] } return idle } proc trinamic::checkCalib {} { if {[silent "" hgetpropval [sct parent]/flowsave saved] ne [currentCalib]} { hupdate [sct parent]/flowsave 0 } else { hupdate [sct parent]/flowsave 1 } } proc trinamic::saveCalib {} { if {[sct target]} { sct send "str2 sr / str18" sct saved [currentCalib] sct print "saved calib [sct saved]" } else { sct print "marked calib as dirty" } sct update [sct target] return stdSct::complete } proc trinamic::send {cmd {nr 0} {bank 0} {value 0}} { variable cmds set cmd $cmds($cmd) # sct send "int 1 $cmd $nr $bank int4 $value crc 0 / 2 1 100 $cmd int4 crc" sct send "int 1 $cmd $nr $bank int4 $value crc 0 / 2 1 skip1 $cmd int4 crc" } proc trinamic::response {} { if {[llength [sct result]] != 1} { error "illegal result on [sct]: [sct result]" } return [string trim [sct result]] } proc trinamic::complete {} { response return idle } proc trinamic::logmsg {text} { if {[hval [sct objectPath]/verbose]} { clientput $text } } proc trinamic::halt {} { logmsg HALT trinamic::endrun send motor_stop return trinamic::complete } proc trinamic::init {} { # mark nodes for load foreach var [hlist [sct]] { if {[silent 1 hgetpropval [sct]/$var eeprom] != 1} { hsetprop [sct]/$var eeprom 1 } } # load eeprom (with "halt" priority, higher than write) [sct controller] queue [sct]/eeprom halt "trinamic::eeprom load" hsetprop [sct]/encoder adjust_zero 1 # set pullup resistors on send set_io 0 0 1 return trinamic::complete } proc trinamic::startCmd {} { sct try_cnt 3 send get_glob_par 255 2 return trinamic::startCmd0 } proc trinamic::startCmd0 {} { if {[response] ne "1" && [response] ne "2"} { if {[sct try_cnt] > 0} { sct try_cnt [expr [sct try_cnt] - 1] send get_glob_par 255 2 return trinamic::startCmd0 } clientput "[sct] reboot detected" send set_glob_par 255 2 1 return trinamic::startCmd1 } send get_glob_par 1 2 return complete } proc trinamic::startCmd1 {} { # clientput "start cmd1 [response]" send get_glob_par 1 2 return trinamic::startUpd } proc trinamic::startUpd {} { # clientput "start upd [response]" [sct controller] queue [sct objectnode] start trinamic::init return complete } proc trinamic::eewrite {} { # mark nodes for load or save foreach var [hlist [sct parent]] { if {[silent 1 hgetpropval [sct parent]/$var eeprom] == 0} { hsetprop [sct parent]/$var eeprom 1 } } switch [sct target] { 2 { return "trinamic::eeprom save" } 3 { return "trinamic::eeprom load" } } clientlog "nothing to do" sct update [hvali [sct]] return idle } proc trinamic::eeprom {saveorload} { foreach var [hlist [sct parent]] { if {[silent 0 hgetpropval [sct parent]/$var eeprom]} { lassign "[hgetpropval [sct parent]/$var adr] 0 0" typ nr bank if {$saveorload eq "load"} { set cmd load_$typ [sct controller] queue [sct parent]/$var progress read } else { set cmd save_$typ } # sct send "int 1 $cmd $nr $bank int4 0 crc / skip8 crc" send $cmd $nr $bank hsetprop [sct parent]/$var eeprom 0 # clientlog "$saveorload $var" return "trinamic::eeprom $saveorload" } } # set o.k. sct update 0 # clientlog "finished eeprom $saveorload" return idle } proc trinamic::write {} { lassign "[sct adr] 0 0" typ nr bank hupdate [sct parent]/eeprom 1 set val [expr round([sct target] * [silent 1 sct fact])] # sct send "int 1 $cmd $nr $bank int4 $val crc / skip8 crc" send set_$typ $nr $bank $val set old [hvali [sct]] if {$old != [sct target]} { #clientput "SET [sct] $old -> [sct target]" } set trigger [silent "" sct trigger_path] if {$trigger ne ""} { [sct controller] queue $trigger read read } return read } proc trinamic::read {} { if {[DoubleTime] < [sct @due]} { return idle } lassign "[sct adr] 0 0" typ nr bank # sct send "int 1 $cmd $nr $bank int4 0 crc / skip4 int4 crc" send get_$typ $nr $bank sct crctry 3 # clientlog [sct] return update } proc trinamic::update {} { set v [response] set f [silent 1 sct fact] set z 0 sct rawvalue $v set vv [expr $v / double($f)] if {[silent 0 sct usezero]} { set z [silent -999 hval [sct objectPath]/zero] if {$z == -999} { error "undefined zero" } } set vv [format %.2f [expr $vv + $z]] if {[silent 0 sct adjust_zero]} { #clientput "encoder $vv raw [expr $vv - $z]" set uplim [hval [sct objectPath]/upperlimit] set lolim [hval [sct objectPath]/lowerlimit] set reserve [expr 360 - ($uplim - $lolim)] if {$reserve > 0} { set uplim [expr $uplim + $reserve * 0.5] set lolim [expr $lolim - $reserve * 0.5] } #clientput "limits $lolim $uplim reserve $reserve" set dz 0 if {$vv > $uplim && $vv - 360 <= $uplim && $vv - 360 >= $lolim} { set dz -360 } elseif {$vv < $lolim && $vv + 360 >= $lolim && $vv + 360 <= $uplim} { set dz 360 } if {$dz != 0} { clientput "adjust zero $z to [expr $z + $dz]" set z [expr $z + $dz] hset [sct objectPath]/zero $z set vv [expr $vv + $dz] } sct adjust_zero 0 } # switch [sct] { # /nv/nvmot/pos - /nv/nvmot/target - /nv/nvmot/custompar { # clientput "[expr fmod([DoubleTime],60)] [sct] $vv" # } # } sct update $vv return idle } proc trinamic::writezero {} { set val [expr round([sct target] * [silent 1 sct fact])] if {$val <= 0} { incr val -1 } if {[silent -1 sct eeprom] == 0} { sct eeprom 1 hupdate [sct parent]/eeprom 1 } # sct send "int 1 9 0 2 int4 $val crc / skip8 crc" send set_glob_par 0 2 $val #clientput "set zero [hvali [sct]] -> [sct target] $val" return read } proc trinamic::readzero {} { if {[DoubleTime] < [sct @due]} { return idle } send get_glob_par 0 2 return trinamic::updatezero } proc trinamic::updatezero {} { set v [response] if {$v == 0} { clientlog "zero undefined" } if {$v < 0} { incr v } set v [format %.2f [expr $v / double([silent 1 sct fact])]] # if {$v != 0} { # clientput "zero $v [sct result]" # } sct update $v return idle } proc trinamic::updatePos {} { set res [trinamic::update] updateval [sct parent] [hvali [sct]] return $res } proc trinamic::setcustom {} { hsetprop [sct parent]/custompar adr [sct target] sct update [sct target] [sct controller] queue [sct parent]/custompar read read return idle } proc trinamic::setpos {} { if {![hvali [sct]/disablelimits]} { if {[sct target] > [hval [sct]/upperlimit]} { error "ERROR: [sct target] is above upper limit" } if {[sct target] < [hval [sct]/lowerlimit]} { error "ERROR: [sct target] is below lower limit" } } sct goto [sct target] set period 0 if {[sct status] eq "run"} { set period 0.1 } if {[silent 0 sct startime] == 0} { sct startime [DoubleTime] } # if {[sct] eq "/nv/nvmot"} { # debug nvmot # } [sct controller] poll [sct] $period progress trinamic::start } proc trinamic::start {} { set now [DoubleTime] if {[sct status] eq "run"} { if {$now < [sct startime] + 60} { return idle } clientlog "[sct] timeout when waiting for idle" } sct startime 0 sct adjustcnt 0 [sct controller] poll [sct] 0.1 progress trinamic::adjustPosNew sct afteradjust trinamic::start1 # set idle mode hupdate [sct]/runstate 0 sct status run return unpoll } proc trinamic::calcdelay {} { set s [hgetpropval [sct]/maxspeed actvalue] set a [hgetpropval [sct]/acceleration actvalue] set p [hgetpropval [sct]/pos rawvalue] set t [sct moveto] # calculate time: pulse_div 3 assumed, ramp_div 7 assumed" set delay [expr abs($t - $p) / 30.5 / $s + $s / $a / 15.25 + 0.5] return $delay } proc trinamic::adjustPosNew {} { set adjustcnt [sct adjustcnt] sct adjustcnt [expr $adjustcnt+1] if {$adjustcnt % 10 == 0} { # read encoder and pos before start [sct controller] queue [sct]/pos progress trinamic::read [sct controller] queue [sct]/encoder progress trinamic::read return idle } if {$adjustcnt % 10 == 1} { set enc [hgetpropval [sct]/encoder rawvalue] set pos [hgetpropval [sct]/pos rawvalue] if {abs($enc - $pos) < 256} { [sct controller] queue [sct] progress [sct afteradjust] return unpoll } send set_axis_par 1 0 $enc logmsg "[sct]: correct pos [hvali [sct]/pos] to enc [hvali [sct]/encoder]" return "trinamic::adjustPosNew1 $enc" } return idle } proc trinamic::adjustPosNew1 {target} { send set_axis_par 0 0 $target return "trinamic::complete" } proc trinamic::adjustPos {next} { set e [hval [sct]/encoder] set p [hval [sct]/pos] set dif [format %.2f [expr $e - $p]] set prec [hvali [sct]/precision] if {abs($dif) <= $prec && abs($dif) <= [hvali [sct]/maxencdif] * 0.9} { return $next } temp_value maxcurrent 0 temp_value maxspeed 2047 temp_value acceleration 2047 temp_value maxencdif 0 sct moveto [hgetpropval [sct]/encoder rawvalue] # if {abs($dif) > [hvali [sct]/maxencdif]} { # clientput "[sct] correct motor position by $dif" # } logmsg "[sct] correct motor position by $dif" sct delay [trinamic::calcdelay] sct afterrun $next return trinamic::setrunpars } proc trinamic::setrunpars {} { foreach var [hlist [sct]] { set val [silent none hgetpropval [sct]/$var actvalue] if {$val ne "none"} { set f [silent 1 hgetpropval [sct]/$var fact] set val [expr round($val * $f)] lassign "[hgetpropval [sct]/$var adr] 0 0" typ nr bank send set_$typ $nr $bank $val hsetprop [sct]/$var actvalue none return trinamic::setrunpars } } sct @due [expr [DoubleTime] + [sct delay]] send move_to_pos 0 0 [sct moveto] [sct controller] poll [sct] 0.1 progress "trinamic::wait" return trinamic::complete } proc trinamic::wait {} { set now [DoubleTime] if {$now < [sct @due]} { return idle } [sct controller] queue [sct]/pos progress trinamic::read [sct controller] queue [sct]/encoder progress trinamic::read sct finitime $now [sct controller] queue [sct] progress trinamic::fini return unpoll } proc trinamic::fini {} { # get target reached send get_axis_par 8 return trinamic::targetReached } proc trinamic::targetReached {} { set r [response] #clientput "targetreached [expr fmod([DoubleTime],60)] $r" if {$r == 1} { updateval [sct]/runstate 2 ;# finished # get stop status (for clearing only) send get_axis_par 207 return [sct afterrun] } if {$r != 0} { error "[sct] illegal value for target reached: $r" } # get stop status send get_axis_par 207 return trinamic::stopStatus } proc trinamic::stopStatus {} { set r [response] if {$r > 0 && $r <= 3} { logmsg "stopped with error $r" updateval [sct]/runstate 3 return [sct afterrun] } if {$r == 0} { if {[DoubleTime] < [sct finitime] + 2} { return trinamic::fini } updateval [sct]/runstate 3 clientlog "[sct] run timeout [sct delay] [expr [DoubleTime] - [sct @due]]" return [sct afterrun] } error "[sct] illegal stopstatus: $r" } proc trinamic::runmsg {} { # sct print "run [sct objectName] to [sct target]" return idle } proc trinamic::start1 {} { normal_value maxcurrent normal_value maxspeed normal_value acceleration normal_value maxencdif sct enc0 [hvali [sct]/encoder] set val [sct goto] set f [silent 1 sct fact] set val [expr round(($val - [hval [sct objectPath]/zero]) * $f)] sct moveto $val sct delay [trinamic::calcdelay] # sct afterrun "trinamic::adjustPos trinamic::endrun" sct afterrun "trinamic::endrun" return trinamic::setrunpars } proc trinamic::temp_value {var badval} { set val [sctval [sct]/$var] if {$val != $badval} { hsetprop [sct]/$var restorevalue $val } hsetprop [sct]/$var actvalue $badval } proc trinamic::normal_value {var} { set val [sctval [sct]/$var] hsetprop [sct]/$var actvalue [silent $val hgetpropval [sct]/$var restorevalue] } proc trinamic::endrun {} { if {[sct] eq "/hepump" && [result _hepump debug] >= 0} { debug off } set enc [hvali [sct]/encoder] set dif [expr abs($enc - [sct goto])] set prec [hvali [sct]/precision] if {[hvali [sct]/runstate] == 3 && $dif > $prec && $dif <= abs([sct enc0] - [sct goto]) - $prec} { logmsg "[sct] try again enc=$enc goto=[sct goto]" return trinamic::start1 } sct status idle foreach var [hlist [sct]] { set val [silent none hgetpropval [sct]/$var restorevalue] if {$val ne "none"} { hset [sct]/$var $val hdelprop [sct]/$var restorevalue } } # make sure input3 (endswitch) is read immediately send get_io 3 0 return "trinamic::updateInput3 ismainpath" } proc trinamic::updateInput3 {{ismainpath 0}} { if {$ismainpath eq "ismainpath"} { set path [sct] } else { set path [sct parent] } if {[silent 0 hvali $path/nopumpfeedback] == 1} { # assume that pump is on when output0 is 1 updateval $path/input3 [expr ![hval $path/output0]] } else { updateval $path/input3 [response] } return idle } proc trinamic::updateInput0 {} { # input0: 12 bit (0...4095) for 0-10 V # make an average over 0.5 sec (about 5 readings) set v [response] sct sum [expr [silent 0 sct sum] + $v] sct cnt [expr [silent 0 sct cnt] + 1] set now [DoubleTime] if {[sct cnt] < 5 && $now < [sct last] + 1} { return idle } set v [expr double([sct sum]) / [sct cnt]] set volt [expr $v / 409.6] set scaled [expr ($volt - [sct offset]) * [sct fact]] hupdate [sct parent]/input0raw $volt sct update $scaled sct cnt 0 sct sum 0 sct last $now return idle }