Mach3 Plugin - Rigid Tapping


To perform Rigid Tapping from Mach3 the tapping parameters are set into GCode Variables, then a Macro (M84) is called which downloads the parameters to KFLOP, notifies KFlop to perform the Tap Cycle, then waits until KFLOP sets a variable indicating the operation has completed.


A requirement for Rigid Tapping is that the Spindle has encoder feedback and is possible to move in a fairly controlled manner.  The Z axis motion is "geared" to the measured Spindle Encoder Position throughout the cycle.


There are three parts to the process: The GCode, the M84 Macro, and the KFlop User Program.  Examples can be found here.




Example Rigid Tap Call From GCode


We use a Macro M84 as Mach3 uses the normal G84 Tap cycle for a floating tapholder technique and doesn't currently support a rigid tap GCode.


Note that the forward cutting rate (RPM) and the retraction rate (RPM) can be defined separately.  A cyclic forward/retract motion can be specified to cut the thread to the total depth.  If a simple single motion is desired, set the Z depth forward motion to the Z depth Total.



(Call a Rigid Tap Sequence)
#10=20 (TPI - Threads per inch)
#11=700 (Forward Cutting RPM)
#12=1000 (Retract RPM)
#13=0.75 (Z depth Total inches)
#14=0.2 (Z depth Forward per Motion)
#15=0.05 (Z depth Retract per Motion)


(Call a Rigid Tap Sequence)
#10=20 (TPI - Threads per inch)
#11=700 (Forward Cutting RPM)
#12=1000 (Retract RPM)
#13=0.75 (Z depth Total inches)
#14=0.2 (Z depth Forward per Motion)
#15=0.05 (Z depth Retract per Motion)



Mach3 M84 Macro


This macro moves the GCode Tapping Variables to Mach3 User DROs, downloads then to KFLOP UserData variables, Triggers KFLOP to perform the Tap Cycle, then waits until KFLOP sets a User Data Variable indicating the cycle is complete.


'Macro for Rigid Tappin with Dynomotion KFLOP
' pass variables to KFLOP
' Var DRO KFLOP UserVar Description
' #10 1010 18 19 TPI - Threads per inch
' #11 1011 20 21 Forward Cutting RPM
' #12 1012 22 23 Retract RPM
' #13 1013 24 25 Z depth Total inches
' #14 1014 26 27 Z depth Forward per Motion
' #15 1015 28 29 Z depth Retract per Motion
' 1016 30 31 Set by KFLOP when complete

'Move the GCode Vars into DROS and send them to KFLOP User Vars
For i=0 To 5
Call SetUserDRO(1010+i, GetVar(10+i))
Next i

Call SetUserDRO(1016, 0) 'clear the complete flag

NotifyPlugins(10084) 'do the TAP!!

While GetUserDRO(1016)=0
NotifyPlugins(18016) 'upload the complete flag




KFLOP Notify User C Program that performs the Rigid Tap Cycle


The C Program that performs the Rigid Tap Cycle.  This assumes that the Spindle axis can be controlled like a Servo Axis within KFLOP (although it is not defined as an axis within Mach3).  The defines must be set per your specific system.  A low pass filter is used to smooth the commanded Z motion for the case where the Spindle Motion might be too Jerky for the Z Axis to follow without possibly stalling, it also smoothes the response that would be otherwise stepped because user programs only execute every other servo sample.  A Tau of 0.001 performs as a low pass filter with a time constant of 1ms.   


#include "KMotionDef.h"


//Plugin calls for Mach3 NotifyPlugins Commands



void Tap(void);




      int msg = persist.UserData[6];  // Mach3 notify Message 10000-10999


      printf("Mach3 Notify Call, Message = %d\n",msg);


      if (msg==10084)






//  R I G I D   T A P P I N G


#define ZAXIS 7

#define SPINDLE_AXIS 6

#define Z_CNTS_PER_INCH -20000.0

#define CNTS_PER_REV (8192*14/16)

#define TAU 0.001


double SlaveGain,ToCut,TotalCut,Z0,S0;

void DoSlave(void);

void DoTap(double Dist, double Rate, double TPI);


void Tap(void)


      //  #10  1010    18 19          TPI

      //  #11  1011    20 21          Forward Cutting RPM

      //  #12  1012    22 23          Retract RPM

      //  #13  1013    24 25          Z depth Total inches

      //  #14  1014    26 27          Z depth Forward per Motion

      //  #15  1015    28 29          Z depth Retract per Motion

      //  #16  1015    30 31          Complete Flag


      double TPI              = *(double *)&persist.UserData[18];

      double CutRPM           = *(double *)&persist.UserData[20];

      double RetractRPM       = *(double *)&persist.UserData[22];

      double ZDist            = *(double *)&persist.UserData[24];

      double ZForward         = *(double *)&persist.UserData[26];

      double ZReverse         = *(double *)&persist.UserData[28];


      double FeedRate   = CutRPM/(TPI*60);

      double RetractRate      = RetractRPM/(TPI*60.0);


      printf("TPI = %f\n",TPI);

      printf("FeedRate = %f\n",FeedRate);

      printf("RetractRate = %f\n",RetractRate);

      printf("ZDist = %f\n",ZDist);

      printf("ZForward= %f\n",ZForward);

      printf("ZReverse = %f\n",ZReverse);


      // Slave the Z Axis to the Spindle

      SlaveGain = Z_CNTS_PER_INCH/(CNTS_PER_REV * TPI);

      Z0 = chan[ZAXIS].Dest;

      S0 = chan[SPINDLE_AXIS].Dest;


      // in case there is significant spindle position error move there first


      while (!CheckDone(ZAXIS)) ;



      while (TotalCut < ZDist)


            if (TotalCut + ZForward > ZDist) // last feed


                  // yes, do any remaining

                  DoTap(ZDist-TotalCut, FeedRate, TPI);

                  // retract fully

                  DoTap(-ZDist, RetractRate, TPI);





                  // no, just cut a bit

                  DoTap(ZForward, FeedRate, TPI);

                  DoTap(-ZReverse, RetractRate, TPI);






      Move(ZAXIS,Z0);   // move back to where we started

      while (!CheckDone(ZAXIS)) ;


      *(double *)&persist.UserData[30]=1.0;  // set flag that we are complete

      printf("Tap Complete\n");



void DoTap(double Dist, double Rate, double TPI)


      // Tap down







void DoSlave(void)


      MoveExp(ZAXIS,(chan[SPINDLE_AXIS].Dest-S0)*SlaveGain+Z0, TAU);