Hello,
One way Kanalog can be disabled is if your program modifies the IO used to communicate with Kanalog.
I am not sure I understand what do you mean by a "program that modifies the IO used to communicate with Kanalog".
Here is my program that runs when an M6 is called:
Code: Select all
#include "Drill.c"
#include "MillChanger.c"
#include "Spindle.c"
#include "KMotionDef.h"
#ifndef TMP
#define TMP 10 // which spare persist to use to transfer data
#include "KflopToKMotionCNCFunctions.c"
#endif
#define TOOL_VAR 9
// Routine to be executed when M6 TX is called in a G program. (X is the tool number)
void main ()
{
// int previousSlot = persist.UserData[PREVIOUS_TOOL_VAR];
int slot = persist.UserData[TOOL_VAR]; // Requested tool slot. Value stored is an int
// int id = persist.UserData[TOOL_VAR+1]; // value stored is an int
// printf("Tool Set to slot %d id %d\n",slot,id); // print the slot and id
// Turn off drill box if it is on.
if (GetDrillBoxStatus() == 1)
{
ClearDrillOutputs();
}
// Turn off spindle if it is on.
if (GetSpindleStatus() != SPINDLE_OFF)
{
StopSpindle();
}
if(slot >= MILL_TOOL_SLOT_MIN && slot <= MILL_TOOL_SLOT_MAX)
{
if (MillExchangeRoutine(slot))
{
// error, Halt Job
DoPC(PC_COMM_HALT);
}
}
// Drill box routine
else if (slot >= DRILL_BOX_SLOT_MIN && slot <= DRILL_BOX_SLOT_MAX)
{
DrillRoutine(slot);
}
else
{
MsgBox("The selected tool is out of the range. Please select one that is defined inside the tool table.", MB_ICONEXCLAMATION);
}
}
And here are the programs that are called by the main M6 program:
Drill.c
Code: Select all
#include "KMotionDef.h"
#define DRILL_STATUS_VAR 193
#define DRILL_BOX_SLOT_MIN 11
#define DRILL_BOX_SLOT_MAX 20
#define DRILL_1_SLOT 11
#define DRILL_2_SLOT 12
#define DRILL_3_SLOT 13
#define DRILL_4_SLOT 14
#define DRILL_5_SLOT 15
#define DRILL_6_SLOT 16
#define DRILL_7_SLOT 17
#define DRILL_8_SLOT 18
#define DRILL_9_SLOT 19
#define DRILL_10_SLOT 20
#define DRILL_MOTOR_OUTPUT 1133
#define DRILL_1_PISTON_OUTPUT 48
#define DRILL_2_PISTON_OUTPUT 49
#define DRILL_3_PISTON_OUTPUT 50
#define DRILL_4_PISTON_OUTPUT 51
#define DRILL_5_PISTON_OUTPUT 52
#define DRILL_6_PISTON_OUTPUT 53
#define DRILL_7_PISTON_OUTPUT 54
#define DRILL_8_PISTON_OUTPUT 55
#define DRILL_9_PISTON_OUTPUT 56
#define DRILL_10_PISTON_OUTPUT 57
void SetDrillBoxStatus()
{
persist.UserData[DRILL_STATUS_VAR] = 1;
}
void ResetDrillBoxStatus()
{
persist.UserData[DRILL_STATUS_VAR] = 0;
}
int GetDrillBoxStatus()
{
return persist.UserData[DRILL_STATUS_VAR];
}
// Clear all outputs related to the drill operation
void ClearDrillOutputs()
{
ResetDrillBoxStatus();
ClearBit(DRILL_MOTOR_OUTPUT);
ClearBit(DRILL_1_PISTON_OUTPUT);
ClearBit(DRILL_2_PISTON_OUTPUT);
ClearBit(DRILL_3_PISTON_OUTPUT);
ClearBit(DRILL_4_PISTON_OUTPUT);
ClearBit(DRILL_5_PISTON_OUTPUT);
ClearBit(DRILL_6_PISTON_OUTPUT);
ClearBit(DRILL_7_PISTON_OUTPUT);
ClearBit(DRILL_8_PISTON_OUTPUT);
ClearBit(DRILL_9_PISTON_OUTPUT);
ClearBit(DRILL_10_PISTON_OUTPUT);
}
// Select and detach the selected drill
void DrillRoutine(int drillSlot)
{
SetDrillBoxStatus();
Delay_sec(0.25);
SetBit(DRILL_MOTOR_OUTPUT);
Delay_sec(0.25);
switch (drillSlot)
{
case DRILL_1_SLOT:
SetBit(DRILL_1_PISTON_OUTPUT);
break;
case DRILL_2_SLOT:
SetBit(DRILL_2_PISTON_OUTPUT);
break;
case DRILL_3_SLOT:
SetBit(DRILL_3_PISTON_OUTPUT);
break;
case DRILL_4_SLOT:
SetBit(DRILL_4_PISTON_OUTPUT);
break;
case DRILL_5_SLOT:
SetBit(DRILL_5_PISTON_OUTPUT);
break;
case DRILL_6_SLOT:
SetBit(DRILL_6_PISTON_OUTPUT);
break;
case DRILL_7_SLOT:
SetBit(DRILL_7_PISTON_OUTPUT);
break;
case DRILL_8_SLOT:
SetBit(DRILL_8_PISTON_OUTPUT);
break;
case DRILL_9_SLOT:
SetBit(DRILL_9_PISTON_OUTPUT);
break;
case DRILL_10_SLOT:
SetBit(DRILL_10_PISTON_OUTPUT);
break;
default:
break;
}
}
MillChanger.c
Code: Select all
#include "KMotionDef.h"
#define PISTONS_ENABLE_OUTPUT 1127
#define PISTONL_ENABLE_OUTPUT 1128
#define MILL_TOOL_SLOT_MIN 1
#define MILL_TOOL_SLOT_MAX 10
#define TOOL_PRESENT_INPUT 1049
#define CLOSE_MAGAZINE_OUTPUT 1125
#define MAGAZINE_CLOSED_INPUT 1040
#define OPEN_MAGAZINE_OUTPUT 1126
#define MAGAZINE_OPENED_INPUT 1041
#define PISTON_TOOL_OUTPUT 1132
#define SPHERE_GRIPPER_OUTPUT 1129
#define PANTOGRAPH_OFF_SENSOR_INPUT 1042 //Pantografo recuado/alto
#define PANTOGRAPH_MOVING_SENSOR_INPUT 1043 //Pantografo baixo
#define PANTOGRAPH_ON_SENSOR_INPUT 1044 //Pantografo baixo
#define OFFSET_X 20
#define OFFSET_Y -20
#define OFFSET_Z -7.5
#define SLOW_SPEED 60 // mm/sec
// Outputs to be controled for tool exchange
#define EXTRACT_OUTPUT 1130
#define OPEN_TOOL_GRIPPER_OUTPUT 1131
// Vars
#define PREVIOUS_TOOL_VAR 191
#define PREVIOUS_TOOL_LABEL_VAR 192
#define TOOL_DISK_FILE "c:\\Kmotion434\\KMotion\\Data\\ToolChangerData.txt"
#define X_AXIS 0
#define Y_AXIS 1
#define Z_AXIS 2
// Each axis have 2000 counts per revolution
// Resolution of X axis = 20 mm per revolution
// Resolution of Y axis = 20 mm per revolution
// Resolution of Z axis = 7.5 mm per revolution
// FACTOR_X = 20 /2000 = 0.01000 mm/counts
// FACTOR_Y = 20 /2000 = 0.01000 mm/counts
// FACTOR_Z = 7.5/2000 = 0.00375 mm/counts
#define FACTOR_X 0.01000
#define FACTOR_Y 0.01000
#define FACTOR_Z 0.00375
// Routine responsible for exchange mill tool.
// Return 0=Success, 1=Failure
int MillExchangeRoutine(int millSlot)
{
int currentTool;
// -1=Spindle empty, 0=unknown, 1-4 Tool Slot loaded into Spindle
if (GetCurrentTool(¤tTool))
{
return 1;
}
printf("Load Tool Slot %d requested, Current Tool %d\n",millSlot, currentTool);
if (!ToolNumberValid(millSlot)) // check if invalid
{
char s[80];
sprintf(s,"Invalid Tool Change Number %d\n", millSlot);
printf(s);
MsgBox(s, MB_ICONHAND | MB_OK);
return 1;
}
// If the tool requested is already in the spindle return.
if (millSlot == currentTool)
{
return 0;
}
printf("Open Magazine. MillChanger.\n");
OpenMagazine();
if (currentTool != -1) // is there a tool in the Spindle??
{
printf("Unload tool. MillChanger.\n");
if (UnloadTool(currentTool)) // yes, unload it
{
return 1;
}
}
// Now Spindle is empty, load requested tool
printf("Load new tool. MillChanger.\n");
if (LoadNewTool(millSlot))
{
return 1;
}
printf("Close Magazine. MillChanger.\n");
CloseMagazine();
SaveCurrentTool(millSlot); // save the one that has been loaded
return 0; // success
}
// Opens the tool magazine.
void OpenMagazine()
{
SetBit(OPEN_MAGAZINE_OUTPUT);
while(!ReadBit(MAGAZINE_OPENED_INPUT));
//Delay_sec(4);
ClearBit(OPEN_MAGAZINE_OUTPUT);
}
// Closes the tool magazine.
void CloseMagazine()
{
SetBit(CLOSE_MAGAZINE_OUTPUT);
while(!ReadBit(MAGAZINE_CLOSED_INPUT));
//Delay_sec(4);
ClearBit(CLOSE_MAGAZINE_OUTPUT);
}
// save the tool number to KFLOP global Variable and to PC Disk file in case power is lost.
void SaveCurrentTool(int millSlot)
{
persist.UserData[PREVIOUS_TOOL_VAR] = millSlot;
FILE *f=fopen(TOOL_DISK_FILE,"wt");
fprintf(f,"%d\n", millSlot);
fclose(f);
UpdateCurrentToolLabel(millSlot);
return 0;
}
void UpdateCurrentToolLabel(int currentTool)
{
char s[80];
// Now compute and form result
sprintf(s,"%d",currentTool);
// Put it onto the Screen
DROLabel(1000, PREVIOUS_TOOL_LABEL_VAR, s);
}
// 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[PREVIOUS_TOOL_VAR];
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);
MsgBox(s, MB_ICONHAND | MB_OK);
return 1;
}
printf("Current tool = %d\n", tool);
*ptool = tool; // return result to caller
return 0; //success
}
// check if Current Tool number Valid
// -1 = no tool loaded
// 1-10 = valid tool
BOOL ToolNumberValid(int tool)
{
return tool == -1 || (tool>=1 && tool<=10);
}
// Remove tool in spindle by going to holder of current tool.
int UnloadTool(int currentTool)
{
// - Rapid to Z Home to clear any work that may be on the table
if (MoveZ(0.0, SLOW_SPEED))
{
return 1;
}
// - Rapid to current tool position to execute Z move
if (MoveXY(ToolPositionX(currentTool), ToolPositionY(currentTool), SLOW_SPEED))
{
return 1;
}
// - Approach tool holder by matching Z height of tool flange currently in spindle with tool holder claw
if (MoveZ(ToolPositionZ(), SLOW_SPEED))
{
return 1;
}
if (!JOB_ACTIVE)
{
ClearStopImmediately(); // Clear Stop Condition without resuming
return 1; // if Job was terminated/halt exit - return error.
}
// Activate piston actuators to approach tool in z axis.
EnablePistons();
if (!JOB_ACTIVE)
{
DisablePistons();
ClearStopImmediately(); // Clear Stop Condition without resuming
return 1; // if Job was terminated/halt exit - return error.
}
// - Eject tool
if (EjectTool())
{
return 1;
}
if (!JOB_ACTIVE)
{
ClearStopImmediately(); // Clear Stop Condition without resuming
return 1; // if Job was terminated/halt exit - return error.
}
DisablePistons();
if (!JOB_ACTIVE)
{
ClearStopImmediately(); // Clear Stop Condition without resuming
return 1; // if Job was terminated/halt exit - return error.
}
// - Rapid to Z Home
if (MoveZ(0.0, SLOW_SPEED))
{
return 1;
}
return 0; //success
}
// Load new Tool (Spindle must be empty).
int LoadNewTool(int newTool)
{
// - Rapid to Z Home to clear any work that may be on the table
if (MoveZ(0.0, SLOW_SPEED))
{
return 1;
}
// - Rapid to new tool position to execute Z move
if (MoveXY(ToolPositionX(newTool), ToolPositionY(newTool), SLOW_SPEED))
{
return 1;
}
if (MoveZ(ToolPositionZ(), SLOW_SPEED))
{
return 1;
}
if (!JOB_ACTIVE)
{
ClearStopImmediately(); // Clear Stop Condition without resuming
return 1; // if Job was terminated/halt exit - return error.
}
// Activate piston actuators to approach tool in z axis.
EnablePistons();
if (!JOB_ACTIVE)
{
ClearStopImmediately(); // Clear Stop Condition without resuming
DisablePistons();
return 1; // if Job was terminated/halt exit - return error.
}
// - Grab tool
if (GrabTool())
{
return 1;
}
if (!JOB_ACTIVE)
{
ClearStopImmediately(); // Clear Stop Condition without resuming
return 1; // if Job was terminated/halt exit - return error.
}
DisablePistons();
if (!JOB_ACTIVE)
{
ClearStopImmediately(); // Clear Stop Condition without resuming
return 1; // if Job was terminated/halt exit - return error.
}
// - Rapid to Z Home
if (MoveZ(0.0, SLOW_SPEED))
{
return 1;
}
return 0; //success
}
// Return x position of tool holder as a function of the tool in mm.
float ToolPositionX(int tool)
{
float xOffset = 0.0;
if (tool % 2 == 0)
{
xOffset = 120.0;
}
float xPosition = -13.5 + OFFSET_X + xOffset;
return xPosition;
}
// Return y position of tool holder as a function of the tool in mm.
float ToolPositionY(int tool)
{
float yOffset = 0;
if (tool > 6)
{
yOffset = 160*3;
}
else if (tool > 4)
{
yOffset = 160*2;
}
else if (tool > 2)
{
yOffset = 160*1;
}
float yPosition = -868.3 + OFFSET_Y + yOffset;
return yPosition;
}
// Return z position of tool holder in mm.
float ToolPositionZ()
{
float zPosition = -10 + OFFSET_Z;
return zPosition;
}
// 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(X_AXIS, x / FACTOR_X, Speed / FACTOR_X);
MoveAtVel(Y_AXIS, y / FACTOR_Y, Speed / FACTOR_Y);
while (!CheckDone(X_AXIS) || !CheckDone(Y_AXIS))
{
if (!chan[X_AXIS].Enable)
{
printf("Error X Axis Disabled\n");
MsgBox("Error X Axis Disabled\n", MB_ICONHAND | MB_OK);
return 1;
}
if (!chan[Y_AXIS].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(Z_AXIS, z / FACTOR_Z, Speed / FACTOR_Z);
while (!CheckDone(Z_AXIS))
{
if (!chan[Z_AXIS].Enable)
{
printf("Error Z Axis Disabled\n");
MsgBox("Error Z Axis Disabled\n", MB_ICONHAND | MB_OK);
return 1;
}
}
return 0; //success
}
// Activate piston actuators to approach tool holder in z axis.
void EnablePistons()
{
SetBit(PISTONS_ENABLE_OUTPUT);
SetBit(PISTONL_ENABLE_OUTPUT);
Delay_sec(2.0);
}
// Disable piston actuators.
void DisablePistons()
{
ClearBit(PISTONS_ENABLE_OUTPUT);
ClearBit(PISTONL_ENABLE_OUTPUT);
Delay_sec(2.0);
}
// Eject milling tool.
// return 0 = success, 1 if sensor points that the tool is still grabbed.
int EjectTool()
{
SetBit(SPHERE_GRIPPER_OUTPUT);
Delay_sec(1.0);
SetBit(OPEN_TOOL_GRIPPER_OUTPUT);
Delay_sec(0.5);
SetBit(EXTRACT_OUTPUT);
Delay_sec(1.0);
ClearBit(EXTRACT_OUTPUT);
SetBit(PISTON_TOOL_OUTPUT);
Delay_sec(2.0);
ClearBit(SPHERE_GRIPPER_OUTPUT);
// - Wait for time in seconds defined by CLAMP_TIME
Delay_sec(1.0);
// - Read TOOL_PRESENT_INPUT bit to see whether the tool is loose, to make a safe Z move without
// destroying tool holder
// - If TOOL_PRESENT_INPUT bit is high, something has gone wrong;
// halt everything and display message indicating failure
if (ReadBit(TOOL_PRESENT_INPUT))
{
printf("Claw Loose Error\n");
MsgBox("Claw Loose Error\n", MB_ICONHAND | MB_OK);
return 1;
}
SaveCurrentTool(-1);
ClearBit(PISTON_TOOL_OUTPUT);
Delay_sec(2.0);
ClearBit(OPEN_TOOL_GRIPPER_OUTPUT);
Delay_sec(1.0);
return 0; // success
}
// Grab milling tool.
// return 0 = success, 1 if sensor points that the tool is not grabbed.
int GrabTool()
{
SetBit(OPEN_TOOL_GRIPPER_OUTPUT);
SetBit(PISTON_TOOL_OUTPUT);
Delay_sec(2.0);
SetBit(SPHERE_GRIPPER_OUTPUT);
Delay_sec(0.5);
ClearBit(PISTON_TOOL_OUTPUT);
Delay_sec(2.0);
ClearBit(OPEN_TOOL_GRIPPER_OUTPUT);
Delay_sec(1.0);
ClearBit(SPHERE_GRIPPER_OUTPUT);
// - Wait for time in seconds defined by CLAMP_TIME
Delay_sec(1.0);
// - Read TOOL_PRESENT_INPUT bit to see whether the tool is loose, to make a safe Z move without
// destroying tool holder
// - If TOOL_PRESENT_INPUT bit is high, something has gone wrong;
// halt everything and display message indicating failure
if (!ReadBit(TOOL_PRESENT_INPUT))
{
printf("Error while grabbing tool\n");
MsgBox("Error while grabbing tool\n", MB_ICONHAND | MB_OK);
return 1;
}
return 0; // success
}
Spindle.c
Code: Select all
#include "KMotionDef.h"
// Outputs to be controled for spindle interaction
#define CW_ENABLE_OUTPUT 1121
#define CCW_ENABLE_OUTPUT 1122
#define PISTONS_ENABLE_OUTPUT 1127
#define PISTONL_ENABLE_OUTPUT 1128
// Inputs to be monitored for spindle interaction
#define VELOCITY_CONFIRMATION_INPUT 1158
#define STOP_CONFIRMATION_INPUT 1159
//#define PISTONS_SENSOR_INPUT 1042
//#define PISTONL_SENSOR_INPUT 1044
// seconds of delay before execute other G code
#define DELAY_BEFORE_MACHINING 1
// Persist variable to sign the status of the spindle
#define SPINDLE_STATUS_VAR 190 // 0 indicates that spindle is off, 1 CW, 2 CCW
#define SPINDLE_OFF 0
#define SPINDLE_ON_CW 1
#define SPINDLE_ON_CCW 2
void SetSpindleStatus(int Status)
{
persist.UserData[SPINDLE_STATUS_VAR] = Status;
}
int GetSpindleStatus()
{
return persist.UserData[SPINDLE_STATUS_VAR];
}
void StopSpindle()
{
ClearBit(PISTONS_ENABLE_OUTPUT);
ClearBit(PISTONL_ENABLE_OUTPUT);
ClearBit(CCW_ENABLE_OUTPUT);
ClearBit(CW_ENABLE_OUTPUT);
// Blocks the execution before the velocity is zero
// Use Exec/Wait on KMotionCNC for this behavior
while (ReadBit(STOP_CONFIRMATION_INPUT))
{
WaitNextTimeSlice();
}
SetSpindleStatus(SPINDLE_OFF);
}
Sincerely,
Guilherme