Table of contents |

# 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/Kogna, notifies KFLOP/Kogna to perform the Tap Cycle, then waits until KFLOP/Kogna 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.

    	G0X0Y0Z5

    	(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)
    	M84

    	G0X4Y0Z5

    	(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)
    	M84

    	M2

## Mach3 M84 Macro

This macro moves the GCode Tapping Variables to Mach3 User DROs, downloads then to KFLOP/Kogna UserData variables, Triggers KFLOP/Kogna to perform the Tap Cycle, then waits until KFLOP/Kogna 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))
    	NotifyPlugins(19010+i)
    	Next i

    	Call SetUserDRO(1016, 0)'clear the complete flag
    	NotifyPlugins(19010+6)

    	NotifyPlugins(10084) 'do the TAP!!

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

## KFLOP/Kogna 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/Kogna (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);

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

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

    		if (msg==10084)
    		{
    			Tap();
    		}
    	}

    	// 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();
    	{
    	// #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
    	Move(ZAXIS,(chan[SPINDLE_AXIS].Position-S0)*SlaveGain+Z0);
    	while (!CheckDone(ZAXIS)) ;

    	TotalCut=0.0;
    	while (TotalCut < ZDist)
    	{
    		if (TotalCut + ZForward > ZDist) // last feed
    		{
    			// yes, do any remaining
    			DoTap(ZDist-TotalCut, FeedRate, TPI);
    			// retract fully
    			DoTap(-ZDist, RetractRate, TPI);
    			TotalCut=ZDist;
    		}
    		else
    		{
    			// no, just cut a bit
    			DoTap(ZForward, FeedRate, TPI);
    			DoTap(-ZReverse, RetractRate, TPI);
    			TotalCut+=ZForward-ZReverse;
    		}
    	}

    	Delay_sec(1.0);
    	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
    		MoveRelAtVel(SPINDLE_AXIS, Dist*TPI*CNTS_PER_REV, Rate*TPI*CNTS_PER_REV);

    		while (!CheckDone(SPINDLE_AXIS))
    			DoSlave();
    	}

    	void DoSlave(void)
    	{
    		MoveExp(ZAXIS,(chan[SPINDLE_AXIS].Dest-S0)*SlaveGain+Z0, TAU);
    		WaitNextTimeSlice();
    	}