Sort is ascending if cntsperx is positive, descending if negative. Improve error and report logs generated by genmotconf.tcl It is not an error if a missing attributed can be initialised with a default value by genmotconf.tcl. Replace the COLLIMATOR_POSITIONS.csv with Bilby_motion_control_commissioning_checklist.csv Generate new "generated_motor_configuration.tcl" file.
234 lines
8.7 KiB
Tcl
Executable File
234 lines
8.7 KiB
Tcl
Executable File
#!/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 CANCFG_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 "absenchome" 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_MOTATTLIST: Extra attributes required to configure a motor object in SICS.
|
|
# SICS_CFG_ENCMOTATTLIST: Extra attributes required to configure a motor object with an encoder 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 {cnts_per_x fwd_enc_lim rev_enc_lim}]
|
|
set ENCMOT_ATTLIST [lsort [concat $MOT_ATTLIST $ENC_ATTLIST]]
|
|
set SICS_CFG_MOTATTLIST [lsort {home fwd_lim rev_lim maxspeed maxaccel maxdecel part units}]
|
|
set SICS_CFG_ENCMOTATTLIST [lsort [concat absenchome $SICS_CFG_MOTATTLIST]]
|
|
set REQ_ATTLIST [lsort [concat $MOT_ATTLIST $SICS_CFG_MOTATTLIST]]
|
|
set ALL_ATTRIBUTES [lsort [concat $ENCMOT_ATTLIST $SICS_CFG_ENCMOTATTLIST]]
|
|
|
|
array set autogen_attarr {}
|
|
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 encmot_attlist [lsort [array names ${mn}_encatts]]
|
|
set mot_attlist [lsort [concat [array names ${mn}_attarr] [array names ${mn}_encatts]]]
|
|
set num_encatts_defined [llength $encmot_attlist]
|
|
set posnum 0
|
|
|
|
# Decide if a motor configuration should be generated.
|
|
if [subset $ALL_ATTRIBUTES $mot_attlist] {
|
|
set mk_config 1
|
|
} elseif [subset $REQ_ATTLIST $mot_attlist] {
|
|
set mk_config 1
|
|
} else {
|
|
set mk_config 0
|
|
}
|
|
|
|
# Does this motor have an absolute encoder?
|
|
if {$num_encatts_defined > 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
|
|
}
|
|
|
|
if [info exists ${mn}_encatts(cnts_per_x)] {
|
|
# Assume that the values of any attributes we don't recognise are encoder
|
|
# readings for a "posit" motor.
|
|
set posit_list {}
|
|
#TODO Sort posits by value can we take into acount if cnts_per_x is -ve or +ve?
|
|
set posit_nameval_list {}
|
|
foreach att [setdiff $mot_attlist $ALL_ATTRIBUTES] {
|
|
lappend posit_nameval_list "$att [set ${mn}_attarr($att)]"
|
|
}
|
|
if {[llength $posit_nameval_list] > 0} {
|
|
set posnum 0
|
|
if { [set ${mn}_encatts(cnts_per_x)] > 0} {
|
|
set sorted_nv_list [join [lsort -integer -increasing -index 1 $posit_nameval_list]]
|
|
} else {
|
|
set sorted_nv_list [join [lsort -integer -decreasing -index 1 $posit_nameval_list]]
|
|
}
|
|
foreach {att v} $sorted_nv_list {
|
|
incr posnum
|
|
lappend posit_list "posit_${posnum} \$${mn}_$att"
|
|
puts "posit_${posnum} \$${mn}_$att = $v"
|
|
}
|
|
}
|
|
}
|
|
|
|
# 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_motatts [setdiff $MOT_ATTLIST $mot_attlist]
|
|
set missing_encatts [setdiff $ENC_ATTLIST $encmot_attlist]
|
|
set num_missing_motatts [llength $missing_motatts]
|
|
set num_missing_encatts [llength $missing_encatts]
|
|
if { $num_missing_encatts > 0 && $absenc} {
|
|
puts $fhe "$mn: found partial config for an axis with an absolute encoder,"
|
|
puts $fhe " need: ([concat $missing_motatts $missing_encatts]) to configure the $mn motor with an encoder"
|
|
} elseif { $num_missing_motatts > 0 } {
|
|
puts $fhe "$mn: found partial config for an axis,"
|
|
puts $fhe " need: ($missing_motatts) to configure $mn motor"
|
|
puts $fhe " also need: ($missing_encatts) if $mn has an encoder"
|
|
}
|
|
incr FAILED_MOTCFG_CNT
|
|
incr ERRCNT
|
|
if {$mk_missing_atts} {
|
|
set undef_atts [setdiff [lsort "absenchome $SICS_CFG_MOTATTLIST"] $mot_attlist]
|
|
foreach att $undef_atts {
|
|
set attval [gen_attval $mn $att]
|
|
if {$attval != "NOATT"} {
|
|
lappend autogen_attarr($mn) "${mn}_$att,$attval"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# If there are any autogenerated attributes then write them to a file.
|
|
if {[array size autogen_attarr] > 0} {
|
|
set fh [open "missing_attlist.csv" "w"]
|
|
puts "The attributes with default values needed to complete the configuration of the following motors has been written to missing_attlist.csv,"
|
|
foreach n [lsort [array names autogen_attarr]] {
|
|
puts -nonewline "$n "
|
|
foreach attval [lsort $autogen_attarr($n)] {
|
|
puts $fh $attval
|
|
}
|
|
}
|
|
close $fh
|
|
puts ""
|
|
puts "Rename missing_attlist.csv and redo to generate a configuration file which also includes the motors listed above."
|
|
puts "Eg,"
|
|
puts "mv missing_attlist.csv sicsmot_attlist.csv"
|
|
puts "$argv0 $argv sicsmot_attlist.csv"
|
|
}
|
|
|
|
# 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"
|
|
}
|