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.

Tag: CNC

Making parts with mathematics

  • 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
  • The Joggy Thing vs. LinuxCNC 2.8

    The Joggy Thing vs. LinuxCNC 2.8

    After getting the Sherline mostly working with LinuxCNC 2.8 and the Mesa 5I25 FPGA card, I updated the HAL code turning the Logitech gamepad into The Joggy Thing:

    Sherline Mill - Logitech Gamepad Joggy Thing
    Sherline Mill – Logitech Gamepad Joggy Thing

    This required significantly more effort than I expected, mainly because I can no longer edit the Eagle schematics defining the HAL file. In the intervening years, Autodesk bought the Eagle EE CAD program, converted it into a subscription service, sutured it onto their Fusion 360 package, and priced the result far beyond my toy budget. While they do offer a free tier limited to “individuals for personal, non-commercial use”, schematics with only two sheets pretty much wipes out its value.

    Because the EESchema part of Kicad can export its netlists as XML files, someone experienced in wrangling XSLT, perhaps using Python + lxml, could recreate the function of the Eagle ULP with Kicad schematics / netlists. I am not, however, that person, although it would certainly be a Learning Experience™ of the first water.

    So I updated the automatically generated HAL file on hard mode with a text editor, which, given HAL’s limited debugging support, somewhat resembles juggling a greasy bowling ball, a full-throttle chainsaw, and a squalling baby in a poopy diaper.

    The major conceptual problem was LinuxCNC’s recent separation of “axes” from “joints”, with resulting changes in both nomenclature and control. Eventually, I found some key hints in a very recent update to a LinuxCNC wiki entry describing a similar Logitech gamepad interface.

    The basic Joggy Thing logic remains the same, with “analog” values from the joysticks now presented to both the halui.axis and halui.joint controls. The new trick of holding the pre-startup values (presumably zeros) with feedback around a multiplexer qualifies as a Moby Hack preventing a startup glitch from triggering an error having something to do with an E-stop.

    The machine still runs away on X and Z at full throttle instantly after tapping the Machine-On button for the first time in the morning. Come to find out the gamepad starts up with all four joysticks jammed at -1 until the first activation of any axis or button, which I’m sure it always did, but something in HAL’s bowels now responds differently. More work will be required, although I think the simplest solution will involve holding everything inert until the logic sees a specific gamepad button.

    The LinuxCNC HAL code as a GitHub Gist:

    # HAL for Logitech Joggy Thing
    ####################################################
    # Load realtime and userspace modules
    loadusr -W hal_input -KA Dual
    #loadrt logic count=1 personality=0x104
    loadrt constant count=13
    loadrt and2 count=17
    loadrt conv_float_s32 count=1
    loadrt flipflop count=4
    loadrt mux2 count=1
    loadrt mux4 count=5
    loadrt not count=8
    loadrt or2 count=13
    loadrt scale count=7
    loadrt timedelay count=1
    loadrt toggle count=1
    ####################################################
    # Hook functions into threads
    #addf logic.0 servo-thread
    addf constant.0 servo-thread
    addf constant.1 servo-thread
    addf constant.2 servo-thread
    addf constant.3 servo-thread
    addf constant.4 servo-thread
    addf constant.5 servo-thread
    addf constant.6 servo-thread
    addf constant.7 servo-thread
    addf constant.8 servo-thread
    addf constant.9 servo-thread
    addf constant.10 servo-thread
    addf constant.11 servo-thread
    addf constant.12 servo-thread
    addf and2.0 servo-thread
    addf and2.1 servo-thread
    addf and2.2 servo-thread
    addf and2.3 servo-thread
    addf and2.4 servo-thread
    addf and2.5 servo-thread
    addf and2.6 servo-thread
    addf and2.7 servo-thread
    addf and2.8 servo-thread
    addf and2.9 servo-thread
    addf and2.10 servo-thread
    addf and2.11 servo-thread
    addf and2.12 servo-thread
    addf and2.13 servo-thread
    addf and2.14 servo-thread
    addf and2.15 servo-thread
    addf and2.16 servo-thread
    addf conv-float-s32.0 servo-thread
    addf toggle.0 servo-thread
    addf flipflop.0 servo-thread
    addf flipflop.1 servo-thread
    addf flipflop.2 servo-thread
    addf flipflop.3 servo-thread
    addf timedelay.0 servo-thread
    addf or2.0 servo-thread
    addf or2.1 servo-thread
    addf or2.2 servo-thread
    addf or2.3 servo-thread
    addf or2.4 servo-thread
    addf or2.5 servo-thread
    addf or2.6 servo-thread
    addf or2.7 servo-thread
    addf or2.8 servo-thread
    addf or2.9 servo-thread
    addf or2.10 servo-thread
    addf or2.11 servo-thread
    addf or2.12 servo-thread
    addf not.0 servo-thread
    addf not.1 servo-thread
    addf not.2 servo-thread
    addf not.3 servo-thread
    addf not.4 servo-thread
    addf not.5 servo-thread
    addf not.6 servo-thread
    addf not.7 servo-thread
    addf scale.0 servo-thread
    addf scale.1 servo-thread
    addf scale.2 servo-thread
    addf scale.3 servo-thread
    addf scale.4 servo-thread
    addf scale.5 servo-thread
    addf scale.6 servo-thread
    addf mux2.0 servo-thread
    addf mux4.0 servo-thread
    addf mux4.1 servo-thread
    addf mux4.2 servo-thread
    addf mux4.3 servo-thread
    addf mux4.4 servo-thread
    ####################################################
    # Set constants
    setp constant.0.value 0.1
    setp constant.1.value 20
    setp constant.2.value [TRAJ]MAX_LINEAR_VELOCITY
    setp constant.3.value [TRAJ]MAX_ANGULAR_VELOCITY
    setp constant.4.value 60
    setp constant.5.value 0.50
    setp constant.6.value 1.00
    setp constant.7.value 0.10
    setp constant.8.value 0.10
    setp constant.9.value 0.0
    setp constant.10.value -1.0
    setp constant.11.value 0.020
    setp constant.12.value 0.000
    ####################################################
    # Connect Modules with nets
    # both rear top buttons for e-stop, bottom right to reset
    net estop-a input.0.btn-top2 and2.0.in0
    net estop-b input.0.btn-base and2.0.in1
    net n_13 and2.0.out halui.estop.activate
    net reset-estop input.0.btn-base2 halui.estop.reset
    # button to start manual mode (probably not needed with 2.8)
    net manual-mode halui.mode.manual input.0.btn-base3
    net program-resume halui.program.resume input.0.btn-base4
    net n_14 or2.3.in0 input.0.btn-base5
    net n_15 or2.3.in1 input.0.btn-base6
    net n_16 toggle.0.in or2.3.out
    net n_17 conv-float-s32.0.out input.0.abs-x-flat input.0.abs-y-flat input.0.abs-z-flat input.0.abs-rz-flat
    net n_18 constant.1.out conv-float-s32.0.in
    net n_19 constant.4.out scale.0.gain
    net n_20 constant.5.out scale.1.gain
    net n_21 constant.6.out scale.2.gain
    net n_22 constant.7.out scale.3.gain
    net n_23 scale.4.gain constant.8.out
    net n_24 constant.0.out halui.axis.jog-deadband
    net n_42 or2.7.in0 input.0.abs-x-is-pos
    net n_43 or2.7.in1 input.0.abs-x-is-neg
    net n_44 or2.8.in0 input.0.abs-y-is-pos
    net n_45 or2.8.in1 input.0.abs-y-is-neg
    net n_46 or2.9.in0 input.0.abs-z-is-pos
    net n_47 or2.9.in1 input.0.abs-z-is-neg
    net n_48 or2.10.in0 input.0.abs-rz-is-pos
    net n_49 or2.10.in1 input.0.abs-rz-is-neg
    net n_51 constant.10.out scale.5.gain scale.6.gain
    net n_57 and2.1.out halui.axis.x.minus halui.joint.0.minus
    net n_58 and2.2.out halui.axis.x.plus halui.joint.0.plus
    net n_59 and2.3.out halui.axis.y.minus halui.joint.1.minus
    net n_60 and2.4.out halui.axis.y.plus halui.joint.1.plus
    net n_61 and2.5.out halui.axis.z.minus halui.joint.2.minus
    net n_62 and2.6.out halui.axis.z.plus halui.joint.2.plus
    net n_63 and2.7.out halui.axis.a.minus halui.joint.3.minus
    net n_64 and2.8.out halui.axis.a.plus halui.joint.3.plus
    # sort out jog speeds
    net az-buttons-active or2.1.out or2.12.in1
    net xy-buttons-active or2.5.out or2.12.in0
    net any-buttons-active or2.12.out mux4.0.sel0 timedelay.0.in
    net n_54 constant.11.out timedelay.0.on-delay
    net n_55 constant.12.out timedelay.0.off-delay
    net n_56 timedelay.0.out and2.1.in1 and2.2.in1 and2.3.in1 and2.4.in1 and2.5.in1 and2.6.in1 and2.7.in1 and2.8.in1
    net jog-crawl toggle.0.out mux4.0.sel1
    net knob-fast scale.1.out mux4.0.in0 scale.3.in
    net button-fast scale.2.out mux4.0.in1 scale.4.in
    net knob-crawl scale.3.out mux4.0.in2
    net button-crawl scale.4.out mux4.0.in3
    net jog-speed mux4.0.out halui.axis.jog-speed halui.joint.jog-speed
    net angular_motion or2.11.out mux2.0.sel
    net n_25 constant.2.out mux2.0.in0
    net n_26 constant.3.out mux2.0.in1
    net vel-per-second mux2.0.out scale.0.in
    net vel-per-minute scale.0.out scale.1.in scale.2.in
    net az-reset and2.14.out flipflop.2.reset flipflop.3.reset
    net xy-reset and2.10.out flipflop.0.reset flipflop.1.reset
    # hold jog speed unchanged until machine turns on
    # mux S&H from https://wiki.linuxcnc.org/cgi-bin/wiki.pl?Simple_Remote_Pendant
    net jog-mux-enable halui.machine.is-on mux4.1.sel1 mux4.2.sel1 mux4.3.sel1 mux4.4.sel1
    net axis-disabled-value constant.9.out mux4.1.in2 mux4.2.in2 mux4.3.in2 mux4.4.in2
    net x-analog mux4.1.out mux4.1.in0 mux4.1.in1 halui.axis.x.analog halui.joint.0.analog
    net y-analog mux4.2.out mux4.2.in0 mux4.2.in1 halui.axis.y.analog halui.joint.1.analog
    net z-analog mux4.3.out mux4.3.in0 mux4.3.in1 halui.axis.z.analog halui.joint.2.analog
    net a-analog mux4.4.out mux4.4.in0 mux4.4.in1 halui.axis.a.analog halui.joint.3.analog
    #net x-amp-enable logic.0.in-00
    #net y-amp-enable logic.0.in-01
    #net z-amp-enable logic.0.in-02
    #net a-amp-enable logic.0.in-03
    net x-buttons-active or2.4.out or2.5.in0
    net x-disable not.4.out and2.12.in1
    net x-enable flipflop.0.out not.4.in mux4.1.sel0
    net x-hat-minus or2.4.in1 input.0.abs-hat0x-is-neg and2.1.in0
    net x-hat-plus or2.4.in0 input.0.abs-hat0x-is-pos and2.2.in0
    net x-jog input.0.abs-x-position mux4.1.in3
    net x-knob-active or2.7.out not.0.in and2.9.in0
    net x-knob-inactive not.0.out and2.10.in0 and2.11.in0
    net x-set and2.9.out flipflop.0.set
    net y-buttons-active or2.6.out or2.5.in1
    net y-disable not.5.out and2.9.in1
    net y-enable flipflop.1.out not.5.in mux4.2.sel0
    net y-hat-minus or2.6.in1 input.0.abs-hat0y-is-neg and2.4.in0
    net y-hat-plus or2.6.in0 input.0.abs-hat0y-is-pos and2.3.in0
    net y-jog input.0.abs-y-position scale.5.in
    net y-jog-reversed scale.5.out mux4.2.in3
    net y-knob-active not.1.in or2.8.out and2.11.in1
    net y-knob-inactive not.1.out and2.10.in1
    net y-select and2.12.in0 and2.11.out
    net y-set flipflop.1.set and2.12.out
    net z-button-minus or2.2.in0 input.0.btn-thumb and2.5.in0
    net z-button-plus or2.2.in1 input.0.btn-top and2.6.in0
    net z-buttons-active or2.2.out or2.1.in1
    net z-disable not.6.out and2.16.in1
    net z-enable not.6.in flipflop.2.out mux4.3.sel0
    net z-jog input.0.abs-rz-position scale.6.in
    net z-jog-reversed scale.6.out mux4.3.in3
    net z-knob-active not.3.in or2.10.out and2.13.in0
    net z-knob-inactive not.3.out and2.15.in0 and2.14.in0
    net z-set and2.13.out flipflop.2.set
    net a-button-minus or2.0.in0 input.0.btn-joystick and2.7.in0
    net a-button-plus or2.0.in1 input.0.btn-thumb2 and2.8.in0
    net a-buttons-active or2.0.out or2.1.in0 or2.11.in1
    net a-disable not.7.out and2.13.in1
    net a-enable or2.11.in0 flipflop.3.out not.7.in mux4.4.sel0
    net a-jog input.0.abs-z-position mux4.4.in3
    net a-knob-active or2.9.out not.2.in and2.15.in1
    net a-knob-inactive not.2.out and2.14.in1
    net a-select and2.16.in0 and2.15.out
    net a-set flipflop.3.set and2.16.out
    view raw joggy.hal hosted with ❤ by GitHub
  • LinuxCNC: Mesa 5I25 For The Sherline Mill

    LinuxCNC: Mesa 5I25 For The Sherline Mill

    Updating the Sherline’s LinuxCNC from 2.7.ancient to 2.8.1, which I did by the simple expedient of replacing the hard drive with an SSD from the heap and doing a clean installation, provided the opportunity of switching from the parallel port to a Mesa 5I25 FPGA card to put timing-critical step generation under hardware control.

    I has flashed the card with Mesa’s Probotix PBX-RF BIT file, then invoked it with a configuration string turning off everything except the stepgen modules:

    loadrt hm2_pci config="num_encoders=0 num_pwmgens=0 num_stepgens=4"
    

    Which produces a simple pinout on the back panel DB-25 connector:

    hm2_pci: loading Mesa AnyIO HostMot2 driver version 0.7
    hm2_pci: discovered 5i25 at 0000:04:02.0
    hm2/hm2_5i25.0: Low Level init 0.15
    hm2/hm2_5i25.0: 34 I/O Pins used:
    hm2/hm2_5i25.0:     IO Pin 000 (P3-01): IOPort
    hm2/hm2_5i25.0:     IO Pin 001 (P3-14): IOPort
    hm2/hm2_5i25.0:     IO Pin 002 (P3-02): StepGen #0, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 003 (P3-15): IOPort
    hm2/hm2_5i25.0:     IO Pin 004 (P3-03): StepGen #0, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 005 (P3-16): IOPort
    hm2/hm2_5i25.0:     IO Pin 006 (P3-04): StepGen #1, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 007 (P3-17): IOPort
    hm2/hm2_5i25.0:     IO Pin 008 (P3-05): StepGen #1, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 009 (P3-06): StepGen #2, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 010 (P3-07): StepGen #2, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 011 (P3-08): StepGen #3, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 012 (P3-09): StepGen #3, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 013 (P3-10): IOPort
    hm2/hm2_5i25.0:     IO Pin 014 (P3-11): IOPort
    hm2/hm2_5i25.0:     IO Pin 015 (P3-12): IOPort
    hm2/hm2_5i25.0:     IO Pin 016 (P3-13): IOPort
    
    

    The Sherline CNC driver requires an adapter to swap the Step and Direction signals on the output connector.

    The Sherline controller expects active-low Step signals:

    # invert step output bits
    setp   [HMOT](FPGA0).gpio.002.invert_output     1
    setp   [HMOT](FPGA0).gpio.006.invert_output     1
    setp   [HMOT](FPGA0).gpio.009.invert_output     1
    setp   [HMOT](FPGA0).gpio.011.invert_output     1
    

    The Y and Z drivers needed the same Direction swap as before:

    # invert direction output bits
    setp   [HMOT](FPGA0).gpio.008.invert_output     1
    setp   [HMOT](FPGA0).gpio.010.invert_output     1
    

    Because the 5I25 uses 3.3 V logic with interface drivers to match the “parallel port” 5 V levels, it has different electrical characteristics than the parallel port built into the Dell Optiplex 760. Putting a 100 nF cap across the Probe input reduced, but did not eliminate, what looked like a nice 60 Hz signal on that long wire, so I added a firmware debouncer:

    loadrt debounce cfg=2
    addf debounce.0               servo-thread
    setp debounce.0.delay 3
    
    net probe-raw debounce.0.1.in [HMOT](FPGA0).gpio.003.in_not
    net probe-in debounce.0.1.out
    

    The additional 3 ms delay doesn’t amount to much distance, even were I to probe at the machine’s top 10 mm/s speed.

    Although the seemingly identical Home switch input seemed stable, it got the same treatment:

    net home-raw debounce.0.0.in [HMOT](FPGA0).gpio.013.in_not
    net all-home debounce.0.0.out
    

    The PID loops have a very simple setup, with P = 1000 and FF1 = 1, which seems entirely adequate without any attempt at tuning. The following errors seems to stay under 20 ppm, in the machine’s native inches, while cutting the standard Axis “splash G-Code” file with all the speeds cranked up to 24 in/min = 610 mm/min:

    LinuxCNC - Sherline f-error
    LinuxCNC – Sherline f-error

    Claiming a 20 µinch error for a Sherline is certainly aspirational.

    The INI and HAL files as a GitHub Gist:

    # DO NOT RUN PNCCONF EVER AGAIN
    loadrt [KINS]KINEMATICS
    loadrt [EMCMOT]EMCMOT servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS
    loadrt hostmot2
    loadrt hm2_pci config="num_encoders=0 num_pwmgens=0 num_stepgens=4"
    loadrt debounce cfg=2
    addf debounce.0 servo-thread
    setp debounce.0.delay 3
    setp [HMOT](FPGA0).watchdog.timeout_ns 5000000
    loadrt pid names=pid.x,pid.y,pid.z,pid.a
    addf [HMOT](FPGA0).read servo-thread
    addf motion-command-handler servo-thread
    addf motion-controller servo-thread
    addf pid.x.do-pid-calcs servo-thread
    addf pid.y.do-pid-calcs servo-thread
    addf pid.z.do-pid-calcs servo-thread
    addf pid.a.do-pid-calcs servo-thread
    addf [HMOT](FPGA0).write servo-thread
    # external output signals
    #setp [HMOT](FPGA0).gpio.000.out 1
    net estop-out [HMOT](FPGA0).gpio.000.out
    #net all-amps-enabled logic.0.and [HMOT](FPGA0).gpio.007.out
    # Home switch
    net home-raw debounce.0.0.in [HMOT](FPGA0).gpio.013.in_not
    net all-home debounce.0.0.out
    # Probe switch
    net probe-raw debounce.0.1.in [HMOT](FPGA0).gpio.003.in_not
    net probe-in debounce.0.1.out
    #*******************
    # AXIS X JOINT 0
    #*******************
    setp pid.x.Pgain [JOINT_0]P
    setp pid.x.Igain [JOINT_0]I
    setp pid.x.Dgain [JOINT_0]D
    setp pid.x.bias [JOINT_0]BIAS
    setp pid.x.FF0 [JOINT_0]FF0
    setp pid.x.FF1 [JOINT_0]FF1
    setp pid.x.FF2 [JOINT_0]FF2
    setp pid.x.deadband [JOINT_0]DEADBAND
    setp pid.x.maxoutput [JOINT_0]MAX_OUTPUT
    setp pid.x.error-previous-target true
    # This setting is to limit bogus stepgen
    # velocity corrections caused by position
    # feedback sample time jitter.
    setp pid.x.maxerror 0.000500
    net x-index-enable <=> pid.x.index-enable
    net x-amp-enable => pid.x.enable
    net x-pos-cmd => pid.x.command
    net x-pos-fb => pid.x.feedback
    net x-output <= pid.x.output
    # Step Gen signals/setup
    setp [HMOT](FPGA0).stepgen.00.dirsetup [JOINT_0]DIRSETUP
    setp [HMOT](FPGA0).stepgen.00.dirhold [JOINT_0]DIRHOLD
    setp [HMOT](FPGA0).stepgen.00.steplen [JOINT_0]STEPLEN
    setp [HMOT](FPGA0).stepgen.00.stepspace [JOINT_0]STEPSPACE
    setp [HMOT](FPGA0).stepgen.00.position-scale [JOINT_0]STEP_SCALE
    setp [HMOT](FPGA0).stepgen.00.step_type 0
    setp [HMOT](FPGA0).stepgen.00.control-type 1
    setp [HMOT](FPGA0).stepgen.00.maxaccel [JOINT_0]STEPGEN_MAXACCEL
    setp [HMOT](FPGA0).stepgen.00.maxvel [JOINT_0]STEPGEN_MAXVEL
    # invert step output bit
    setp [HMOT](FPGA0).gpio.002.invert_output 1
    # —closedloop stepper signals—
    net x-pos-cmd <= joint.0.motor-pos-cmd
    net x-vel-cmd <= joint.0.vel-cmd
    net x-output <= [HMOT](FPGA0).stepgen.00.velocity-cmd
    net x-pos-fb <= [HMOT](FPGA0).stepgen.00.position-fb
    net x-pos-fb => joint.0.motor-pos-fb
    net x-amp-enable <= joint.0.amp-enable-out
    net x-amp-enable => [HMOT](FPGA0).stepgen.00.enable
    # —setup home / limit switch signals—
    net all-home => joint.0.home-sw-in
    net x-neg-limit => joint.0.neg-lim-sw-in
    net x-pos-limit => joint.0.pos-lim-sw-in
    #*******************
    # AXIS Y JOINT 1
    #*******************
    setp pid.y.Pgain [JOINT_1]P
    setp pid.y.Igain [JOINT_1]I
    setp pid.y.Dgain [JOINT_1]D
    setp pid.y.bias [JOINT_1]BIAS
    setp pid.y.FF0 [JOINT_1]FF0
    setp pid.y.FF1 [JOINT_1]FF1
    setp pid.y.FF2 [JOINT_1]FF2
    setp pid.y.deadband [JOINT_1]DEADBAND
    setp pid.y.maxoutput [JOINT_1]MAX_OUTPUT
    setp pid.y.error-previous-target true
    # This setting is to limit bogus stepgen
    # velocity corrections caused by position
    # feedback sample time jitter.
    setp pid.y.maxerror 0.000500
    net y-index-enable <=> pid.y.index-enable
    net y-amp-enable => pid.y.enable
    net y-pos-cmd => pid.y.command
    net y-pos-fb => pid.y.feedback
    net y-output <= pid.y.output
    # Step Gen signals/setup
    setp [HMOT](FPGA0).stepgen.01.dirsetup [JOINT_1]DIRSETUP
    setp [HMOT](FPGA0).stepgen.01.dirhold [JOINT_1]DIRHOLD
    setp [HMOT](FPGA0).stepgen.01.steplen [JOINT_1]STEPLEN
    setp [HMOT](FPGA0).stepgen.01.stepspace [JOINT_1]STEPSPACE
    setp [HMOT](FPGA0).stepgen.01.position-scale [JOINT_1]STEP_SCALE
    setp [HMOT](FPGA0).stepgen.01.step_type 0
    setp [HMOT](FPGA0).stepgen.01.control-type 1
    setp [HMOT](FPGA0).stepgen.01.maxaccel [JOINT_1]STEPGEN_MAXACCEL
    setp [HMOT](FPGA0).stepgen.01.maxvel [JOINT_1]STEPGEN_MAXVEL
    # invert step output bit
    setp [HMOT](FPGA0).gpio.006.invert_output 1
    # invert direction output bit
    setp [HMOT](FPGA0).gpio.008.invert_output 1
    # —closedloop stepper signals—
    net y-pos-cmd <= joint.1.motor-pos-cmd
    net y-vel-cmd <= joint.1.vel-cmd
    net y-output <= [HMOT](FPGA0).stepgen.01.velocity-cmd
    net y-pos-fb <= [HMOT](FPGA0).stepgen.01.position-fb
    net y-pos-fb => joint.1.motor-pos-fb
    net y-amp-enable <= joint.1.amp-enable-out
    net y-amp-enable => [HMOT](FPGA0).stepgen.01.enable
    # —setup home / limit switch signals—
    net all-home => joint.1.home-sw-in
    net y-neg-limit => joint.1.neg-lim-sw-in
    net y-pos-limit => joint.1.pos-lim-sw-in
    #*******************
    # AXIS Z JOINT 2
    #*******************
    setp pid.z.Pgain [JOINT_2]P
    setp pid.z.Igain [JOINT_2]I
    setp pid.z.Dgain [JOINT_2]D
    setp pid.z.bias [JOINT_2]BIAS
    setp pid.z.FF0 [JOINT_2]FF0
    setp pid.z.FF1 [JOINT_2]FF1
    setp pid.z.FF2 [JOINT_2]FF2
    setp pid.z.deadband [JOINT_2]DEADBAND
    setp pid.z.maxoutput [JOINT_2]MAX_OUTPUT
    setp pid.z.error-previous-target true
    # This setting is to limit bogus stepgen
    # velocity corrections caused by position
    # feedback sample time jitter.
    setp pid.z.maxerror 0.000500
    net z-index-enable <=> pid.z.index-enable
    net z-amp-enable => pid.z.enable
    net z-pos-cmd => pid.z.command
    net z-pos-fb => pid.z.feedback
    net z-output <= pid.z.output
    # Step Gen signals/setup
    setp [HMOT](FPGA0).stepgen.02.dirsetup [JOINT_2]DIRSETUP
    setp [HMOT](FPGA0).stepgen.02.dirhold [JOINT_2]DIRHOLD
    setp [HMOT](FPGA0).stepgen.02.steplen [JOINT_2]STEPLEN
    setp [HMOT](FPGA0).stepgen.02.stepspace [JOINT_2]STEPSPACE
    setp [HMOT](FPGA0).stepgen.02.position-scale [JOINT_2]STEP_SCALE
    setp [HMOT](FPGA0).stepgen.02.step_type 0
    setp [HMOT](FPGA0).stepgen.02.control-type 1
    setp [HMOT](FPGA0).stepgen.02.maxaccel [JOINT_2]STEPGEN_MAXACCEL
    setp [HMOT](FPGA0).stepgen.02.maxvel [JOINT_2]STEPGEN_MAXVEL
    # invert step output bit
    setp [HMOT](FPGA0).gpio.009.invert_output 1
    # invert direction output bit
    setp [HMOT](FPGA0).gpio.010.invert_output 1
    # —closedloop stepper signals—
    net z-pos-cmd <= joint.2.motor-pos-cmd
    net z-vel-cmd <= joint.2.vel-cmd
    net z-output <= [HMOT](FPGA0).stepgen.02.velocity-cmd
    net z-pos-fb <= [HMOT](FPGA0).stepgen.02.position-fb
    net z-pos-fb => joint.2.motor-pos-fb
    net z-amp-enable <= joint.2.amp-enable-out
    net z-amp-enable => [HMOT](FPGA0).stepgen.02.enable
    # —setup home / limit switch signals—
    net all-home => joint.2.home-sw-in
    net z-neg-limit => joint.2.neg-lim-sw-in
    net z-pos-limit => joint.2.pos-lim-sw-in
    #*******************
    # AXIS A JOINT 3
    #*******************
    setp pid.a.Pgain [JOINT_3]P
    setp pid.a.Igain [JOINT_3]I
    setp pid.a.Dgain [JOINT_3]D
    setp pid.a.bias [JOINT_3]BIAS
    setp pid.a.FF0 [JOINT_3]FF0
    setp pid.a.FF1 [JOINT_3]FF1
    setp pid.a.FF2 [JOINT_3]FF2
    setp pid.a.deadband [JOINT_3]DEADBAND
    setp pid.a.maxoutput [JOINT_3]MAX_OUTPUT
    setp pid.a.error-previous-target true
    # This setting is to limit bogus stepgen
    # velocity corrections caused by position
    # feedback sample time jitter.
    setp pid.a.maxerror 0.000500
    net a-index-enable <=> pid.a.index-enable
    net a-amp-enable => pid.a.enable
    net a-pos-cmd => pid.a.command
    net a-pos-fb => pid.a.feedback
    net a-output <= pid.a.output
    # Step Gen signals/setup
    setp [HMOT](FPGA0).stepgen.03.dirsetup [JOINT_3]DIRSETUP
    setp [HMOT](FPGA0).stepgen.03.dirhold [JOINT_3]DIRHOLD
    setp [HMOT](FPGA0).stepgen.03.steplen [JOINT_3]STEPLEN
    setp [HMOT](FPGA0).stepgen.03.stepspace [JOINT_3]STEPSPACE
    setp [HMOT](FPGA0).stepgen.03.position-scale [JOINT_3]STEP_SCALE
    setp [HMOT](FPGA0).stepgen.03.step_type 0
    setp [HMOT](FPGA0).stepgen.03.control-type 1
    setp [HMOT](FPGA0).stepgen.03.maxaccel [JOINT_3]STEPGEN_MAXACCEL
    setp [HMOT](FPGA0).stepgen.03.maxvel [JOINT_3]STEPGEN_MAXVEL
    # invert step output bit
    setp [HMOT](FPGA0).gpio.011.invert_output 1
    # —closedloop stepper signals—
    net a-pos-cmd <= joint.3.motor-pos-cmd
    net a-vel-cmd <= joint.3.vel-cmd
    net a-output <= [HMOT](FPGA0).stepgen.03.velocity-cmd
    net a-pos-fb <= [HMOT](FPGA0).stepgen.03.position-fb
    net a-pos-fb => joint.3.motor-pos-fb
    net a-amp-enable <= joint.3.amp-enable-out
    net a-amp-enable => [HMOT](FPGA0).stepgen.03.enable
    # —setup home / limit switch signals—
    net all-home => joint.3.home-sw-in
    net a-neg-limit => joint.3.neg-lim-sw-in
    net a-pos-limit => joint.3.pos-lim-sw-in
    #******************************
    # connect miscellaneous signals
    #******************************
    # —HALUI signals—
    net axis-select-x halui.axis.x.select
    net x-is-homed halui.joint.0.is-homed
    net axis-select-y halui.axis.y.select
    net y-is-homed halui.joint.1.is-homed
    net axis-select-z halui.axis.z.select
    net z-is-homed halui.joint.2.is-homed
    net axis-select-a halui.axis.a.select
    net a-is-homed halui.joint.3.is-homed
    net jog-selected-pos halui.axis.selected.plus
    net jog-selected-neg halui.axis.selected.minus
    net spindle-manual-cw halui.spindle.0.forward
    net spindle-manual-ccw halui.spindle.0.reverse
    net spindle-manual-stop halui.spindle.0.stop
    net MDI-mode halui.mode.is-mdi
    # —coolant signals—
    net coolant-mist <= iocontrol.0.coolant-mist
    net coolant-flood <= iocontrol.0.coolant-flood
    # —probe signal—
    net probe-in => motion.probe-input
    # —motion control signals—
    net in-position <= motion.in-position
    net machine-is-enabled <= motion.motion-enabled
    # —digital in / out signals—
    # —estop signals—
    net estop-out <= iocontrol.0.user-enable-out
    net estop-out => iocontrol.0.emc-enable-in
    # —manual tool change signals—
    loadusr -W hal_manualtoolchange
    net tool-change-request iocontrol.0.tool-change => hal_manualtoolchange.change
    net tool-change-confirmed iocontrol.0.tool-changed <= hal_manualtoolchange.changed
    net tool-number iocontrol.0.tool-prep-number => hal_manualtoolchange.number
    net tool-prepare-loopback iocontrol.0.tool-prepare => iocontrol.0.tool-prepared
    view raw razor-5i25.hal hosted with ❤ by GitHub
    # DO NOT RUN PNCCONF EVER AGAIN
    [EMC]
    MACHINE = Razor-5i25
    DEBUG = 0
    VERSION = 1.1
    [DISPLAY]
    DISPLAY = axis
    POSITION_OFFSET = RELATIVE
    POSITION_FEEDBACK = ACTUAL
    MAX_FEED_OVERRIDE = 2.000000
    MAX_SPINDLE_OVERRIDE = 1.000000
    MIN_SPINDLE_OVERRIDE = 0.500000
    INTRO_GRAPHIC = /home/ed/linuxcnc/configs/razor-5i25/Sherline.gif
    INTRO_TIME = 3
    PROGRAM_PREFIX = /mnt/bulkdata/
    INCREMENTS = 50mm 10mm 1mm 0.1mm 90 45 10 5 1
    GRIDS = 100mm 50mm 25mm 10mm 5mm
    POSITION_FEEDBACK = ACTUAL
    DEFAULT_LINEAR_VELOCITY = 0.200000
    MAX_LINEAR_VELOCITY = 0.400000
    MIN_LINEAR_VELOCITY = 0.016670
    DEFAULT_ANGULAR_VELOCITY = 12.000000
    MAX_ANGULAR_VELOCITY = 180.000000
    MIN_ANGULAR_VELOCITY = 1.666667
    EDITOR = gedit
    GEOMETRY = axyz
    [FILTER]
    PROGRAM_EXTENSION = .png,.gif,.jpg Greyscale Depth Image
    PROGRAM_EXTENSION = .py Python Script
    png = image-to-gcode
    gif = image-to-gcode
    jpg = image-to-gcode
    py = python
    [TASK]
    TASK = milltask
    CYCLE_TIME = 0.010
    [RS274NGC]
    PARAMETER_FILE = linuxcnc.var
    RS274NGC_STARTUP_CODE = G21 G40 G49 G54 G80 G90 G92.1 G94 G97 G98
    [EMCMOT]
    EMCMOT = motmod
    COMM_TIMEOUT = 1.0
    SERVO_PERIOD = 1000000
    [HMOT]
    FPGA0 = hm2_5i25.0
    [HAL]
    TWOPASS = on
    HALUI = halui
    HALFILE = razor-5i25.hal
    #HALFILE = joggy.hal
    HALFILE = custom.hal
    POSTGUI_HALFILE = postgui_call_list.hal
    SHUTDOWN = shutdown.hal
    #HALFILE = LIB:halcheck.tcl
    [HALUI]
    [KINS]
    JOINTS = 4
    KINEMATICS = trivkins coordinates=XYZA
    [TRAJ]
    COORDINATES = XYZA
    LINEAR_UNITS = inch
    ANGULAR_UNITS = degree
    DEFAULT_LINEAR_VELOCITY = 0.10
    MAX_LINEAR_VELOCITY = 0.4
    MAX_ANGULAR_VELOCITY = 45
    DEFAULT_ANGULAR_VELOCITY = 25.00
    NO_FORCE_HOMING = 1
    POSITION_FILE = lastposition.txt
    [EMCIO]
    EMCIO = io
    CYCLE_TIME = 0.100
    TOOL_TABLE = tool.tbl
    #******************************************
    [AXIS_X]
    MIN_LIMIT = -1.0
    MAX_LIMIT = 9.5
    MAX_VELOCITY = 0.4
    MAX_ACCELERATION = 5.0
    [JOINT_0]
    TYPE = LINEAR
    FERROR = 0.01
    MIN_FERROR = 0.001
    MAX_VELOCITY = 0.4
    MAX_ACCELERATION = 5.0
    BACKLASH = 0.003
    # The values below should be 25% larger than MAX_VELOCITY and MAX_ACCELERATION
    # If using BACKLASH compensation STEPGEN_MAXACCEL should be 100% larger.
    STEPGEN_MAXVEL = 0.6
    STEPGEN_MAXACCEL = 20
    P = 1000.0
    I = 0.0
    D = 0.0
    FF0 = 0.0
    FF1 = 1.0
    FF2 = 0.0
    BIAS = 0.0
    DEADBAND = 0.0
    MAX_OUTPUT = 0.0
    # these are in nanoseconds
    DIRSETUP = 25000
    DIRHOLD = 25000
    STEPLEN = 25000
    STEPSPACE = 25000
    STEP_SCALE = 16000
    MIN_LIMIT = -1.0
    MAX_LIMIT = 9.5
    HOME = 5.25
    HOME_OFFSET = 9.1
    HOME_SEARCH_VEL = 0.3
    HOME_LATCH_VEL = 0.03
    HOME_FINAL_VEL = 0.4
    HOME_USE_INDEX = NO
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 1
    #******************************************
    #******************************************
    [AXIS_Y]
    MIN_LIMIT = 0.00
    MAX_LIMIT = 5.10
    MAX_VELOCITY = 0.4
    MAX_ACCELERATION = 5.0
    [JOINT_1]
    TYPE = LINEAR
    FERROR = 0.01
    MIN_FERROR = 0.001
    MAX_VELOCITY = 0.4
    MAX_ACCELERATION = 5.0
    BACKLASH = 0.003
    # The values below should be 25% larger than MAX_VELOCITY and MAX_ACCELERATION
    # If using BACKLASH compensation STEPGEN_MAXACCEL should be 100% larger.
    STEPGEN_MAXVEL = 0.6
    STEPGEN_MAXACCEL = 10.0
    P = 1000.0
    I = 0.0
    D = 0.0
    FF0 = 0.0
    FF1 = 1.0
    FF2 = 0.0
    BIAS = 0.0
    DEADBAND = 0.0
    MAX_OUTPUT = 0.0
    # these are in nanoseconds
    DIRSETUP = 25000
    DIRHOLD = 25000
    STEPLEN = 25000
    STEPSPACE = 25000
    STEP_SCALE = 16000
    MIN_LIMIT = 0.0
    MAX_LIMIT = 5.1
    HOME = 4.5
    HOME_OFFSET = 5.1
    HOME_SEARCH_VEL = 0.3
    HOME_LATCH_VEL = 0.03
    HOME_FINAL_VEL = 0.4
    HOME_USE_INDEX = NO
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 2
    #******************************************
    #******************************************
    [AXIS_Z]
    MIN_LIMIT = 0.0
    MAX_LIMIT = 6.680
    MAX_VELOCITY = 0.333
    MAX_ACCELERATION = 3.0
    [JOINT_2]
    TYPE = LINEAR
    FERROR = 0.01
    MIN_FERROR = 0.001
    MAX_VELOCITY = 0.333
    MAX_ACCELERATION = 3.0
    BACKLASH = 0.005
    # The values below should be 25% larger than MAX_VELOCITY and MAX_ACCELERATION
    # If using BACKLASH compensation STEPGEN_MAXACCEL should be 100% larger.
    STEPGEN_MAXVEL = 0.6
    STEPGEN_MAXACCEL = 6
    P = 1000.0
    I = 0.0
    D = 0.0
    FF0 = 0.0
    FF1 = 1.0
    FF2 = 0.0
    BIAS = 0.0
    DEADBAND = 0.0
    MAX_OUTPUT = 0.0
    # these are in nanoseconds
    DIRSETUP = 25000
    DIRHOLD = 25000
    STEPLEN = 25000
    STEPSPACE = 25000
    STEP_SCALE = 16000
    MIN_LIMIT = 0.0
    MAX_LIMIT = 6.68
    HOME = 6.5
    HOME_OFFSET = 6.68
    HOME_SEARCH_VEL = 0.15
    HOME_LATCH_VEL = 0.015
    HOME_FINAL_VEL = 0.33
    HOME_USE_INDEX = NO
    HOME_IS_SHARED = 1
    HOME_SEQUENCE = 0
    #******************************************
    #******************************************
    [AXIS_A]
    MIN_LIMIT = -9999999
    MAX_LIMIT = 9999999
    MAX_VELOCITY = 45.0
    MAX_ACCELERATION = 250.0
    [JOINT_3]
    TYPE = ANGULAR
    FERROR = 0.1
    MIN_FERROR = 0.01
    MAX_VELOCITY = 45.0
    MAX_ACCELERATION = 250.0
    # The values below should be 25% larger than MAX_VELOCITY and MAX_ACCELERATION
    # If using BACKLASH compensation STEPGEN_MAXACCEL should be 100% larger.
    STEPGEN_MAXVEL = 50
    STEPGEN_MAXACCEL = 300
    P = 1000.0
    I = 0.0
    D = 0.0
    FF0 = 0.0
    FF1 = 1.0
    FF2 = 0.0
    BIAS = 0.0
    DEADBAND = 0.0
    MAX_OUTPUT = 0.0
    # these are in nanoseconds
    DIRSETUP = 25000
    DIRHOLD = 25000
    STEPLEN = 25000
    STEPSPACE = 25000
    STEP_SCALE = 160
    MIN_LIMIT = -9999999
    MAX_LIMIT = 9999999
    HOME = 0.0
    HOME_OFFSET = 0
    HOME_SEARCH_VEL = 0
    HOME_LATCH_VEL = 0
    HOME_FINAL_VEL = 0
    HOME_USE_INDEX = NO
    HOME_SEQUENCE = 3
    #******************************************
    view raw razor-5i25.ini hosted with ❤ by GitHub

    Adapting the HAL code driving my Joggy Thing to its new home didn’t go quite as smoothly, about which, more later.

  • Handle With Care – FRAGILE – Thank You

    Handle With Care – FRAGILE – Thank You

    I wonder if somebody took careful aim at this particular corner:

    FRAGILE package damage
    FRAGILE package damage

    Well, it arrived in a more-or-less timely manner, unlike some packages and letters we’ve both sent and received of late. Tracking data suggests packages can vanish for days at a time, teleport to distant sorting centers, and sometimes loop between centers.

    The USPS may simply have run out of people willing to work under the current conditions.

  • Mesa 5i25 Superport: Reflash and Step-Direction Pin Swap

    Mesa 5i25 Superport: Reflash and Step-Direction Pin Swap

    For reasons lost in the mists of time, the DB-25 pinout used in the Sherline CNC Driver Box is kinda-sorta the same as everybody else’s DB-25 pinout, with minor difference of swapping the Step and Direction pins on each axis. This made no difference with the LinuxCNC parallel port driver, because (nearly) all pins are alike to it, but having recently found the Mesa 5i25 Everything I/O card and being desirous of upgrading to the latest & Greatest LinuxCNC, I figured why not throw all the balls in the air at once?

    Although it’s theoretically possible to recompile the FPGA source code to swap the pins, the least horrible alternative was converting a null modem (remember null modems?) into a passthrough pinswapper:

    DB-25 Parallel Adapter - Step-Direction pin swap
    DB-25 Parallel Adapter – Step-Direction pin swap

    Make sure you put jumper W2 in the DOWN position to route pins 22-25 to DC ground, rather than +5 V. W1 does the same for the internal header, herein unused, but it’s in the same position just for neatness.

    Similarly, put both W3 and W4 in their UP position to enable +5 V tolerance, connect the pullups to +5 V, and enable the pullups, thereby keeping the Sherline logic happy.

    Jumper W5 must be UP in order to have the thing work.

    The relevant diagram:

    Mesa 5i25 - jumper locations
    Mesa 5i25 – jumper locations

    Flashing the 5i25 with the Probotix PBX-RF firmware produced the best fit to a simple parallel port:

    sudo mesaflash --verbose --device 5i25 --write 5i25/configs/hostmot2/5i25_prob_rfx2.bit
    sudo mesaflash --verbose --device 5i25 --reload
    

    The mesaflash utility and all the BIT files come from their 5i25.zip file with all the goodies.

    The Gecko G540 pinout came in a close second and, should the Sherline box go toes-up, I’ll probably replace it with a G540 and (definitely) rewire the steppers from Sherline’s unipolar drive to bipolar drive mode.

    The 5i25 pinout now looks like this:

    halrun
    
    halcmd: loadrt hostmot2
    Note: Using POSIX realtime
    hm2: loading Mesa HostMot2 driver version 0.15
    
    halcmd: loadrt hm2_pci
    hm2_pci: loading Mesa AnyIO HostMot2 driver version 0.7
    hm2_pci: discovered 5i25 at 0000:04:02.0
    hm2/hm2_5i25.0: Low Level init 0.15
    hm2/hm2_5i25.0: 34 I/O Pins used:
    hm2/hm2_5i25.0:     IO Pin 000 (P3-01): IOPort
    hm2/hm2_5i25.0:     IO Pin 001 (P3-14): PWMGen #0, pin Out0 (PWM or Up) (Output)
    hm2/hm2_5i25.0:     IO Pin 002 (P3-02): StepGen #0, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 003 (P3-15): IOPort
    hm2/hm2_5i25.0:     IO Pin 004 (P3-03): StepGen #0, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 005 (P3-16): PWMGen #0, pin Out1 (Dir or Down) (Output)
    hm2/hm2_5i25.0:     IO Pin 006 (P3-04): StepGen #1, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 007 (P3-17): IOPort
    hm2/hm2_5i25.0:     IO Pin 008 (P3-05): StepGen #1, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 009 (P3-06): StepGen #2, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 010 (P3-07): StepGen #2, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 011 (P3-08): StepGen #3, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 012 (P3-09): StepGen #3, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 013 (P3-10): IOPort
    hm2/hm2_5i25.0:     IO Pin 014 (P3-11): Encoder #0, pin A (Input)
    hm2/hm2_5i25.0:     IO Pin 015 (P3-12): Encoder #0, pin B (Input)
    hm2/hm2_5i25.0:     IO Pin 016 (P3-13): Encoder #0, pin Index (Input)
    hm2/hm2_5i25.0:     IO Pin 017 (P2-01): IOPort
    hm2/hm2_5i25.0:     IO Pin 018 (P2-14): PWMGen #1, pin Out0 (PWM or Up) (Output)
    hm2/hm2_5i25.0:     IO Pin 019 (P2-02): StepGen #4, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 020 (P2-15): IOPort
    hm2/hm2_5i25.0:     IO Pin 021 (P2-03): StepGen #4, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 022 (P2-16): PWMGen #1, pin Out1 (Dir or Down) (Output)
    hm2/hm2_5i25.0:     IO Pin 023 (P2-04): StepGen #5, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 024 (P2-17): IOPort
    hm2/hm2_5i25.0:     IO Pin 025 (P2-05): StepGen #5, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 026 (P2-06): StepGen #6, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 027 (P2-07): StepGen #6, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 028 (P2-08): StepGen #7, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 029 (P2-09): StepGen #7, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 030 (P2-10): IOPort
    hm2/hm2_5i25.0:     IO Pin 031 (P2-11): Encoder #1, pin A (Input)
    hm2/hm2_5i25.0:     IO Pin 032 (P2-12): Encoder #1, pin B (Input)
    hm2/hm2_5i25.0:     IO Pin 033 (P2-13): Encoder #1, pin Index (Input)
    hm2/hm2_5i25.0: registered
    hm2_5i25.0: initialized AnyIO board at 0000:04:02.0

    P3 is the DB-25 on the back panel and P2 is the internal IDC header.

  • 123 Block Links: Sherline Tooling Plate

    123 Block Links: Sherline Tooling Plate

    Because the 123 block hole spacing doesn’t match the Sherline tooling plate’s 1.16 inch screw hole grid, each block has only a single 10-32 SHCS holding it down through a cap screw head pin:

    123 Block Links - Sherline table alignment
    123 Block Links – Sherline table alignment

    The spring clamp squashes a pair of reasonably straight steel bars against the blocks, whereupon gentle tightening can produce perfect Good Enough™ alignment.

    You could remove the tooling plate and attach the blocks directly to the Sherline’s table with two (or more!) T-nuts and screws per block. I expect no standard SHCS length would be quite right for the distance between the head held in the block pin and the T-nut in the table slot, not to mention removing and reinstalling the tooling plate is enough of a nuisance I’d rather not do it without good reason.

    Just to see how things looked, I attached the cursor milling fixture with threaded block pins:

    123 Block Links - Sherline layout
    123 Block Links – Sherline layout

    Note that the remaining 10-32 clearance hole in the fixture (for the cursor hub) doesn’t align with the underlying hole in the block; the next fixture must take into account both the Sherline and the 123 block grids, as well as which block holes align with the tooling plate. Bleh!

  • 123 Block Links: Threaded Pins

    123 Block Links: Threaded Pins

    The pins capturing the SHCS heads will mount the 123 blocks to the Sherline’s table or tooling plate, but attaching things to the blocks or joining them requires threaded pins on the other end of the screws:

    123 Block Links - trial assembly
    123 Block Links – trial assembly

    Optical illusion: those two pins are the same length.

    I grabbed a length of 3/8 inch aluminum rod in the Sherline vise, center-drilled four holes spaced 7/8 inch apart, then drilled them with a #20 drill for E-Z tapping.

    Space the holes with manual CNC command entry:

    GO X[0*0.875*25.4]
    GO X[1*0.875*25.4]
    GO X[2*0.875*25.4]
    GO X[3*0.875*25.4]

    That’s LinuxCNC on a Sherline with hard-inch leadscrews and G21 active. I normally use millimeters, but inch dimensions make more sense for these pins.

    Transfer the rod to the lathe for hand tapping:

    123 Block Links - tapping
    123 Block Links – tapping

    Not shown here: stick a transfer punch in one of the holes and eyeballometrically align tap with punch to get straight threads.

    Then, for each pin:

    • Chuck rod so the whole pin sticks out
    • Turn OD to 8.4 mm
    • Face to 3/8 inch rightward from hole center
    • Chamfer edge with file
    • Part off a little more than 3/8 inch leftward from hole center
    • Find pin in chip tray
    • Rechuck the other way around
    • Face to 3/8 inch rightward from hole center
    • Chamfer edge with file
    • Ease thread entries with a round file
    • Done!

    Again, I can’t believe I’m the first person to think of these pins; aim me at the commercial offerings I can’t find anywhere.

    Update: The keywords “cross dowel nut” and “furniture bolt” will turn up useful products intended for woodworkers. Thanks to blaz for the suggestion.