Scripts which generate a motor configuration file from CSV data files.
This commit is contained in:
200
site_ansto/instrument/util/genmotconf.tcl
Executable file
200
site_ansto/instrument/util/genmotconf.tcl
Executable file
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env tclsh
|
||||
# @file Generate a motor configuration file from CSV files of name value pairs.
|
||||
#
|
||||
# Input: List of CSV files.
|
||||
# Output files:
|
||||
# generated_motor_configuration.tcl
|
||||
# genmotconf_report.log
|
||||
# genmotconf_errors.log: Lists missing attributes if a spec is incomplete.
|
||||
# missing_attlist.csv
|
||||
#
|
||||
# TODO
|
||||
# Optionally split configuration accross multiple files for cases where
|
||||
# axes are swapped out, eg Eulerian cradles, sample-stick rotation.
|
||||
# This could be done by supplying a file which contains lines as follows,
|
||||
# CFG_NAME1,m1 m2 m3
|
||||
# CFG_NAME2,m4 m5 m6
|
||||
# Where CFG_NAMEn is the name of a config file and mn's are motor names.
|
||||
# In this case generated_motor_configuration.tcl will define the header and asyncqueues.
|
||||
# The motor_configuration.tcl file would then be hand-coded to fileeval the CFG_NAMEn files as required.
|
||||
#
|
||||
source [file dirname $argv0]/genmotconf_procs.tcl
|
||||
|
||||
set ERRCNT 0
|
||||
set MOTCFG_CNT 0
|
||||
set FAILED_MOTCFG_CNT 0
|
||||
# MOT_ATTLIST: Attributes required to configure an axis without an encoder
|
||||
# ENC_ATTLIST: Attributes required to describe an encoder.
|
||||
# NOTE Encoder readings for the limit switch positions are required.
|
||||
# If the encoder "home" reading is not supplied it is set equal to rev_enc_lim
|
||||
# ENCMOT_ATTLIST: Attributes which describe an axis which has both a motor and encoder.
|
||||
# REQ_ATTLIST: List of attributes required to generate a configuration for a motor object.
|
||||
# SICS_CFG_ATTLIST: Extra attributes required to configure a motor object in SICS.
|
||||
# ALL_ATTRIBUTES: List of all attributes recognised by this program.
|
||||
#
|
||||
# Attributes which are not in these lists are assumed to define the encoder
|
||||
# readings for each position on an axis which has a set of meaningful positions
|
||||
# such as apertures or multi-sample tables.
|
||||
set MOT_ATTLIST [lsort {axis mc steps_per_x}]
|
||||
set ENC_ATTLIST [lsort {absenchome cnts_per_x fwd_enc_lim rev_enc_lim}]
|
||||
set ENCMOT_ATTLIST [lsort [concat $MOT_ATTLIST ENCMOT_ATTLIST]]
|
||||
set SICS_CFG_ATTLIST [lsort {home fwd_lim rev_lim maxspeed maxaccel maxdecel part units}]
|
||||
set REQ_ATTLIST [lsort [concat $MOT_ATTLIST $SICS_CFG_ATTLIST]]
|
||||
set ALL_ATTRIBUTES [lsort [concat $ENCMOT_ATTLIST $SICS_CFG_ATTLIST]]
|
||||
|
||||
set scriptname [file tail [file rootname $argv0]]
|
||||
set file_list $argv
|
||||
|
||||
set fhr [open ${scriptname}_report.log "w"]
|
||||
set fhe [open ${scriptname}_errors.log "w"]
|
||||
|
||||
# @brief Generate a default value for missing attributes.
|
||||
# @param mot motor name
|
||||
# @param att attribute name
|
||||
# @return value for attribute or NOATT if no attribute should be generated.
|
||||
proc gen_attval {mot att} {
|
||||
switch $att {
|
||||
"absenchome" {
|
||||
if [info exists ::${mot}_encatts(rev_enc_lim)] {
|
||||
return [set ::${mot}_encatts(rev_enc_lim)]
|
||||
} else {
|
||||
return "NOATT"
|
||||
}
|
||||
}
|
||||
"maxspeed" {return 1}
|
||||
"maxaccel" {return 1}
|
||||
"maxdecel" {return 1}
|
||||
"rev_lim" {return 0}
|
||||
"home" {return 0}
|
||||
"fwd_lim" {
|
||||
if { [info exists ::${mot}_encatts(fwd_enc_lim)] && [info exists ::${mot}_encatts(cnts_per_x)] } {
|
||||
set fwd_enc_lim_val [set ::${mot}_encatts(fwd_enc_lim)]
|
||||
set cnts_per_x_val [set ::${mot}_encatts(cnts_per_x)]
|
||||
|
||||
if [info exists ::${mot}_encatts(rev_enc_lim)] {
|
||||
set rev_enc_lim_val [set ::${mot}_encatts(rev_enc_lim)]
|
||||
} else {
|
||||
set rev_enc_lim_val 0
|
||||
}
|
||||
if [info exists ::${mot}_encatts(home)] {
|
||||
set home_val [set ::${mot}_encatts(home)]
|
||||
} else {
|
||||
set home_val 0
|
||||
}
|
||||
return [expr {($fwd_enc_lim_val - $rev_enc_lim_val) / $cnts_per_x_val + $home_val}]
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
"part" {return "instrument"}
|
||||
"units" {return "xxx"}
|
||||
}
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Parse all files and generate ::mn(matt) and ::controllers(cn)
|
||||
foreach f $file_list {
|
||||
parse_file $f $fhr $fhe
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# GENERATE MOTOR CONFIGURATION FILE
|
||||
puts $fhr "GENERATE MOTOR CONFIGURATIONS"
|
||||
puts $fhe "GENERATE MOTOR CONFIGURATIONS"
|
||||
puts $fhe "Required attributes: $REQ_ATTLIST"
|
||||
|
||||
set fhmc [open "generated_motor_configuration.tcl" "w"]
|
||||
# Write configuration file header and make asyncqueues
|
||||
mk_cfg_header $fhmc
|
||||
puts $fhmc ""
|
||||
|
||||
foreach mn [lsort [array names motor_attcnt]] {
|
||||
set mot_attlist [lsort [array names $mn]]
|
||||
set mot_encattlist [lsort [array names ${mn}_encatts]]
|
||||
set num_encatts [llength $mot_encattlist]
|
||||
set missing_enc_atts [setdiff $ENC_ATTLIST $mot_encattlist]
|
||||
set num_missing_encatts [llength $missing_enc_atts]
|
||||
set posnum 0
|
||||
|
||||
# Decide if a motor configuration should be generated.
|
||||
if [subset $REQ_ATTLIST $mot_attlist] {
|
||||
set mk_config 1
|
||||
} else {
|
||||
if {$num_missing_encatts == 0} {
|
||||
set mk_config 1
|
||||
} else {
|
||||
set mk_config 0
|
||||
}
|
||||
}
|
||||
|
||||
# Does this motor have an absolute encoder?
|
||||
if {$num_missing_encatts == 0} {
|
||||
set absenc 1
|
||||
} else {
|
||||
set absenc 0
|
||||
}
|
||||
|
||||
# Decide if a list missing attributes with default values should be written.
|
||||
if [subset $ENCMOT_ATTLIST $mot_attlist] {
|
||||
set mk_missing_atts 1
|
||||
} elseif [subset $MOT_ATTLIST $mot_attlist] {
|
||||
set mk_missing_atts 1
|
||||
} else {
|
||||
set mk_missing_atts 0
|
||||
}
|
||||
|
||||
# Assume that the values of any attributes we don't recognise are encoder
|
||||
# readings for a "posit" motor.
|
||||
set posit_list {}
|
||||
foreach att [setdiff $mot_attlist $ALL_ATTRIBUTES] {
|
||||
incr posnum
|
||||
lappend posit_list "posit_${posnum} \$${mn}_$att"
|
||||
}
|
||||
|
||||
# Generate a motor configuration and/or a list of missing attributes.
|
||||
if ${mk_config} {
|
||||
mk_motconf $mn $fhmc $absenc $posnum posit_list
|
||||
puts $fhr "Configured $mn"
|
||||
incr MOTCFG_CNT
|
||||
} else {
|
||||
set missing_atts [lsort [concat $missing_enc_atts [setdiff $::REQ_ATTLIST [array names $mn]]]]
|
||||
puts $fhe "$mn attributes missing: $missing_atts"
|
||||
incr FAILED_MOTCFG_CNT
|
||||
incr ERRCNT
|
||||
if {$mk_missing_atts} {
|
||||
set undef_atts [setdiff [lsort "absenchome $SICS_CFG_ATTLIST"] $mot_attlist]
|
||||
foreach att $undef_atts {
|
||||
set attval [gen_attval $mn $att]
|
||||
if {$attval != "NOATT"} {
|
||||
lappend missing_attlist "${mn}_$att,$attval"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If there are any missing attributes then write them to a file.
|
||||
if [info exists missing_attlist] {
|
||||
set fh [open "missing_attlist.csv" "w"]
|
||||
foreach attval [lsort $missing_attlist] {
|
||||
puts $fh $attval
|
||||
}
|
||||
close $fh
|
||||
puts "Generated list of missing attributes in missing_attlist.csv. You should rename this if you want to keep it."
|
||||
}
|
||||
|
||||
# The SICS init code calls motor_set_sobj_attributes. It can be redefined in
|
||||
# the motor_configuration.tcl file.
|
||||
puts $fhmc "proc motor_set_sobj_attributes {} {}"
|
||||
puts stderr "Generated $MOTCFG_CNT motor driver configurations"
|
||||
puts $fhr "Generated $MOTCFG_CNT motor driver configurations"
|
||||
puts stderr "Found $FAILED_MOTCFG_CNT incomplete motor configurations. See ${scriptname}_errors.log and ${scriptname}_report.log"
|
||||
puts $fhe "Found $FAILED_MOTCFG_CNT incomplete motor configurations"
|
||||
|
||||
close $fhmc
|
||||
close $fhr
|
||||
close $fhe
|
||||
|
||||
if {$ERRCNT > 0} {
|
||||
puts stderr "Finished with $::ERRCNT errors"
|
||||
}
|
||||
Reference in New Issue
Block a user