#------------------------------------------------------------------ # This is driver for the combination Phytron MCC-2 Motor Controller # and SICS using the scriptcontext asynchronous I/O system. The # MCC-2 has a funny protocol as that messages are enclosed into # data sequences. This protocol is handled by the # C-language phytron protocol handler. Per default, the MCC-2 is # configured to use 57600 baud. I have configured it to use 9600 # baud and it ought to remember this. The command to change this # 0IC1S9600, the command to read this is 0IC1R. # # So, if this thing does not work on a serial port then the solution is # to set the terminal server to 57600 and try again. And set the baud rate # or leave it. # # There are surely many ways to use the MCC-2. It supports two axes, X and Y. # All examples below are given for X only. This driver uses it in # this way: # # Nothing works properly without a reference run. The reference run is done # in the following way: # 1) Send it into the negative limit switch with 0X0- # 2) Set the mechanical position with 0XP20Swert to the negative limit # 3) Set the encoder position with 0XP22Swert to the negative limit # # Position ever afterwards with 0XAwert, read encoder with 0XP22R # # While driving 0X=H return ACKN, else ACKE # # Stopping goes via 0XSN # # copyright: see file COPYRIGHT # # Script chains: # # - reading position: # readpos - posrcv # # - writing postion: # setpos - setrcv # # - reading status: # sendstatus - rcvstatus - statpos # # - reading speed: # readspeed - rcvspeed # # - setting speed: # writespeed - rcvwspeed - rcvspeed # # Mark Koennecke, June 2009 # # Added code to switch a brake on for schneider_m2 # # Mark Koennecke, September 2009 # # Added code to support the speed parameter # # Mark Koennecke, December 2009 # # Added more code to configure non encoder phytron motors which need to # read another parameter for position # # Mark Koennecke, January 2011 # # Added withencoder parameter to give the user the possiblilty to change # encoder mode # # Markus Zolliker, April 2011 # # Modified error handling: set status to "error" in case of a communication # error and set the property of the main object accordingly # # Markus Zolliker, June 2012 # # Set the motor position to the encoder position before staring the motor # This is only active when wthencoder is 1 # Markus Zolliker, August 2017 # # Revised to allow for an address replacing the 0 in the example above. # The address is in the range from 0-F # Mark Koennecke, June 2018 #------------------------------------------------------------------------- namespace eval phytron {} #----------------------------------------------------------------------- proc phytron::check {} { global count set data [sct result] if {[string match "ASCERR: *" $data]} { set err [string range $data 8 end] catch {hupdate [sct parent]/status error} if {[string match "*unconnected*" $err] || [string match "*offline*" $err]} { set err [silent $err hgetpropval [sct parent] offline_msg] } elseif {[string match "Connection refused*" $err]} { set err [silent $err hgetpropval [sct parent] refused_msg] } hsetprop [sct parent] geterror $err error $err } catch {hdelprop [sct parent] geterror} return $data } #------------------------------------------------------------------------ proc phytron::readpos {addr axis} { # the following command must be P20R without encoder, P22R with encoder if {[hval [sct @withencoderpath]] == 1} { sct send "${addr}${axis}P22R" } else { sct send "${addr}${axis}P20R" } return posrcv } #------------------------------------------------------------------------ proc phytron::posrcv {} { set data [phytron::check] set pos [string range $data 3 end] sct update $pos return idle } #------------------------------------------------------------------------ proc phytron::setpos {addr axis name} { if {[hval [sct @withencoderpath]] == 1} { # set motor position to encoder position" sct send "${addr}${axis}P20S[hval [sct]]" return setpos_raw } return [phytron::setpos_raw $addr $axis $name] } #------------------------------------------------------------------------ proc phytron::setpos_raw {addr axis name} { set val [sct target] if {abs($val) < .001} { set val .001 } sct send "${addr}${axis}A$val" hupdate /sics/${name}/status run return setrcv } #------------------------------------------------------------------------ proc phytron::setrcv {controller name} { set data [phytron::check] if {[string first NACK $data] >= 0} { error "Invalid command" } $controller queue /sics/${name}/status progress read return idle } #------------------------------------------------------------------------- proc phytron::sendstatus {addr axis} { sct send "${addr}${axis}=H" return rcvstatus } #------------------------------------------------------------------------- proc phytron::rcvstatus {addr axis controller} { set data [phytron::check] if {[string first ACKN $data] >= 0} { sct update run $controller queue [sct] progress read } if {[string first ACKE $data] >= 0} { phytron::readpos $addr $axis return posrcv } # update motor position during run $controller queue [sct parent]/hardposition progress read return idle } #------------------------------------------------------------------------- proc phytron::statpos {addr axis name} { set data [phytron::check] set pos [string range $data 3 end] hupdate /sics/${name}/hardposition $pos sct send "${addr}${axis}=I+" return statposlim } #------------------------------------------------------------------------ proc phytron::statposlim {addr axis} { set data [phytron::check] if {[string first ACKE $data] >= 0} { sct update error clientput "Hit positive limit switch" return idle } sct send "${addr}${axis}=I-" return statneglim } #------------------------------------------------------------------------ proc phytron::statneglim {addr axis} { set data [phytron::check] if {[string first ACKE $data] >= 0} { sct update error clientput "Hit negative limit switch" return idle } sct send "${addr}${axis}=E" return statend } #------------------------------------------------------------------------ proc phytron::statend {addr axis} { set data [phytron::check] if {[string first ACKE $data] >= 0} { sct update error clientput "Electronics error" return idle } sct update idle return idle } #------------------------------------------------------------------------ proc phytron::readspeed {addr axis} { sct send "${addr}${axis}P14R" return rcvspeed } #------------------------------------------------------------------------ proc phytron::rcvspeed {} { set data [phytron::check] set speed [string range $data 3 end] sct update $speed return idle } #------------------------------------------------------------------------ proc phytron::writespeed {addr axis} { set val [sct target] sct send "${addr}${axis}P14S$val" return rcvwspeed } #------------------------------------------------------------------------ proc phytron::rcvwspeed {addr axis} { set data [phytron::check] if {[string first NACK $data] >= 0} { error "Invalid command" } return [phytron::readspeed $addr $axis] } #------------------------------------------------------------------------- proc phytron::halt {controller addr axis} { $controller send "${addr}${axis}SN" return Done } #-------------------------------------------------------------------------- proc phytron::refrun {name controller addr axis lowlim} { set path /sics/${name}/status $controller send "${addr}${axis}0-" hupdate $path run set motstat run wait 3 while {[string compare $motstat run] == 0} { $controller queue $path progress read wait 1 set motstat [string trim [hval $path]] } $controller transact "${addr}${axis}P20S$lowlim" $controller transact "${addr}${axis}P22S$lowlim" return Done } #------------------------------------------------------------------------- proc phytron::defpos {controller addr axis value} { $controller transact "${addr}${axis}P20S$value" $controller transact "${addr}${axis}P22S$value" return Done } #------------------------------------------------------------------------- proc phytron::connect {controller name hostport} { $controller reconnect $hostport # queue a read operation in order to update the error message $controller queue /sics/${name}/hardposition read read } #-------------------------------------------------------------------------- proc phytron::make {name axis controller lowlim upperlim {enc 1}} { return [phytron::makefull $name 0 $axis $controller $lowlim $upperlim $enc] } #--------------------------------------------------------------------------- proc phytron::makefull {name addr axis controller lowlim upperlim {enc 1}} { MakeSecMotor $name # make geterror work on the object $controller connect /sics/$name hdel /sics/${name}/hardupperlim hdel /sics/${name}/hardlowerlim hfactory /sics/${name}/hardupperlim plain internal float hfactory /sics/${name}/hardlowerlim plain internal float $name hardlowerlim $lowlim $name softlowerlim $lowlim $name hardupperlim $upperlim $name softupperlim $upperlim hsetprop /sics/${name}/hardposition read phytron::readpos $addr $axis hsetprop /sics/${name}/hardposition posrcv phytron::posrcv $controller poll /sics/${name}/hardposition 10 hsetprop /sics/${name}/hardposition write phytron::setpos $addr $axis $name hsetprop /sics/${name}/hardposition setpos_raw phytron::setpos_raw $addr $axis $name hsetprop /sics/${name}/hardposition setrcv phytron::setrcv $controller $name $controller write /sics/${name}/hardposition hsetprop /sics/${name}/status read phytron::sendstatus $addr $axis hsetprop /sics/${name}/status rcvstatus phytron::rcvstatus $addr $axis $controller hsetprop /sics/${name}/status posrcv phytron::statpos $addr $axis $name hsetprop /sics/${name}/status statposlim phytron::statposlim $addr $axis hsetprop /sics/${name}/status statneglim phytron::statneglim $addr $axis hsetprop /sics/${name}/status statend phytron::statend $addr $axis $controller poll /sics/${name}/status 10 hfactory /sics/${name}/speed plain user float hsetprop /sics/${name}/speed read "phytron::readspeed $addr $axis" hsetprop /sics/${name}/speed rcvspeed "phytron::rcvspeed" hsetprop /sics/${name}/speed write "phytron::writespeed $addr $axis" hsetprop /sics/${name}/speed rcvwspeed "phytron::rcvwspeed $addr $axis" $controller poll /sics/${name}/speed 10 $controller write /sics/${name}/speed $name makescriptfunc halt "phytron::halt $controller $addr $axis" user $name makescriptfunc refrun "phytron::refrun $name $controller $addr $axis $lowlim" user $name makescriptfunc sethardpos "phytron::defpos $controller $addr $axis" user hfactory /sics/${name}/sethardpos/value plain user float $name makescriptfunc connect "phytron::connect $controller $name" user hfactory /sics/${name}/connect/hostport plain user text $name makescriptfunc disconnect "phytron::connect $controller $name unconnected" user hfactory /sics/${name}/withencoder plain user int hupdate /sics/${name}/withencoder $enc hsetprop /sics/${name} @withencoderpath /sics/${name}/withencoder hupdate /sics/${name}/status idle $controller queue /sics/${name}/hardposition progress read $controller queue /sics/${name}/speed progress read } #=============================================================================================== # At MORPHEUS there is a special table where one motor needs a brake. This requires a digital I/O # to be disabled before driving and enabled after driving. The code below adds this feature to # a phytron motor. This shite has propagated to the CCD camera on BOA too. #----------------------------------------------------------------------------------------------- proc phytron::openset {addr out} { sct send [format "${addr}A%dS" $out] return openans } #---------------------------------------------------------------------------------------------- proc phytron::openans {addr axis name} { after 100 return [phytron::setpos $addr $axis $name] } #---------------------------------------------------------------------------------------------- proc phytron::outsend {addr axis out} { set data [phytron::check] if {[string first ACKE $data] >= 0} { sct update error clientput "Electronics error" return idle } sct send [format "${addr}A%dR" $out] return outend } #---------------------------------------------------------------------------------------------- proc phytron::outend {} { sct update idle return idle } #---------------------------------------------------------------------------------------------- proc phytron::configureM2 {motor axis out {addr 0}} { set path /sics/${motor} hsetprop $path/hardposition write phytron::openset $addr $out hsetprop $path/hardposition openans phytron::openans $addr $axis $motor hsetprop $path/status statend phytron::outsend $addr $axis $out hsetprop $path/status outend phytron::outend }