Difference between revisions of "Main Page"
From Dynomotion
(→Tool Changer - router linear 4 Tools - C Program) |
(→Tool Changer - router linear 4 Tools - C Programnone|link=|246x178px) |
||
Line 141: | Line 141: | ||
:* Place links to pages that explain how you accomplished your particular project. Write clear explanations that provide background on what you did and how you did it. | :* Place links to pages that explain how you accomplished your particular project. Write clear explanations that provide background on what you did and how you did it. | ||
====[[Tool Changer - router linear 4 Tools - C Program]][[File:LINEAT+ATC.jpg|none|link=|246x178px]]==== | ====[[Tool Changer - router linear 4 Tools - C Program]][[File:LINEAT+ATC.jpg|none|link=|246x178px]]==== | ||
+ | <pre class="brush:c">#include "KMotionDef.h" | ||
+ | #define TMP 10 // which spare persist to use to transfer data | ||
+ | #include "..\..\KflopToKMotionCNCFunctions.c" | ||
+ | |||
+ | //----------------------------------------- | ||
+ | // LINEAR TOOL CHANGING | ||
+ | //----------------------------------------- | ||
+ | #define AXISX 0 | ||
+ | #define AXISY 1 | ||
+ | #define AXISZ 2 | ||
+ | |||
+ | //---------Absolute position of tool holders | ||
+ | #define HOLDER_X_1 100 | ||
+ | #define HOLDER_X_2 200 | ||
+ | #define HOLDER_X_3 300 | ||
+ | #define HOLDER_X_4 400 | ||
+ | #define HOLDER_Y 1300 | ||
+ | #define HOLDER_Z -200 | ||
+ | // absolute position of the tool height setting plate | ||
+ | #define TOOL_HEIGHT_PLATE_X 50 | ||
+ | #define TOOL_HEIGHT_PLATE_Y 50 | ||
+ | |||
+ | // absolute position to move to that is permanently unobstructed, and safe to move down in Z | ||
+ | #define TOOL_CHANGE_SAFE_POS_X 250 | ||
+ | #define TOOL_CHANGE_SAFE_POS_Y 1200 | ||
+ | |||
+ | #define AXIS_SAFE_DISTANCE_Y 100 // distance in mm to approach tool holder | ||
+ | //--------- | ||
+ | |||
+ | //--------- Spindle IO bits | ||
+ | #define CLAW_EJECT 58 // IO bit to eject tool from spindle (KONNECT OUTPUT 10) | ||
+ | #define SPINDLE_CLEAN 59 // IO bit to blow air out of spindle taper (KONNECT OUTPUT 11) | ||
+ | #define CLAW_LOOSE 1048 // IO bit to sense whether the claw has ejected (KONNECT INPUT 24) | ||
+ | #define TOOL_SENSE 1049 // IO bit to sense whether the a tool is in the spindle (KONNECT INPUT 24) | ||
+ | //--------- | ||
+ | |||
+ | #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-4 Tool Slot loaded into Spindle | ||
+ | #define TOOL_DISK_FILE "c:\\Temp\\ToolChangerData.txt" | ||
+ | |||
+ | |||
+ | #define CLAMP_TIME 1.0 // seconds to wait for the clamp/unclamp | ||
+ | #define TOOL_HEIGHT_BIT 1055 //bit to read tool height plate (KONNECT INPUT 31) | ||
+ | |||
+ | #define SAFE_HEIGHT_Z 100 // relative distance in mm to move to clear the top of the tool taper | ||
+ | #define TOOL_RETRACT_SPEED_Z 5000 //speed in counts/second to move spindle up after tool has been ejected | ||
+ | |||
+ | #define SlowSpeed 10.0 //mm/sec | ||
+ | |||
+ | #define CNT_PER_MM_X 800.0 | ||
+ | #define CNT_PER_MM_Y 800.0 | ||
+ | #define CNT_PER_MM_Z 800.0 | ||
+ | |||
+ | // 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 EjectTool(void); | ||
+ | |||
+ | |||
+ | |||
+ | 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-4 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; | ||
+ | |||
+ | SaveCurrentTool(ToolSlot); // save the one that has been loaded | ||
+ | return 0; // success | ||
+ | } | ||
+ | |||
+ | |||
+ | // - Load new Tool (Spindle must be empty) | ||
+ | int LoadNewTool(int Tool) | ||
+ | { | ||
+ | // - Move to position of requested tool | ||
+ | // - Rapid move to absolute position of new tool only in X and Y | ||
+ | if (MoveXY(ToolPositionX(Tool),HOLDER_Y,SlowSpeed)) return 1; | ||
+ | |||
+ | // - Move to tool Z position at TOOL_RETRACT_SPEED_Z | ||
+ | if (MoveZ(HOLDER_Z,SlowSpeed)) return 1; | ||
+ | |||
+ | // - Engage new tool | ||
+ | // - CLAW_EJECT and SPINDLE_CLEAN bits are currently high from tool removal operation | ||
+ | // - Turn off CLAW_EJECT and SPINDLE_CLEAN bits to engage tool | ||
+ | ClearBit(CLAW_EJECT); | ||
+ | ClearBit(SPINDLE_CLEAN); | ||
+ | |||
+ | // - Wait for time in seconds defined by CLAMP_TIME | ||
+ | Delay_sec(CLAMP_TIME); | ||
+ | |||
+ | // - Check to see if CLAW_LOOSE and TOOL_SENSE are high; if either are not, | ||
+ | // something has gone wrong; halt everything and display message indicating failure | ||
+ | // - Tool has been engaged | ||
+ | if (!ReadBit(CLAW_LOOSE)) | ||
+ | { | ||
+ | printf("Claw Still Loose Error\n"); | ||
+ | MsgBox("Claw Still Loose Error\n", MB_ICONHAND | MB_OK); | ||
+ | return 1; | ||
+ | } | ||
+ | if (!ReadBit(TOOL_SENSE)) | ||
+ | { | ||
+ | printf("Tool Sense Error\n"); | ||
+ | MsgBox("Tool Sense Error\n", MB_ICONHAND | MB_OK); | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | // - Leave tool holder by moving Y axis by the negative value of Y_AXIS_SAFE_DISTANCE | ||
+ | // - Move to position of requested tool | ||
+ | // - Rapid move to absolute position of new tool only in X and Y | ||
+ | if (MoveXY(ToolPositionX(Tool),HOLDER_Y+AXIS_SAFE_DISTANCE_Y,SlowSpeed)) return 1; | ||
+ | |||
+ | // - Rapid to Z home | ||
+ | if (MoveZ(0.0,SlowSpeed)) return 1; | ||
+ | |||
+ | return 0; //success | ||
+ | } | ||
+ | |||
+ | |||
+ | // - 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,SlowSpeed)) return 1; | ||
+ | |||
+ | // - Rapid to TOOL_CHANGE_SAFE_POS to execute a safe negative Z move | ||
+ | if (MoveXY(TOOL_CHANGE_SAFE_POS_X,TOOL_CHANGE_SAFE_POS_Y,SlowSpeed)) return 1; | ||
+ | |||
+ | // - Approach tool holder by matching Z height of tool flange currently in spindle with tool holder claw | ||
+ | if (MoveZ(HOLDER_Z,SlowSpeed)) return 1; | ||
+ | |||
+ | // - After matching height above, approach tool holder by moving to holder X position | ||
+ | if (MoveXY(ToolPositionX(CurrentTool),TOOL_CHANGE_SAFE_POS_Y,SlowSpeed)) return 1; | ||
+ | |||
+ | // - After matching X position, match tool Y position | ||
+ | if (MoveXY(ToolPositionX(CurrentTool),HOLDER_Y,SlowSpeed)) return 1; | ||
+ | |||
+ | // - Move only in Y position until current position matches tool holder position (maybe disable X) axis?) | ||
+ | // ??? | ||
+ | |||
+ | // - Eject tool | ||
+ | if (EjectTool()) return 1; | ||
+ | |||
+ | |||
+ | return 0; //success | ||
+ | } | ||
+ | |||
+ | |||
+ | // - Eject tool | ||
+ | int EjectTool(void) | ||
+ | { | ||
+ | // - Turn on CLAW_EJECT bit to remove tool from spindle | ||
+ | SetBit(CLAW_EJECT); | ||
+ | |||
+ | // - Turn on SPINDLE_CLEAN bit to remove any debris from taper and tools | ||
+ | SetBit(SPINDLE_CLEAN); | ||
+ | |||
+ | // - Wait for time in seconds defined by CLAMP_TIME | ||
+ | Delay_sec(CLAMP_TIME); | ||
+ | |||
+ | // - Read CLAW_LOOSE bit to see whether the tool is loose, to make a safe Z move without | ||
+ | // destroying tool holder | ||
+ | // - If CLAW_LOOSE bit is high, something has gone wrong; | ||
+ | // halt everything and display message indicating failure | ||
+ | if (ReadBit(CLAW_LOOSE)) | ||
+ | { | ||
+ | printf("Claw Loose Error\n"); | ||
+ | MsgBox("Claw Loose Error\n", MB_ICONHAND | MB_OK); | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | // - Move Z axis up at speed defined by 'Z_TOOL_RETRACT_SPEED', to Z_SAFE_HEIGHT | ||
+ | if (MoveZ(HOLDER_Z+SAFE_HEIGHT_Z,TOOL_RETRACT_SPEED_Z)) return 1; | ||
+ | |||
+ | // - Read TOOL_SENSE bit to see whether the tool has been successfully ejected from the spindle | ||
+ | // - If TOOL_SENSE bit is high, something has gone wrong; | ||
+ | // halt everything and display message indicating failure | ||
+ | if (ReadBit(TOOL_SENSE)) | ||
+ | { | ||
+ | printf("Tool Sense Release Error\n"); | ||
+ | MsgBox("Tool Sense Release Error\n", MB_ICONHAND | MB_OK); | ||
+ | return 1; | ||
+ | } | ||
+ | return 0; // success | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | //return x position of tool holder as a function of the tool | ||
+ | float ToolPositionX(int tool) | ||
+ | { | ||
+ | return (HOLDER_X_2-HOLDER_X_1)*(tool-1) + HOLDER_X_1; | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | // 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]; | ||
+ | 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 | ||
+ | } | ||
+ | |||
+ | // 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"); | ||
+ | fprintf(f,"%d\n",tool); | ||
+ | fclose(f); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | // check if Current Tool number Valid | ||
+ | // -1 = no tool loaded | ||
+ | // 1-4 = valid tool | ||
+ | BOOL ToolNumberValid(int tool) | ||
+ | { | ||
+ | return tool == -1 || (tool>=1 && tool<=4); | ||
+ | } | ||
+ | |||
+ | |||
+ | // 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_MM_X, Speed * CNT_PER_MM_X); | ||
+ | MoveAtVel(AXISZ, y * CNT_PER_MM_Y, Speed * CNT_PER_MM_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_MM_Z, Speed * CNT_PER_MM_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 | ||
+ | } | ||
+ | </pre> |
Revision as of 12:10, 3 November 2015
Contents
Dynomotion wiki
Welcome to our wiki where you can find and share knowledge on Dynomotion's systems. To begin adding information to this wiki, simply create an account, verify your email, and start editing (click pencil icon). To make editing pages easier for everyone, we have installed a visual editor by default. This visual editor allows you to edit a wiki page much like you would a standard word processing document. For the seasoned wiki editors, standard MediaWiki editing may also be used.
Warning: Use at your own risk. Information is for example purposes only and may contain errors. It is up to the User to verify the information is correct and is safe to use. In no case will any contributor or Dynomotion be liable for incorrect information. Dynomotion reserves the right to modify or delete any contributions.
Thanks for Contributing!
Editing and Creating Wiki Pages
Unintuitively, you first create a link to the page you want to make before you can make the page. To make a new page: while editing, right-click where you want your link to be, insert a link with a descriptive title and link text, save the page, click on the link you created, then click on "Empty Page" to begin editing your new page.
Here are a few other quick tips:
- You can insert links or images by Right-Clicking with the mouse on the line where you want the link or image to appear.
- For Spell Correction you can use Ctrl-Right-Click.
- To insert a YouTube Video use an EmbedVideo command such as {{#ev:youtube|xxxxx}} with xxxxx changed to the Video ID.
- Choose a descriptive page name and link text when creating a new page: e.g. Not "My Machine", but rather "Brand X Three Axis Milling Machine Retrofit"
- Create pages in an organized manner: Describe what the page is about, create clear sections that flow
For more information:
How to Edit and insert Media into your wiki pages
Dynomotion Software Topics
Installation Topics
- Latest Production Release: Full release download page
- Latest Test Release: Released 08/29/2015: KMotion.exe V4.33q, See the release notes for this test version here: V4.33q release notes (pdf)
- How to install KMotion.exe and KMotionCNC
- How to update KFLOP Firmware - whenever a new version of software is installed, the firmware within KFLOP must be updated to match the new version
KMotion.exe Executive Software Topics
KMotion.exe is the main program that is used to configure settings in KFLOP, initialize axes, and to write C programs to configure and setup KFLOP to control your system. In this program you can plot step response, test movement, view Bode plots, monitor I/O, set filter parameters, and generally set the pertinent parameters.
- General software information from the manuals
- Insert pages for other KMotion.exe-related topics here
Configuration Topics
Channels, Channels, Channels what are they?
KMotionCNC Software Topics
KMotionCNC is Dynomotion's CNC program used as a graphical user interface to your KFLOP-enabled machine tool. KMotionCNC has all of the basic functionality you need to run a machine of up to 6 axes, in addition to spindle control.
- Insert pages for other KMotionCNC-related general topics here
Using KMotionCNC
- Homing discussion - page to be created
- Insert other KMotionCNC use pages here
Customize KMotionCNC
KMotionCNC is written as a Windows C++ MFC (Microsoft Foundation Classes) program developed in Visual Studio. Source code is provided and may be customized using Visual Studio. MFC Support is a requirement.
- General Information
- Compiling KMotionCNC
- The KMotionCNC's Visual Studio Project Solution (\PC VC Programs\KMotionCNC\KMotionCNC.sln) is currently written for Visual Studio 2008 Standard. This version can be used for the simplest compatibility. Projects can be upgraded to newer version of VS with minimal effort. Including Microsoft's Free Visual Studio 2013 Community. More info on PC Example Applications.
- KMotionCNC Customization Examples and Applications
- Links to examples of projects that explain KMotionCNC customizations
- Troy (tmday7) created some helpful documents listed on the Yahoo Group Files Section here.
- Links to examples of projects that explain KMotionCNC customizations
PC Example Applications
A number of PC Applications using the KMotion Libraries are available in the Software download. Visual Studio should be used to modify/compile the applications.
Currently the projects are compatible with VS 2008 Standard but later Versions can upgrade the projects and can be used including the free Microsoft Version of VS 2013 Community. In some cases MFC capability needs to be added as a separate download.
KFLOP C Programs
C Programs provide a powerful and flexible capability to perform almost any sequence of operations within KFLOP. In most cases after you have tested and tuned all your hardware using the KMotion.exe setup program all the settings and initialization steps required for your system can be placed into an Initialization C Program so that your system can be fully initialized simply by executing the Initialization program.
Dynomotion Hardware Topics
General Hardware Information
KFLOP Hardware Info
KStep Hardware Info
Kanalog Hardware Info
SnapAmp Hardware Info
Konnect Hardware Info
Wiring Diagrams
Basic Kanalog DAC and Encoder Connections 3 Axis
Basic Kanalog DAC and Encoder Connections 3 Axis #2
KFLOP+SnapAmp DC Brush Motors with MPG
KFLOP JP5 Open Collector Step/Dir Connections to Power Step PSD5042-2P Drives
Wiring Topics
Place links to pages on wiring inputs and outputs specific to your experiences and projects. Be descriptive with page titles and links.
MPG Wiring and Interface
MPGs (Manual Pulse Generators) should be connected directly to KFLOP for guaranteed real-time response (not USB based or connected to the PC). MPGs are handled by a C Program that monitors the MPG and creates motion based on the MPG Encoder changes and switch selections for axis, speed, and so forth. See the MPG C Program Examples. Here is a Discussion with other links.
https://groups.yahoo.com/neo/groups/DynoMotion/conversations/messages/12287
Axes Servo Tuning and Trajectory Planner
Velocity, Acceleration, and Jerk
The KMotionCNC parameters are used for 2nd order (infinite Jerk) coordinated motion paths. These are GCode G1,G2,G3 continuous paths. The units are in Inches (or in some cases degrees).
Tests to find optimal settings for both types of moves should be made using the Step Response Screen. The Step Response Screen always performs 3rd order motion but 2nd order motion can be simulated by temporarily setting the Jerk to a huge value (1000X the acceleration value). In general reducing the Jerk value will result in longer times to perform motions, but often the improved smoothness will permit higher maximum accelerations and velocities to be used resulting in overall shorter motion times.
Make sure when testing the size of move is long enough for full acceleration and velocity are achieved. As a common mistake is to have Acceleration or Velocity Settings set to too high for your system but when testing a short move there is no indication of a problem. The plot mode of Velocity Output vs Time can be helpful to verify full Velocity is being achieved.
Noisy GCode - Trajectory Planner Smoothing
Problems and Resolutions
General
- Dealing with noise on inputs. If you experience issues with inputs misreading, the issue may be noise. This page provides examples on what might be causing noise issues and examples of how to possibly deal with noise.
- Other
Software-Specific Problems and Resolutions
- Place links to pages explaining resolutions to problems that are largely software-related here
Hardware-Specific Problems and Resolutions
- Place links to pages explaining resolutions to problems that are largely hardware-related
Applications and Projects
- Place links to pages that explain how you accomplished your particular project. Write clear explanations that provide background on what you did and how you did it.
Tool Changer - router linear 4 Tools - C Program
#include "KMotionDef.h" #define TMP 10 // which spare persist to use to transfer data #include "..\..\KflopToKMotionCNCFunctions.c" //----------------------------------------- // LINEAR TOOL CHANGING //----------------------------------------- #define AXISX 0 #define AXISY 1 #define AXISZ 2 //---------Absolute position of tool holders #define HOLDER_X_1 100 #define HOLDER_X_2 200 #define HOLDER_X_3 300 #define HOLDER_X_4 400 #define HOLDER_Y 1300 #define HOLDER_Z -200 // absolute position of the tool height setting plate #define TOOL_HEIGHT_PLATE_X 50 #define TOOL_HEIGHT_PLATE_Y 50 // absolute position to move to that is permanently unobstructed, and safe to move down in Z #define TOOL_CHANGE_SAFE_POS_X 250 #define TOOL_CHANGE_SAFE_POS_Y 1200 #define AXIS_SAFE_DISTANCE_Y 100 // distance in mm to approach tool holder //--------- //--------- Spindle IO bits #define CLAW_EJECT 58 // IO bit to eject tool from spindle (KONNECT OUTPUT 10) #define SPINDLE_CLEAN 59 // IO bit to blow air out of spindle taper (KONNECT OUTPUT 11) #define CLAW_LOOSE 1048 // IO bit to sense whether the claw has ejected (KONNECT INPUT 24) #define TOOL_SENSE 1049 // IO bit to sense whether the a tool is in the spindle (KONNECT INPUT 24) //--------- #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-4 Tool Slot loaded into Spindle #define TOOL_DISK_FILE "c:\\Temp\\ToolChangerData.txt" #define CLAMP_TIME 1.0 // seconds to wait for the clamp/unclamp #define TOOL_HEIGHT_BIT 1055 //bit to read tool height plate (KONNECT INPUT 31) #define SAFE_HEIGHT_Z 100 // relative distance in mm to move to clear the top of the tool taper #define TOOL_RETRACT_SPEED_Z 5000 //speed in counts/second to move spindle up after tool has been ejected #define SlowSpeed 10.0 //mm/sec #define CNT_PER_MM_X 800.0 #define CNT_PER_MM_Y 800.0 #define CNT_PER_MM_Z 800.0 // 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 EjectTool(void); 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-4 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; SaveCurrentTool(ToolSlot); // save the one that has been loaded return 0; // success } // - Load new Tool (Spindle must be empty) int LoadNewTool(int Tool) { // - Move to position of requested tool // - Rapid move to absolute position of new tool only in X and Y if (MoveXY(ToolPositionX(Tool),HOLDER_Y,SlowSpeed)) return 1; // - Move to tool Z position at TOOL_RETRACT_SPEED_Z if (MoveZ(HOLDER_Z,SlowSpeed)) return 1; // - Engage new tool // - CLAW_EJECT and SPINDLE_CLEAN bits are currently high from tool removal operation // - Turn off CLAW_EJECT and SPINDLE_CLEAN bits to engage tool ClearBit(CLAW_EJECT); ClearBit(SPINDLE_CLEAN); // - Wait for time in seconds defined by CLAMP_TIME Delay_sec(CLAMP_TIME); // - Check to see if CLAW_LOOSE and TOOL_SENSE are high; if either are not, // something has gone wrong; halt everything and display message indicating failure // - Tool has been engaged if (!ReadBit(CLAW_LOOSE)) { printf("Claw Still Loose Error\n"); MsgBox("Claw Still Loose Error\n", MB_ICONHAND | MB_OK); return 1; } if (!ReadBit(TOOL_SENSE)) { printf("Tool Sense Error\n"); MsgBox("Tool Sense Error\n", MB_ICONHAND | MB_OK); return 1; } // - Leave tool holder by moving Y axis by the negative value of Y_AXIS_SAFE_DISTANCE // - Move to position of requested tool // - Rapid move to absolute position of new tool only in X and Y if (MoveXY(ToolPositionX(Tool),HOLDER_Y+AXIS_SAFE_DISTANCE_Y,SlowSpeed)) return 1; // - Rapid to Z home if (MoveZ(0.0,SlowSpeed)) return 1; return 0; //success } // - 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,SlowSpeed)) return 1; // - Rapid to TOOL_CHANGE_SAFE_POS to execute a safe negative Z move if (MoveXY(TOOL_CHANGE_SAFE_POS_X,TOOL_CHANGE_SAFE_POS_Y,SlowSpeed)) return 1; // - Approach tool holder by matching Z height of tool flange currently in spindle with tool holder claw if (MoveZ(HOLDER_Z,SlowSpeed)) return 1; // - After matching height above, approach tool holder by moving to holder X position if (MoveXY(ToolPositionX(CurrentTool),TOOL_CHANGE_SAFE_POS_Y,SlowSpeed)) return 1; // - After matching X position, match tool Y position if (MoveXY(ToolPositionX(CurrentTool),HOLDER_Y,SlowSpeed)) return 1; // - Move only in Y position until current position matches tool holder position (maybe disable X) axis?) // ??? // - Eject tool if (EjectTool()) return 1; return 0; //success } // - Eject tool int EjectTool(void) { // - Turn on CLAW_EJECT bit to remove tool from spindle SetBit(CLAW_EJECT); // - Turn on SPINDLE_CLEAN bit to remove any debris from taper and tools SetBit(SPINDLE_CLEAN); // - Wait for time in seconds defined by CLAMP_TIME Delay_sec(CLAMP_TIME); // - Read CLAW_LOOSE bit to see whether the tool is loose, to make a safe Z move without // destroying tool holder // - If CLAW_LOOSE bit is high, something has gone wrong; // halt everything and display message indicating failure if (ReadBit(CLAW_LOOSE)) { printf("Claw Loose Error\n"); MsgBox("Claw Loose Error\n", MB_ICONHAND | MB_OK); return 1; } // - Move Z axis up at speed defined by 'Z_TOOL_RETRACT_SPEED', to Z_SAFE_HEIGHT if (MoveZ(HOLDER_Z+SAFE_HEIGHT_Z,TOOL_RETRACT_SPEED_Z)) return 1; // - Read TOOL_SENSE bit to see whether the tool has been successfully ejected from the spindle // - If TOOL_SENSE bit is high, something has gone wrong; // halt everything and display message indicating failure if (ReadBit(TOOL_SENSE)) { printf("Tool Sense Release Error\n"); MsgBox("Tool Sense Release Error\n", MB_ICONHAND | MB_OK); return 1; } return 0; // success } //return x position of tool holder as a function of the tool float ToolPositionX(int tool) { return (HOLDER_X_2-HOLDER_X_1)*(tool-1) + HOLDER_X_1; } // 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]; 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 } // 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"); fprintf(f,"%d\n",tool); fclose(f); return 0; } // check if Current Tool number Valid // -1 = no tool loaded // 1-4 = valid tool BOOL ToolNumberValid(int tool) { return tool == -1 || (tool>=1 && tool<=4); } // 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_MM_X, Speed * CNT_PER_MM_X); MoveAtVel(AXISZ, y * CNT_PER_MM_Y, Speed * CNT_PER_MM_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_MM_Z, Speed * CNT_PER_MM_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 }