The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Author: Ed

  • Kicad-to-HAL: Threads

    Kicad-to-HAL: Threads

    The Kicad THREAD symbol (center bottom) creates the HAL addf commands connecting HAL component functions to the realtime threads:

    Kicad-to-HAL Demo Schematic
    Kicad-to-HAL Demo Schematic

    Change the Kicad reference to match the HAL thread name. AFAICT, you can use either servo-thread or base-thread, as defined by the LoadRT configuration (center top).

    Opinion: contemporary x86-64 PC architecture pretty much prevents running a base-thread at the pace required for step generation through a parallel port. In point of fact, I wrote Kicad-to-HAL specifically to configure a PC around a Mesa Electronics 5i25 FPGA controller for my Sherline CNC mill, as the real-time latency had regular glitches far exceeding the nominal 50 µs period. I suspect few new CNC installations will need a fast base thread.

    The THREAD symbol has seven “Power output” pins drawn in the Clock graphic style:

    Kicad symbol - THREAD
    Kicad symbol – THREAD

    Kicad-to-HAL finds the other components attached to each pin and generates addf commands:

    #------
    # Function hookups
    
    # Position: 1
    
    addf hm2_5i25.0.read		servo-thread
     
    # Position: _
    
    addf and2.0		servo-thread
    addf constant.0		servo-thread
    addf constant.1		servo-thread
    addf not.0		servo-thread
    addf timedelay.0		servo-thread
    addf toggle.0		servo-thread
     
    # Position: -1
    
    addf hm2_5i25.0.write		servo-thread
    

    FiXME: Contrary to the comment in the symbol, addf commands for each pin come out sorted by reference.

    The Mesa hostmot2 HAL component (middle right in the first screenshot) generates several function names that don’t require connections, but Kicad-to-HAL produces a warning for single-pin (i.e. unconnected) nets with non-default names. Prefix the pin name with an asterisk (*read-gpio) to suppress the error message.

    The motion HAL component (lower right below) has functions that do not follow the normal naming convention:

    Servo Thread Hookup schematic
    Servo Thread Hookup schematic

    Prefix the Kicad pin name with a slash (/motion-controller) to tell Kicad-to-HAL to use the name without the standard motion. prefix:

    # Position: 2
    
    addf motion-command-handler		servo-thread
    addf motion-controller		servo-thread
    

    Perhaps they were supposed to be motion.command-handler and motion.controller, but it’s too late to change? If so, I know that feeling.

    Other quirks surely lurk within other HAL components, but, on the whole, this seems to work pretty well.

  • Thermal Laminator Un-jamming

    Thermal Laminator Un-jamming

    My AmazonBasics laminator wrapped a small card around one of its rollers and jammed solid:

    AmazonBasics laminator - interior bottom
    AmazonBasics laminator – interior bottom

    The lever sticking out on the lower right (above) drives the rollers in reverse by moving the motor from one gear to the other:

    AmazonBasics laminator - roller gears
    AmazonBasics laminator – roller gears

    Obviously, reverse gear wouldn’t get me anywhere, but dismantling the rollers required cutting the junction between the heating elements running through the aluminum extrusions:

    AmazonBasics laminator - heater junction
    AmazonBasics laminator – heater junction

    I spliced a few inches of wire onto those leads. If there’s a next time, I can cut the splice in the middle and use a wire nut.

    The white plastic curl in the lower right showed they ran a deburring tool around the exit slot and called it Good Enough™.

    The gears slide off the roller shafts and the rollers out of the extrusions, after which removing the tightly wrapped and completely useless card posed no problem.

    One lone, short, and eagerly self-tapping screw holds each plastic end plate to the extrusion, so be careful about cross-threading.

    All in all, this was easy enough, although I’m sure I was supposed to just throw the laminator away and buy a new one.

    Update: If you dislodged some of the wires, a few more pix of the interior may come in handy.

  • Defensive Driving Course

    Defensive Driving Course

    This year was my turn to take an online Defensive Driving Course to knock a few percent off our automobile insurance premium. It’s admittedly difficult to make traffic law interesting, but this was the worst-written, poorest-edited, and most factually incorrect course I have ever had the misfortune to waste eight hours of my life taking.

    For example:

    Emergency signals, also called emergency flashers or hazard warning devices, are flashing red lights found on the front and rear of the vehicle

    No, they’re amber on both ends of the vehicle. Flashing red on the front is reserved for vehicles with police and firefighters inside.

    … material used to block the sun from coming into a vehicle through the windshield and windows must have a luminous transmittance of less than 70%. That means the material must allow at least 30% of the light to pass through it

    No, lower transmittance means less light passing through the glass.

    I think the author and editors live in a part of the world once colonized by the British Empire:

    Driving class - mirror-image roadway crossing
    Driving class – mirror-image roadway crossing

    Here in New York State, we drive on the right.

    Update: scruss recalls the image in an old UK driving manual. It describes a type of pedestrian crossing unknown in the US.

    The sign recognition lesson claimed this sign marks a section of road with two-lane traffic:

    Driving class - 2-lane traffic
    Driving class – 2-lane traffic

    NYS DMV says it actually indicates two-way traffic on an undivided road.

    The course says this sign marks the point where the two-lane section ends:

    Driving class - lane reductIon
    Driving class – lane reductIon

    It really means a divided highway ends and two-way traffic begins.

    The course definitely offered amusing incorrect answers:

    Driving class - slippery area
    Driving class – slippery area

    The sign really means slippery when wet, but I suppose that’s in the nature of fine tuning.

    The closing page of the course told me I could take a survey, but, somehow, the survey never appeared.

  • Kicad-to-HAL: LoadRT

    Kicad-to-HAL: LoadRT

    Each Kicad LOADRT symbol (upper right):

    Kicad-to-HAL Demo Schematic
    Kicad-to-HAL Demo Schematic

    produces a corresponding HAL loadrt command:

    loadrt [KINS]KINEMATICS		# loadrt.0.0
    loadrt [EMCMOT]EMCMOT servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS		# loadrt.1.0
    loadrt hostmot2		# loadrt.2.0
    loadrt hm2_pci config="num_encoders=0 num_pwmgens=0 num_stepgens=4"		# loadrt.3.0
    

    Symbols with a (typically not-visble) + in their LoadRT field generate matching loadrt commands with the total number of identical symbols:

    loadrt and2 count=1<br>loadrt constant count=2<br>loadrt not count=1<br>loadrt timedelay count=1<br>loadrt toggle count=1
    

    Kicad symbols may have additional text after the (typically visible) + sign, as in the LOGIC symbol:

    Gamepad Valid schematic
    Gamepad Valid schematic

    Kicad-to-HAL will concatenate the text, in reference order, into the loadrt command:

    loadrt logic		count=1 personality=0x804
    

    The LOGIC symbol shows how that works:

    Kicad symbol - LOGIC
    Kicad symbol – LOGIC

    Edit the LoadRT field text as needed for each Kicad component, with subsequent blocks omitting the personality= and including a leading comma:

    + ,0x1004
    

    Because the order of the symbols matters, the symbol reference includes a number (the 0 in the symbol reference field) that you must edit by hand for each new schematic component, because the Kicad annotation tacked on the end will change every time you generate new annotations.

    The current version of Kicad-to-HAL sorts schematic references alphanumerically, so if you have more than ten LOGIC symbols with concatenated text, it won’t work: FIXME. Maybe annotating with Kicad numbers starting at 100, then subtracting 100 to get the HAL numbers would be simpler?

    Update: Yes, numbering from 100 works fine, along with automagically finding the lowest annotation and subtracting it. Upcoming snippets will show both ways.

    The Kicad LOGIC symbol has eight input pins and all five possible output pins, despite what the configuration value may create in the corresponding HAL function. As long as you don’t connect anything to the undefined inputs and outputs, Kicad turns them into one-pin anonymous nets which Kicad-to-HAL weeds out of the HAL file.

    The demo schematic as a GitHub Gist:

    EESchema Schematic File Version 4
    EELAYER 30 0
    EELAYER END
    $Descr USLetter 11000 8500
    encoding utf-8
    Sheet 1 1
    Title "Kicad-to-HAL Demo Schematic"
    Date "2021-03-23"
    Rev ""
    Comp "Ed Nisley – KE4ZNU"
    Comment1 ""
    Comment2 ""
    Comment3 ""
    Comment4 ""
    $EndDescr
    $Comp
    L LinuxCNC-HAL:THREAD servo-thread.0
    U 1 1 6059ED1C
    P 5650 5200
    F 0 "servo-thread.0" H 5650 5750 59 0000 C CNN
    F 1 "THREAD" H 5650 5650 50 0000 C CNN
    F 2 "" H 5750 5300 50 0001 C CNN
    F 3 "" H 5750 5300 50 0001 C CNN
    F 4 "1" H 6050 5650 50 0000 C CNN "StripAnno"
    1 5650 5200
    1 0 0 -1
    $EndComp
    $Comp
    L LinuxCNC-HAL:LOGITECH_GAMEPAD_GUF13A input.0.0
    U 2 1 605A12D7
    P 3000 3500
    F 0 "input.0.0" H 3000 5350 50 0000 C CNN
    F 1 "LOGITECH_GAMEPAD_GUF13A" H 2950 5250 50 0000 C CNN
    F 2 "" H 8500 7100 50 0001 C CNN
    F 3 "" H 8500 7100 50 0001 C CNN
    F 4 "1" H 3550 5250 50 0000 C CNN "StripAnno"
    F 5 "-W hal_input -KA Dual" H 2950 5150 50 0000 C CNN "LoadUsr"
    2 3000 3500
    1 0 0 -1
    $EndComp
    $Comp
    L LinuxCNC-HAL:AND2 and2.0
    U 1 1 605A4CD8
    P 4350 3300
    F 0 "and2.0" H 4350 3500 50 0000 C CNN
    F 1 "AND2" H 4350 3300 50 0000 C CNN
    F 2 "" H 4350 3300 50 0001 C CNN
    F 3 "" H 4350 3300 50 0001 C CNN
    F 4 "+" H 4350 3300 50 0001 C CNN "LoadRT"
    1 4350 3300
    1 0 0 -1
    $EndComp
    Wire Wire Line
    3700 3800 3850 3800
    Wire Wire Line
    3850 3800 3850 3400
    Wire Wire Line
    3850 3400 4050 3400
    Wire Wire Line
    4050 3200 3700 3200
    $Comp
    L LinuxCNC-HAL:TOGGLE toggle.0
    U 1 1 605A7FF1
    P 5750 3400
    F 0 "toggle.0" H 5750 3700 50 0000 C CNN
    F 1 "TOGGLE" H 5750 3600 50 0000 C CNN
    F 2 "" H 6050 3350 50 0001 C CNN
    F 3 "" H 6050 3350 50 0001 C CNN
    F 4 "+" H 5750 3400 50 0001 C CNN "LoadRT"
    1 5750 3400
    1 0 0 -1
    $EndComp
    $Comp
    L LinuxCNC-HAL:PARAMETER parameter.0
    U 1 1 605A8894
    P 4950 3500
    F 0 "parameter.0" H 4950 3600 50 0001 C CNN
    F 1 "5" H 5150 3500 50 0000 R CNN
    F 2 "" H 5250 3500 50 0001 C CNN
    F 3 "" H 5250 3500 50 0001 C CNN
    1 4950 3500
    1 0 0 -1
    $EndComp
    $Comp
    L LinuxCNC-HAL:HM2_5I25 hm2_5i25.0.0
    U 1 1 605A8E84
    P 7700 4300
    F 0 "hm2_5i25.0.0" H 7700 4800 50 0000 C CNN
    F 1 "HM2_5I25" H 7700 4700 50 0000 C CNN
    F 2 "" H 8250 4100 50 0001 C CNN
    F 3 "" H 8250 4100 50 0001 C CNN
    F 4 "1" H 8100 4700 50 0000 C CNN "StripAnno"
    1 7700 4300
    1 0 0 -1
    $EndComp
    Wire Wire Line
    4650 3300 5450 3300
    Wire Wire Line
    5350 3500 5500 3500
    Wire Wire Line
    6100 3300 6950 3300
    Wire Wire Line
    7150 4550 6900 4550
    Wire Wire Line
    6900 4550 6900 5550
    Wire Wire Line
    6900 5550 6200 5550
    $Comp
    L LinuxCNC-HAL:LOADRT loadrt.3.?
    U 1 1 605AF190
    P 5000 2950
    AR Path="/6047689B/605AF190" Ref="loadrt.3.?" Part="1"
    AR Path="/605AF190" Ref="loadrt.3.0" Part="1"
    F 0 "loadrt.3.0" H 5000 3200 50 0000 C CNN
    F 1 "LOADRT" H 4950 3100 50 0000 C CNN
    F 2 "" H 5800 2450 50 0001 C CNN
    F 3 "https://linuxcnc.org/docs/2.8/html/hal/basic-hal.html#_loadrt&quot; H 5800 2450 50 0001 C CNN
    F 4 "hm2_pci config=\"num_encoders=0 num_pwmgens=0 num_stepgens=4\"" H 4750 3000 50 0000 L CNN "LoadRT"
    F 5 "1" H 5250 3100 50 0000 C CNN "StripAnno"
    1 5000 2950
    1 0 0 -1
    $EndComp
    $Comp
    L LinuxCNC-HAL:LOADRT loadrt.2.?
    U 1 1 605AF198
    P 5000 2600
    AR Path="/6047689B/605AF198" Ref="loadrt.2.?" Part="1"
    AR Path="/605AF198" Ref="loadrt.2.0" Part="1"
    F 0 "loadrt.2.0" H 5000 2850 50 0000 C CNN
    F 1 "LOADRT" H 4950 2750 50 0000 C CNN
    F 2 "" H 5800 2100 50 0001 C CNN
    F 3 "https://linuxcnc.org/docs/2.8/html/hal/basic-hal.html#_loadrt&quot; H 5800 2100 50 0001 C CNN
    F 4 "hostmot2" H 4750 2650 50 0000 L CNN "LoadRT"
    F 5 "1" H 5250 2750 50 0000 C CNN "StripAnno"
    1 5000 2600
    1 0 0 -1
    $EndComp
    Text GLabel 6450 5200 2 50 Output ~ 0
    _
    $Comp
    L LinuxCNC-HAL:LOADRT loadrt.0.?
    U 1 1 605B697F
    P 5000 1900
    AR Path="/6047689B/605B697F" Ref="loadrt.0.?" Part="1"
    AR Path="/605B697F" Ref="loadrt.0.0" Part="1"
    F 0 "loadrt.0.0" H 5000 2150 50 0000 C CNN
    F 1 "LOADRT" H 4950 2050 50 0000 C CNN
    F 2 "" H 5800 1400 50 0001 C CNN
    F 3 "https://linuxcnc.org/docs/2.8/html/hal/basic-hal.html#_loadrt&quot; H 5800 1400 50 0001 C CNN
    F 4 "[KINS]KINEMATICS" H 4750 1950 50 0000 L CNN "LoadRT"
    F 5 "1" H 5250 2050 50 0000 C CNN "StripAnno"
    1 5000 1900
    1 0 0 -1
    $EndComp
    $Comp
    L LinuxCNC-HAL:LOADRT loadrt.1.?
    U 1 1 605B6987
    P 5000 2250
    AR Path="/6047689B/605B6987" Ref="loadrt.1.?" Part="1"
    AR Path="/605B6987" Ref="loadrt.1.0" Part="1"
    F 0 "loadrt.1.0" H 5000 2500 50 0000 C CNN
    F 1 "LOADRT" H 4950 2400 50 0000 C CNN
    F 2 "" H 5800 1750 50 0001 C CNN
    F 3 "https://linuxcnc.org/docs/2.8/html/hal/basic-hal.html#_loadrt&quot; H 5800 1750 50 0001 C CNN
    F 4 "[EMCMOT]EMCMOT servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS" H 4750 2300 50 0000 L CNN "LoadRT"
    F 5 "1" H 5250 2400 50 0000 C CNN "StripAnno"
    1 5000 2250
    1 0 0 -1
    $EndComp
    Wire Wire Line
    6200 5200 6450 5200
    Wire Wire Line
    6700 4450 7150 4450
    Wire Wire Line
    6700 4450 6700 4850
    Wire Wire Line
    6700 4850 6200 4850
    $Comp
    L LinuxCNC-HAL:TIMEDELAY timedelay.0
    U 1 1 605C692D
    P 5200 4250
    F 0 "timedelay.0" H 5200 4600 50 0000 C CNN
    F 1 "TIMEDELAY" H 5200 4500 50 0000 C CNN
    F 2 "" H 5200 4400 50 0001 C CNN
    F 3 "" H 5200 4400 50 0001 C CNN
    F 4 "+" H 5200 4250 50 0001 C CNN "LoadRT"
    1 5200 4250
    1 0 0 -1
    $EndComp
    $Comp
    L LinuxCNC-HAL:CONSTANT constant.0
    U 1 1 605C7C1F
    P 4350 4300
    F 0 "constant.0" H 4350 4400 50 0001 C CNN
    F 1 "[BLINKY]ON" H 4500 4300 50 0000 R CNN
    F 2 "" H 4600 4050 50 0001 C CNN
    F 3 "" H 4600 4050 50 0001 C CNN
    F 4 "+" H 4350 4300 50 0001 C CNN "LoadRT"
    1 4350 4300
    1 0 0 -1
    $EndComp
    $Comp
    L LinuxCNC-HAL:CONSTANT constant.1
    U 1 1 605C822C
    P 4350 4400
    F 0 "constant.1" H 4350 4500 50 0001 C CNN
    F 1 "[BLINKY]OFF" H 4500 4400 50 0000 R CNN
    F 2 "" H 4600 4150 50 0001 C CNN
    F 3 "" H 4600 4150 50 0001 C CNN
    F 4 "+" H 4350 4400 50 0001 C CNN "LoadRT"
    1 4350 4400
    1 0 0 -1
    $EndComp
    Wire Wire Line
    4750 4300 4850 4300
    Wire Wire Line
    4750 4400 4850 4400
    Wire Wire Line
    7150 4000 6950 4000
    Wire Wire Line
    6950 4000 6950 3300
    $Comp
    L LinuxCNC-HAL:NOT not.0
    U 1 1 605D425F
    P 6000 4100
    F 0 "not.0" H 6100 4250 50 0000 C CNN
    F 1 "NOT" H 6000 4100 50 0000 C CNN
    F 2 "" H 6350 3850 50 0001 C CNN
    F 3 "" H 6350 3850 50 0001 C CNN
    F 4 "+" H 6000 4100 50 0001 C CNN "LoadRT"
    1 6000 4100
    1 0 0 -1
    $EndComp
    Wire Wire Line
    5550 4100 5750 4100
    Wire Wire Line
    6450 4100 6600 4100
    Wire Wire Line
    6600 4100 6600 3800
    Wire Wire Line
    6600 3800 4700 3800
    Wire Wire Line
    4700 3800 4700 4100
    Wire Wire Line
    4700 4100 4850 4100
    Wire Wire Line
    6600 4100 7150 4100
    Connection ~ 6600 4100
    $EndSCHEMATC
    [EMCMOT]
    EMCMOT = motmod
    COMM_TIMEOUT = 1.0
    SERVO_PERIOD = 1000000
    [KINS]
    JOINTS = 4
    KINEMATICS = trivkins coordinates=XYZA
    [BLINKY]
    ON = 0.2
    OFF = 2.0
    view raw machine.ini hosted with ❤ by GitHub
    # LinuxCNC HAL file
    # Kicad netlist: LinuxCNC Test Schematic.xml
    # Tue 23 Mar 2021 10:47:04 AM EDT
    #——
    # LoadRT modules
    loadrt [KINS]KINEMATICS # loadrt.0.0
    loadrt [EMCMOT]EMCMOT servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS # loadrt.1.0
    loadrt hostmot2 # loadrt.2.0
    loadrt hm2_pci config="num_encoders=0 num_pwmgens=0 num_stepgens=4" # loadrt.3.0
    loadrt and2 count=1
    loadrt constant count=2
    loadrt not count=1
    loadrt timedelay count=1
    loadrt toggle count=1
    #——
    # LoadUsr modules
    loadusr -W hal_input -KA Dual # input.0.0
    #——
    # Function hookups
    # Position: 1
    addf hm2_5i25.0.read servo-thread
    # Position: _
    addf and2.0 servo-thread
    addf constant.0 servo-thread
    addf constant.1 servo-thread
    addf not.0 servo-thread
    addf timedelay.0 servo-thread
    addf toggle.0 servo-thread
    # Position: -1
    addf hm2_5i25.0.write servo-thread
    #——
    # Parameters
    setp toggle.0.debounce 5 # parameter.0
    #——
    # Constants
    setp constant.0.value [BLINKY]ON
    setp constant.1.value [BLINKY]OFF
    #——
    # Nets
    net N_001 <= constant.1.out => timedelay.0.off-delay
    net N_002 <= constant.0.out => timedelay.0.on-delay
    net N_003 <= not.0.out => hm2_5i25.0.led.CR02 timedelay.0.in
    net N_004 <= toggle.0.out => hm2_5i25.0.led.CR01
    net N_006 <= and2.0.out => toggle.0.in
    net N_007 <= timedelay.0.out => not.0.in
    net N_008 <= input.0.btn-top2 => and2.0.in0
    net N_009 <= input.0.btn-base => and2.0.in1
    #——
    # Done!

  • Kicad-to-HAL: Basic Schematic Symbols

    Kicad-to-HAL: Basic Schematic Symbols

    The LinuxCNC definition of the HAL NOT component looks like this:

    LinuxCNC HAL component - NOT
    LinuxCNC HAL component – NOT

    The loadrt command uses the “module name”, which is the file name of the module.

    Functions and Pins use the “function name”, as defined by whatever code lives inside the module.

    As a rule of thumb, module names will have underscores between words, where the corresponding function name will have hyphens, but this is not mandatory.

    The numeric suffix on the Function name tells you which of the many identical components it is.

    The Pin names generally have the Function name and numeric suffix as their prefix.

    The NOT gate symbol in LinuxCNC-HAL.lib looks like this:

    Kicad symbol - NOT
    Kicad symbol – NOT

    Note that there is no Kicad footprint: these components will never see a circuit board.

    The symbol Reference (above the symbol: not.) must match the HAL Function name and must end in a period to make the Kicad numeric annotation easily separable. Jellybean components use the Kicad annotation as their identifier, so that the references will look like not.0, not.1, and so on.

    The symbol Value (inside the symbol: NOT) must match the HAL module name; it will be lowercaseified as needed.

    Kicad pin names must match the HAL pin names, must use only Kicad’s Input and Output “Electrical Type”, and must use only the Line “Graphic Style”. Kicad-to-HAL will glue the pin onto the Kicad reference with a period in between (not.0.out) for use in the HAL configuration.

    I made the pins names visible for that screenshot. For a graphical component like this, I generally make them invisible.

    The “Power input” pin is named “_” (a single underscore) and, in this case, is invisible. Kicad will automagically connect all such pins into a single net, so including a corresponding pin on a THREAD component (more about this later) will invoke Kicad-to-HAL magick connecting the function name (with the numeric suffix) to the appropriate thread:

    addf not.0 servo-thread
    

    The light gray + in the middle of the symbol (not quite centered in the O of NOT) comes from the LoadRT field you must include in the symbol properties:

    Kicad Symbol Properties - NOT
    Kicad Symbol Properties – NOT

    That tells Kicad-to-HAL to add up the total number of NOT components and generate an appropriate loadrt command:

    loadrt not		count=1
    

    Not having to count the damn symbols, keep track of their numeric suffixes, and manually generate the addf commands justified this entire project.

  • Kicad-to-HAL: Proof of Concept

    Kicad-to-HAL: Proof of Concept

    So it turns out a few hundred lines of Python can convert a Kicad schematic:

    Gamepad Axis Priority - schematic sample
    Gamepad Axis Priority – schematic sample

    Into a LinuxCNC HAL machine configuration file:

    loadrt and2		count=22 
    loadrt flipflop		count=5 
    loadrt not		count=8 
    <<< … etc … >>>
    
    addf and2.0		servo-thread
    <<< … etc … >>>
    
    net X-Knob-Active <= or2.2.out => and2.1.in0 not.0.in
    net X-Knob-Inactive <= not.0.out => and2.2.in0 and2.3.in0
    <<< … etc … >>>
    net Y-Knob-Active <= or2.3.out => and2.3.in1 not.1.in
    net Y-Knob-Inactive <= not.1.out => and2.2.in1
    <<< … etc … >>>
    net _Axis_Priority_XY-Reset <= and2.2.out => flipflop.0.reset flipflop.1.reset
    net _Axis_Priority_Y-Disable <= not.5.out => and2.1.in1
    net _Axis_Priority_Y-Select <= and2.3.out => and2.7.in0
    net _Axis_Priority_Y-Set <= and2.7.out => flipflop.1.set
    

    The Kicad schematic interconnects components from a library defining LinuxCNC HAL devices:

    Kicad symbol - AND2
    Kicad symbol – AND2

    The process goes a little something like this:

    • Draw schematic using components in LinuxCNC-HAL.lib
    • Add missing components to LinuxCNC-HAL.lib
    • Iterate
    • Annotate schematic (starting from 0)
    • Generate netlist in XML format
    • Run Kicad-to-HAL.py with Python 3.9.2 (sorry)
    • Fix whatever LinuxCNC complains about
    • Iterate
    • Fix logic flaws by adjusting schematic
    • Iterate

    The Kicad components include magick HAL features, the Python program rides roughshod over Kicad conventions, and this thing stands deep in “It works for me!” territory, but I must coerce my notes into something resembling coherence before I forget the grisly details.

    More to follow, but you can peruse the Python3 source code and Kicad library as a GitHub Gist:

    # Parse Kicad schematic netlist into a LinuxCNC HAL configuration file
    #
    # Ed Nisley – KE4ZNU
    # 2021-03
    import argparse
    from pathlib import Path
    from lxml import etree
    # ———-
    # remove Kicad annotation from reference as needed
    # kref = Kicad annotated reference
    # component has field entries for anything other than and value
    def cleanHALref(kref):
    comp = etree.XPath('comp[@ref="' + kref + '"]')(components)[0]
    fields = etree.XPath('fields/field[@name="StripAnno"]')(comp)
    if len(fields) and (fields[0].text).startswith("1"):
    retval = kref.rpartition(".")[0]
    else:
    retval = kref
    # print('strip: {} -> {}'.format(kref,retval))
    return retval
    # ———-
    # do the whole thing
    parser = argparse.ArgumentParser(
    description="Process Kicad schematic netlist into LinuxCNC HAL configuration file"
    )
    parser.add_argument("netlist", help="input: Kicad XML netlist file describing HAL configuration")
    parser.add_argument("hal", help="output: LinuxCNC HAL configuration file")
    args = parser.parse_args()
    xmlfn = Path(args.netlist)
    if not xmlfn.exists():
    print("** No such file: {!s}".format(xmlfn))
    exit()
    print("Opening XML file: {!s}".format(xmlfn))
    Netlist = etree.parse(xmlfn.name)
    halfn = Path(args.hal)
    if halfn is None:
    halfn = xmlfn.with_name(xmlfn.stem + ".hal")
    print("Writing HAL file: {!s}".format(halfn))
    halfile = open(halfn, "w")
    design = etree.XPath("//design")(Netlist)[0]
    print("XML date: {}".format(etree.XPath("date")(design)[0].text))
    libraries = etree.XPath("//libraries")(Netlist)[0]
    print("Libraries:")
    for l in libraries:
    print(" {}".format(etree.XPath("uri")(l)[0].text))
    components = etree.XPath("//components")(Netlist)[0]
    print("Components: {:.0f}".format(etree.XPath("count(comp)")(components)))
    libparts = etree.XPath("//libparts")(Netlist)[0]
    print("Library parts: {:.0f}".format(etree.XPath("count(libpart)")(libparts)))
    nets = etree.XPath("//nets")(Netlist)[0]
    print("Nets: {:.0f}".format(etree.XPath("count(net)")(nets)))
    halfile.write("# LinuxCNC HAL file\n\n# Kicad netlist: {}\n".format(xmlfn))
    halfile.write("# {}\n\n".format(etree.XPath("date")(design)[0].text))
    # —–
    # load realtime modules
    # LOADRT components
    comps = etree.XPath('comp[value="LOADRT"]')(components)
    comps.sort(key=lambda r: r.attrib["ref"])
    # print('LRT sort: {}'.format(comps))
    llist = []
    for comp in comps:
    ref = comp.attrib["ref"]
    fld = etree.XPath('fields/field[@name="LoadRT"]')(comp)[0]
    # print(' cfg: {} -> {}'.format(ref,fld.text))
    llist += ["loadrt {}\t\t# {}".format(fld.text, ref)]
    if len(llist):
    llist += [" "]
    # collect all other components with a LoadRT field
    # a leading + indicates a component using Kicad reference counting
    # concatenate rest of field in order of ref sequence
    rtfs = etree.XPath('comp[value!="LOADRT"]/fields/field[@name="LoadRT"]')(components)
    # print('Flds: {}'.format(rtfs))
    rtfs.sort(key=lambda f: f.xpath("ancestor::comp")[0].attrib["ref"])
    modules = {}
    for f in rtfs:
    comp = etree.XPath("ancestor::comp")(f)[0]
    ref = comp.attrib["ref"]
    mod = (etree.XPath("libsource")(comp)[0]).attrib["part"]
    # print(' ref: {} mod: {}'.format(ref,mod))
    if f.text.startswith("+"):
    if mod in modules:
    modules[mod][0] += 1
    modules[mod][1] += f.text.lstrip("+ ")
    else:
    modules.update({mod: [1, f.text.lstrip("+ ")]})
    # print(" added {} {}".format(mod,modules[mod]))
    else:
    llist += ["loadrt {}\t{}\t\t# {}".format(mod, f.text, ref)]
    if len(modules):
    # print('modules: {}'.format(modules))
    for mod, v in sorted(modules.items(), key=lambda kv: kv[0]):
    llist += ["loadrt {}\t\tcount={} {}".format(mod.lower(), v[0], v[1])]
    if len(llist):
    halfile.write("\n#——\n# LoadRT modules\n\n")
    halfile.write("\n".join(llist) + "\n")
    # —–
    # collect LoadUsr fields from components
    llist = []
    ufs = etree.XPath('comp/fields/field[@name="LoadUsr"]')(components)
    # print('Flds: {}'.format(ufs))
    for f in ufs:
    comp = etree.XPath("ancestor::comp")(f)[0]
    ref = comp.attrib["ref"]
    if len(f.text):
    llist += ["loadusr {}\t\t# {}".format(f.text, ref)]
    if len(llist):
    halfile.write("\n#——\n# LoadUsr modules\n\n")
    halfile.write("\n".join(llist) + "\n")
    # —–
    # collect power-input pins into addf statements
    halfile.write("\n#——\n# Function hookups\n\n")
    addflist = []
    # find library THREAD part to get pins for addf sequencing
    tpart = etree.XPath('libpart[@part="THREAD"]')(libparts)[0]
    tpins = etree.XPath("pins/pin")(tpart)
    # print('tpart: {}'.format(tpart))
    # print('tpins: {}'.format(tpins))
    # step through all THREAD components
    tcomps = etree.XPath('comp[value="THREAD"]')(components)
    # print('tcomps: {}'.format(tcomps))
    for tcomp in tcomps:
    tcref = tcomp.attrib["ref"]
    # print('tcomp: {} tref: {}'.format(tcomp,tcref))
    for tpin in tpins:
    pnum = tpin.attrib["num"]
    pname = tpin.attrib["name"]
    # use pin number to find other nodes in net
    pnode = etree.XPath('net/node[@ref="' + tcref + '" and @pin="' + pnum + '"]')(nets)[0]
    nodes = etree.XPath("preceding-sibling::node")(pnode)
    nodes += etree.XPath("following-sibling::node")(pnode)
    # print('nodes: {}'.format(nodes))
    if len(nodes) == 0:
    continue
    nlist = ["# Position: " + pname + "\n"]
    # print(' thread position: {}'.format(pname))
    for node in nodes:
    ref = node.attrib["ref"]
    cleanref = cleanHALref(ref)
    pin = node.attrib["pin"]
    # print(' node: {} ref: {} = {} pin: {}'.format(node,ref,cleanref,pin))
    # look up destination pin name to weed out "_" defaults
    # and find "/" prefix indicating no ref prefix
    dval = etree.XPath('comp[@ref="' + ref + '"]/value')(components)[0]
    # print(' dval: {} {}'.format(dval,dval.text))
    dsrc = etree.XPath('comp[@ref="' + ref + '"]/libsource')(components)[0]
    dpart = dsrc.attrib["part"]
    # print(' dsrc: {} {}'.format(dsrc,dpart))
    ldparts = etree.XPath('libpart[@part="' + dpart + '"]')(libparts)
    # print(' ldparts: {}'.format(ldparts))
    if len(ldparts):
    ldpart = ldparts[0]
    ldpin = etree.XPath('pins/pin[@num="' + pin + '"]')(ldpart)[0]
    ldpname = ldpin.attrib["name"]
    # print(' ldpin: {} name: {} part: {}'.format(ldpin,ldpname,dpart))
    if ldpname == "_":
    nlist += ["addf {}\t\t{}".format(cleanref, cleanHALref(tcref))]
    else:
    if ldpname.startswith("/"):
    nlist += [
    "addf {}\t\t{}".format(ldpname.removeprefix("/"), cleanHALref(tcref))
    ]
    else:
    nlist += ["addf {}.{}\t\t{}".format(cleanref, ldpname, cleanHALref(tcref))]
    if pname == "_":
    nlist.sort()
    addflist += nlist + [" "]
    if len(addflist):
    halfile.write("\n".join(addflist) + "\n")
    # —–
    # set parameter values
    # trace through nets to find other nodes to set
    params = 0
    parlist = []
    for comp in components:
    ref = comp.attrib["ref"]
    # ignore non-parameter components
    if not ref.startswith("parameter."):
    continue
    params += 1
    value = etree.XPath("value")(comp)[0].text
    # print('param: {} = {}'.format(ref,value))
    pnode = etree.XPath('net/node[@ref="' + ref + '"]')(nets)[0]
    nodes = etree.XPath("preceding-sibling::node")(pnode) + etree.XPath("following-sibling::node")(
    pnode
    )
    for node in nodes:
    nref = node.attrib["ref"]
    npin = node.attrib["pin"]
    ncomp = etree.XPath('comp[@ref="' + nref + '"]')(components)[0]
    nls = etree.XPath("libsource")(ncomp)[0]
    nname = nls.attrib["part"]
    lpart = etree.XPath('libpart[@part="' + nname + '"]')(libparts)[0]
    lpin = etree.XPath('pins/pin[@num="' + npin + '"]')(lpart)[0]
    # print('ref: {} nref: {} npin: {} lpin: {}'.format(ref,cleanHALref(nref),npin,lpin))
    parlist += [
    "setp {}.{} {}\t\t# {}".format(cleanHALref(nref), lpin.attrib["name"], value, ref)
    ]
    if len(parlist):
    halfile.write("\n#——\n# Parameters\n\n")
    parlist.sort()
    halfile.write("\n".join(parlist) + "\n")
    print("Parameters: {}".format(params))
    # —–
    # set constant parameters
    # the .value pin is hardcoded here to keep the schematic part tidy
    consts = 0
    conlist = []
    for comp in components:
    ref = comp.attrib["ref"]
    # ignore non-constant components
    if not ref.startswith("constant."):
    continue
    consts += 1
    value = etree.XPath("value")(comp)[0].text
    # print('const: {} = {}'.format(ref,value))
    pval = ref + ".value"
    conlist += ["setp {} {}".format(pval, value)]
    if len(conlist):
    halfile.write("\n#——\n# Constants\n\n")
    conlist.sort()
    halfile.write("\n".join(conlist) + "\n")
    print("Constants: {}".format(consts))
    # —–
    # generate HAL net connections
    halfile.write("\n#——\n# Nets\n\n")
    hallist = []
    single = 0
    multi = 0
    netID = 1
    for net in nets:
    name = net.attrib["name"]
    # skip special net for unconnected addf functions
    if name == "_":
    multi += 1
    continue
    # print('net {}'.format(net.attrib))
    nodes = etree.XPath("node")(net)
    # skip single-pin nets
    # suppress error for pin names starting with *
    if len(nodes) < 2:
    if not (name.startswith("Net-") or name.startswith("*")):
    hallist += [
    "#* Named net with single pin: {} {}\n".format(nodes[0].attrib["ref"], name)
    ]
    single += 1
    continue
    nameclean = name.translate(name.maketrans("/ ", "__", "()"))
    # print('name: {} -> {}'.format(name,nameclean))
    multi += 1
    halstr = "net "
    halsinks = []
    outputs = 0
    for node in nodes:
    ref = node.attrib["ref"]
    pnum = node.attrib["pin"]
    # print('node: {}'.format(node.attrib))
    comp = etree.XPath('comp[@ref="' + ref + '"]')(components)[0]
    ls = etree.XPath("libsource")(comp)[0]
    # print('libsource: {}'.format(ls.attrib))
    lpart = etree.XPath('libpart[@part="' + ls.attrib["part"] + '"]')(libparts)[0]
    # print('libpart: {}'.format(lpart.attrib))
    lpin = etree.XPath('pins/pin[@num="' + pnum + '"]')(lpart)[0]
    pname = lpin.attrib["name"]
    cleanname = pname.lstrip("*")
    ptype = lpin.attrib["type"]
    # print('pin: {} {}'.format(ptype,pname))
    if ptype == "output":
    if name.startswith("Net-"):
    halstr += "N_{:0>3d} <= {}.{} => ".format(netID, cleanHALref(ref), cleanname)
    netID += 1
    else:
    halstr += "{} <= {}.{} => ".format(nameclean, cleanHALref(ref), cleanname)
    outputs += 1
    else:
    halsinks += [cleanHALref(ref) + "." + cleanname]
    halstr += " ".join(sorted(halsinks))
    if "parameter" in halstr or "-thread" in halstr: # discard parameters and threads
    # print('discard: {}'.format(halstr))
    multi -= 1
    continue
    elif outputs == 0:
    halstr = "#* No output pins: {}\n".format(halstr)
    elif outputs > 1:
    halstr = "#* Multiple output pins: {}\n".format(halstr)
    # print('result {}'.format(halstr))
    hallist += [halstr]
    if len(hallist):
    hallist.sort()
    halfile.write("\n".join(hallist) + "\n")
    halfile.write("\n#——\n# Done!\n")
    halfile.close()
    # print(' = 1 : {:d}'.format(single))
    # print(' > 1 : {:d}'.format(multi))
    view raw Kicad-to-HAL.py hosted with ❤ by GitHub
    EESchema-LIBRARY Version 2.4
    #encoding utf-8
    #
    # AND2
    #
    DEF AND2 and2. 0 0 N Y 1 F N
    F0 "and2." 0 200 50 H V C CNN
    F1 "AND2" 0 0 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    A 0 0 150 0 900 0 1 0 f 150 0 0 150
    A 0 0 150 0 -900 0 1 0 f 150 0 0 -150
    P 4 0 1 0 0 150 -150 150 -150 -150 0 -150 f
    X in0 1 -300 100 150 R 50 50 1 1 I
    X in1 2 -300 -100 150 R 50 50 1 1 I
    X out 3 300 0 150 L 50 50 1 1 O
    X _ 4 -250 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # COMP
    #
    DEF COMP comp. 0 20 N Y 1 F N
    F0 "comp." -50 300 50 H V C CNN
    F1 "COMP" -50 200 50 H V C CNN
    F2 "" 300 -50 50 H I C CNN
    F3 "" 300 -50 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    T 0 -100 -50 50 0 0 0 + Normal 0 C C
    T 0 -100 50 50 0 0 0 – Normal 0 C C
    S 200 150 -300 250 0 1 0 f
    S -300 150 200 -350 1 1 0 N
    X in0 1 -400 50 100 R 50 50 1 1 I
    X out 2 300 50 100 L 50 50 1 1 O
    X in1 3 -400 -50 100 R 50 50 1 1 I
    X hyst 4 -400 -250 154 R 50 50 1 1 I I
    X _ 5 -400 -150 100 R 50 50 1 1 W NC
    X equal 6 300 -50 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # CONSTANT
    #
    DEF CONSTANT constant. 0 0 N N 1 F N
    F0 "constant." 0 100 50 H I C CNN
    F1 "CONSTANT" 150 0 50 H V R CNN
    F2 "" 250 -250 50 H I C CNN
    F3 "" 250 -250 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    P 4 0 1 0 -250 50 200 50 200 -50 -250 -50 N
    X out 1 400 0 200 L 50 50 1 1 O
    X _ 2 -350 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # CONV_FLOAT_S32
    #
    DEF CONV_FLOAT_S32 conv-float-s32. 0 20 N Y 1 F N
    F0 "conv-float-s32." 0 300 50 H V C CNN
    F1 "CONV_FLOAT_S32" 0 200 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "+" 0 100 50 H I C CNN "LoadRT"
    DRAW
    S 400 150 -400 250 0 1 0 f
    S -400 150 400 -150 1 1 0 N
    X in 1 -500 100 100 R 50 50 1 1 I
    X clamp 2 -500 -100 157 R 50 50 1 1 I I
    X out-of-range 3 500 0 100 L 50 50 1 1 O
    X out 4 500 100 100 L 50 50 1 1 O
    X _ 5 -500 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # CONV_FLOAT_U32
    #
    DEF CONV_FLOAT_U32 conv-float-u32. 0 40 N Y 1 F N
    F0 "conv-float-u32." 0 300 50 H V C CNN
    F1 "CONV_FLOAT_U32" 0 200 50 H V C CNN
    F2 "" 0 50 50 H I C CNN
    F3 "" 0 50 50 H I C CNN
    F4 "+" 0 100 50 H I C CNN "LoadRT"
    DRAW
    S -400 150 400 -150 1 1 0 N
    S 400 150 -400 250 1 1 0 f
    X in 1 -500 100 100 R 50 50 1 1 I
    X clamp 2 -500 -100 157 R 50 50 1 1 I I
    X out-of-range 3 500 0 100 L 50 50 1 1 O
    X out 4 500 100 100 L 50 50 1 1 O
    X _ 5 -500 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # DBOUNCE
    #
    DEF DBOUNCE dbounce. 0 20 N Y 1 F N
    F0 "dbounce." 0 300 50 H V C CNN
    F1 "DBOUNCE" 0 200 50 H V C CNN
    F2 "" 600 -350 50 H I C CNN
    F3 "" 600 -350 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 200 150 -200 250 0 1 0 f
    S -200 150 200 -150 1 1 0 N
    X in 1 -300 100 100 R 50 50 1 1 I
    X out 2 300 100 100 L 50 50 1 1 O
    X delay 3 -300 -100 100 R 50 50 1 1 I
    X _ 4 -300 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # FLIPFLOP
    #
    DEF FLIPFLOP flipflop. 0 20 N Y 1 F N
    F0 "flipflop." 0 450 50 H V C CNN
    F1 "FLIPFLOP" 0 350 50 H V C CNN
    F2 "" 400 -150 50 H I C CNN
    F3 "" 400 -150 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 200 300 -200 400 0 1 0 f
    S -200 300 200 -300 1 1 0 N
    X data 2 -300 200 100 R 50 50 1 0 I
    X out 5 300 0 100 L 50 50 1 0 O
    X reset 1 -300 -200 100 R 50 50 1 1 I
    X clk 3 -300 100 100 R 50 50 1 1 I
    X set 4 -300 -100 100 R 50 50 1 1 I
    X _ 6 -300 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # HALUI
    #
    DEF HALUI halui. 0 40 N Y 1 F N
    F0 "halui." 0 500 59 H V C CNN
    F1 "HALUI" 0 400 50 H V C CNN
    F2 "" -150 300 50 H I C CNN
    F3 "" -150 300 50 H I C CNN
    F4 "1" 350 400 50 H V C CNN "StripAnno"
    DRAW
    S -400 -300 400 350 0 1 0 N
    S -400 450 400 350 0 1 0 f
    X abort 1 -500 250 100 R 0 50 1 0 I
    X home-all 2 -500 100 100 R 50 50 1 1 I
    X mdi-command-00 ~ -500 -100 100 R 50 50 1 1 I
    X mdi-command-01 ~ -500 -200 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_AXIS
    #
    DEF HALUI_AXIS halui.axis. 0 40 N Y 1 F N
    F0 "halui.axis." 0 400 50 H V C CNN
    F1 "HALUI_AXIS" 0 300 50 H V C CNN
    F2 "" 450 400 50 H I C CNN
    F3 "" 450 400 50 H I C CNN
    F4 "1" 500 300 50 H V C CNN "StripAnno"
    DRAW
    S -550 -50 550 250 0 1 0 N
    S 550 350 -550 250 0 1 0 f
    X jog-deadband 1 -650 50 100 R 50 50 1 1 I
    X jog-speed 2 -650 150 100 R 50 50 1 1 I
    X selected 3 650 150 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_AXIS_L
    #
    DEF HALUI_AXIS_L halui.axis.x. 0 40 N Y 1 F N
    F0 "halui.axis.x." 0 400 50 H V C CNN
    F1 "HALUI_AXIS_L" 0 300 50 H V C CNN
    F2 "" -100 350 50 H I C CNN
    F3 "" -100 350 50 H I C CNN
    F4 "1" 600 300 50 H V C CNN "StripAnno"
    DRAW
    S -650 350 650 250 0 1 0 f
    S 650 250 -650 -600 0 1 0 N
    X analog 1 -750 50 100 R 50 50 1 1 I
    X pos-relative 10 750 -150 100 L 50 50 1 1 O
    X select 11 -750 200 100 R 50 50 1 1 I
    X increment 2 -750 -100 100 R 50 50 1 1 I
    X increment-minus 3 -750 -200 100 R 50 50 1 1 I
    X increment-plus 4 -750 -300 100 R 50 50 1 1 I
    X is-selected 5 750 200 100 L 50 50 1 1 O
    X minus 6 -750 -450 100 R 50 50 1 1 I
    X plus 7 -750 -550 100 R 50 50 1 1 I
    X pos-commanded 8 750 50 100 L 50 50 1 1 O
    X pos-feedback 9 750 -50 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_AXIS_SELECTED
    #
    DEF HALUI_AXIS_SELECTED halui.axis.selected. 0 40 N Y 1 F N
    F0 "halui.axis.selected." 50 400 50 H V C CNN
    F1 "HALUI_AXIS_SELECTED" 50 300 50 H V C CNN
    F2 "" 1200 850 50 H I C CNN
    F3 "" 1200 850 50 H I C CNN
    F4 "1" 550 300 50 H V C CNN "StripAnno"
    DRAW
    S -500 -500 600 250 1 1 0 N
    S 600 350 -500 250 1 1 0 f
    X increment 1 -600 150 100 R 50 50 1 1 I
    X increment-minus 2 -600 0 100 R 50 50 1 1 I
    X increment-plus 3 -600 -100 100 R 50 50 1 1 I
    X minus 4 -600 -300 100 R 50 50 1 1 I
    X plus 5 -600 -400 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_ESTOP
    #
    DEF HALUI_ESTOP halui.estop. 0 40 N Y 1 F N
    F0 "halui.estop." 0 300 50 H V C CNN
    F1 "HALUI_ESTOP" 0 200 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "1" 300 200 50 H V C CNN "StripAnno"
    DRAW
    S -350 -150 350 150 0 1 0 N
    S 350 150 -350 250 0 1 0 f
    X activate 1 -450 100 100 R 0 50 1 1 I
    X is-activated 2 450 0 100 L 0 50 1 1 O
    X reset 3 -450 -100 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_FEED_OVERRIDE
    #
    DEF HALUI_FEED_OVERRIDE halui.feed-override. 0 40 N Y 1 F N
    F0 "halui.feed-override." 0 450 50 H V C CNN
    F1 "HALUI_FEED_OVERRIDE" 0 350 50 H V C CNN
    F2 "" 200 50 50 H I C CNN
    F3 "" 200 50 50 H I C CNN
    F4 "1" 500 350 50 H V C CNN "StripAnno"
    DRAW
    S -450 -400 450 300 0 1 0 N
    S 450 300 -450 400 0 1 0 f
    X count-enable 1 -550 250 100 R 0 50 1 1 I
    X counts 2 -550 150 100 R 0 50 1 1 I
    X decrease 3 -550 -100 100 R 0 50 1 1 I
    X direct-value 4 -550 -250 100 R 0 50 1 1 I
    X increase 5 -550 0 100 R 0 50 1 1 I
    X scale 6 -550 -350 100 R 0 50 1 1 I
    X value 7 550 250 100 L 0 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_FLOOD
    #
    DEF HALUI_FLOOD halui.flood. 0 40 N Y 1 F N
    F0 "halui.flood." 0 250 50 H V C CNN
    F1 "HALUI_FLOOD" 0 150 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "1" 350 150 50 H V C CNN "StripAnno"
    DRAW
    S -300 100 300 -100 1 1 0 N
    S -300 200 300 100 1 1 0 f
    X is-on 1 400 0 100 L 0 50 1 1 O
    X off 2 -400 -50 100 R 0 50 1 1 I
    X on 3 -400 50 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_JOINT
    #
    DEF HALUI_JOINT halui.joint. 0 40 N Y 1 F N
    F0 "halui.joint." 0 200 50 H V C CNN
    F1 "HALUI_JOINT" 0 100 50 H V C CNN
    F2 "" 750 150 50 H I C CNN
    F3 "" 750 150 50 H I C CNN
    F4 "1" 400 100 50 H V C CNN "StripAnno"
    DRAW
    S 450 50 -450 -250 1 1 0 N
    S 450 50 -450 150 1 1 0 f
    X jog-deadband 1 -550 -150 100 R 50 50 1 1 I
    X selected 2 550 -50 100 L 50 50 1 1 O
    X jog-speed 3 -550 -50 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_JOINT_N
    #
    DEF HALUI_JOINT_N halui.joint.0. 0 40 N Y 1 F N
    F0 "halui.joint.0." 0 300 50 H V C CNN
    F1 "HALUI_JOINT_N" 0 200 50 H V C CNN
    F2 "" 400 300 50 H I C CNN
    F3 "" 400 300 50 H I C CNN
    F4 "1" 700 200 50 H V C CNN "StripAnno"
    DRAW
    S -800 -1050 750 150 0 1 0 N
    S 750 150 -800 250 0 1 0 f
    X minus 1 -900 -850 100 R 50 50 1 1 I
    X analog 10 -900 -350 100 R 50 50 1 1 I
    X is-selected 11 850 50 100 L 50 50 1 1 O
    X is-homed 12 850 -100 100 L 50 50 1 1 O
    X increment-plus 13 -900 -700 100 R 50 50 1 1 I
    X increment-minus 14 -900 -600 100 R 50 50 1 1 I
    X increment 15 -900 -500 100 R 50 50 1 1 I
    X home 16 -900 -100 100 R 50 50 1 1 I
    X has-fault 17 850 -950 100 L 50 50 1 1 O
    X unhome 2 -900 -200 100 R 50 50 1 1 I
    X select 3 -900 50 100 R 50 50 1 1 I
    X plus 4 -900 -950 100 R 50 50 1 1 I
    X override-limits 5 850 -850 100 L 50 50 1 1 O
    X on-soft-min-limit 6 850 -700 100 L 50 50 1 1 O
    X on-soft-max-limit 7 850 -600 100 L 50 50 1 1 O
    X on-hard-min-limit 8 850 -450 100 L 50 50 1 1 O
    X on-hard-max-limit 9 850 -350 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_JOINT_SELECTED
    #
    DEF HALUI_JOINT_SELECTED halui.joint.selected. 0 40 N Y 1 F N
    F0 "halui.joint.selected." 0 500 50 H V C CNN
    F1 "HALUI_JOINT_SELECTED" 0 400 50 H V C CNN
    F2 "" 150 450 50 H I C CNN
    F3 "" 150 450 50 H I C CNN
    F4 "1" 700 400 50 H V C CNN "StripAnno"
    DRAW
    S 750 350 -800 -550 0 1 0 N
    S 750 350 -800 450 0 1 0 f
    X is-homed 1 850 250 100 L 50 50 1 1 O
    X increment-plus 10 -900 -200 100 R 50 50 1 1 I
    X increment-minus 11 -900 -100 100 R 50 50 1 1 I
    X increment 12 -900 0 100 R 50 50 1 1 I
    X home 13 -900 250 100 R 50 50 1 1 I
    X has-fault 14 850 150 100 L 50 50 1 1 O
    X unhome 2 -900 150 100 R 50 50 1 1 I
    X plus 3 -900 -450 100 R 50 50 1 1 I
    X override-limits 4 850 -450 100 L 50 50 1 1 O
    X on-soft-min-limit 5 850 -350 100 L 50 50 1 1 O
    X on-soft-max-limit 6 850 -250 100 L 50 50 1 1 O
    X on-hard-min-limit 7 850 -100 100 L 50 50 1 1 O
    X on-hard-max-limit 8 850 0 100 L 50 50 1 1 O
    X minus 9 -900 -350 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_LUBE
    #
    DEF HALUI_LUBE halui.lube. 0 40 N Y 1 F N
    F0 "halui.lube." 0 250 50 H V C CNN
    F1 "HALUI_LUBE" -50 150 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "1" 250 150 50 H V C CNN "StripAnno"
    DRAW
    S -300 100 300 -100 1 1 0 N
    S -300 200 300 100 1 1 0 f
    X is-on 1 400 0 100 L 0 50 1 1 O
    X off 2 -400 -50 100 R 0 50 1 1 I
    X on 3 -400 50 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_MACHINE
    #
    DEF HALUI_MACHINE halui.machine. 0 40 N Y 1 F N
    F0 "halui.machine." 0 300 50 H V C CNN
    F1 "HALUI_MACHINE" 0 200 50 H V C CNN
    F2 "" 2450 1450 50 H I C CNN
    F3 "" 2450 1450 50 H I C CNN
    F4 "1" 400 200 50 H V C CNN "StripAnno"
    DRAW
    S -400 -250 450 150 0 1 0 N
    S 450 150 -400 250 0 1 0 f
    X is-on 1 550 50 100 L 0 50 1 1 O
    X off 2 -500 -50 100 R 0 50 1 1 I
    X on 3 -500 50 100 R 0 50 1 1 I
    X units-per-mm 4 550 -150 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_MAX_VELOCITY
    #
    DEF HALUI_MAX_VELOCITY halui.max-velocity. 0 40 N Y 1 F N
    F0 "halui.max-velocity." 0 550 50 H V C CNN
    F1 "HALUI_MAX_VELOCITY" -50 450 50 H V C CNN
    F2 "" 1350 900 50 H I C CNN
    F3 "" 1350 900 50 H I C CNN
    F4 "1" 450 450 50 H V C CNN "StripAnno"
    DRAW
    S -500 -400 500 400 0 1 0 N
    S 500 400 -500 500 0 1 0 f
    X direct-value 1 -600 -200 100 R 50 50 0 0 I
    X count 2 -600 200 100 R 0 50 1 1 I
    X count-enable 3 -600 300 100 R 0 50 1 1 I
    X decrease 4 -600 50 100 R 0 50 1 1 I
    X increase 5 -600 -50 100 R 0 50 1 1 I
    X scale 6 -600 -300 100 R 0 50 1 1 I
    X value 7 600 200 100 L 0 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_MIST
    #
    DEF HALUI_MIST halui.mist. 0 40 N Y 1 F N
    F0 "halui.mist." 0 250 50 H V C CNN
    F1 "HALUI_MIST" 0 150 50 H V C CNN
    F2 "" 0 -50 50 H I C CNN
    F3 "" 0 -50 50 H I C CNN
    F4 "1" 300 150 50 H V C CNN "StripAnno"
    DRAW
    S -300 100 350 -100 0 1 0 N
    S -300 200 350 100 0 1 0 f
    X is-on 1 450 0 100 L 0 50 1 1 O
    X off 2 -400 -50 100 R 0 50 1 1 I
    X on 3 -400 50 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_MODE
    #
    DEF HALUI_MODE halui.mode. 0 40 N Y 1 F N
    F0 "halui.mode." 0 500 50 H V C CNN
    F1 "HALUI_MODE" 0 400 50 H V C CNN
    F2 "" 900 750 50 H I C CNN
    F3 "" 900 750 50 H I C CNN
    F4 "1" 350 400 50 H V C CNN "StripAnno"
    DRAW
    S -400 -650 400 350 0 1 0 N
    S 400 350 -400 450 0 1 0 f
    X auto 1 -500 250 100 R 0 50 1 1 I
    X teleop 10 -500 -550 100 R 0 50 1 1 I
    X is-auto 2 500 250 100 L 0 50 1 1 O
    X is-joint 3 500 50 100 L 0 50 1 1 O
    X is-manual 4 500 -150 100 L 0 50 1 1 O
    X is-mdi 5 500 -350 100 L 0 50 1 1 O
    X is-teleop 6 500 -550 100 L 0 50 1 1 O
    X joint 7 -500 50 100 R 0 50 1 1 I
    X manual 8 -500 -150 100 R 0 50 1 1 I
    X mdi 9 -500 -350 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_PROGRAM
    #
    DEF HALUI_PROGRAM halui.program. 0 40 N Y 1 F N
    F0 "halui.program." -50 550 50 H V C CNN
    F1 "HALUI_PROGRAM" -50 450 50 H V C CNN
    F2 "" 50 300 50 H I C CNN
    F3 "" 50 300 50 H I C CNN
    F4 "1" 400 450 50 H V C CNN "StripAnno"
    DRAW
    S -500 400 450 -950 0 1 0 N
    S 450 400 -500 500 0 1 0 f
    X block-delete.is-on 1 550 -750 100 L 0 50 1 1 O
    X pause 10 -600 -50 100 R 0 50 1 1 I
    X resume 11 -600 -150 100 R 0 50 1 1 I
    X run 12 -600 300 100 R 0 50 1 1 I
    X step 13 -600 200 100 R 0 50 1 1 I
    X stop 14 -600 100 100 R 0 50 1 1 I
    X block-delete.off 2 -600 -850 100 R 0 50 1 1 I
    X block-delete.on 3 -600 -650 100 R 0 50 1 1 I
    X is-idle 4 550 200 100 L 0 50 1 1 O
    X is-paused 5 550 -50 100 L 0 50 1 1 O
    X is-running 6 550 300 100 L 0 50 1 1 O
    X optional-stop.is-on 7 550 -400 100 L 0 50 1 1 O
    X optional-stop.off 8 -600 -500 100 R 0 50 1 1 I
    X optional-stop.on 9 -600 -300 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_RAPID_OVERRIDE
    #
    DEF HALUI_RAPID_OVERRIDE halui.rapid-override. 0 40 N Y 1 F N
    F0 "halui.rapid-override." 0 450 50 H V C CNN
    F1 "HALUI_RAPID_OVERRIDE" -50 350 50 H V C CNN
    F2 "" 1050 750 50 H I C CNN
    F3 "" 1050 750 50 H I C CNN
    F4 "1" 500 350 50 H V C CNN "StripAnno"
    DRAW
    S -550 -500 550 300 1 1 0 N
    S 550 300 -550 400 1 1 0 f
    X count-enable 1 -650 200 100 R 0 50 1 1 I
    X counts 2 -650 100 100 R 0 50 1 1 I
    X decrease 3 -650 -150 100 R 0 50 1 1 I
    X direct-value 4 -650 -300 100 R 0 50 1 1 I
    X increase 5 -650 -50 100 R 0 50 1 1 I
    X scale 6 -650 -400 100 R 0 50 1 1 I
    X value 7 650 200 100 L 0 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_SPINDLE_N
    #
    DEF HALUI_SPINDLE_N halui.spindle.0. 0 40 N Y 1 F N
    F0 "halui.spindle.0." 0 900 50 H V C CNN
    F1 "HALUI_SPINDLE_N" 0 800 50 H V C CNN
    F2 "" -50 1450 50 H I C CNN
    F3 "" -50 1450 50 H I C CNN
    F4 "1" 550 800 50 H V C CNN "StripAnno"
    DRAW
    S -650 -950 600 750 0 1 0 N
    S 600 750 -650 850 0 1 0 f
    X override.direct-value 11 -750 -850 100 R 50 50 0 0 I
    X override.counts 1 -750 -550 100 R 0 50 1 1 I
    X override.decrease 10 -750 -650 100 R 0 50 1 1 I
    X override.count-enable 12 -750 -450 100 R 0 50 1 1 I
    X is-on 13 700 -100 100 L 0 50 1 1 O
    X increase 14 -750 150 100 R 0 50 1 1 I
    X forward 15 -750 400 100 R 0 50 1 1 I
    X decrease 16 -750 50 100 R 0 50 1 1 I
    X brake.off 17 -750 550 100 R 0 50 1 1 I
    X brake-on 18 -750 650 100 R 0 50 1 1 I
    X brake-is-on 19 700 650 100 L 0 50 1 1 O
    X stop 2 -750 -200 100 R 0 50 1 1 I
    X start 3 -750 -100 100 R 0 50 1 1 I
    X runs-forward 4 700 400 100 L 0 50 1 1 O
    X runs-backwards 5 700 300 100 L 0 50 1 1 O
    X reverse 6 -750 300 100 R 0 50 1 1 I
    X override.value 7 700 -350 100 L 0 50 1 1 O
    X override.scale 8 -750 -350 100 R 0 50 1 1 I
    X override.increase 9 -750 -750 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_TOOL
    #
    DEF HALUI_TOOL halui.tool. 0 40 N Y 1 F N
    F0 "halui.tool." -50 750 50 H V C CNN
    F1 "HALUI_TOOL" -50 650 50 H V C CNN
    F2 "" -50 300 50 H I C CNN
    F3 "" -50 300 50 H I C CNN
    F4 "1" 250 650 50 H V C CNN "StripAnno"
    DRAW
    S -400 600 300 700 0 1 0 f
    S 300 600 -400 -800 0 1 0 N
    X diameter 1 400 400 100 L 0 50 1 1 O
    X length-offset.z 10 400 -700 100 L 0 50 1 1 O
    X number 11 400 500 100 L 0 50 1 1 O
    X length-offset.a 2 400 250 100 L 0 50 1 1 O
    X length-offset.b 3 400 150 100 L 0 50 1 1 O
    X length-offset.c 4 400 50 100 L 0 50 1 1 O
    X length-offset.u 5 400 -150 100 L 0 50 1 1 O
    X length-offset.v 6 400 -250 100 L 0 50 1 1 O
    X length-offset.w 7 400 -350 100 L 0 50 1 1 O
    X length-offset.x 8 400 -500 100 L 0 50 1 1 O
    X length-offset.y 9 400 -600 100 L 0 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HAL_MANUALTOOLCHANGE
    #
    DEF HAL_MANUALTOOLCHANGE hal_manualtoolchange. 0 40 Y Y 1 F N
    F0 "hal_manualtoolchange." -50 300 59 H V C CNN
    F1 "HAL_MANUALTOOLCHANGE" -100 200 50 H V C CNN
    F2 "" 0 -100 50 H I C CNN
    F3 "" 0 -100 50 H I C CNN
    F4 "1" 450 200 50 H V C CNN "StripAnno"
    F5 "-W hal_manualtoolchange" -50 100 50 H V C CNN "LoadUsr"
    DRAW
    S -600 -450 500 50 1 1 0 N
    S 500 50 -600 250 1 1 0 f
    X change 1 -700 -50 100 R 0 50 1 0 I
    X change_button 2 -700 -200 100 R 0 50 1 0 I
    X changed 3 600 -50 100 L 0 50 1 0 O
    X number 4 -700 -350 100 R 0 50 1 0 I
    ENDDRAW
    ENDDEF
    #
    # HM2_5I25
    #
    DEF HM2_5I25 hm2_5i25.0. 0 20 N Y 1 F N
    F0 "hm2_5i25.0." 0 500 50 H V C CNN
    F1 "HM2_5I25" 0 400 50 H V C CNN
    F2 "" 550 -200 50 H I C CNN
    F3 "" 550 -200 50 H I C CNN
    F4 "1" 400 400 50 H V C CNN "StripAnno"
    DRAW
    S -450 350 450 -550 0 1 0 N
    S 450 350 -450 450 0 1 0 f
    X watchdog.timeout_ns 8 -550 50 157 R 50 50 1 0 I I
    X watchdog.has_bit 1 550 -50 100 L 50 50 1 1 O
    X led.CR01 2 -550 300 100 R 50 50 1 1 I
    X led.CR02 3 -550 200 100 R 50 50 1 1 I
    X read 4 -550 -150 100 R 50 50 1 1 W C
    X *read_gpio 5 -550 -350 100 R 50 50 1 1 W NC
    X write 6 -550 -250 100 R 50 50 1 1 W C
    X *write_gpio 7 -550 -450 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # HM2_5I25_GPIO
    #
    DEF HM2_5I25_GPIO hm2_5i25.0.gpio.000. 0 40 N Y 1 F N
    F0 "hm2_5i25.0.gpio.000." 0 300 50 H V C CNN
    F1 "HM2_5I25_GPIO" -50 200 50 H V C CNN
    F2 "" 150 -250 50 H I C CNN
    F3 "" 150 -250 50 H I C CNN
    F4 "1" 350 200 50 H V C CNN "StripAnno"
    DRAW
    S -400 150 400 250 0 1 0 f
    S 400 150 -400 -350 0 1 0 N
    X in 1 500 100 100 L 50 50 1 1 O
    X in_not 2 500 0 100 L 50 50 1 1 O
    X invert_output 3 -500 -200 157 R 50 50 1 1 I I
    X is_opendrain 4 -500 -300 157 R 50 50 1 1 I I
    X is_output 5 -500 -100 157 R 50 50 1 1 I I
    X out 6 -500 100 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HM2_5I25_STEPGEN
    #
    DEF HM2_5I25_STEPGEN hm2_5i25.0.stepgen.00. 0 20 N Y 1 F N
    F0 "hm2_5i25.0.stepgen.00." -50 900 50 H V C CNN
    F1 "HM2_5I25_STEPGEN" -50 800 50 H V C CNN
    F2 "" 0 500 50 H I C CNN
    F3 "" 0 500 50 H I C CNN
    F4 "1" 400 800 50 H V C CNN "StripAnno"
    DRAW
    S -500 750 450 -1250 0 1 0 N
    S -500 850 450 750 0 1 0 f
    X control-type 1 -600 500 100 R 50 50 1 1 I
    X position-scale 10 -600 -50 157 R 50 50 1 1 I I
    X step_type 11 -600 -1150 157 R 50 50 1 1 I I
    X steplen 12 -600 -200 157 R 50 50 1 1 I I
    X stepspace 13 -600 -300 157 R 50 50 1 1 I I
    X step.invert_output 14 -600 -400 157 R 50 50 1 1 I I
    X direction.invert_output 15 -600 -750 157 R 50 50 1 1 I I
    X velocity-cmd 16 -600 200 100 R 50 50 1 1 I
    X velocity-fb 17 550 100 100 L 50 50 1 1 O
    X counts 2 550 650 100 L 50 50 1 1 O
    X dirhold 3 -600 -650 157 R 50 50 1 1 I I
    X dirsetup 4 -600 -550 157 R 50 50 1 1 I I
    X enable 5 -600 650 100 R 50 50 1 1 I
    X maxaccel 6 -600 -1000 157 R 50 50 1 1 I I
    X maxvel 7 -600 -900 157 R 50 50 1 1 I I
    X position-cmd 8 -600 400 100 R 50 50 1 1 I
    X position-fb 9 550 300 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # IOCONTROL
    #
    DEF IOCONTROL iocontrol.0. 0 40 N Y 1 F N
    F0 "iocontrol.0." 0 700 59 H V C CNN
    F1 "IOCONTROL" 0 600 50 H V C CNN
    F2 "" -100 200 50 H I C CNN
    F3 "" -100 200 50 H I C CNN
    F4 "1" 650 600 50 H V C CNN "StripAnno"
    DRAW
    S -750 550 700 650 1 1 0 f
    S 700 550 -750 -950 1 1 0 N
    X coolant-flood 1 800 -50 100 L 0 50 1 0 O
    X tool-prep-pocket 10 800 -750 100 L 0 50 1 0 O
    X tool-prepare 11 800 -550 100 L 0 50 1 0 O
    X tool-prepared 12 -850 -550 100 R 0 50 1 0 I
    X user-enable-out 13 800 450 100 L 0 50 1 0 O
    X user-request-enable 14 800 350 100 L 0 50 1 0 O
    X coolant-mist 2 800 -150 100 L 0 50 1 0 O
    X emc-enable-in 3 -850 450 100 R 0 50 1 0 I
    X lube 4 800 150 100 L 0 50 1 0 O
    X lube-level 5 -850 150 100 R 0 50 1 0 I
    X tool-change 6 800 -850 100 L 0 50 1 0 O
    X tool-changed 7 -850 -850 100 R 0 50 1 0 I
    X tool-number 8 800 -350 100 L 0 50 1 0 O
    X tool-prep-number 9 800 -650 100 L 0 50 1 0 O
    X tool-prep-index 15 800 -450 157 L 50 50 1 1 O I
    ENDDRAW
    ENDDEF
    #
    # JOINT_N
    #
    DEF JOINT_N joint.0. 0 40 N Y 1 F N
    F0 "joint.0." 0 800 50 H V C CNN
    F1 "JOINT_N" 0 700 50 H V C CNN
    F2 "" 1050 150 50 H I C CNN
    F3 "" 1050 150 50 H I C CNN
    F4 "1" 700 700 50 H V C CNN "StripAnno"
    DRAW
    S -700 650 750 -1500 0 1 0 N
    S -700 650 750 750 0 1 0 f
    X jog-enable 1 -800 -950 100 R 50 50 1 1 I
    X motor-pos-cmd 10 850 550 100 L 50 50 1 1 O
    X jog-vel-mode 11 -800 -1150 100 R 50 50 1 1 I
    X jog-scale 12 -800 -1050 100 R 50 50 1 1 I
    X active 13 850 50 100 L 50 50 1 1 O
    X jog-counts 14 -800 -850 100 R 50 50 1 1 I
    X jog-accel-fraction 15 -800 -750 100 R 50 50 1 1 I
    X is-unlocked 16 -800 -600 100 R 50 50 1 1 I
    X index-enable 17 -800 -450 100 R 50 50 1 1 B
    X homing 18 850 -450 100 L 50 50 1 1 O
    X homed 19 850 -350 100 L 50 50 1 1 O
    X unlock 2 850 -600 100 L 50 50 1 1 O
    X home-sw-in 20 -800 -350 100 R 50 50 1 1 I
    X faulted 21 850 -150 100 L 50 50 1 1 O
    X error 22 850 -50 100 L 50 50 1 1 O
    X amp-fault-in 23 -800 -150 100 R 50 50 1 1 I
    X amp-enable-out 24 850 450 100 L 50 50 1 1 O
    X pos-lim-sw-in 3 -800 -1400 100 R 50 50 1 1 I
    X pos-hard-limit 4 850 -1400 100 L 50 50 1 1 O
    X pos-fb 5 850 200 100 L 50 50 1 1 O
    X pos-cmd 6 850 300 100 L 50 50 1 1 O
    X neg-lim-sw-in 7 -800 -1300 100 R 50 50 1 1 I
    X neg-hard-limit 8 850 -1300 100 L 50 50 1 1 O
    X motor-pos-fb 9 -800 550 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # LOADRT
    #
    DEF LOADRT loadrt.0. 0 0 N N 1 F N
    F0 "loadrt.0." 0 250 50 H V C CNN
    F1 "LOADRT" -50 150 50 H V C CNN
    F2 "" 800 -500 50 H I C CNN
    F3 "" 800 -500 50 H I C CNN
    F4 "Component + options go here" -250 50 50 H V L CNN "LoadRT"
    F5 "1" 250 150 50 H V C CNN "StripAnno"
    DRAW
    P 2 0 0 0 300 100 950 100 N
    P 2 0 0 0 300 200 300 100 N
    P 3 0 0 0 -300 100 -300 0 950 0 N
    P 4 0 1 0 300 200 -300 200 -300 100 300 100 f
    ENDDRAW
    ENDDEF
    #
    # LOADUSR
    #
    DEF LOADUSR loadusr.0. 0 0 N N 1 F N
    F0 "loadusr.0." 0 250 50 H V C CNN
    F1 "LOADUSR" -50 150 50 H V C CNN
    F2 "" 850 -500 50 H I C CNN
    F3 "" 850 -500 50 H I C CNN
    F4 "Module + options go here" -250 50 50 H V L CNN "LoadUsr"
    F5 "1" 250 150 50 H V C CNN "StripAnno"
    DRAW
    P 2 1 1 0 300 100 850 100 N
    P 2 1 1 0 300 200 300 100 N
    P 3 1 1 0 -300 100 -300 0 850 0 N
    P 4 1 1 0 300 200 -300 200 -300 100 300 100 f
    ENDDRAW
    ENDDEF
    #
    # LOGIC
    #
    DEF LOGIC logic.0. 0 20 N Y 1 F N
    F0 "logic.0." 0 650 50 H V C CNN
    F1 "LOGIC" 0 550 50 H V C CNN
    F2 "" 350 -200 50 H I C CNN
    F3 "" 350 -200 50 H I C CNN
    F4 "1" 300 550 50 H V C CNN "StripAnno"
    F5 "+ personality=0x108" -50 -550 50 H V C CNN "LoadRT"
    DRAW
    T 0 -50 400 50 0 0 0 " 100" Normal 0 L C
    T 0 -50 300 50 0 0 0 " 200" Normal 0 L C
    T 0 -50 200 50 0 0 0 " 400" Normal 0 L C
    T 0 -50 100 50 0 0 0 " 800" Normal 0 L C
    T 0 -50 0 50 0 0 0 1000 Normal 0 L C
    S 350 500 -400 600 0 1 0 f
    S -400 500 350 -500 1 1 0 N
    X in-00 1 -500 400 100 R 50 50 1 1 I
    X or 10 450 300 100 L 50 50 1 1 O
    X xor 11 450 200 100 L 50 50 1 1 O
    X nand 12 450 100 100 L 50 50 1 1 O
    X nor 13 450 0 100 L 50 50 1 1 O
    X _ 14 -500 -400 100 R 50 50 1 1 W NC
    X in-01 2 -500 300 100 R 50 50 1 1 I
    X in-02 3 -500 200 100 R 50 50 1 1 I
    X in-03 4 -500 100 100 R 50 50 1 1 I
    X in-04 5 -500 0 100 R 50 50 1 1 I
    X in-05 6 -500 -100 100 R 50 50 1 1 I
    X in-06 7 -500 -200 100 R 50 50 1 1 I
    X in-07 8 -500 -300 100 R 50 50 1 1 I
    X and 9 450 400 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # LOGITECH_GAMEPAD_GUF13A
    #
    DEF LOGITECH_GAMEPAD_GUF13A input.0. 0 40 N Y 2 L N
    F0 "input.0." 0 1850 50 H V C CNN
    F1 "LOGITECH_GAMEPAD_GUF13A" -50 1750 50 H V C CNN
    F2 "" 5500 3600 50 H I C CNN
    F3 "" 5500 3600 50 H I C CNN
    F4 "1" 550 1750 50 H V C CNN "StripAnno"
    F5 "-W hal_input -KA Dual" -50 1650 50 H V C CNN "LoadUsr"
    DRAW
    T 0 -350 1400 59 0 2 1 1 Normal 0 L B
    T 0 -400 -1300 59 0 2 1 10 Normal 0 L B
    T 0 -350 1100 59 0 2 1 2 Normal 0 L B
    T 0 -350 800 59 0 2 1 3 Normal 0 L B
    T 0 -350 500 59 0 2 1 4 Normal 0 L B
    T 0 -350 200 59 0 2 1 5 Normal 0 L B
    T 0 -350 -100 59 0 2 1 6 Normal 0 L B
    T 0 -350 -400 59 0 2 1 7 Normal 0 L B
    T 0 -350 -700 59 0 2 1 8 Normal 0 L B
    T 0 -350 -1000 59 0 2 1 9 Normal 0 L B
    T 0 -550 -1600 59 0 2 1 "L Push" Normal 0 L B
    T 0 -550 -1900 59 0 2 1 "R Push" Normal 0 L B
    S -850 -1400 750 1600 1 1 0 N
    S 750 1600 -850 1800 1 1 0 f
    S -650 1600 600 1800 2 1 0 f
    S 600 -1950 -650 1600 2 1 0 N
    X abs-z-offset 1 -950 -500 100 R 0 50 1 1 I
    X abs-z-is-pos 11 850 -700 100 L 0 50 1 1 O
    X abs-z-is-neg 12 850 -800 100 L 0 50 1 1 O
    X abs-z-fuzz 13 -950 -800 100 R 0 50 1 1 I
    X abs-z-flat 14 -950 -700 100 R 0 50 1 1 I
    X abs-z-counts 15 850 -500 100 L 0 50 1 1 O
    X abs-y-scale 16 -950 -100 100 R 0 50 1 1 I
    X abs-y-position 17 850 -100 100 L 0 50 1 1 O
    X abs-y-offset 18 -950 0 100 R 0 50 1 1 I
    X abs-y-is-pos 28 850 -200 100 L 0 50 1 1 O
    X abs-hat0y-flat 37 -950 800 100 R 0 50 1 1 I
    X abs-rz-flat 38 -950 -1200 100 R 0 50 1 1 I
    X abs-rz-counts 39 850 -1000 100 L 0 50 1 1 O
    X abs-hat0y-scale 40 -950 900 100 R 0 50 1 1 I
    X abs-hat0y-position 41 850 900 100 L 0 50 1 1 O
    X abs-hat0y-offset 42 -950 1000 100 R 0 50 1 1 I
    X abs-hat0y-is-pos 43 850 800 100 L 0 50 1 1 O
    X abs-hat0y-is-neg 44 850 700 100 L 0 50 1 1 O
    X abs-hat0y-fuzz 45 -950 700 100 R 0 50 1 1 I
    X abs-rz-fuzz 46 -950 -1300 100 R 0 50 1 1 I
    X abs-hat0y-counts 47 850 1000 100 L 0 50 1 1 O
    X abs-hat0x-scale 48 -950 1400 100 R 0 50 1 1 I
    X abs-hat0x-position 49 850 1400 100 L 0 50 1 1 O
    X abs-hat0x-offset 50 -950 1500 100 R 0 50 1 1 I
    X abs-hat0x-is-pos 51 850 1300 100 L 0 50 1 1 O
    X abs-hat0x-is-neg 52 850 1200 100 L 0 50 1 1 O
    X abs-hat0x-fuzz 53 -950 1200 100 R 0 50 1 1 I
    X abs-hat0x-flat 54 -950 1300 100 R 0 50 1 1 I
    X abs-x-is-neg 55 850 200 100 L 0 50 1 1 O
    X abs-y-is-neg 56 850 -300 100 L 0 50 1 1 O
    X abs-y-fuzz 57 -950 -300 100 R 0 50 1 1 I
    X abs-y-flat 58 -950 -200 100 R 0 50 1 1 I
    X abs-y-counts 59 850 0 100 L 0 50 1 1 O
    X abs-x-scale 60 -950 400 100 R 0 50 1 1 I
    X abs-x-position 61 850 400 100 L 0 50 1 1 O
    X abs-x-offset 62 -950 500 100 R 0 50 1 1 I
    X abs-x-is-pos 63 850 300 100 L 0 50 1 1 O
    X abs-hat0x-counts 64 850 1500 100 L 0 50 1 1 O
    X abs-x-fuzz 65 -950 200 100 R 0 50 1 1 I
    X abs-x-flat 66 -950 300 100 R 0 50 1 1 I
    X abs-x-counts 67 850 500 100 L 0 50 1 1 O
    X abs-rz-scale 68 -950 -1100 100 R 0 50 1 1 I
    X abs-rz-position 69 850 -1100 100 L 0 50 1 1 O
    X abs-rz-offset 70 -950 -1000 100 R 0 50 1 1 I
    X abs-rz-is-pos 71 850 -1200 100 L 0 50 1 1 O
    X abs-rz-is-neg 72 850 -1300 100 L 0 50 1 1 O
    X abs-z-scale 8 -950 -600 100 R 0 50 1 1 I
    X abs-z-position 9 850 -600 100 L 0 50 1 1 O
    X btn-base4 10 700 -1200 100 L 0 50 2 1 O
    X btn-pinkie-not 19 700 -100 100 L 0 50 2 1 O
    X btn-base3-not 2 700 -1000 100 L 0 50 2 1 O
    X btn-top2-not 20 700 200 100 L 0 50 2 1 O
    X btn-top2 21 700 300 100 L 0 50 2 1 O
    X btn-top-not 22 700 500 100 L 0 50 2 1 O
    X btn-top 23 700 600 100 L 0 50 2 1 O
    X btn-thumb2-not 24 700 800 100 L 0 50 2 1 O
    X btn-thumb2 25 700 900 100 L 0 50 2 1 O
    X btn-thumb-not 26 700 1100 100 L 0 50 2 1 O
    X btn-thumb 27 700 1200 100 L 0 50 2 1 O
    X btn-pinkie 29 700 0 100 L 0 50 2 1 O
    X btn-base3 3 700 -900 100 L 0 50 2 1 O
    X btn-joystick-not 30 700 1400 100 L 0 50 2 1 O
    X btn-joystick 31 700 1500 100 L 0 50 2 1 O
    X btn-base6-not 32 700 -1900 100 L 0 50 2 1 O
    X btn-base6 33 700 -1800 100 L 0 50 2 1 O
    X btn-base5-not 34 700 -1600 100 L 0 50 2 1 O
    X btn-base5 35 700 -1500 100 L 0 50 2 1 O
    X btn-base4-not 36 700 -1300 100 L 0 50 2 1 O
    X btn-base2-not 4 700 -700 100 L 0 50 2 1 O
    X btn-base2 5 700 -600 100 L 0 50 2 1 O
    X btn-base-not 6 700 -400 100 L 0 50 2 1 O
    X btn-base 7 700 -300 100 L 0 50 2 1 O
    ENDDRAW
    ENDDEF
    #
    # MOTION
    #
    DEF MOTION motion. 0 40 N Y 1 F N
    F0 "motion." 0 1550 59 H V C CNN
    F1 "MOTION" 0 1450 50 H V C CNN
    F2 "" 0 350 50 H I C CNN
    F3 "" 0 350 50 H I C CNN
    F4 "1" 600 1450 50 H V C CNN "StripAnno"
    DRAW
    S -600 1400 650 -1100 1 1 0 N
    S 650 1400 -600 1500 1 1 0 f
    X feed-hold 1 -700 1000 100 R 0 50 1 0 I
    X coord-mode 10 750 950 100 L 0 50 1 0 O
    X distance-to-go 11 750 350 100 L 0 50 1 0 O
    X probe-input 12 -700 600 100 R 0 50 1 0 I
    X in-position 13 750 1300 100 L 0 50 1 0 O
    X adaptive-feed 14 -700 800 100 R 0 50 1 0 I
    X enable 15 -700 1300 100 R 0 50 1 0 I
    X digital-out-03 16 750 -750 100 L 0 50 1 0 O
    X digital-out-02 17 750 -650 100 L 0 50 1 0 O
    X digital-out-01 18 750 -550 100 L 0 50 1 0 O
    X digital-out-00 19 750 -450 100 L 0 50 1 0 O
    X homing-inhibit 2 -700 450 100 R 0 50 1 0 I
    X analog-out-00 20 750 -200 100 L 0 50 1 0 O
    X analog-out-01 21 750 -300 100 L 0 50 1 0 O
    X digital-in-03 22 -700 -750 100 R 0 50 1 0 I
    X digital-in-02 23 -700 -650 100 R 0 50 1 0 I
    X digital-in-01 24 -700 -550 100 R 0 50 1 0 I
    X analog-in-00 25 -700 -200 100 R 0 50 1 0 I
    X analog-in-01 26 -700 -300 100 R 0 50 1 0 I
    X digital-in-00 27 -700 -450 100 R 0 50 1 0 I
    X feed-inhibit 3 -700 900 100 R 0 50 1 0 I
    X on-soft-limit 30 750 -50 100 L 0 50 1 0 O
    X requested-vel 31 750 500 100 L 0 50 1 0 O
    X teleop-mode 32 750 750 100 L 0 50 1 0 O
    X motion-type 4 750 1100 100 L 0 50 1 0 O
    X motion-enabled 5 750 1200 100 L 0 50 1 0 O
    X offset-limited 6 750 100 100 L 0 50 1 0 O
    X current-vel 7 750 600 100 L 0 50 1 0 O
    X coord-error 8 750 850 100 L 0 50 1 0 O
    X offset-active 9 750 200 100 L 0 50 1 0 O
    X /motion-controller 28 -700 -1000 100 R 50 50 1 1 W C
    X /motion-command-handler 29 -700 -900 100 R 50 50 1 1 W C
    ENDDRAW
    ENDDEF
    #
    # MUX2
    #
    DEF MUX2 mux2. 0 20 N Y 1 F N
    F0 "mux2." 0 300 50 H V C CNN
    F1 "MUX2" 0 200 50 H V C CNN
    F2 "" 350 -150 50 H I C CNN
    F3 "" 350 -150 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S -150 150 150 -250 0 1 0 N
    S 150 150 -150 250 0 1 0 f
    X in0 1 -250 100 100 R 50 50 1 1 I
    X in1 2 -250 0 100 R 50 50 1 1 I
    X sel 3 -250 -200 100 R 50 50 1 1 I
    X out 4 250 100 100 L 50 50 1 1 O
    X _ 5 -250 -100 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # MUX4
    #
    DEF MUX4 mux4. 0 20 N Y 1 F N
    F0 "mux4." 0 450 50 H V C CNN
    F1 "MUX4" 0 350 50 H V C CNN
    F2 "" 400 -100 50 H I C CNN
    F3 "" 400 -100 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 150 300 -150 400 0 1 0 f
    S -150 300 150 -400 1 1 0 N
    X in0 1 -250 250 100 R 50 50 1 1 I
    X in1 2 -250 150 100 R 50 50 1 1 I
    X in2 3 -250 50 100 R 50 50 1 1 I
    X in3 4 -250 -50 100 R 50 50 1 1 I
    X sel0 5 -250 -250 100 R 50 50 1 1 I
    X sel1 6 -250 -350 100 R 50 50 1 1 I
    X out 7 250 250 100 L 50 50 1 1 O
    X _ 8 -250 -150 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # MUX8
    #
    DEF MUX8 mux8. 0 20 N Y 1 F N
    F0 "mux8." 0 750 50 H V C CNN
    F1 "MUX8" 0 650 50 H V C CNN
    F2 "" 350 -100 50 H I C CNN
    F3 "" 350 -100 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 150 600 -150 700 0 1 0 f
    S -150 600 150 -600 1 1 0 N
    X in0 1 -250 550 100 R 50 50 1 1 I
    X sel1 10 -250 -450 100 R 50 50 1 1 I
    X sel2 11 -250 -550 100 R 50 50 1 1 I
    X _ 12 -250 -250 100 R 50 50 1 1 W NC
    X in1 2 -250 450 100 R 50 50 1 1 I
    X in2 3 -250 350 100 R 50 50 1 1 I
    X in3 4 -250 250 100 R 50 50 1 1 I
    X in4 5 -250 150 100 R 50 50 1 1 I
    X in5 6 -250 50 100 R 50 50 1 1 I
    X in6 7 -250 -50 100 R 50 50 1 1 I
    X out 7 250 550 100 L 50 50 1 1 O
    X in7 8 -250 -150 100 R 50 50 1 1 I
    X sel0 9 -250 -350 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # NOT
    #
    DEF NOT not. 0 0 N N 1 F N
    F0 "not." 100 150 50 H V C CNN
    F1 "NOT" 0 0 50 H V C CNN
    F2 "" 350 -250 50 H I C CNN
    F3 "" 350 -250 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    C 225 0 25 0 1 0 f
    P 4 1 0 10 -100 150 -100 -150 200 0 -100 150 f
    X in 1 -250 0 150 R 50 50 1 1 I
    X out 2 450 0 197 L 50 50 1 1 O
    X _ 3 -200 -100 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # OR2
    #
    DEF OR2 or2. 0 0 N N 1 F N
    F0 "or2." 0 200 50 H V C CNN
    F1 "OR2" 0 0 50 H V C CNN
    F2 "" 50 0 50 H I C CNN
    F3 "" 50 0 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    A -360 0 258 354 -354 1 1 10 N -150 150 -150 -150
    A -47 -52 204 150 837 1 1 10 f 150 0 -24 150
    A -47 52 204 -150 -837 1 1 10 f 150 0 -24 -150
    P 2 1 1 10 -150 -150 -25 -150 f
    P 2 1 1 10 -150 150 -25 150 f
    P 12 1 1 -1000 -25 150 -150 150 -150 150 -140 134 -119 89 -106 41 -103 -10 -109 -59 -125 -107 -150 -150 -150 -150 -25 -150 f
    X in0 1 -300 100 177 R 50 50 1 1 I
    X in1 2 -300 -100 177 R 50 50 1 1 I
    X out 3 300 0 150 L 50 50 1 1 O
    X _ 4 -200 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # PARAMETER
    #
    DEF PARAMETER parameter. 0 0 N N 1 F N
    F0 "parameter." 0 100 50 H I C CNN
    F1 "PARAMETER" 200 0 50 H V R CNN
    F2 "" 300 0 50 H I C CNN
    F3 "" 300 0 50 H I C CNN
    DRAW
    P 4 1 1 0 -350 50 300 50 300 -50 -350 -50 N
    X out 1 400 0 154 L 50 50 1 0 O I
    ENDDRAW
    ENDDEF
    #
    # PID
    #
    DEF PID pid.0. 0 40 N Y 1 F N
    F0 "pid.0." 0 1400 50 H V C CNN
    F1 "PID" 0 1300 50 H V C CNN
    F2 "" 750 600 50 H I C CNN
    F3 "" 750 600 50 H I C CNN
    F4 "1" 600 1300 50 H V C CNN "StripAnno"
    DRAW
    S -550 1250 650 -1750 0 0 0 N
    S 650 1250 -550 1350 0 0 0 f
    X do-pid-calcs 1 -650 -1650 100 R 0 50 1 0 I C
    X maxerrorD 10 -650 -1000 100 R 0 50 1 0 I
    X maxerror 11 -650 -900 100 R 0 50 1 0 I
    X maxcmdDDD 12 -650 -1450 100 R 0 50 1 0 I
    X maxcmdDD 13 -650 -1350 100 R 0 50 1 0 I
    X maxcmdD 14 -650 -1250 100 R 0 50 1 0 I
    X index-enable 15 -650 600 100 R 0 50 1 0 I
    X Igain 16 -650 100 100 R 0 50 1 0 I
    X FF3 17 -650 -450 100 R 0 50 1 0 I
    X FF2 18 -650 -350 100 R 0 50 1 0 I
    X FF1 19 -650 -250 100 R 0 50 1 0 I
    X command 2 -650 950 100 R 0 50 1 0 I
    X FF0 20 -650 -150 100 R 0 50 1 0 I
    X feedback-deriv 21 -650 1100 100 R 0 50 1 0 I
    X feedback 22 -650 1200 100 R 0 50 1 0 I
    X error-previous-target 23 -650 -650 100 R 0 50 1 0 I
    X error 24 750 850 100 L 0 50 1 0 O
    X enable 25 -650 700 100 R 0 50 1 0 I
    X Dgain 26 -650 0 100 R 0 50 1 0 I
    X deadband 27 -650 350 100 R 0 50 1 0 I
    X command-deriv 28 -650 850 100 R 0 50 1 0 I
    X bias 29 -650 450 100 R 0 50 1 0 I
    X saturated-s 3 750 600 100 L 0 50 1 0 O
    X saturated-count 4 750 500 100 L 0 50 1 0 O
    X saturated 5 750 700 100 L 0 50 1 0 O
    X Pgain 6 -650 200 100 R 0 50 1 0 I
    X output 7 750 950 100 L 0 50 1 0 O
    X maxoutput 8 -650 -750 100 R 0 50 1 0 I
    X maxerrorI 9 -650 -1100 100 R 0 50 1 0 I
    ENDDRAW
    ENDDEF
    #
    # SCALE
    #
    DEF SCALE scale. 0 20 N Y 1 F N
    F0 "scale." 0 300 50 H V C CNN
    F1 "SCALE" 0 200 50 H V C CNN
    F2 "" 550 -350 50 H I C CNN
    F3 "" 550 -350 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 150 150 -150 250 0 1 0 f
    S -150 150 150 -250 1 1 0 N
    X in 1 -250 100 100 R 50 50 1 1 I
    X gain 2 -250 -100 100 R 50 50 1 1 I
    X offset 3 -250 -200 100 R 50 50 1 1 I
    X out 4 250 100 100 L 50 50 1 1 O
    X _ 5 -250 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # SPINDLE
    #
    DEF SPINDLE spindle.0. 0 40 N Y 1 F N
    F0 "spindle.0." -50 900 50 H V C CNN
    F1 "SPINDLE" -50 800 50 H V C CNN
    F2 "" -50 100 50 H I C CNN
    F3 "" -50 100 50 H I C CNN
    F4 "1" 550 800 50 H V C CNN "StripAnno"
    DRAW
    S -650 750 600 -1000 1 1 0 N
    S 600 750 -650 850 1 1 0 f
    X at-speed 1 -750 -650 100 R 0 50 1 1 I
    X index-enable 10 -750 200 100 R 0 50 1 1 B
    X amp-fault-in 11 -750 -200 100 R 0 50 1 1 I
    X speed-out-abs 12 700 -700 100 L 0 50 1 1 O
    X speed-out-rps-abs 13 700 -900 100 L 0 50 1 1 O
    X speed-out-rps 14 700 -800 100 L 0 50 1 1 O
    X speed-cmd-rps 15 700 -450 100 L 0 50 1 1 O
    X orient-mode 16 700 -200 100 L 0 50 1 1 O
    X orient-angle 17 700 -100 100 L 0 50 1 1 O
    X speed-in 18 -750 -550 100 R 0 50 1 1 I
    X revs 19 -750 -300 100 R 0 50 1 1 I
    X speed-out 2 700 -550 100 L 0 50 1 1 O
    X orient-fault 20 -750 -50 100 R 0 50 1 1 I
    X is-oriented 21 -750 50 100 R 0 50 1 1 I
    X orient 3 700 0 100 L 0 50 1 1 O
    X locked 4 700 200 100 L 0 50 1 1 O
    X reverse 5 700 450 100 L 0 50 1 1 O
    X on 6 700 650 100 L 0 50 1 1 O
    X forward 7 700 550 100 L 0 50 1 1 O
    X brake 8 700 350 100 L 0 50 1 1 O
    X inhibit 9 -750 650 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # THREAD
    #
    DEF THREAD name-thread. 0 40 N Y 1 F N
    F0 "name-thread." 0 550 59 H V C CNN
    F1 "THREAD" 0 450 50 H V C CNN
    F2 "" 100 100 50 H I C CNN
    F3 "" 100 100 50 H I C CNN
    F4 "1" 400 450 50 H V C CNN "StripAnno"
    DRAW
    T 0 300 0 50 0 0 0 "Add in order found" Normal 0 R C
    T 0 300 350 50 0 0 0 "First in thread" Normal 0 R C
    T 0 250 -350 50 0 0 0 "Last in thread" Normal 0 R C
    S -450 400 450 500 0 1 0 f
    S 450 -450 -450 400 0 1 0 N
    X 1 1 550 350 100 L 0 50 1 0 w C
    X 2 2 550 250 100 L 0 50 1 0 w C
    X 3 3 550 150 100 L 0 50 1 0 w C
    X _ 4 550 0 100 L 0 50 1 0 w C
    X -3 5 550 -150 100 L 0 50 1 0 w C
    X -2 6 550 -250 100 L 0 50 1 0 w C
    X -1 7 550 -350 100 L 0 50 1 0 w C
    ENDDRAW
    ENDDEF
    #
    # THREAD_FLAG
    #
    DEF THREAD_FLAG thread-flag. 0 0 N N 1 F N
    F0 "thread-flag." 0 250 50 H V C CNN
    F1 "THREAD_FLAG" 0 150 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "1" 100 50 50 H V C CNN "StripAnno"
    DRAW
    P 6 0 1 0 0 0 0 50 -40 75 0 100 40 75 0 50 N
    X thread 1 0 0 0 U 50 50 0 0 B C
    ENDDRAW
    ENDDEF
    #
    # TIMEDELAY
    #
    DEF TIMEDELAY timedelay. 0 20 N Y 1 F N
    F0 "timedelay." 0 350 50 H V C CNN
    F1 "TIMEDELAY" 0 250 50 H V C CNN
    F2 "" 0 150 50 H I C CNN
    F3 "" 0 150 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 250 200 -250 300 0 1 0 f
    S -250 200 250 -200 1 1 0 N
    X in 1 -350 150 100 R 50 50 1 1 I
    X on-delay 2 -350 -50 100 R 50 50 1 1 I
    X off-delay 3 -350 -150 100 R 50 50 1 1 I
    X out 4 350 150 100 L 50 50 1 1 O
    X elapsed 5 350 50 100 L 50 50 1 1 O
    X _ 6 -350 50 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # TOGGLE
    #
    DEF TOGGLE toggle. 0 20 N Y 1 F N
    F0 "toggle." 0 300 50 H V C CNN
    F1 "TOGGLE" 0 200 50 H V C CNN
    F2 "" 300 -50 50 H I C CNN
    F3 "" 300 -50 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 250 150 -200 250 0 1 0 f
    S -200 150 250 -150 1 1 0 N
    X in 1 -300 100 100 R 50 50 1 1 I
    X out 2 350 100 100 L 50 50 1 1 O
    X debounce 4 -250 -100 100 R 50 50 1 1 I I
    X _ 5 -300 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # XOR2
    #
    DEF XOR2 xor2. 0 0 N N 1 F N
    F0 "xor2." -50 200 50 H V C CNN
    F1 "XOR2" 25 0 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    A -385 0 258 354 -354 1 1 10 N -175 150 -175 -150
    A -360 0 258 354 -354 1 1 10 N -150 150 -150 -150
    A -47 -52 204 150 837 1 1 10 f 150 0 -24 150
    A -47 52 204 -150 -837 1 1 10 f 150 0 -24 -150
    P 2 1 1 10 -150 -150 -25 -150 f
    P 2 1 1 10 -150 150 -25 150 f
    P 12 1 1 -1000 -25 150 -150 150 -150 150 -140 134 -119 89 -106 41 -103 -10 -109 -59 -125 -107 -150 -150 -150 -150 -25 -150 f
    X in0 1 -350 100 228 R 50 50 1 1 I
    X in1 2 -350 -100 228 R 50 50 1 1 I
    X out 3 300 0 150 L 50 50 1 1 O
    X _ 4 -250 0 150 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    #End Library

  • Schauer Solid State Battery Charger: Digital Meter Retrofit

    Schauer Solid State Battery Charger: Digital Meter Retrofit

    The Forester’s battery has been on life support from an ancient Schauer “Solid State” charger (which may have Come With The House™) for the last year:

    Schauer battery charger - analog ammeter
    Schauer battery charger – analog ammeter

    A remote Squidwrench session provided an opportunity to replace its OEM ammeter with a cheap volt-amp meter:

    Schauer battery charger - digital meter
    Schauer battery charger – digital meter

    The charger is “solid state” because it contains silicon electronics:

    Schauer battery charger - solid state components
    Schauer battery charger – solid state components

    That’s an SCR implanted in the aluminum heatsink. The other side has a Motorola 18356 house number, a date code that might be 523, and the word MEXICO. The company now known as NXP says Motorola opened its Guadalajara plant in 1969, so they could have built the SCR in either 1973 or 1975; it’s not clear who manufactures what these days.

    The black tubing contains at least one part with enough value to justify the (presumably) Kovar lead; nowadays, it would be a “gold tone” finish. It’s probably a Zener diode setting the trickle-charging voltage, joined to the resistor lead in the crimped block. I don’t know if the glass diode is soldered to the Zener, but I’m reasonably sure if the third lead came from a transistor tucked inside the sleeve, we’d read about it on the charger’s front cover.

    In an ideal world, a digital meter would fit into a matching rectangular hole in the front panel, but that’s not the world we live in. After wrestling my gotta-make-a-solid-model jones to the floor, I got primal on a random slab of soft-ish plastic sheet:

    Schauer battery charger - bezel nibbling
    Schauer battery charger – bezel nibbling

    There’s nothing like some bandsaw / belt sander / nibbler action to jam a square peg into a round hole:

    Schauer battery charger - bezel test fit
    Schauer battery charger – bezel test fit

    It’s actually a firm press fit; whenever something like that happens, you know the project will end well.

    Hot melt glue FTW:

    Schauer battery charger - digital meter wiring
    Schauer battery charger – digital meter wiring

    The new meter’s (heavy) red-black leads go to the same terminals as the old meter’s wires, paying attention to the polarity. I splurged with insulated QD terminals on the old wires where a joint was needed.

    The meter’s thin red lead expects to see a power supply under 50 V with no particular regulation requirements, so I used the same flying-component design as the rest of the charger:

    Schauer battery charger - meter power supply
    Schauer battery charger – meter power supply

    The meter draws basically no current, at least on the scale of an automotive battery charger, so the 220 µf cap holds pretty nearly the peak 18 V half-wave rectified from the center tap by a 1N5819 Schottky diode.

    Those two squares riveted to the back panel are genuine selenium rectifiers, from back in the day when silicon power diodes weren’t cheap and readily available. They also limit the charger’s peak current and have yet to emit their incredibly foul stench upon failure; you always know exactly what died when that happens.

    Selenium rectifiers were pretty much obsolete by the early 1970s, agreeing with a 1973 date code. Schauer might have been working through their stockpile of obsolete rectifiers, which would have been sunk-cost-cheap compared to silicon diodes.

    The meter’s thin black lead goes to the power supply common point, which turns out to be where those rectifiers meet. The larger black wire goes off to the meter’s fat black lead on the other side of the aluminum heatsink, joining it in a new insulated QD terminal.

    The meter’s thin yellow wire is its voltage sense input, which gets soldered directly to the hot lead of the SCR.

    The meter indicates DC voltages and currents, which definitely isn’t the situation in the 100 Ω power resistor shown in the second picture.

    The voltage:

    Schauer battery charger - voltage waveform
    Schauer battery charger – voltage waveform

    And the current at 20 mA/div, showing why silicon replaced selenium:

    Schauer battery charger - current waveform
    Schauer battery charger – current waveform

    Yes, the current does go negative while the rectifiers figure out what to do next.

    The charger seems a little happier out in the garage:

    Schauer battery charger - in use
    Schauer battery charger – in use

    The battery holds the voltage steady at 13.7 V, with the charger producing 85 mV blips every second or so:

    Schauer battery charger - float V pulse
    Schauer battery charger – float V pulse

    Those blips correspond to 3 A pulses rammed into the battery:

    Schauer battery charger - float A pulse - 1 A-div
    Schauer battery charger – float A pulse – 1 A-div

    They’re measured across a 1 Ω series resistor that’s surely limiting the maximum current: 18 V from the transformer minus 13.7 V on the battery minus other IR losses doesn’t leave room for anything more than 3 V across the resistor. I wasn’t going to haul the Tek current probes out to the garage just for the occasion.

    Opening the Forester’s door to turn on all its LED interior lights bumps the meter to about 1 A, although the truth is more complicated:

    Schauer battery charger - loaded A pulse - 1 A-div
    Schauer battery charger – loaded A pulse – 1 A-div

    The average current is, indeed, just under 1 A, but in this situation the meter’s cool blue number seems more like a comfort indicator than anything particularly reliable.

    All I really wanted from the meter was an indication that the trickle charger was trickling, so I disconnected Tiny Scope, declared victory, and closed the garage door.