#%TITLE% SMARACT.MAC
#
#%NAME%
# Macro motor for SmarAct piezo controller used through a serial line.
#
#%CATEGORY% Positioning
#
#
#%DESCRIPTION%
#%DL%
#%DT%Configuring macro motors %DD%
# %DL%
# %DT% 1)
# You must have an entry in "MOTORS" table for each icepap MASTER
# %DL%
# %DT% -
# The "DEVICE" field must be set to string "smaract"
# %DT% -
# The "ADDR" is set to the serial line entry in the config
# %DT% -
# The "NUM" should be set to 10
# %DT% -
# The "TYPE" field must be set to "Macro Motors"
# %XDL%
# %DT% 2)
# For each axis you must define a motor with:
# %DL%
# %DT% -
# The "Controller" field set to "MAC_MOT"
# %DT% -
# The "Unit" must be set to the above MOTORS entry
# %DT% -
# The "Module" field, must be set to 0
# %DT% -
# The "Chan" field, numbered from 0,
# must be set to the SmartAct axis channel
# %DT% -
# The "Linear/Rotary" must be set to 1 for rotation stages
# %DT% -
# The "Readback slop" has probably to be set also (typically 100)
# %XDL%
# %XDL%
#%XDL%
#
#%END%
#
#%UU%
#%MDESC%
# Setup smaract controller
# (NOTE MP: utility of this macro ??????)
#
def smaract_setup '{
global SMARACT_PAR[]
SMARACT_PAR["setup_done"] = 1
print "smaract_setup"
}'
#%UU%
#%MDESC%
# Unsetup smaract controller
# (NOTE MP: utility of this macro ??????)
#
def smaract_unsetup '{
unglobal SMARACT_PAR
print "smaract_unsetup"
}'
#%IU% (mne, type, unit, module, channel)
#%MDESC%
#
def smaract_config(mot_num, type, unit, module, channel) '{
global SMARACT_PAR
SMARACT_PAR["first"] = 1
if (mot_num == "..") {
# called for each macro hardware controller unit.
# mot_num = ".."
# type = "ctrl"
# unit = unit number of the controller.
# module = number of channels (as specified
# in the device screen of config)
SMARACT_PAR[unit]["addr"] = smaract_ADDR+0
rep = _smaract_query(unit, "GIV")
if (index(rep, "IV") == 0) {
_smaract_perror("no answer from controller")
return ".error."
# Spec will now consider the CONTROLLER unresponsive.
}
# set smaract controller in asynchronuous mode
_smaract_set(unit, "SCM1")
# check closed-loop on all channels
rep = _smaract_query(unit, "GSE")
if (substr(rep, 1, 4) != ":SE1") {
_smaract_set(unit, "SSE1")
}
_smaract_print("Found SmarAct controller")
}
else{
if (type == "mot") {
local comm rep
local stype
local str
local nval vals[]
# Get sensor type
comm = sprintf("GST%d", channel)
rep = _smaract_query(unit, comm)
nval = split(rep, vals, "," )
stype = substr(vals[1], 0, length(vals[1])-1)
str = sprintf("motor:%-8s type:%s", \
motor_mne(mot_num), _smaract_gettype(stype))
_smaract_print(str)
comm = sprintf("GPPK%d", channel)
rep = _smaract_query(unit, comm)
nval = split(rep, vals, "," )
stype = substr(vals[1], 0, length(vals[1])-1)
if (stype != 1) {
str = sprintf("motor:%-8s Unknown physical position", motor_mne(mot_num))
_smaract_perror(str)
str = sprintf("Use chg_dial(%s, \"home\") to find home ref mark", \
motor_mne(mot_num))
_smaract_print(str)
}
SMARACT_PAR[motor_mne(mot_num)]["movend"]= 0
SMARACT_PAR[motor_mne(mot_num)]["moving"]= 0
SMARACT_PAR[motor_mne(mot_num)]["askpos"]= 0
return
}
}
return
}'
#%IU% (motnum, key, action, p1, p2)
#%MDESC%
# The smaract_par function is called when various motor parameters
# are set and when the motor_par() function is used to retrieve a
# user-defined parameter.
def smaract_par(motnum, key, action, p1, p2) '{
local unit channel comm rep
local val nval vals[]
unit = motor_par(motnum, "unit")
channel = motor_par(motnum, "channel")
if (action=="get") {
# should return a value for the parameter named as key for
# motor number motnum. It is never called for an internal spec param.
# return 0
if (key == "acceleration"){
}
else if (key == "backlash") {
}
else if (key == "backlash_rate") {
}
else if (key == "base_rate") {
}
else if (key == "disable") {
}
else if (key == "slew_rate" || key == "velocity") {
}
else if (key == "step_size") {
}
else if (key == "limits") {
}
else if (key == "offset") {
}
else if (key == "misc_par_1") {
}
}
else if (action == "set"){
if (key == "acceleration"){
}
else if (key == "backlash") {
}
else if (key == "backlash_rate") {
}
else if (key == "base_rate") {
}
else if (key == "disable") {
}
else if (key == "slew_rate" || key == "velocity") {
}
else if (key == "step_size") {
}
else if (key == "chan0") {
}
else if (key == "read_mode") {
}
else if (key == "slop") {
}
else if (key == "limits") {
}
else if (key == "offset") {
}
}
}'
#%IU%(<motnum>, <cmd>, <p1>, <p2>)
#%MDESC%
# This function is called to control *hardware* macro_motors.
# <p1> and <p2> signification depends on cmd.
#
def smaract_cmd(motnum, cmd, p1, p2, p3) '{
global SMARACT_PAR[]
local unit comm channel rep _notreasy pos motmne
local nval vals[]
if (SMARACT_PAR["first"]){
SMARACT_PAR["first"] = 0
}
if (motnum == "..") {
# cmd apply to all motors.
# !! no motor_par(motnum,...) here -> crash.
# print "in smaract_cmd motnum=", motnum, "cmd=", cmd
if (cmd == "preread_all") {
# Sent prior a "position" command.
# Can be the place for an "Update all positions" here ???
}
else if (cmd == "prestart_all") {
# ?
}
else if (cmd == "start_all") {
# ?
}
}
else{
# "cmd" applies to individual motor.
# "motnum" is the motor number.
# A minimal implementation requires to recognize the commands:
# *start_one
# *get_status
# *position
# *set_position.
unit = motor_par(motnum, "unit")
channel = motor_par(motnum, "channel")
motmne = motor_mne(motnum)
if (cmd == "get_status") {
local sta staold
staold= -1
sta= -2
while (sta!=staold) {
comm = sprintf("GS%d", channel)
rep = _smaract_query(unit, comm)
# Get the status code
staold= sta
sta = substr(rep, 5, length(rep)-5)
}
# The controller status is very verbose:
# 0 == stopped
# 1 == stepping, open-loop motion (MST)
# 2 == scanning, (MSCA or MCSR)
# 3 == holding, target or reference position (MPA MAA FRM)
# 4 == targeting, closed-loop motion (MPA MAA)
# 5 == move delay
# 6 == calibrating, (CS)
# 7 == finding reference, (FRM)
# 9 == locked, emergency stop
# Inform SPEC that there is no motion
if((sta == 0) || (sta == 3) || (sta==9)) {
if (SMARACT_PAR[motmne]["moving"]) {
SMARACT_PAR[motmne]["movend"]= 1
SMARACT_PAR[motmne]["moving"]= 0
}
return (0)
}
# Inform SPEC that there the motor is not ready
return (0x02)
}
else if (cmd == "start_one") {
local pos
# p1 : target position in dial units for absolute motion.
# p2 : magnitude in dial units for relative motion.
# Calculate target position in udeg or um
pos = p1*motor_par(motnum, "step_size")
if (motor_par(motnum, "rotary")) {
# Mininum check to avoid controller failure
if((pos<0) || (pos>360e6)) {
_smaract_perror("invalid target position, out of [0-360]")
return
}
# Move to absolute angle with infinite hold time (=60s)
comm= sprintf("MAA%d,%d,0,60000", channel, pos)
} else {
# Move to absolute position with infinite hold time (=60s)
comm= sprintf("MPA%d,%d,60000", channel, pos)
}
rep = _smaract_set(unit, comm)
SMARACT_PAR[motmne]["movend"]= 0
SMARACT_PAR[motmne]["moving"]= 1
SMARACT_PAR[motmne]["askpos"]= p1
}
else if (cmd == "position") {
if (SMARACT_PAR[motmne]["movend"]==1) {
pos= SMARACT_PAR[motmne]["askpos"]
} else {
# Must return the current real motor position in dial units.
if (motor_par(motnum, "rotary")) {
comm= sprintf("GA%d", channel)
} else {
comm= sprintf("GP%d", channel)
}
rep = _smaract_query(unit, comm)
nval= split(rep, vals, "," )
pos = vals[1]
pos = pos / motor_par(motnum, "step_size")
}
return pos
}
else if (cmd == "set_position") {
comm = sprintf("SP%d,%d", channel, p1)
rep = _smaract_set(unit, comm)
}
else if (cmd == "base_rate") {
# p1 is the base_rate defined in spec config.
}
else if (cmd == "slew_rate") {
comm = sprintf("SCLS%d,%d", channel,p1)
rep = _smaract_set(unit, comm)
}
else if (cmd == "acceleration") {
# p1 is the acceleration defined in spec config.
}
else if (cmd == "home_base_rate") {
#
}
else if (cmd == "home_slew_rate") {
#
}
else if (cmd == "home_acceleration") {
#
}
else if (cmd == "preread_all") {
# Can be use to read a controller ?
}
else if (cmd == "preread_one") {
# Can be use to read a controller ?
}
else if (cmd == "prestart_one") {
#
}
else if (cmd == "magnitude") {
# p1 is the relative quantity of movement of the move.
}
else if (cmd == "flush_all") {
#
}
else if (cmd == "flush_one") {
#
}
else if (cmd == "abort_one") {
if (SMARACT_PAR[motmne]["moving"]) {
comm = sprintf("S%d", channel)
rep = _smaract_set(unit, comm)
}
SMARACT_PAR[motmne]["moving"]= 0
SMARACT_PAR[motmne]["movend"]= 0
}
else if (cmd == "abort_all") {
#
}
else if (cmd == "search") {
# Initiates a home or limit search.
# A prestart_one call will precede this call.
# The parameter p1 indicates the type of search.
# The parameter p2 contains the position in dial units
# that corresponds to the home or limit switch.
if((p1 == "home") || (p1 == "home-")){
# find home position by moving in negative direction.
comm = sprintf("FRM%d,1,60000,0", channel)
_smaract_set(unit, comm)
}
else if(p1 == "home+"){
# find home position by moving in positive direction.
comm = sprintf("FRM%d,0,60000,0", channel)
_smaract_set(unit, comm)
}
else if(p1 == "lim+"){
# find the positive limit.
_smaract_perror("not implemented, use \"home+\" or \"home-\"")
}
else if(p1 == "lim-"){
# find the negative limit.
_smaract_perror("not implemented, use \"home+\" or \"home-\"")
}
}
else if (cmd == "diff_position") {
#
print "SMARCAT--smaract_cmd()--cmd=", cmd
}
else {
#
print cmd, " -> not implemented ?"
}
}
}'
#%IU%
#%MDESC%
#
def _smaract_set(unit, comm) '{
local dev scomm
dev = SMARACT_PAR[unit]["addr"]
scomm = sprintf(":%s\n", comm)
ser_put(dev, scomm)
}'
#%IU%(code)
#%MDESC%
# Return a string corresponding to the encoder type hardcoded in
# the controller, no way to set its resolution
#
def _smaract_gettype(typ) '{
local str
str="= unknown positioner and sensor"
if(typ == 1) { str="=\"S\" linear positioner with nano sensor" }
if(typ == 2) { str="=\"SR\" rotary positioner with nano sensor" }
if(typ == 4) { str="=\"MR\" rotary positioner with micro sensor" }
if(typ == 5) { str="=\"SP\" linear positioner with nano sensor" }
if(typ == 6) { str="=\"SP\" linear positioner with nano sensor" }
if(typ == 7) { str="=\"M25\" rotary positioner with micro sensor" }
if(typ == 8) { str="=\"SR20\" rotary positioner with nano sensor" }
if(typ == 9) { str="=\"M\" linear positioner with micro sensor" }
if(typ == 10) { str="=\"GC\" rotary positioner with micro sensor" }
if(typ == 11) { str="=\"GD\" goniometer with micro sensor" }
if(typ == 12) { str="=\"GE\" goniometer with micro sensor" }
if(typ == 13) { str="=\"RA\" rotary positioner with abs sensor" }
if(typ == 14) { str="=\"GF\" rotary positioner with micro sensor" }
if(typ == 15) { str="=\"RB\" rotary positioner with micro sensor" }
if(typ == 20) { str="=\"SR77\" rotary positioner with nano sensor" }
if(typ == 21) { str="=\"SD\" linear positioner with nano sensor" }
return(sprintf("%2d%s",typ, str))
}'
#%IU%(code)
#%MDESC%
# Return a string corresponding to the specified error code
#
def _smaract_geterr(err) '{
# No sense, but controller can return a no error error
if(err == 0) { return("") }
# At this point, we are in trouble
if(err == 1) { return("Syntax error") }
if(err == 2) { return("Invalid command") }
if(err == 3) { return("Overflow error") }
if(err == 4) { return("Parse error") }
if(err == 5) { return("Too few parameters") }
if(err == 6) { return("Too many parameters") }
if(err == 7) { return("Invalid parameter") }
if(err == 8) { return("Wrong mode") }
if(err == 129) { return("No sensor present") }
if(err == 140) { return("Sensor disable") }
if(err == 141) { return("Command overridden") }
if(err == 142) { return("End stop reached") }
if(err == 143) { return("Wrong sensor type") }
if(err == 144) { return("Could not find reference") }
if(err == 145) { return("Wrong end effoctor type") }
if(err == 146) { return("Movement locked") }
if(err == 147) { return("Range limit reached") }
if(err == 148) { return("Physical position unknown")}
return(sprintf("Unknown error: %d",err))
}'
#%IU%(answer)
#%MDESC%
# Return a non zero value if the controller answer contains an error
# and print out an explicit error message.
#
def _smaract_checkerr(rep) '{
local nval vals[] err
# Check if controller complains
if(substr(rep,0,2) != ":E") { return(0) }
# Handle controller errors
nval = split(rep, vals, "," )
str = _smaract_geterr(vals[1])
if(str == "") { return(0) }
# Be friendly with the user
_smaract_perror(sprintf("controller error: %s\n", str))
return(-1)
}'
#%IU%
#%MDESC%
#
def _smaract_get(unit) '{
local dev rep
dev = SMARACT_PAR[unit]["addr"]
rep = ser_get(dev, "\n")
if(_smaract_checkerr(rep)) { rep="" }
return rep
}'
#%IU%
#%MDESC%
#
def _smaract_query(unit, comm) '{
local dev
dev = SMARACT_PAR[unit]["addr"]
ser_par(dev, "flush")
_smaract_set(unit, comm)
return _smaract_get(unit)
}'
#%IU%(string)
#%MDESC%
#
def _smaract_perror(str) '{
tty_cntl("md")
printf("SMARACT ERROR: ")
tty_cntl("me")
printf("%s\n", str)
}'
#%IU%(string)
#%MDESC%
#
def _smaract_print(str) '{
# tty_cntl("md")
printf("SMARACT: ")
# tty_cntl("me")
printf("%s\n", str)
}'
#%MACROS%
#%IMACROS%
#%AUTHOR% GB+EP+MP BLISS
# %BR%$Revision: 1.3 $ / $Date: 2014/01/10 09:17:32 $
#%TOC%
|