# hallib procs: source [file join $::env(HALLIB_DIR) hal_procs_lib.tcl] # # hookup_moveoff.tcl -- HALFILE to: # 1) disconnect initial pos-cmd and pos-fb pin connections # 2) loadrt the moveoff component with name=mv # 3) addf the moveoff component functions in required sequence # 4) reconnect the pos-cmd and pos-fb pins to use the component # # Support for demo type INI files where the pos-cmd and pos-fb pins are # 'shortcircuit' connected together is included. # # The moveoff component may be initialized with settings from the INI file # # Usage: # 1) Specify this file in the INI file as [HAL]HALFILE # Its position must follow halfiles that connect the pos-cmd and # pos-fb pins. # [HAL] # ... # HALFILE = hookup_moveoff.tcl # ... # # 2) Include INI file entries for moveoff component settings: # [MOVEOFF] # EPSILON = # WAYPOINT_SAMPLE_SECS = # WAYPOINT_THRESHOLD = # BACKTRACK_ENABLE = # # If these settings are not found in the INI file, the moveoff # component defaults will be used. # # 3) Include INI file entries for the per-joint settings # [MOVEOFF_n] # MAX_VELOCITY = # MAX_ACCELERATION = # MAX_LIMIT = # MIN_LIMIT = # # If settings are not found in the INI file, the items # [JOINT_n] # MAX_VELOCITY = # MAX_ACCELERATION = # MAX_LIMIT = # MIN_LIMIT = # are used. If these are not defined, the moveoff component # defaults are used. # # To use the (optional) demonstration gui named moveoff_gui, # include an INI entry: # # [APPLICATIONS] # APP = moveoff_gui option1 option2 ... # # For available options, Use: # $ moveoff_gui --help # # The moveoff_gui will provide a display and control for # enabling offsetting if the pin mv.move-enable is not connected # when moveoff_gui is started. # # If the mv.move-enable pin is connected when moveoff_gui # is started, then it will provide a display but no control. # This mode supports hal connections for a jog wheel or other # methods of controlling the offset input pins (mv.offset-M) #----------------------------------------------------------------------- # Copyright: 2014 # Authors: Dewey Garrett # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #----------------------------------------------------------------------- proc do_hal {args} { if {[info exists ::noexecute] && $::noexecute} { puts "((do_hal))$args" } else { if {$::HU(verbose)} {puts do_hal:$args} eval hal $args } } ;# do_hal proc setup_pinnames {} { # Note: works for standard names but a custom proc is needed # here if the Hal alias command is used on the names # Identify JOINT_n stanzas for {set a 0} {$a < 9} {incr a} { if [info exists ::JOINT_[set a](TYPE)] { lappend ::HU(axes) $a set ::HU(highest_joint_num) $a } } foreach a $::HU(axes) { set ::HU($a,pos,pinname) joint.${a}.motor-pos-cmd set ::HU($a,fb,pinname) joint.${a}.motor-pos-fb } } ;# setup_pinnames proc install_moveoff {} { # note expected name for moveoff_gui is $::m set pnumber [expr 1 + $::HU(highest_joint_num)] do_hal loadrt moveoff personality=$pnumber names=$::m set mot_thread $::HU(motion-controller,threadname) if [info exists ::HU($mot_thread,motion-controller)] { set write_index [expr 1 + $::HU($mot_thread,motion-controller)] } else { set write_index [expr 1 + $::HU($mot_thread,index,last)] } do_hal addf $::m.write-outputs $mot_thread $write_index if [info exists ::HU($mot_thread,motion-command-handler)] { if {1 == $::HU($mot_thread,motion-command-handler) } { set read_index 1 } else { set read_index [expr -1 + $::HU($mot_thread,motion-command-handler)] } } else { set read_index 1 } do_hal addf $::m.read-inputs $mot_thread $read_index } ;# install_moveoff proc disconnect_pos_from_motion {a} { set pinname $::HU($a,pos,pinname) set inpins {}; set outpin {} if [connection_info tmp $pinname] { if {$tmp(signame) != ""} { get_netlist inpins outpin iopins $tmp(signame) set ::HU($a,pos,signame) $tmp(signame) set ::HU($a,pos,inputs) $inpins set ::HU($a,pos,output) $outpin } } else { return -code error "<$pinname> not connected as expected" } do_hal unlinkp $pinname } ;# disconnect_pos_from_motion proc disconnect_fb_to_motion {a} { set pinname $::HU($a,fb,pinname) set inpins {}; set outpin {} if [connection_info tmp $pinname] { if {$tmp(signame) != ""} { get_netlist inpins outpin iopins $tmp(signame) set ::HU($a,fb,signame) $tmp(signame) set ::HU($a,fb,inputs) $inpins set ::HU($a,fb,output) $outpin } } else { return -code error "<$pinname> not connected as expected" } do_hal unlinkp $pinname } ;# disconnect_fb_to_motion proc check_for_short_circuit {a} { if {$::HU($a,fb,signame) == $::HU($a,pos,signame)} { set ::HU($a,shortcircuit) 1 } else { set ::HU($a,shortcircuit) 0 } } ;# check_for_short_circuit proc new_connect_pos_to_moveoff {a} { do_hal delsig $::HU($a,pos,signame) do_hal net hu:pos-$a <= $::HU($a,pos,pinname) do_hal net hu:pos-$a => $::m.pos-$a } ;# new_connect_pos_to_moveoff proc new_connect_plus_offset {a} { if $::HU($a,shortcircuit) return do_hal net hu:plus-$a <= $::m.pos-plusoffset-$a foreach in_pinname $::HU($a,pos,inputs) { if {"$in_pinname" == "$::HU($a,fb,pinname)"} continue do_hal unlinkp $in_pinname do_hal net hu:plus-$a => $in_pinname } } ;# new_connect_plus_offset proc new_connect_minus_offset {a} { do_hal net hu:minus-$a <= $::m.fb-minusoffset-$a do_hal net hu:minus-$a => $::HU($a,fb,pinname) } ;# new_connect_plus_offset proc new_connect_fb_to_moveoff {a} { if $::HU($a,shortcircuit) return do_hal delsig $::HU($a,fb,signame) do_hal net hu:fb-$a => $::m.fb-$a do_hal net hu:fb-$a <= $::HU($a,fb,output) foreach in_pinname $::HU($a,fb,inputs) { if {"$in_pinname" == "$::HU($a,fb,pinname)"} continue do_hal unlinkp $in_pinname do_hal net hu:fb-$a => $in_pinname } } ;# new_connect_fb_to_moveoff proc reconnect_short_circuit {a} { do_hal net hu:shortcircuit-$a <= $::m.pos-plusoffset-$a do_hal net hu:shortcircuit-$a => $::m.fb-$a foreach in_pinname $::HU($a,pos,inputs) { if {"$in_pinname" == "$::HU($a,fb,pinname)"} {continue} do_hal unlinkp $in_pinname do_hal net hu:shortcircuit-$a => $in_pinname } } ;# reconnect_short_circuit proc set_moveoff_inputs {a} { foreach {pin ininame} { offset-vel MAX_VELOCITY \ offset-accel MAX_ACCELERATION \ offset-max MAX_LIMIT \ offset-min MIN_LIMIT \ } { if [info exists ::MOVEOFF_[set a]($ininame)] { set ::HU($a,$pin) [set ::MOVEOFF_[set a]($ininame)] # lindex is used in case there are duplicate entries set ::HU($a,$pin) [lindex $::HU($a,$pin) end] } elseif { [info exists ::JOINT_[set a]($ininame)] } { set ::HU($a,$pin) [set ::JOINT_[set a]($ininame)] # lindex is used in case there are duplicate entries set ::HU($a,$pin) [lindex $::HU($a,$pin) end] puts "hookup_moveoff.tcl:use \[JOINT_$a\]$ininame=$::HU($a,$pin)" } if [info exists ::HU($a,$pin)] { do_hal setp $::m.$pin-$a $::HU($a,$pin) } } } ;# set_moveoff_inputs proc set_moveoff_parms {} { foreach {pin ininame} { epsilon EPSILON \ waypoint-sample-secs WAYPOINT_SAMPLE_SECS \ waypoint-threshold WAYPOINT_THRESHOLD \ backtrack-enable BACKTRACK_ENABLE \ } { if {[info exists ::MOVEOFF($ininame)]} { # lindex is used in case there are duplicate entries set ::HU($pin) [lindex $::MOVEOFF($ininame) end] do_hal setp $::m.$pin $::HU($pin) } } } ;# set_moveoff_parms proc set_moveoff_controls {} { return # provision for future offset control connections } ;# set_moveoff_controls # begin----------------------------------------------------------------- set ::m mv ;# moveoff component name #(must agree with the (optionaL) gui moveoff_gui) # debugging items set ::HU(verbose) 0 set ::noexecute 0 # Provision for twopass compatibility # (::tp is the namespace for [HAL]TWOPASS processing) if [namespace exists ::tp] { set passno [::tp::passnumber] if {$passno == 0} { # With twopass processing, the initial pass0 only collects # loadrt and loadusr commands with no execution. # So the checks etc herein cannot work until pass1 # Note that this file only uses loadrt once for the moveoff # component so it manages its loadrt exclusively puts "hookup_moveoff.tcl: twopass active, pass $passno skipped" return } else { puts "hookup_moveoff.tcl: twopass active, pass $passno active" } } if [catch { set ::HU(cmd) "thread_info ::HU"; eval $::HU(cmd) set ::HU(cmd) setup_pinnames; eval $::HU(cmd) set ::HU(cmd) install_moveoff; eval $::HU(cmd) foreach a $::HU(axes) { set ::HU(cmd) "disconnect_pos_from_motion $a"; eval $::HU(cmd) set ::HU(cmd) "disconnect_fb_to_motion $a"; eval $::HU(cmd) set ::HU(cmd) "check_for_short_circuit $a"; eval $::HU(cmd) set ::HU(cmd) "new_connect_pos_to_moveoff $a"; eval $::HU(cmd) set ::HU(cmd) "new_connect_plus_offset $a"; eval $::HU(cmd) set ::HU(cmd) "new_connect_minus_offset $a"; eval $::HU(cmd) set ::HU(cmd) "new_connect_fb_to_moveoff $a"; eval $::HU(cmd) if $::HU($a,shortcircuit) { set ::HU(cmd) "reconnect_short_circuit $a "; eval $::HU(cmd) } set ::HU(cmd) "set_moveoff_inputs $a"; eval $::HU(cmd) } set ::HU(cmd) "set_moveoff_parms"; eval $::HU(cmd) set ::HU(cmd) "set_moveoff_controls"; eval $::HU(cmd) if $::HU(verbose) {parray ::HU} } msg ] { puts "\n\n$::argv0 $::argv" parray ::HU catch {puts filename=$filename} puts "\n failing cmd=$::HU(cmd)" puts msg=<$msg> return -code error }