# 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)
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; 	// 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;
double CutRPM  = *(double *)&persist.UserData;
double RetractRPM  = *(double *)&persist.UserData;
double ZDist  = *(double *)&persist.UserData;
double ZForward = *(double *)&persist.UserData;
double ZReverse = *(double *)&persist.UserData;

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

```
```