DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Moderators: TomKerekes, dynomotion

Tim G
Posts: 38
Joined: Wed Jan 13, 2021 9:51 pm

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by Tim G » Sat Sep 13, 2025 6:56 pm

Thanks so much! I believe I adapted the code and was attempting to give it a try, however, I'm having an intermittent problem with my spindle that's now rather permanent. Occassionally, my spindle wouldn't turn on during the tool changes, which would be detrimental and cause major machine damage if it attempted to load a new tool when it hadn't unloaded the old tool. I have a Cat 6 cable carrying the signals from the VFD to the KFLOP, and it seems like I have to plug/unplug that a few times when this occurs to get the spindle working correctly again. Now, it will turn on when I manually give it an M3 or M4 command, however, during the tool changes, it start to turn on, spins a time or two, and then turns off (almost as if it's not getting a clear signal from the wire). I'm just not sure why it's consistently turning on when I manually give it commands and consistently giving me that on-then-quit behavior during the tool changes.

I'll have to sort that out before I can continue testing, so hopefully I can figure that out quickly! Thanks again for the help with the coding and I'm looking forward to giving that a try! The probing file worked and I confirmed the tool tip went successfully to the workpiece surface.

Tim G
Posts: 38
Joined: Wed Jan 13, 2021 9:51 pm

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by Tim G » Sun Sep 14, 2025 9:38 pm

Okay, so I didn't originally catch that you had changed the "CorrectAnalogFunction" command to an int command in the load and unload tool sections for testing when I was comparing the lines of code. It looks like that was the culprit for keeping the spindle from staying on. I put the CorrectAnalogFunction part back for both the load and unload procedures and now they're working seamlessly again. I tried the new code and it ended up with the second bit about a 1/4" too high off of the workpiece. Something interesting I noticed based off of the console messages is that the offset value was supposed to be 4.3801. However, when it applied that value to the second tool, it didn't match up with what I was seeing at the machine. After noticing it was a 1/4" too high with the second bit, I commanded the machine to G53 G0 Z-1.3816, where the tool triggered the tool setter. This should have put the G54 DRO up to the 4.3801 offset value the program supposedly set at the tool setter trigger point, according to the console messages. However, at that height, the DRO only read 4.1285 (which is 0.2516" less that 4.3801). When I tool changed back to tool 1 (the one i started with), the z height was correct again. Out of curiosity, I moved the z back to G53 G0 Z-1.3816 (the trigger height for tool 2 instead of the current bit - tool 1). I got that same 4.1285 value. This makes me wonder if it's not resetting the DRO effectively after tool changes somehow. It's reporting in the console that it's resetting the DRO after a tool change, but it seems like it's not taking effect somehow. It's like the probing file is effectively setting the offset, but the tool setter file isn't resetting the DRO.


Z probe triggered at -5.0001, workpiece zero set to -5.5101
Bit 29 (TOOL_HEIGHT_BIT) initial state: 1
Pushed tool table out
Tool setter triggered at -1.1300 inches
Pulled tool table back in
Stored job-specific G54 Z DRO: 4.3801 inches at G53 Z=-1.1300, touchplate surface=-5.0001
Persist var 8 value: 0
Read Disk File Value of 1
Current tool = 1
Load Tool Slot 2 requested, Current Tool 1
Tool setter triggered at -1.3816 inches
Set G54 Z DRO to 4.3800 inches (job-specific offset) at G53 Z=-1.3816
Tool change succeeded, saving new tool 2
Saved tool 2 to file C:\Users\NUA_TIM\Desktop\Machine Programs\ToolChangerData.txt
Persist var 8 value: 2
Current tool = 2
Load Tool Slot 1 requested, Current Tool 2
Tool setter triggered at -1.1290 inches
Set G54 Z DRO to 4.3800 inches (job-specific offset) at G53 Z=-1.1290
Tool change succeeded, saving new tool 1
Saved tool 1 to file C:\Users\NUA_TIM\Desktop\Machine Programs\ToolChangerData.txt

User avatar
TomKerekes
Posts: 2868
Joined: Mon Dec 04, 2017 1:49 am

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by TomKerekes » Sun Sep 14, 2025 10:58 pm

Hi Tim,

This is fighting us every step of the way 🫤

Just to double check, the Z counts/inch in KMotionCNC is 10000 correct?

Please post/attach latest programs.

“Resetting the DRO” is really computing a G92 offset (there is an option to use the fixture offset instead) such that the current position is the specified value. Please repeat and after running each program record the computed value.

It seems Tool 2 is 1/4 inch shorter than Tool 1?

Note: WinMerge is a great program to compare C Programs and merge changes.
Regards,

Tom Kerekes
Dynomotion, Inc.

Tim G
Posts: 38
Joined: Wed Jan 13, 2021 9:51 pm

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by Tim G » Sun Sep 14, 2025 11:37 pm

Thanks a ton for all of the help and sorry it's giving us so much guff! Yes, 10000 counts/inch is how Z is currently setup in KmotionCNC. That's correct as well that Tool 2 is 1/4" shorter than Tool 1. I've attached the programs below along with the console results and some notes after running each program.

After Probing/Offset Program with Tool 2:
Z probe triggered at -5.2555, workpiece zero set to -5.7655
Bit 29 (TOOL_HEIGHT_BIT) initial state: 1
Pushed tool table out
Tool setter triggered at -1.3846 inches
Pulled tool table back in
Stored job-specific G54 Z DRO: 4.3809 inches at G53 Z=-1.3846, touchplate surface=-5.2555

G54 Z0 correctly positioned the tool tip at the zero point at G53 Z -5.7655
When commanded to the G53 Z-1.3846 tool setter trigger point for the tool, the G54 DRO correctly read 4.3809

After Tool Change Program, Tool 2 switched to Tool 1:
Persist var 8 value: 0
Read Disk File Value of 2
Current tool = 2
Load Tool Slot 1 requested, Current Tool 2
Tool setter triggered at -1.1313 inches
Set G54 Z DRO to 4.3808 inches (job-specific offset) at G53 Z=-1.1313
Tool change succeeded, saving new tool 1
Saved tool 1 to file C:\Users\NUA_TIM\Desktop\Machine Programs\ToolChangerData.txt

G54 Z0 incorrectly positioned the tool tip roughly 1/4" below the zero point at G53 Z -5.7655 (Tool 1 is about 1/4" longer than Tool 2)
When commanded to the G53 Z-1.1313 tool setter trigger point for the tool, the G54 DRO incorrectly read 4.6342. When moved to the other tool's trigger position, it correctly read 4.3809, suggesting the DRO has not been adjusted for tool 1 (correct reading for tool 2).

ProbeZ.c: Probe and Tool Setter Offset Program

Code: Select all

#include "KMotionDef.h"
#define TMP 10
#include "C:\Users\NUA_TIM\Desktop\KMotion5.4.0\C Programs\KflopToKMotionCNCFunctions.c"
#define AXISZ 3
#define AXISX 2
#define AXISY 0
#define CNT_PER_INCH_Z 10000
#define CNT_PER_INCH_X 3175
#define CNT_PER_INCH_Y 3180.3
#define Z_PROBE_BIT 7
#define TOOL_HEIGHT_BIT 29 // Bit to read tool height plate 
#define WORKPIECE_ZERO_VAR 12
#define REF_TOOL_OFFSET_VAR 11 // Stores job-specific G54 Z DRO (counts)
#define TOOL_HEIGHT_PLATE_X 23.5613
#define TOOL_HEIGHT_PLATE_Y 30.1356
#define MAX_Z_PROBE_DEPTH -6.0 // Safety limit to prevent over-travel (inches)
#define TOUCH_PLATE_THICKNESS 0.51

// Function prototypes
int MoveXY(float x, float y, float Speed);
int MoveZ(float z, float Speed);
int ProbeToolSetter(float *z_position);

int main()
{
	float trig_pos;
    SetBitDirection(Z_PROBE_BIT, 0);
    ch3->LimitSwitchOptions = 0;
    FPGA(STEP_PULSE_LENGTH_ADD) = 63 + 0x80;

    Jog(AXISZ, -3000);
    while (ReadBit(Z_PROBE_BIT));
    trig_pos = chan[AXISZ].Dest;
    Move(AXISZ, trig_pos);  // revese and stop where triggered
    while (!CheckDone(AXISZ));

    float z_position = trig_pos / CNT_PER_INCH_Z;
    float workpiece_zero = z_position - TOUCH_PLATE_THICKNESS;
    persist.UserData[WORKPIECE_ZERO_VAR] = (int)(workpiece_zero * CNT_PER_INCH_Z);
    printf("Z probe triggered at %.4f, workpiece zero set to %.4f\n", z_position, workpiece_zero);
    Delay_sec(5);

    DoPCFloat(PC_COMM_SET_Z, TOUCH_PLATE_THICKNESS); // Set Z=0 at workpiece surface
    
    Delay_sec(1);

    MoveAtVel(AXISZ, 0, 20000);
    while (!CheckDone(AXISZ));

    Delay_sec(1);
    
    ch3->LimitSwitchOptions = 0x11a;

    // Tool setter probing
    float z_toolsetter, dro_value;

    // Verify tool setter bit state
    printf("Bit 29 (TOOL_HEIGHT_BIT) initial state: %d\n", ReadBit(TOOL_HEIGHT_BIT));

    // Move to machine Z=0
    if (MoveZ(0, 4)) {
        printf("Error: Failed to move to machine Z=0. Halting.\n");
        DoPC(PC_COMM_HALT);
        return 0;
    }

    // Push tool table out
    SetBit(19);
    printf("Pushed tool table out\n");

    // Probe tool setter
    if (ProbeToolSetter(&z_toolsetter)) {
        printf("Error: Failed to probe tool setter. Halting.\n");
        DoPC(PC_COMM_HALT);
        return 0;
    }

    // Pull tool table back in
    ClearBit(19);
    printf("Pulled tool table back in\n");

    // Store job-specific G54 Z DRO as tool setter trigger height minus touchplate surface
    dro_value = z_toolsetter - workpiece_zero;
    persist.UserData[REF_TOOL_OFFSET_VAR] = (int)(dro_value * CNT_PER_INCH_Z);
    printf("Stored job-specific G54 Z DRO: %.4f inches at G53 Z=%.4f, touchplate surface=%.4f\n", dro_value, z_toolsetter, z_position);
}

// Probe tool setter. Return 0=Success, 1=Failure
int ProbeToolSetter(float *z_position)
{
    int SaveZLimits;

    // Move to tool setter position
    if (MoveXY(TOOL_HEIGHT_PLATE_X, TOOL_HEIGHT_PLATE_Y, 10)) return 1;

    // Save limit switch settings and disable limits
    SaveZLimits = ch3->LimitSwitchOptions;
    ch3->LimitSwitchOptions = 0;
    FPGA(STEP_PULSE_LENGTH_ADD) = 63 + 0x80;

    // Jog Z down until tool setter is triggered or safety limit reached
    Jog(3, -3000); // Jog at 3000 counts/sec
    while (ReadBit(TOOL_HEIGHT_BIT)) {
        float current_z = chan[AXISZ].Dest / CNT_PER_INCH_Z;
        if (current_z < MAX_Z_PROBE_DEPTH) {
            Jog(3, 0); // Stop
            while (!CheckDone(3)); // Wait for motion to complete
            printf("Error: Tool setter not triggered, exceeded max depth %.4f inches. Halting.\n", MAX_Z_PROBE_DEPTH);
            ch3->LimitSwitchOptions = SaveZLimits;
            return 1; // Failure
        }
    }
    // Get current Z position
    *z_position = chan[AXISZ].Dest / CNT_PER_INCH_Z;

    Jog(3, 0); // Stop
    while (!CheckDone(3)); // Wait for motion to complete

    printf("Tool setter triggered at %.4f inches\n", *z_position);

    // Move back up to machine Z=0
    if (MoveZ(0, 4)) return 1; // Move at 4 inch per second

    // Restore limit settings
    ch3->LimitSwitchOptions = SaveZLimits;
    return 0; // Success
}

// Move Axis XY at specified Speed and wait until complete
int MoveXY(float x, float y, float Speed)
{
    MoveAtVel(AXISX, x * CNT_PER_INCH_X, Speed * CNT_PER_INCH_X);
    MoveAtVel(AXISY, y * CNT_PER_INCH_Y, Speed * CNT_PER_INCH_Y);
    
    while (!CheckDone(AXISX) || !CheckDone(AXISY))
    {
        if (!chan[AXISX].Enable)
        {
            printf("Error X Axis Disabled. Halting.\n");
            return 1;
        }
        if (!chan[AXISY].Enable)
        {
            printf("Error Y Axis Disabled. Halting.\n");
            return 1;
        }
    }
    return 0; // success
}

// Move Axis Z at specified Speed and wait until complete
int MoveZ(float z, float Speed)
{
    MoveAtVel(AXISZ, z * CNT_PER_INCH_Z, Speed * CNT_PER_INCH_Z);
    
    while (!CheckDone(AXISZ))
    {
        if (!chan[AXISZ].Enable)
        {
            printf("Error Z Axis Disabled. Halting.\n");
            return 1;
        }
    }
    return 0; // success
}
Linear16ToolHolders: Tool Changer Program

Code: Select all

#include "KMotionDef.h"
#define TMP 10 // which spare persist to use to transfer data
#include "C:\Users\NUA_TIM\Desktop\KMotion5.4.0\C Programs\KflopToKMotionCNCFunctions.c"
#include "C:\Users\NUA_TIM\Desktop\Machine Programs\CorrectAnalogFunction.c"
#define RPM_FACTOR 22200.0 // RPM for full duty cycle (max analog out)

//-----------------------------------------
//		LINEAR TOOL CHANGING
//-----------------------------------------
#define AXISX 2
#define AXISY 0
#define AXISZ 3

//---------Absolute position of tool holders
#define HOLDER_X_1 1.7143
#define HOLDER_X_2 3.9643
#define HOLDER_X_3 6.2143
#define HOLDER_X_4 8.4643
#define HOLDER_X_5 12.0703
#define HOLDER_X_6 14.3203
#define HOLDER_X_7 16.5703
#define HOLDER_X_8 18.8203
#define HOLDER_X_9 28.2643
#define HOLDER_X_10 30.5143
#define HOLDER_X_11 32.7643
#define HOLDER_X_12 35.0143
#define HOLDER_X_13 38.6203
#define HOLDER_X_14 40.8703
#define HOLDER_X_15 43.1203
#define HOLDER_X_16 45.3703
#define HOLDER_Y 30.1156
#define HOLDER_Z 0

// absolute position of the tool height setting plate
#define TOOL_HEIGHT_PLATE_X 23.5613 
#define TOOL_HEIGHT_PLATE_Y 30.1356

#define TOOL_VAR 9        	// Tool changer desired new tool Var

// Tool changer Last tool loaded is saved globally in this Var
#define LAST_TOOL_VAR 8   	//  -1=Spindle empty, 0=unknown, 1-16 Tool Slot loaded into Spindle
#define TOOL_DISK_FILE "C:\\Users\\NUA_TIM\\Desktop\\Machine Programs\\ToolChangerData.txt"

#define TOOL_HEIGHT_BIT	29	//bit to read tool height plate (KONNECT INPUT 31)

#define CNT_PER_INCH_X 3175 
#define CNT_PER_INCH_Y 3180.3 
#define CNT_PER_INCH_Z 10000 

#define MAX_Z_PROBE_DEPTH -6.0 // Safety limit to prevent over-travel (inches)
#define REF_TOOL_OFFSET_VAR 11 // Job-specific G54 Z DRO (counts)

// function prototypes
int DoToolChange(int ToolSlot);
int GetCurrentTool(int *tool);
int SaveCurrentTool(int tool);
BOOL ToolNumberValid(int tool);
float ToolPositionX(int tool);
int MoveXY(float x, float y, float Speed);
int MoveZ(float z, float Speed);
int UnloadTool(int CurrentTool);
int LoadNewTool(int Tool);
int ProbeToolSetter(float *z_position);

main()
{
	int ToolSlot = persist.UserData[TOOL_VAR];  // Requested tool to load (value stored an integer) 

	if (DoToolChange(ToolSlot))  // perform Tool Change
	{
		// error, Halt Job
		DoPC(PC_COMM_HALT);
	}
}

// Perform Tool Change.  Return 0=Success, 1=Failure
int DoToolChange(int ToolSlot)
{
    int CurrentTool;

    if (GetCurrentTool(&CurrentTool)) return 1;  //  -1=Spindle empty, 0=unknown, 1-16 Tool Slot loaded into Spindle

    printf("Load Tool Slot %d requested, Current Tool %d\n",ToolSlot, CurrentTool);
    
    if (!ToolNumberValid(ToolSlot))  // check if invalid
    {
        char s[80];
        sprintf(s,"Invalid Tool Change Number %d\n",ToolSlot);
        printf(s);
        MsgBox(s, MB_ICONHAND | MB_OK);
        return 1;
    }
    
    if (CurrentTool!=-1) // is there a tool in the Spindle??
        if (UnloadTool(CurrentTool)) return 1;  // yes, unload it
        
    // Now Spindle is empty, load requested tool
    if (LoadNewTool(ToolSlot)) return 1;

    // Probe tool setter to locate tool tip
    float z_toolsetter;
    if (ProbeToolSetter(&z_toolsetter)) {
        char s[80];
        sprintf(s,"Error: Failed to probe tool setter for tool %d. Halting.\n", ToolSlot);
        printf(s);
        MsgBox(s, MB_ICONHAND | MB_OK);
        return 1;
    }

    printf("Tool change succeeded, saving new tool %d\n", ToolSlot);
    SaveCurrentTool(ToolSlot);  // save the one that has been loaded
    return 0;  // success
}

// Probe tool setter. Return 0=Success, 1=Failure
int ProbeToolSetter(float *z_position)
{
    int SaveZLimits;
    float trig_pos;

    // Ensure tool table is out
    SetBit(19);

    // Move to tool setter position
    if (MoveXY(TOOL_HEIGHT_PLATE_X, TOOL_HEIGHT_PLATE_Y, 10)) return 1;

    // Save limit switch settings and disable limits
    SaveZLimits = ch3->LimitSwitchOptions;
    ch3->LimitSwitchOptions = 0;
    FPGA(STEP_PULSE_LENGTH_ADD) = 63 + 0x80;

    // Jog Z down until tool setter is triggered or safety limit reached
    Jog(3, -3000); // Jog at 3000 counts/sec
    while (ReadBit(TOOL_HEIGHT_BIT)) {
            float current_z = chan[AXISZ].Dest / CNT_PER_INCH_Z;
        if (current_z < MAX_Z_PROBE_DEPTH) {
            Jog(3, 0); // Stop
            while (!CheckDone(3)); // Wait for motion to complete
            char s[80];
            sprintf(s,"Error: Tool setter not triggered, exceeded max depth %.4f inches.\n", MAX_Z_PROBE_DEPTH);
            printf(s);
            MsgBox(s, MB_ICONHAND | MB_OK);
            ch3->LimitSwitchOptions = SaveZLimits;
            return 1; // Failure
        }
    }
    trig_pos = chan[AXISZ].Dest;  // save triggered position
    Move(AXISZ, trig_pos); // reverse and stop at triggered position
    while (!CheckDone(3)); // Wait for motion to complete

    // Get triggered Z position
    *z_position = trig_pos / CNT_PER_INCH_Z;
    printf("Tool setter triggered at %.4f inches\n", *z_position);

    // Set G54 Z DRO to job-specific offset from persist.UserData[11]
    float dro_value = persist.UserData[REF_TOOL_OFFSET_VAR] / (float)CNT_PER_INCH_Z;
    DoPCFloat(PC_COMM_SET_Z, dro_value);
    printf("Set G54 Z DRO to %.4f inches (job-specific offset) at G53 Z=%.4f\n", dro_value, *z_position);

    // Move back up to machine Z=0
    if (MoveZ(0, 4)) return 1; // Move at 4 inch per second

    // Pull tool table in
    ClearBit(19);

    // Restore limit settings
    ch3->LimitSwitchOptions = SaveZLimits;
    return 0; // Success
}

// - Load new Tool (Spindle must be empty)
int LoadNewTool(int Tool)
{
	SetBit(19); // Move tool table out
	MoveZ(0, 4); // Move Z at 4 inch per second (240 in/minute)
    	MoveXY(ToolPositionX(Tool),HOLDER_Y, 10);  // Move XY at 10 inch per second (600 in/minute)
    	MoveZ(-3, 2); // Move Z to tool bay at 2 in per second (120 in/minute) - Tool lowers into bay 1 inch above engagement with socket bearings
    	float speed = 1500.0; // Hardcoded speed value in RPM
    	SetBitDirection(26,1); // define bit as an output
    	FPGA(IO_PWMS_PRESCALE) = 46; // divide clock by 46 (1.4 KHz)
    	FPGA(IO_PWMS+1) = 1; // Enable
    	FPGA(IO_PWMS) = CorrectAnalog(speed/RPM_FACTOR); // Set PWM
    	ClearBit(0);
    	MoveZ(-4, 1); // Move Z at 1 inch per second (60 in/min) to engage collet nut
    	MoveZ(-3, 3); // Move Z  at 3 inch per second (180 in/min) upward by an inch to disengage collet nut from socket
    	MoveZ(-4, 1); // Move Z at 1 inch per second (60 in/min) to engage/tighten collet nut
    	MoveZ(-3, 3); // Move Z up 1 inch to disengage collet nut from socket
    	SetBit(0);
    	MoveZ(0, 4); // Move Z at 4 inch per second (240 In/min) to machine coordinates Z zero (fully up and clear of tool bays)
	Delay_sec(0.5);
	ClearBit(19); // Move tool table in
	return 0;
}

// - Remove tool in spindle by going to holder of current tool
int UnloadTool(int CurrentTool)
{
	SetBit(19); // Move tool table out
	Delay_sec(1.0);
	MoveZ(0, 4); // Move Z at 4 inch per second (240 in/minute)
    	MoveXY(ToolPositionX(CurrentTool),HOLDER_Y,10);  // Move XY at 10 inch per second (600 in/minute)
    	MoveZ(-3, 2); // Move Z to tool bay at 2 in per second (120 in/minute) - Tool lowers into bay 1 inch above engagement with socket bearings
    	float speed = 1600.0; // Hardcoded speed value in RPM
    	SetBitDirection(26,1); // define bit as an output
    	FPGA(IO_PWMS_PRESCALE) = 46; // divide clock by 46 (1.4 KHz)
    	FPGA(IO_PWMS+1) = 1; // Enable
    	FPGA(IO_PWMS) = CorrectAnalog(speed/RPM_FACTOR); // Set PWM
    	SetBit(45);
    	MoveZ(-4, 1); // Move Z at 1 inch per second (60 in/min) to engage collet nut
    	MoveZ(-3, 1); // Move Z  at 1 inch per second (180 in/min) upward by an inch to disengage collet nut from socket
    	ClearBit(45);
    	MoveZ(0, 4); // Move Z at 5 inch per second (300 In/min) to machine coordinates Z zero (fully up and clear of tool bays)
	return 0;
}

//return x position of tool holder as a function of the tool
float ToolPositionX(int tool)
{
	if (tool == 1) return HOLDER_X_1;
	if (tool == 2) return HOLDER_X_2;
	if (tool == 3) return HOLDER_X_3;
	if (tool == 4) return HOLDER_X_4;
	if (tool == 5) return HOLDER_X_5;
	if (tool == 6) return HOLDER_X_6;
	if (tool == 7) return HOLDER_X_7;
	if (tool == 8) return HOLDER_X_8;
	if (tool == 9) return HOLDER_X_9;
	if (tool == 10) return HOLDER_X_10;
	if (tool == 11) return HOLDER_X_11;
	if (tool == 12) return HOLDER_X_12;
	if (tool == 13) return HOLDER_X_13;
	if (tool == 14) return HOLDER_X_14;
	if (tool == 15) return HOLDER_X_15;
	if (tool == 16) return HOLDER_X_16;
	return 0;  // should never happen
}

// Get the last loaded tool.  Parameter points to where to return tool
// First try to get from KFLOP memory
// if memory is invalid, try to read from disk
// if can't read disk then ask Operator
// returns 0 on success, 1 on fail or Operator asked to abort
int GetCurrentTool(int *ptool)
{
	int success,Answer,result,tool;
	float value;

	tool = persist.UserData[LAST_TOOL_VAR];
	printf("Persist var 8 value: %d\n", tool);
	success = ToolNumberValid(tool);  // check if valid

	if (!success)   // invalid after power up, try to read from PC Disk File
	{
		// Try to open file
		FILE *f=fopen(TOOL_DISK_FILE,"rt");
		if (f)  // did file open?
		{
			// read a line and convert it
			result=fscanf(f,"%d",&tool);
			fclose(f);
			
			if (result==1 && ToolNumberValid(tool))
			{
				printf("Read Disk File Value of %d\n",tool);
				success=TRUE; // success if one value converted
			}
		}
		
		if (!success) printf("Unable to open/read file:%s\n",TOOL_DISK_FILE);  
	}

	if (!success)   // if still no success ask Operator
	{
		Answer = InputBox("Tool in Spindle or -1",&value);
		if (Answer)
		{
			printf("Operator Canceled\n");
			return 1;
		}
		else
		{
			tool=value;
			printf("Operator Entered Value of %d\n",tool);
		}
	}

	if (!ToolNumberValid(tool))  // check if invalid
	{
		char s[80];
		sprintf(s,"Invalid Current Tool Number %d\n",tool);
		printf("%s",s);
		MsgBox(s, MB_ICONHAND | MB_OK);
		return 1;
	}
	
	printf("Current tool = %d\n",tool);
	*ptool = tool;  // return result to caller
	return 0;  //success
}

// save the tool number to KFLOP global Variable and to PC Disk file in case we loose power
int SaveCurrentTool(int tool)
{
    persist.UserData[LAST_TOOL_VAR] = tool;
    FILE *f = fopen(TOOL_DISK_FILE, "wt");
    if (f == NULL) {
        printf("Error: Unable to open/write to file %s\n", TOOL_DISK_FILE);
        // Optionally add: MsgBox("Error saving tool data to file!", MB_ICONHAND | MB_OK);
        return 1;  // Failure
    }
    if (fprintf(f, "%d\n", tool) < 0) {  // Add this to check write
        printf("Error: fprintf failed for file %s\n", TOOL_DISK_FILE);
        fclose(f);
        return 1;
    }
    fclose(f);
    printf("Saved tool %d to file %s\n", tool, TOOL_DISK_FILE);  // For debugging
    return 0;  // Success
}

// check if Current Tool number Valid
// -1 = no tool loaded
// 1-16 = valid tool
BOOL ToolNumberValid(int tool)
{
	return tool == -1 || (tool>=1 && tool<=16);
}

// Move Axis XY at specified Speed and wait until complete
// return 0 = success, 1 if axis disabled
int MoveXY(float x, float y, float Speed)
{
	MoveAtVel(AXISX, x * CNT_PER_INCH_X, Speed * CNT_PER_INCH_X);
	MoveAtVel(AXISY, y * CNT_PER_INCH_Y, Speed * CNT_PER_INCH_Y);
	
	while (!CheckDone(AXISX) || !CheckDone(AXISY))
	{
		if (!chan[AXISX].Enable)
		{
			printf("Error X Axis Disabled\n");
			MsgBox("Error X Axis Disabled\n", MB_ICONHAND | MB_OK);
			return 1;
		}
		if (!chan[AXISY].Enable)
		{
			printf("Error Y Axis Disabled\n");
			MsgBox("Error Y Axis Disabled\n", MB_ICONHAND | MB_OK);
			return 1;
		}
	}
	return 0;  //success
}

// Move Axis Z at specified Speed and wait until complete
// return 0 = success, 1 if axis disabled
int MoveZ(float z, float Speed)
{
	MoveAtVel(AXISZ, z * CNT_PER_INCH_Z, Speed * CNT_PER_INCH_Z);
	
	while (!CheckDone(AXISZ))
	{
		if (!chan[AXISZ].Enable)
		{
			printf("Error Z Axis Disabled\n");
			MsgBox("Error Z Axis Disabled\n", MB_ICONHAND | MB_OK);
			return 1;
		}
	}
	return 0;  //success
}

User avatar
TomKerekes
Posts: 2868
Joined: Mon Dec 04, 2017 1:49 am

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by TomKerekes » Mon Sep 15, 2025 4:03 pm

Hi Tim,

I see the problem. We intentionally block changes to the Fixture Offsets while GCode is executing. If we had checked the return code from DoPCFloat we would have known that it failed. I was running the Tool Change program from KMotion rather than KMotionCNC so GCode wasn't involved so it worked.

Let me think of a workaround. Otherwise we may need to remove the block or add an override. Or we could change to use the Tool Length offset like normal.

Thanks for your patience.
Regards,

Tom Kerekes
Dynomotion, Inc.

Tim G
Posts: 38
Joined: Wed Jan 13, 2021 9:51 pm

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by Tim G » Mon Sep 15, 2025 4:53 pm

No worries at all and I should be thanking you for your patience! I really appreciate all of the time you're spending helping someone as inexperienced as I am to figure all of this out. Thanks a ton! If you happen to find a work-around to make this approach work, that would be fantastic in terms of ensuring the highest accuracy for tool tip zero. However, in case tool length offset is better way to go, I figured I'd let you know I found a way to ensure the tool length protrusion for a given tool stays consistent. I've 3D printed some tight-fitting collars and I use a dab of super glue on the tool shank as well as the collet face under the collar to ensure they're stuck in place well. They're still pretty easy to remove by tapping the back of the tool with a punch to break the glue joint on the collet, so it seems like this solution should work well, while still allowing me to clean up glue residue and reuse the collets easily.

Image

User avatar
TomKerekes
Posts: 2868
Joined: Mon Dec 04, 2017 1:49 am

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by TomKerekes » Tue Sep 16, 2025 1:33 am

Hi Tim,

I created a patch for Version 5.4.0 with an option to allow changing offsets with a Job Active.

KMotionCNC.exe Copy to the \KMotion\Release folder
PC_DSP.h Copy to the \DSP_KFLOP folder

Add a PC_COMM_ALLOW_SET_AXIS_W_JOBACTIVE command before setting z in the Tool Change Program like this:

Code: Select all

	if (DoPC(PC_COMM_ALLOW_SET_AXIS_W_JOBACTIVE))  // allow changing offsets
		printf("Allow Set Axis failed\n");

	if (DoPCFloat(PC_COMM_SET_Z, dro_value))  // set the offset
		printf("Set Z Failed %d\n");
Hope this works :)
Regards,

Tom Kerekes
Dynomotion, Inc.

Tim G
Posts: 38
Joined: Wed Jan 13, 2021 9:51 pm

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by Tim G » Tue Sep 16, 2025 4:39 am

The sweet taste of victory! :D

It took me a moment to believe it, but it's officially changing tools and zeroing the tool tips to the same point. Can't thank you enough for all of the help with this! Creating a custom patch for me to get this thing working turned out to be a life-saver and was incredibly kind of you. I'm excited to figure out the post processor changes needed and give this setup it's first official job. A 16 bay tool changer setup on a pneumatic table w/compressor included, all-in at $500 feels pretty dang good!

I'll put a video below in case you're curious to see a successful tool change with it. I'll try to put together a video of it's first successful job as well, after I figure out the post processor stuff. Can't thank you enough, Tom! Exciting stuff!:)

https://imgur.com/a/6hqaA2A


Final probing section from the tool changer file:

Code: Select all

// Probe tool setter. Return 0=Success, 1=Failure
int ProbeToolSetter(float *z_position)
{
    int SaveZLimits;
    float trig_pos;

    // Ensure tool table is out
    SetBit(19);

    // Move to tool setter position
    if (MoveXY(TOOL_HEIGHT_PLATE_X, TOOL_HEIGHT_PLATE_Y, 10)) return 1;

    // Save limit switch settings and disable limits
    SaveZLimits = ch3->LimitSwitchOptions;
    ch3->LimitSwitchOptions = 0;
    FPGA(STEP_PULSE_LENGTH_ADD) = 63 + 0x80;

    // Jog Z down until tool setter is triggered or safety limit reached
    Jog(3, -3000); // Jog at 3000 counts/sec
    while (ReadBit(TOOL_HEIGHT_BIT)) {
            float current_z = chan[AXISZ].Dest / CNT_PER_INCH_Z;
        if (current_z < MAX_Z_PROBE_DEPTH) {
            Jog(3, 0); // Stop
            while (!CheckDone(3)); // Wait for motion to complete
            char s[80];
            sprintf(s,"Error: Tool setter not triggered, exceeded max depth %.4f inches.\n", MAX_Z_PROBE_DEPTH);
            printf(s);
            MsgBox(s, MB_ICONHAND | MB_OK);
            ch3->LimitSwitchOptions = SaveZLimits;
            return 1; // Failure
        }
    }
    trig_pos = chan[AXISZ].Dest;  // save triggered position
    Move(AXISZ, trig_pos); // reverse and stop at triggered position
    while (!CheckDone(3)); // Wait for motion to complete

    // Get triggered Z position
    *z_position = trig_pos / CNT_PER_INCH_Z;
    printf("Tool setter triggered at %.4f inches\n", *z_position);

    // Set G54 Z DRO to job-specific offset from persist.UserData[11]
    float dro_value = persist.UserData[REF_TOOL_OFFSET_VAR] / (float)CNT_PER_INCH_Z;

    if (DoPC(PC_COMM_ALLOW_SET_AXIS_W_JOBACTIVE))  // allow changing offsets
	printf("Allow Set Axis failed\n");

    if (DoPCFloat(PC_COMM_SET_Z, dro_value))  // set the offset
	printf("Set Z Failed %d\n");
   
    printf("Set G54 Z DRO to %.4f inches (job-specific offset) at G53 Z=%.4f\n", dro_value, *z_position);

    // Move back up to machine Z=0
    if (MoveZ(0, 4)) return 1; // Move at 4 inch per second

    // Pull tool table in
    ClearBit(19);

    // Restore limit settings
    ch3->LimitSwitchOptions = SaveZLimits;
    return 0; // Success
}

Tim G
Posts: 38
Joined: Wed Jan 13, 2021 9:51 pm

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by Tim G » Wed Sep 17, 2025 12:04 am

Well, I had a heck of a time with the setup after trying to get the post processor configured. Unfortunately, the tool changes started cross-threading for the first time, and fairly consistently. Looks like the alignment of the spindle to the tool changer bays shifted about 5-7 thousandths in both X and Y. Not sure how that occurred or if it was gradual, but I'll have to keep an eye on that. I'm hoping the hardware isn't compounding this too much between mechanic limit switches possibly not being as accurate as necessary, and the pneumatic table against the hard stops slowly drifting things out of position. I'll keep thinking about ways to enhance the precision of the hardware. I've also had some issue with significant vibration at full cutting speeds with certain tools. I bought pretty inexpensive collets and collet nuts since I needed so many, so I'm concerned they might be the culprits here. If I can get the tool changing happening reliably, I may consider dumping some more cash towards better balanced collet nuts and collets.

UPDATE: I haven't tracked down anything concrete yet that could be causing the drift/irregular alignment. However, I did decide to precisely determined positions again and this time I did it for each individual tool bay. While they're very close to being inline the entire length across, there's still about 5-7 thousandths + or - of variance. Due to this, I think when I had aligned the left and rightmost bays originally, relying on the idea that they would be close enough to inline, it worked initially, but some would be 7 thousandths out of aligned from the start, so a few more thousandths of drift/irregularity caused them to start cross threading on certain bays. I had the idea to just redo the code to provide individual Y location values for each tool slot instead of assuming they would all be in line. This has work really well so far. I've done 30+ tool changes since with multiple on/off cycles so that part is going much better now.

The big issue is I am having trouble with the gcode files tripping the Y axis somehow when it tries to start the second tool path after a tool change. It can change tools all day if I'm not running a gcode file, but if I try to do a change within a gcode file, it trips every time. It's not actually tripping the limit switch hardware, it's just that the DRO suddenly goes yellow for the Y axis, kmotion reports a following error in the console, and it stops the program. You can also hear the steppers slowly ramping down as the axis drifts slowly after the trip. I've tried a few versions of the post processor, tried inserting a dwell command to give it time before the next file starts, but it always seems to do this. Oddly enough, one time I had a cross thread, so I paused it just after the tool touched off, but before it started the new toolpath. For some reason, that time I was able to start it again and have the toolpath run, but when it changed to the third tool, it tripped the Y axis again. I can't find anything wrong with the post processor at this point, and it will even do this now when I try to run with with my previous post processor (used M6 command for manual tool changes before), so I think it could have something to do with how the patch allows resetting the DRO. Maybe some other aspect of KmotionCNC doesn't play well with that when running a file?

I've put the gcode file and the VCarve Pro post processor below in case it could be something to do with the code, but I'm thinking it's more likely an issue with something else.


Gcode Test File:

Code: Select all

( First ATC Test File )
( File created: Tuesday September 16 2025 - 08:24 PM)
( for Kmotion from Vectric )
( Material Size)
( X= 16.000, Y= 12.000, Z= 0.250)
(Toolpaths used in this file:)
(Holes)
(V-Carve 1)
(Cutout)
(Tools used in this file: )
(5 = End Mill {1/8"})
(9 = V-Bit {60.0° - 1/4"})
(1 = End Mill {1/4"})
N13 G20 G17 G90 G40 G49 G80
N14 G53 G00 Z0
N15 M05
N16 T5 M06
N17 (Tool: End Mill {1/8"})
N18 G00 Z4.0000
N19 G54
N20 S19000 M03
N21 ( Toolpath:- Holes)
N22 G00 X0.0000 Y0.0000
N23 G00 X0.6937 Y0.6900 
N24 G00 X0.6937 Y0.6900 Z0.2000
N25 G1 X0.6937 Y0.6900 Z-0.1250 F20.0
N26 G3 X0.7312 Y0.6525 I0.0375 J0.0000 F80.0
N27 G3 X0.7687 Y0.6900 I0.0000 J0.0375
N28 G3 X0.7312 Y0.7275 I-0.0375 J0.0000
N29 G3 X0.6937 Y0.6900 I0.0000 J-0.0375
N30 G1 X0.6937 Y0.6900 Z-0.2500 F20.0
N31 G3 X0.7312 Y0.6525 I0.0375 J0.0000 F80.0
N32 G3 X0.7687 Y0.6900 I0.0000 J0.0375
N33 G3 X0.7312 Y0.7275 I-0.0375 J0.0000
N34 G3 X0.6937 Y0.6900 I0.0000 J-0.0375
N35 G00 X0.6937 Y0.6900 Z0.2000
N36 G00 X0.7312 Y2.2725 Z0.2000
N37 G1 X0.7312 Y2.2725 Z-0.1250 F20.0
N38 G3 X0.7687 Y2.3100 I0.0000 J0.0375 F80.0
N39 G3 X0.7312 Y2.3475 I-0.0375 J0.0000
N40 G3 X0.6937 Y2.3100 I0.0000 J-0.0375
N41 G3 X0.7312 Y2.2725 I0.0375 J0.0000
N42 G1 X0.7312 Y2.2725 Z-0.2500 F20.0
N43 G3 X0.7687 Y2.3100 I0.0000 J0.0375 F80.0
N44 G3 X0.7312 Y2.3475 I-0.0375 J0.0000
N45 G3 X0.6937 Y2.3100 I0.0000 J-0.0375
N46 G3 X0.7312 Y2.2725 I0.0375 J0.0000
N47 G00 X0.7312 Y2.2725 Z0.2000
N48 G00 X4.2313 Y2.3100 Z0.2000
N49 G1 X4.2313 Y2.3100 Z-0.1250 F20.0
N50 G3 X4.2688 Y2.2725 I0.0375 J0.0000 F80.0
N51 G3 X4.3063 Y2.3100 I0.0000 J0.0375
N52 G3 X4.2688 Y2.3475 I-0.0375 J0.0000
N53 G3 X4.2313 Y2.3100 I0.0000 J-0.0375
N54 G1 X4.2313 Y2.3100 Z-0.2500 F20.0
N55 G3 X4.2688 Y2.2725 I0.0375 J0.0000 F80.0
N56 G3 X4.3063 Y2.3100 I0.0000 J0.0375
N57 G3 X4.2688 Y2.3475 I-0.0375 J0.0000
N58 G3 X4.2313 Y2.3100 I0.0000 J-0.0375
N59 G00 X4.2313 Y2.3100 Z0.2000
N60 G00 X4.2688 Y0.7275 Z0.2000
N61 G1 X4.2688 Y0.7275 Z-0.1250 F20.0
N62 G3 X4.2313 Y0.6900 I0.0000 J-0.0375 F80.0
N63 G3 X4.2688 Y0.6525 I0.0375 J0.0000
N64 G3 X4.3063 Y0.6900 I0.0000 J0.0375
N65 G3 X4.2688 Y0.7275 I-0.0375 J0.0000
N66 G1 X4.2688 Y0.7275 Z-0.2500 F20.0
N67 G3 X4.2313 Y0.6900 I0.0000 J-0.0375 F80.0
N68 G3 X4.2688 Y0.6525 I0.0375 J0.0000
N69 G3 X4.3063 Y0.6900 I0.0000 J0.0375
N70 G3 X4.2688 Y0.7275 I-0.0375 J0.0000
N71 G00 X4.2688 Y0.7275 Z0.2000
N72 G00 X4.2688 Y0.7275 Z4.0000
N73 G53 G00 Z0
N74 M05
N75 (Tool: V-Bit {60.0° - 1/4"})
N76 T9M6
N77 G54
N78 (Tool: V-Bit {60.0° - 1/4"})
N79 S16000 M03
N80 (V-Carve 1)
N81 G04 P2500
N82 G00 X2.5003 Y1.6793 
N83 G00 X2.5003 Y1.6793 Z0.2000
N84 G1 X2.5003 Y1.6793 Z-0.0359 F15.0
N85 G1 X2.5003 Y1.6738 Z-0.0321 F45.0
N86 G1 X2.5003 Y1.6686 Z-0.0308
N87 G1 X2.5003 Y1.3178 Z-0.0308
N88 G1 X2.4825 Y1.3000 Z0.0000
N89 G1 X2.5003 Y1.3178 Z-0.0308
N90 G1 X2.5180 Y1.3000 Z0.0000
N91 G1 X2.5003 Y1.3178 Z-0.0308
N92 G1 X2.5003 Y1.6686 Z-0.0308
N93 G1 X2.5003 Y1.6738 Z-0.0321
N94 G1 X2.5003 Y1.6793 Z-0.0359
N95 G1 X2.5055 Y1.6818 Z-0.0316
N96 G1 X2.5117 Y1.6837 Z-0.0283
N97 G1 X2.5180 Y1.6843 Z-0.0272
N98 G1 X2.5642 Y1.6843 Z-0.0272
N99 G1 X2.5799 Y1.6686 Z0.0000
N100 G1 X2.5642 Y1.6843 Z-0.0272
N101 G1 X2.5799 Y1.7000 Z0.0000
N102 G1 X2.5642 Y1.6843 Z-0.0272
N103 G1 X2.5180 Y1.6843 Z-0.0272
N104 G1 X2.5117 Y1.6837 Z-0.0283
N105 G1 X2.5055 Y1.6818 Z-0.0316
N106 G1 X2.5003 Y1.6793 Z-0.0359
N107 G1 X2.4951 Y1.6818 Z-0.0316
N108 G1 X2.4888 Y1.6837 Z-0.0283
N109 G1 X2.4825 Y1.6843 Z-0.0272
N110 G1 X2.4358 Y1.6843 Z-0.0272
N111 G1 X2.4201 Y1.7000 Z0.0000
N112 G1 X2.4358 Y1.6843 Z-0.0272
N113 G1 X2.4201 Y1.6686 Z0.0000
N114 G1 X2.4358 Y1.6843 Z-0.0272
N115 G1 X2.4825 Y1.6843 Z-0.0272
N116 G1 X2.4888 Y1.6837 Z-0.0283
N117 G1 X2.4951 Y1.6818 Z-0.0316
N118 G1 X2.5003 Y1.6793 Z-0.0359
N119 G00 X2.5003 Y1.6793 Z0.2000
N120 G00 X2.5003 Y1.6793 Z4.0000
N121 G53 G00 Z0
N122 M05
N123 (Tool: End Mill {1/4"})
N124 T1M6
N125 G54
N126 (Tool: End Mill {1/4"})
N127 S18000 M03
N128 (Cutout)
N129 G04 P2500
N130 G00 X-0.1250 Y0.1250 
N131 G00 X-0.1250 Y0.1250 Z0.2000
N132 G1 X-0.1250 Y0.1250 Z-0.2500 F50.0
N133 G1 X-0.1250 Y2.8750 Z-0.2500 F100.0
N134 G2 X0.1250 Y3.1250 I0.2500 J0.0000
N135 G1 X4.8750 Y3.1250 Z-0.2500 
N136 G2 X5.1250 Y2.8750 I0.0000 J-0.2500
N137 G1 X5.1250 Y0.1250 Z-0.2500 
N138 G2 X4.8750 Y-0.1250 I-0.2500 J0.0000
N139 G1 X0.1250 Y-0.1250 Z-0.2500 
N140 G2 X-0.1250 Y0.1250 I0.0000 J0.2500
N141 G00 X-0.1250 Y0.1250 Z0.2000
N142 G53 G00 Z0
N143 G54
N144 M05
N145 M30
%

Post processor file:

Code: Select all

+================================================
+                                                
+ KMotion - Vectric machine output configuration file   
+   for automatic tool change projects                                          
+================================================
+  Modified by Tim Grimwood 9-16-2025                                         

+================================================

POST_NAME = "Kmotion-AutoTC (inch) (*.txt)"

FILE_EXTENSION = "ngc"

UNITS = "inches"

SUBSTITUTE = "({)}"

+------------------------------------------------
+    Line terminating characters                 
+------------------------------------------------

LINE_ENDING = "[13][10]"

+------------------------------------------------
+    Block numbering                             
+------------------------------------------------

LINE_NUMBER_START     = 0
LINE_NUMBER_INCREMENT = 1
LINE_NUMBER_MAXIMUM = 999999

+================================================
+                                                
+    Formating for variables                     
+                                                
+================================================

VAR LINE_NUMBER = [N|A|N|1.0]
VAR SPINDLE_SPEED = [S|A|S|1.0]
VAR FEED_RATE = [F|C|F|1.1]
VAR X_POSITION = [X|A|X|1.4]
VAR Y_POSITION = [Y|A|Y|1.4]
VAR Z_POSITION = [Z|A|Z|1.4]
VAR ARC_CENTRE_I_INC_POSITION = [I|A|I|1.4]
VAR ARC_CENTRE_J_INC_POSITION = [J|A|J|1.4]
VAR X_HOME_POSITION = [XH|A|X|1.4]
VAR Y_HOME_POSITION = [YH|A|Y|1.4]
VAR Z_HOME_POSITION = [ZH|A|Z|1.4]
VAR SAFE_Z_HEIGHT = [SAFEZ|A|Z|1.4]
VAR DWELL_TIME = [DWELL|A|P|1.2]
+================================================
+                                                
+    Block definitions for toolpath output       
+                                                
+================================================

+---------------------------------------------------
+  Commands output at the start of the file
+---------------------------------------------------

begin HEADER

"( [TP_FILENAME] )"
"( File created: [DATE] - [TIME])"
"( for Kmotion from Vectric )"
"( Material Size)"
"( X= [XLENGTH], Y= [YLENGTH], Z= [ZLENGTH])"
"(Toolpaths used in this file:)"
"([TOOLPATHS_OUTPUT])"
"(Tools used in this file: )"
"([TOOLS_USED])"
"[N] G20 G17 G90 G40 G49 G80"  
"[N] G53 G00 Z0"               
"[N] M05"                      
"[N] T[T] M06"                
"[N] (Tool: [TOOLNAME])"
"[N] G00 [ZH]"                 
"[N] G54"                      
"[N] [S] M03"                  
"[N] ( Toolpath:- [TOOLPATH_NAME])"
"[N] G00 [XH] [YH]"            


+---------------------------------------------------
+  Commands output for rapid moves 
+---------------------------------------------------

begin RAPID_MOVE

"[N] G00 [X] [Y] [Z]"


+---------------------------------------------------
+  Commands output for the first feed rate move
+---------------------------------------------------

begin FIRST_FEED_MOVE

"[N] G1 [X] [Y] [Z] [F]"


+---------------------------------------------------
+  Commands output for feed rate moves
+---------------------------------------------------

begin FEED_MOVE

"[N] G1 [X] [Y] [Z]"

+---------------------------------------------------
+  Commands output for the first clockwise arc move
+---------------------------------------------------

begin FIRST_CW_ARC_MOVE

"[N] G2 [X] [Y] [I] [J][F]"

+---------------------------------------------------
+  Commands output for clockwise arc  move
+---------------------------------------------------

begin CW_ARC_MOVE

"[N] G2 [X] [Y] [I] [J]"

+---------------------------------------------------
+  Commands output for the first counterclockwise arc move
+---------------------------------------------------

begin FIRST_CCW_ARC_MOVE

"[N] G3 [X] [Y] [I] [J] [F]"

+---------------------------------------------------
+  Commands output for counterclockwise arc  move
+---------------------------------------------------

begin CCW_ARC_MOVE

"[N] G3 [X] [Y] [I] [J]"

+---------------------------------------------------
+  Commands output at toolchange
+---------------------------------------------------

begin TOOLCHANGE

"[N] G53 G00 Z0"   
"[N] M05"          
"[N] (Tool: [TOOLNAME])"  
"[N] T[T]M6"       
"[N] G54"          


+---------------------------------------------------
+  Commands output for a new segment - toolpath
+  with same toolnumber but maybe different feedrates
+---------------------------------------------------

begin NEW_SEGMENT

"[N] (Tool: [TOOLNAME])"
"[N] [S] M03"
"[N] ([TOOLPATH_NAME])"
"[N] G04 P2500"

+---------------------------------------------
+  Commands output for a dwell move
+---------------------------------------------

begin DWELL_MOVE

"G04 [DWELL]"

+---------------------------------------------------
+  Commands output at the end of the file
+---------------------------------------------------

begin FOOTER

"[N] G53 G00 Z0"  
"[N] G54"
"[N] M05"         
"[N] M30"         
%


User avatar
TomKerekes
Posts: 2868
Joined: Mon Dec 04, 2017 1:49 am

Re: DIY Collet-Spinning ATC - Adapting Linear ATC C Programs?

Post by TomKerekes » Fri Sep 19, 2025 9:13 pm

I don't exactly follow that. Is it the Y axis or Z axis that has a following error?

Do you have the M6 configured as Exec/wait/Sync? When a program moves things around behind the Interpreter's back it must be told to re-sync to the new position before continuing.
Regards,

Tom Kerekes
Dynomotion, Inc.

Post Reply