Thoughts on Multi-Tool Alignment (long)



  • BACKGROUND

    Building a Tool Changing printer called the Jubilee. It is up and working on a Duet3 6HC and two expansion boards. It is still being commissioned. At this point, it produces excellent single tool prints. It also produces multi tool prints that contain two and three thousand tool changes with absolute reliability on the changes.

    However...

    I am finding the process of aligning the tools to each other very frustrating. It CAN be done; I'm just impatient or whatever.

    Therefore, let's automate that process! The goal is to find the XYZ position of each tool's nozzle (or equivalent) and ultimately produce a list of G10 commands so that they all "just work" when toolchanges occur.

    IDEAS

    People have discussed:

    • USB microscope looking up at the nozzle. Image recognition for the 'circle'. Maybe this could all be on the Pi in a Duet 3.

    • Touch probing various switches or piezeos. This might include separate ones for Z vs XY.

    • Running a wire to the nozzle, and probing into a metal plate or square hole. Again, probably separate for Z (probe the plate) vs XY (stick the nozzle down in the center, and then probe the edges of the hole)

    Here's question one: Are there any other broad categories? Beyond optical/camera, probe switch, probe piezo, probe by metal-metal contact?

    CONSTRAINTS

    Ultimately there are none, because we could totally redesign any printer. Nonetheless, I'd like to stay as compatible to the original Jubilee design as possible. The only real constraint there is the microswitch probe for setting Z0 of the bed is on the bottom of the tool-picker on the gantry. This means it cannot touch the bed if a tool is mounted.

    This is not a big constraint, it is more of a "sequence of events" thing. Home the printer, all axis, THEN calibrate tool-to-tool offsets. And, TTT should only need to be done when things change.

    My Preferences

    I am really focused on the "metal-to-metal" for the sensing and "probe into a square hole" philosophy. This comes from an underlying desire to add minimal "extra stuff" to the printer. Let's use the steppers we already have, etc.

    Here's question two: Any and all thoughts?



  • Part 2: Current Efforts - Background

    I am using a Duet3 + Expansion, and RRF3 firmware.

    Since I am focused on "metal to metal" sensing, this implies a wire to each tool nozzle. Since tools are probed one at a time, these wires can be brought in parallel to a single point, and connected to a single input. I've done this, and conducted some experiments.

    XYZ Normally Closed microswitches are IO0.in, IO1.in, and IO3.in There is also a tool locker axis U with microswitch on IO2.in (why the out of order? I couldn't resist having U axis be driver/endstop, etc, number two. That is: U2). All the endstops look like: M574 X1 S1 P"io0.in" or similar. The Z switch is defined as a probe: M558 K0 P5 C"io3.in" H5 A5 T6000 S0.02 so that bed leveling (three z motors) and so forth work as designed.

    The tool, at the moment, has a wire from the nozzle to IO4.in. The plates it will be touching are grounded. This is effectively a Normally Open switch.

    Thought 1: Use G0 H3 moves

    Define the tool as a Z min endstop. (This will be a problem, later, when we want to set X and Y). M574 Z1 S1 P"io4.in"

    • Select T0
    • G10 P0 X0Y0Z0 ; Turn off all tool offsets for tool zero
    • G0 Z10 ; Ensure no hitting the bed or touchplate (which stick up a little)
    • G0 blah blah ; Pre position over touchplate.
    • G0 H3 Z0 ; Probe for touchplate
      Capture Z position. Note1: This script is running on the Pi and I have a way to capture current coordinates. Note2: I am still not absolutely clear on what effect H3 probes have on coordinates.
    • G0 Z10 ; Ensure no hitting the bed or touchplate (which stick up a little)
    • G0 blah blah ; Move nozzle over square hole
    • G0 Zpos captured above minus 1mm. That is, nozzle is now sticking down into hole.
    • G0 H3 Xblah ; Probe toward an edge of the square hole.

    This is where the wheels come off. IO4.in is defined as a stop on the Z axis, so the GO H3 Xblah will not stop when a touch occurs.

    I could dynamically re-define the stops... but then I'd have to put them back to 'normal' and this seems fraught with potential failures.

    Thought 2: Use M585 moves

    This involves defining IO4.in as a probe, not assigned to any axis. Like this M558 K1 P5 C"!io4.in"

    Then probing with M585 specifying probe 1. Something like this: M585 Xxxx P1 S0

    Unfortunately this does not seem to work at the moment. A couple of people have mentioned this do DC42 in a different thread.

    Your Input

    Other approaches besides G0 H3 or M585?

    Thoughts on scripting in G-Code purely (I'm not certain either way this is actually doable), or scripting on the Pi (which means this would never be available to Duet2)?


  • administrators

    one question i have on the metal on metal contact is what the effect of encrusted plastic on the nozzles would be. I am told that the probing scheme you have described is used on CNC. however the end mil and contact plate are presumable more reliable as a metal on metal contact?



  • Personally, I am waiting for conditional statements and variable storage to be added to the firmware. I've stated in the far past about this very function. Metal to metal.

    My version of alignment will be just as it is with my sinker and wire EDM machines. A simple hole probe routine with each tool head.

    1. Probe back and forth in X direction, calculate center between both touch points.
    2. Probe back and forth in Y direction, calculate center between both touch points.
      3.Re-probe back and forth in X direction, calculate center between both touch points.
    3. Store offset in G10 for that tool.

    It's very simple but effective. All tool offsets will be based on G53 Home location.

    With this routine on my wire EDM machine I can get to within .00005" of center with little effort.

    Z can be probed the same way by touching off a setter block or the top corner of the probe block.

    Once the know offsets are in they really should change unless a crash occurs or you change nozzles.

    Of course common sense comes in to play as well. The nozzle has to be clean of plastic. Heated to temp for any heat drifting. And good mechanical design to eliminate as much backlash as possible.



  • @T3P3Tony said in Thoughts on Multi-Tool Alignment (long):

    one question i have on the metal on metal contact is what the effect of encrusted plastic on the nozzles would be. I am told that the probing scheme you have described is used on CNC. however the end mil and contact plate are presumable more reliable as a metal on metal contact?

    The Jubilee has a wiper, a silicone strip, as part of the parking stall. If we heat the nozzle (probably should anyway, for best probe accuracy) and wipe it (possibly some extra wiping), I believe this will work. Yet to be proven... I'm hopeful because I've printed with this thing a fair amount, and the nozzles are REALLY clean.

    So, we'll see.



  • @timcurtis67 said in Thoughts on Multi-Tool Alignment (long):

    Personally, I am waiting for conditional statements and variable storage to be added to the firmware.

    This will be a big enabler. Meanwhile, for D3, we have Python (or anything else) on the Pi, and modules that can send and fetch to the Duet. I've already got all the Python interfaces working. I can issue any Gcode, including probes, and I can fetch anything that is in an M114 JSON response. Of course, variables, conditional, math, etc... it is Python!

    My version of alignment will be just as it is with my sinker and wire EDM machines. A simple hole probe routine with each tool head.

    1. Probe back and forth in X direction, calculate center between both touch points.
    2. Probe back and forth in Y direction, calculate center between both touch points.
      3.Re-probe back and forth in X direction, calculate center between both touch points.
    3. Store offset in G10 for that tool.

    Exactly.

    Z can be probed the same way by touching off a setter block or the top corner of the probe block.

    Exactly.



  • This will be a big enabler. Meanwhile, for D3, we have Python (or anything else) on the Pi, and modules that can send and fetch to the Duet. I've already got all the Python interfaces working. I can issue any Gcode, including probes, and I can fetch anything that is in an M114 JSON response. Of course, variables, conditional, math, etc... it is Python!

    That sounds great! A bonus of using a Pi with the Duet3 board.

    I haven't made the plunge to Duet3 yet. Still working with Duetwifi and a Duex5 expansion. I'm in the process of rebuilding my big IDEX into a jubilee type tool change printer. So aside from capturing M114 commands from the DuetWifi serial port with a Pi, I'll have to continue the wait for conditional statements to be implemented.

    On my IDEX setup I do the same tool alignment manually on a touch block and it works great. Enter the offsets in G10 and away I go. I just have to keep a pad of paper and pencil handy 😀

    Lucky the offsets don't change unless I have a crash which happens from time to time....



  • I think that sensing z height could easily be done electrically by contact but x and y might be a problem because of nozzle coating. I don't know if it has been mentioned or if it goes without saying but there should be a .sys file that sets and stores all offsets for every tool.
    Again not sure if feasible or not but it would be nice if the printer could identify the individual tool as in 'this is tool # 12 (or whatever)' and then the x/y/z coordinates of the .sys file are automatically applied. This implies that more tools could be set up then are actually mounted in the printer. One reason I see this as essential - I could have different nozzle sizes and different heat blocks on different tool heads. I could for example have a 0.4 mm and 0.2 mm nozzle on normal heat blocks, a 0.4 and 0.8 nozzles on a Volcano heat blocks and so on.
    If electrical continuity is set up for z height, there may be implications to other functions such as not being able to measure in the center of the bed or what happens if your glass plate thickness changes.

    I wonder if it would make sense to break the link of bed height compensation and tool so that bed height probing happens without a tool (or a special calibration tool) and then each indidual tool head gets measured individually and an x/y/z offset from a reference position is determined.

    I am just rambling here and haven't really thought about this too much but this makes sense from several perspectives.

    It obviously implies that there is very minimal error due to the toolhead mounting system.



  • @jens55 said in Thoughts on Multi-Tool Alignment (long):

    I think that sensing z height could easily be done electrically by contact but x and y might be a problem because of nozzle coating. I don't know if it has been mentioned or if it goes without saying but there should be a .sys file that sets and stores all offsets for every tool.

    I believe that wiping will take care of this. I've printed a lot already, and the nozzles are REALLY clean. We'll see.

    Again not sure if feasible or not but it would be nice if the printer could identify the individual tool as in 'this is tool # 12 (or whatever)' and then the x/y/z coordinates of the .sys file are automatically applied. This implies that more tools could be set up then are actually mounted in the printer. One reason I see this as essential - I could have different nozzle sizes and different heat blocks on different tool heads. I could for example have a 0.4 mm and 0.2 mm nozzle on normal heat blocks, a 0.4 and 0.8 nozzles on a Volcano heat blocks and so on.

    This is all built into Duet/RepRap firmware already. G10 Pn Xx Yy Zz to set offsets for tool n. Auto-applied when that tool is mounted.

    If electrical continuity is set up for z height, there may be implications to other functions such as not being able to measure in the center of the bed or what happens if your glass plate thickness changes.

    Not for OVERALL z height, that's still the Z probe on the bottom of the carriage. Nozzle-to-touch-block-electrical is used only to calculate (not set, calculate) that individual nozzle's Z offset for that individual tool's G10 command.

    It obviously implies that there is very minimal error due to the toolhead mounting system.

    The Jubilee system is fully compatible with the E3D system of kinematic coupling. Both are extremely repeatable.



  • There is M675 to probe the center of a cavity. This should simplify the probing for metal on metal contact. Unlike for CNC work coordinate systems there doesn't seem to way to set tool offsets relative to the current position. So without extensions it can't currently not be for setting tool offsets. If WCS are useable in 3D printing mode each tool could probe and use a separate WCS instead of tool offsets.



  • Nice! I'd missed that one.

    Given the dynamic nature of Duet configuration, several of these alternatives will work if I make the io4.in pin the endstop for that axis. The only problem with that is, I have to undefine the regular endstop... and of course I'd want to set it back after executing this process. I worry about what would happen if the process is interrupted.

    I have actually considered ending the whole process with an M999. That would reliably ensure that the contents of config.g were in force.

    Hmmm....


  • administrators

    It might also be possible to sense the centre of the nozzle using an inductive sensor, but only if the range of the sensor is short enough for the heater block not to throw it off. Or perhaps use a vertical rod as a capacitive sensor?



  • OK, so people have been talking about sensing. Could be camera, microswitch(es), piezo, inductive, and more. I'm still going to pursue metal-metal for now.

    Now let us think about G-Code vs Scripting on the Pi.

    Q1: Do we believe that tool-to-tool offset could be done ENTIRELY in G-Code?

    • Prior to conditional G-Code?
    • With conditional G-Code?

    Q2: What fundamental probing technique/command is best for this?

    • G1 H3?
    • M585?
    • M675?
    • Other?

    Q3: If scripted on the Pi, what language?

    • Python
    • Perl
    • bash (or similar)

    Or all above in one generic question: SPECIFICALLY how to do this, right now?


  • administrators

    The only way I think it could be done now is using M675. But for XY offset measurement, I think a capacitive sensor and special firmware support may be a better option. Two options in particular spring to mind:

    • Probe above a vertical rod or above a disc on the top surface of a PCB, measuring the capacitance between the rod or disc and the nozzle. It should be a maximum when the nozzle and the rod are aligned on the same axis, unless the capacitance to the heater block is significant.
    • Lower the nozzle into a cone and probe inside that.

    To measure the Z offset, I favour a nozzle-contact sensor. We've already tested one type with the E3D tool changer, but it didn't work as well as we had hoped. We have another design planned.



  • Why a cone for XY? When probing X, Y has not yet been set with absolute certainty, and therefore contacting a chord of X (instead of a radius of X) would throw things off.

    I'm thinking a square hole would be better. Aligned XY as best as possible. That way, when probing X, small errors in Y don't matter.

    This piece has a Z touch area, and a square hole.

    IMG_0161.jpeg



  • At the moment, I'm still shooting for metal to metal contact. I do like the "capacitance to rod" idea. A .5mm rod should "peak" really well with most nozzle tips. May have to look at that some more.

    In fact, with regard to metal-to-metal, I have a prototype working as a Python script on the Pi. It uses the 'CodeConsole' interface over and over. Because I can't get M558/M585 style probing to work at the moment, and because it needs to probe on all three Axis, it dynamically re-configures the M574 style endstops and uses G1 H3 probes. It then has to reset the axis limit that was changed by the H3, and reset the endstop as well. To ensure that these 'reset' reconfigurations never vary from what is in config.g, the python scripts extracts the proper commands from config.g. and runs them.

    The plate (photo a couple of posts up) is on a corner of the bed (for now) and is grounded. Each tool nozzle has a wire... these wires (plural) come back to a common point, where they join a single wire headed for io4.in.

    The python code, in addition to being able to issue any G-Code command, can issue M408, parse the output, and retrieve the position of any axis.

    It is quite nifty that Duet RRF allows dynamic reconfiguration... but... this is all very much a hack, and I look forward to doing it a different way in the future.

    Anyway, it does work. I'm still seeing how consistent it is. An experimental run on one tool, with just "print" statements of the results, looks like this:

    # Start of probing for Tool 0
    G0('','',10,1000)             # Lower bed to avoid collision with square hole plate.
    Gcode('T0')                   # Pick up Tool zero
    Gcode('G10 P0 Z0 X0 Y0')      # Remove all offsets from Tool zero
    
    # Z Axis
    Gcode('M574 Z1 S1 P"!io4.in"')
    G0('','',10,1000)             # Lower bed to avoid collision with square hole plate.
    G0(290,285,'',10000)          # Move nozzle to spot above flat part of plate
    Gcode('G1 H3 Z0')
    toolZ = getPos()[2]           # Capture the Z position at point of contact
    print('>>>>>>>>>> ToolZ '+str(toolZ))
    G0('','',10,1000 )             # Lower bed to avoid collision with square hole plate.
    resetAxisLimits()
    Gcode('M574 Z1 S1 P"nil"')
    
    # X Axis
    Gcode('M574 X1 S1 P"!io4.in"')
    G0('','',10,1000)          # Move the bed to ensure no dragging
    G0(290,270,'',1000)        # Place the nozzle tip in center of square hole.
    G0('','',toolZ-1,100)      # Place the nozzle tip just below surface.
    Gcode('G1 H3 X270')
    toolX = getPos()[0]        # Capture the X position at point of contact
    print('>>>>>>>>>> ToolX '+str(toolX))
    G0(290,270,'',1000)        # Place the nozzle tip in center of square hole.
    resetAxisLimits()
    Gcode('M574 X1 S1 P"nil"')
    
    # Y Axis
    Gcode('M574 Y1 S1 P"!io4.in"')
    G0('','',10,1000)          # Move the bed to ensure no dragging
    G0(290,270,'',1000)        # Place the nozzle tip in center of square hole.
    G0('','',toolZ-1,100)      # Place the nozzle tip just below surface.
    Gcode('G1 H3 Y250')
    toolY = getPos()[1]        # Capture the X position at point of contact
    print('>>>>>>>>>> ToolY '+str(toolY))
    G0(290,270,'',1000)        # Place the nozzle tip in center of square hole.
    resetAxisLimits()
    Gcode('M574 Y1 S1 P"nil"')
    resetEndstops()
    

    The output of the print statements from a run against a single tool:

    >>>>>>>>>> ToolZ 4.962
    >>>>>>>>>> ToolX 281.681
    >>>>>>>>>> ToolY 260.3
    


  • the usual technique is:

    • probe one axis inside a circle - find the ends of the chord

    • move the axis to mid-point of the chord - now you should be on the radius of the other axis

    • probe the other axis - find the ends of the chord

    • move to the mid-point of the chord ( which should be the diameter )

    • re-probe the first axis now that you are centered in the circle

    • midpoint of the chord should be a high accuracy center point



  • Got it, thanks!



  • OK, switched over to M675 for XY. Works great. Doing the X, Y, X again thing... still in the square hole. I will make a round hole plate tomorrow.


Log in to reply