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