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.

	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 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)) 
	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 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);

	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();
	}