Duet3D Logo Duet3D
    • Tags
    • Documentation
    • Order
    • Register
    • Login

    IDEX XY calibration by electrical nozzle contact

    Scheduled Pinned Locked Moved
    Tuning and tweaking
    m558
    3
    12
    931
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • NeoDueundefined
      NeoDue
      last edited by

      I am currently a little stuck what might be the best way to implement an automatic XY calibration for my IDEX printer. The hardware is a Snapmaker J1 which has an electrical contact pulling an input to ground on each nozzle when touches the bed. The nozzles have a quick change system which requires the user to recalibrate after each nozzle change.
      The bed has two types of contacts that are used with this system:

      • three z calibration points - these are relatively trivial to use by defining the nozzle contact inputs with M558 as a z sensor
      • and a rectangular cutout with conductive edges which is supposed to be used for XY calibration, and this is the one I am stuck with.

      The idea behind this is as follows:

      • the rough position of the cutout and its size (20x20mm) is known
      • Tool1 moves to the cutout, dives into it, touches the four sides several times (in the same way it would do with an endstop) and needs to save the positions somewhere in order to calculate the nozzle centre from these measurements (the outer shape of the nozzle is assumed to be round and needs to be removed from the calculation).
      • Then, tool 2 moves to the cutout, dives into it, touches the four sides several times. These values are then used to calculate an offset of tool 2 relative to tool 1 and save this offset.

      If I am not mistaken, I need to dive the nozzle into the hole and then do a probe move with e.g. M558 X10 P[no. of z probe of the corresponding nozzle].
      But how to I read the value I get into a variable instead of applying it as the documentation of M585 suggests? Is there a value similar to "move.calibration.initial.deviation" for a z probe move to read out the offset value and save it into a variable?

      T3P3Tonyundefined 1 Reply Last reply Reply Quote 0
      • T3P3Tonyundefined
        T3P3Tony administrators @NeoDue
        last edited by

        @NeoDue one way to potentially do this is using the H4 switch on G1, and then reading the move.axes[n].machinePosition to get where the contact was made. you can read those into variables and then calculate the center position from that.

        If you want to see something similar in action have a look at @brendon 's autocalibration for the Open5X voron v0 here:

        https://github.com/FreddieHong19/Open5x/tree/main/3D_Model/Voron_0/DuetConfig/macros

        www.duet3d.com

        1 Reply Last reply Reply Quote 0
        • NeoDueundefined
          NeoDue
          last edited by NeoDue

          @T3P3Tony Thanks a lot! I was not aware of that option yet. That would also save me from constantly resetting the tool offset.

          It seems my attempt is just at the right time for RRF to cope with it - I have the feeling I would probably have been more or less lost with previous versions, considering the amount of comands with a "new in RRF 3.x" remark I use 😉

          1 Reply Last reply Reply Quote 0
          • oliofundefined
            oliof
            last edited by

            There is also this

            https://youtu.be/YLhYf1itSuQ?si=-q-A4dsa06cgPxI6

            Starts at 9:15

            Macro is in the comments.

            <>RatRig V-Minion Fly Super5Pro RRF<> V-Core 3.1 IDEX k*****r <> RatRig V-Minion SKR 2 Marlin<>

            NeoDueundefined 1 Reply Last reply Reply Quote 1
            • NeoDueundefined
              NeoDue @oliof
              last edited by

              @oliof Thanks a lot! You might have saved me quite some work!

              I guess it is time to dig out some of my rusty knowledge of the french language this weekend 🙂

              oliofundefined 1 Reply Last reply Reply Quote 0
              • oliofundefined
                oliof @NeoDue
                last edited by

                @NeoDue if you use a precision metal washer instead of the block, you can use M675 as well. The trick in the video is using the piezo to measure contact which alleviates the need to put a lead to the nozzle for offset measuring.

                <>RatRig V-Minion Fly Super5Pro RRF<> V-Core 3.1 IDEX k*****r <> RatRig V-Minion SKR 2 Marlin<>

                NeoDueundefined 1 Reply Last reply Reply Quote 0
                • NeoDueundefined
                  NeoDue @oliof
                  last edited by NeoDue

                  @oliof Thanks, yet another option - this command might make the whole process simpler than I expected 🙂
                  My printer has already a quadratic cutout which is millled out of the PCB that is the heat bed. PCB milling is quite precise, so this should well qualify as a suitable cavity for M675 as it is. No block or washer needed 😉

                  NeoDueundefined 1 Reply Last reply Reply Quote 1
                  • NeoDueundefined
                    NeoDue @NeoDue
                    last edited by NeoDue

                    @dc42 While working on the calibration code I just stumbled upon your comment from last year at https://forum.duet3d.com/post/272898 that M675 might become obsolete soon and that you might replace it with a macro.

                    Just to make sure I do not try to ride an almost dead horse here: may I ask what the state of that decision is? If it will be replaced by a macro, I would try to implement that one directly into my code if you already happen to have it at hand.

                    NeoDueundefined 1 Reply Last reply Reply Quote 0
                    • NeoDueundefined
                      NeoDue @NeoDue
                      last edited by NeoDue

                      Just in case anyone is interested, here is the working solution:

                      ; XY calibration in a cavity that is normally covered by the print plate
                      
                      ; Variables
                      ; print plate thickness in variable "global.Druckplattendicke" needs to be defined before running the macro, e.g. in config.g
                      var Eintauchtiefe = 1          ; how deep the nozzle shall dive into the cavity
                      var Referenzwert_X = 0
                      var Referenzwert_Y = 0
                      var Hotend2_X = 0
                      var Hotend2_Y = 0
                      
                      G28 							; Home
                      
                      ; prepare printer - insert whatever you need here...
                      
                      ; heat up hotends and bed
                      M140 S60 						; heat up bed
                      T0 P0
                      M568 P0 S220 R220				; heat up Hotend 1
                      T1 P0
                      M568 P1 S220 R220				; heat up Hotend 2 auf 220°C 
                      T-1 P0
                      M116							; wait
                      
                      ; let the user clean the nozzles
                      G1 H2 X{move.axes[0].min+50} F3000 
                      G1 H2 U{move.axes[3].max-50} F3000 
                      M400								; wait
                      
                      ; Message
                      M291 "Please clean the nozzles" R"Notice" S3
                      
                      ; Move print heads back to their parking position
                      G1 H2 X{move.axes[0].min} F3000 	
                      G1 H2 U{move.axes[3].max} F3000 	
                      
                      
                      ; lift bed close to measuring level
                      G1 H2 Z5 F6000
                      
                      ; move hotend 1 to cavity and dive in
                      G1 H2 X0 Y0 F6000
                      M400
                      G1 H2 Z{-global.Druckplattendicke - var.Eintauchtiefe} F3000 
                      
                      ; begin reference measurement
                      T0 P0 						        ; activate tool 0
                      while iterations < 8				; measure 8 times in X
                      	M675 X R1 P0 F100
                      	M400
                      	set var.Referenzwert_X = var.Referenzwert_X + move.axes[0].machinePosition   ; save value
                      set var.Referenzwert_X = var.Referenzwert_X / 8 ; calculate final reference value
                      	
                      while iterations < 8				; measure 8 times in Y	
                      	M675 Y R1 P0 F100 
                      	M400
                      	set var.Referenzwert_Y = var.Referenzwert_Y + move.axes[1].machinePosition    save value
                      set var.Referenzwert_Y = var.Referenzwert_Y / 8 ; calculate final reference value
                      
                      ; move back hotend 1
                      G1 H2 Z2 F6000  
                      M400
                      G1 H2 X{move.axes[0].min} F6000
                      
                      ; delete old offset from hotend 2:
                      G10 P1 U0 Y0
                      
                      ; move hotend 1 to cavity and dive in
                      G1 H2 U0 Y0 F6000
                      M400
                      G1 H2 Z{-global.Druckplattendicke - var.Eintauchtiefe} F3000
                      
                      
                      ; measure with hotend 2
                      T1 P0 						        ; activate tool 1
                      
                      while iterations < 8				; measure 8 times in U
                      	M675 U R1 P1 F100 
                      	M400
                      	set var.Hotend2_X = var.Hotend2_X + move.axes[3].machinePosition   ; save data
                      set var.Hotend2_X = var.Hotend2_X / 8 ; ... and calculate final value
                      
                      while iterations < 8				; measure 8 times in Y
                      	M675 Y R1 P1 F100
                      	M400
                      	set var.Hotend2_Y = var.Hotend2_Y + move.axes[1].machinePosition   ; save data
                      set var.Hotend2_Y = var.Hotend2_Y / 8    ; ... and calculate final value
                      
                      ; define new offset  and save it to a file that is read from config.g:     
                      G10 P1 U{var.Referenzwert_X - var.Hotend2_X} Y{var.Referenzwert_Y - var.Hotend2_Y}
                      echo >"Korrekturwert_xy_offset_tool1.g" "G10 P1 U"^{var.Referenzwert_X - var.Hotend2_X}^" Y"^{var.Referenzwert_Y - var.Hotend2_Y}^""
                      
                      ; bring printer back to idle state
                      T0 P0                                               
                      G1 H2 Z5 F6000						
                      G1 H2 U{move.axes[3].max} Y{move.axes[1].min} F3000 	
                      G1 Z120 F6000 
                      M568 P0 S0 R0
                      M568 P1 S0 R0
                      M140 S0
                      
                      ; notify user
                      M291 S2 P"XY-Offset of right Hotend is has been saved!"
                      

                      (edit: added remark, removed unused variables)

                      oliofundefined 1 Reply Last reply Reply Quote 2
                      • oliofundefined
                        oliof @NeoDue
                        last edited by

                        @NeoDue great stuff! You should consider some way to filter out outliers in your 8 runs (use median or just track lowest/highest and reject runs where the difference is greater than some value you deem an acceptable range).

                        <>RatRig V-Minion Fly Super5Pro RRF<> V-Core 3.1 IDEX k*****r <> RatRig V-Minion SKR 2 Marlin<>

                        NeoDueundefined 2 Replies Last reply Reply Quote 0
                        • NeoDueundefined
                          NeoDue @oliof
                          last edited by

                          @oliof That is a great idea, especially for the reference value! But for now, I have no clue on how to that in RRF. I would have to do the measurements, save them all and then do some comparison... before I dig into whatever an internet research might yield on this topic: do you happen to have some more information on how to do this with the basic math RRF offers?

                          1 Reply Last reply Reply Quote 0
                          • NeoDueundefined
                            NeoDue @oliof
                            last edited by NeoDue

                            @oliof said in IDEX XY calibration by electrical nozzle contact:

                            @NeoDue great stuff! You should consider some way to filter out outliers in your 8 runs (use median or just track lowest/highest and reject runs where the difference is greater than some value you deem an acceptable range).

                            @oliof Now I finally had the time to dust off and actually use a bit of my old statistics knowledge... Got it 🙂 - here is a test macro that removes outliers from a given array based on their z-score:

                            ; constraints out of experience: 
                            ; - electrical nozzle contact never gets activated too soon (=> too low values will never happen and are not taken into account here)
                            ;   if that does not apply, a lower acceptance limit for the z-score needs to be defined as well
                            ; - values that are too high are usually at least 0.15...0.2mm off
                            var Referenzwert = {1,1.02,1.05,1.2,1.22,1.3,1.01,}  ; test values - the three values that are too high need to be detected and removed from the mean value
                            var Referenzmittelwert = 0.0
                            var Referenzstandardabw = 0.0
                            var ReferenzZScore = vector(#var.Referenzwert,null)
                            var ZScoregrenze = 0.5
                            var Anzahlgueltig = 0
                            
                            ; calculate mean value
                            while iterations < #var.Referenzwert
                                set var.Referenzmittelwert = var.Referenzmittelwert + var.Referenzwert[iterations]
                            set var.Referenzmittelwert = var.Referenzmittelwert / #var.Referenzwert
                            
                            ; calculate standard deviation
                            while iterations < #var.Referenzwert
                                set var.Referenzstandardabw = var.Referenzstandardabw + (var.Referenzwert[iterations] - var.Referenzmittelwert) * (var.Referenzwert[iterations] - var.Referenzmittelwert)
                            set var.Referenzstandardabw = sqrt(var.Referenzstandardabw / (#var.Referenzwert - 1))
                            
                            ; calculate z-score of each measurement value
                            while iterations < #var.Referenzwert
                                set var.ReferenzZScore[iterations] = (var.Referenzwert[iterations] - var.Referenzmittelwert) / var.Referenzstandardabw
                            
                            ; re-calculate mean value without detected outliers 
                            set var.Referenzmittelwert = 0
                            while iterations < #var.Referenzwert
                                if var.ReferenzZScore[iterations] < var.ZScoregrenze
                                    set var.Referenzmittelwert = var.Referenzmittelwert + var.Referenzwert[iterations]
                                    set var.Anzahlgueltig = var.Anzahlgueltig + 1
                            set var.Referenzmittelwert = var.Referenzmittelwert / var.Anzahlgueltig
                            
                            echo var.Referenzmittelwert
                            

                            While I do not use that for XY calibration (at least yet - that one works perfectly well as it is so far...), I did add it to the two macros I wrote for z calibration and z-leveling of the U axis relative to the X axis. It definitely makes sense there since slight drops of filament coming out of the nozzle can cause errors.

                            1 Reply Last reply Reply Quote 2
                            • First post
                              Last post
                            Unless otherwise noted, all forum content is licensed under CC-BY-SA