I recently tried to add some extra functionality to KmotionCNC, mostly around reporting some additional DROlabels on the screen to report what is happening in the KFLOP, and implementing a toolsetter program that is activated by setting a bit through a user button. Mostly it works fine, but once out of every 10 tries or so it will not report the text in a MsgBoxNoWait as it should, instead producing either an empty OK box or an OK box with about 20 garbage characters in it (empty one attached). The Z axis stays sitting on the toolsetter in this case, and pressing OK does not cause it to move upward like the following "MoveRel(ZAXIS,18514.67366); // move up from knife to 4.0 inches off table (underside of toolsetter)" command should do, and the subsequent dialog boxes are not presented.
Another behavior is that periodically KmotionCNC will also hang, unresponsive to the mouse/keyboard, but still updating the DRO fields from the KFLOP as normal (including a coolant flowmeter that varies in use, giving a source of live data), until I unplug and replug the USB cable, at which time it recovers and works like normal. Not sure if that is related? This one happens infrequently enough that I haven't been able to deduce a common event for it happening.
I have been defining the variables and memory like below, my understanding is that the VAR field is the link from KFLOP to KmotionCNC's buttons and the MEM is the address in the KFLOP memory to be sent to that button (correct?):
Code: Select all
#define FLOWVAR 90 // global persistant variable to store flowmeter rate
#define FLOWMEM 1000 //used to allocate memory to be passed to DROLabels (this number is the address in 32 bit space). Size is 1000000 8 byte doubles
//#define MAX_GATHER_DATA 1000000 // Size of gather buffer (number of doubles, 8 bytes each).
//extern double *gather_buffer; // Large buffer for data gathering, Bode plots, or User use
#define SPINDLETEMPVAR 91
#define SPINDLETEMPMEM 2000 //count of how many 32 bit words
#define XAXISTEMPVAR 92
#define XAXISTEMPMEM 3000
#define XAXISSLAVETEMPVAR 93
#define XAXISSLAVETEMPMEM 4000
#define YAXISTEMPVAR 94
#define YAXISTEMPMEM 5000
#define ZAXISTEMPVAR 95
#define ZAXISTEMPMEM 6000
#define COOLANTTEMPVAR 96
#define COOLANTTEMPMEM 7000
#define CABINETTEMPVAR 97
#define CABINETTEMPMEM 8000
#define INSTANTFEEDVELVAR 162
#define INSTANTFEEDVELMEM 9000
#define INSTANTFEEDVELBAR 163
#define SPINDLESPEEDVAR 164
#define SPINDLESPEEDMEM 10000
#define STATEVAR 98 // global persistant variable to store latest state (-1=CCW,0=off,1=CW)
#define SPEEDVAR 99 // global persistant variable to store latest speed
//variables from 100 to 107 are special (see dynomotion/Help/KMotionCNC/KMotionCNCCmdsFrKFLOP.htm )
#define TIMELEFTVAR 87
#define TIMELEFTMEM 11000
#define SMALLMSGVAR 88
#define SMALLMSGMEM 12000
#define MESSAGEVAR 89
#define MESSAGEMEM 13000
#define DRO_X1VEL_VAR 86
#define DRO_X1VEL_MEM 14000
#define DRO_X2VEL_VAR 85
#define DRO_X2VEL_MEM 15000
#define DRO_YVEL_VAR 84
#define DRO_YVEL_MEM 16000
#define DRO_ZVEL_VAR 83
Code: Select all
#include "KMotionDef.h"
#include "init_definitions.h"
//Set up to watch for toolsetter knife bit
//When knife seen, set tool Z position = height of toolsetter (nominally
//This program always gets started by software button in KmotionCNC
void ServiceToolsetter()
{
//measures 79.0mm when 1037 goes from high to low (using crummy calipers)
char text[1000];
int offer_reset = 0;
if (ReadBit(TOOLSETTER_ACTIVE)) { // don't trigger if not in toolsetting mode
//toolsetter bits active low
if(ReadBit(TOOLSET_OVERTRAVEL) && ReadBit(TOOLSET_KNIFE) && !ReadBit(FEEDHOLDBIT)){
//wait
if(ReadBit(GREEN_SW_BY_CABINET) || !ReadBit(GREEN_SW_FAR_SIDE)){ //far side reversed function
SetBit(1298);
if(!ReadBit(1299)){
Jog(ZAXIS,-500); // move down same speed as homing
SetBit(1299);
}
} else {
if(ReadBit(1298)){
ClearBit(1298);
ClearBit(1299);
Jog(ZAXIS,0.0); //StopMotion
}
}
} else {
ClearBit(1299);
Jog(ZAXIS,0.0); // StopMotion
printf("exiting toolsetter\n");
if(!ReadBit(TOOLSET_OVERTRAVEL)) {
SetBit(FEEDHOLDBIT); //also set in read buttons
printf("Toolsetter overtravel, feedhold set\n");
sprintf(text, "Toolsetter overtravel, feedhold set. Position %f\n", chan[ZAXIS].Position);
DROLabel(MESSAGEMEM,MESSAGEVAR,text); //KFLOP memory location, KMotionCNC variable (?), value
offer_reset = 0;
} else if(ReadBit(FEEDHOLDBIT)){
printf("Aborting toolsetter sequence due to external feedhold\n");
sprintf(text, "Aborting toolsetter sequence due to external feedhold. Position %f\n", chan[ZAXIS].Position);
DROLabel(MESSAGEMEM,MESSAGEVAR,text); //KFLOP memory location, KMotionCNC variable (?), value
offer_reset = 0;
} else if(!ReadBit(TOOLSET_KNIFE)) {
sprintf(text, "Toolsetting Complete. Position %f\nSet to 4.000 inches on DRO.\n", chan[ZAXIS].Position);
// 20807.68 counts/inches (79mm)
// trigger is 3.1102" above table 0" above table
MsgBoxNoWait(text,MB_OK);
MoveRel(ZAXIS,18514.67366); // move up from knife to 4.0 inches off table (underside of toolsetter)
//79mm = 3.110236"
//4" - 3.110236" = 0.889763"
//0.889763"*20807.68counts/in = 18513.93
MsgBoxNoWait("Move to 4.000 complete\n",MB_OK);
//ToolTableSet_am(); // adjust tool table
printf("Toolsetting Complete\nAdjust Z to 4.000 in");
DROLabel(MESSAGEMEM,MESSAGEVAR,"Toolsetting Complete\nAdjust Z to 4.000 in\n"); //KFLOP memory location, KMotionCNC variable (?), value
offer_reset = 1;
}
if (offer_reset == 0){
MsgBoxNoWait(text,MB_OK);
}
if (offer_reset == 1){
Answer = MsgBox("Set Z to 4.000in?\n",MB_YESNO|MB_ICONEXCLAMATION);
if (Answer == IDYES) {
printf("Answer is Yes, set Z to 4.000in\n");
DROLabel(MESSAGEMEM,MESSAGEVAR,"Answer is Yes, set Z to 4.000in\n"); //KFLOP memory location, KMotionCNC variable (?), value
DoPCFloat(PC_COMM_SET_Z, 4.0);
} else {
printf("Answer is No, do not reset\n");
DROLabel(MESSAGEMEM,MESSAGEVAR,"Answer is No, do not reset\n"); //KFLOP memory location, KMotionCNC variable (?), value
}
}
ClearBit(TOOLSETTER_ACTIVE);
}
}
}
Code: Select all
#include "KMotionDef.h" // This is the c library that KFLOP understands
#include "init_definitions.h" // this loads up the mapping of input/output channels and bits to names
#include "function_definitions.h" // load up all the definitions
#include "..\KflopToKMotionCNCFunctions.c"
#include "check_limit_switches.c" // Performs the proximity sensor limit checking
#include "init_x_motors.c" // performs initial motor configuration
#include "init_y_motor.c" // performs initial motor configuration
#include "init_z_motor.c" // performs initial motor configuration
#include "init_spindle.c" // performs initial spindle configuration
#include "startup_configuration.c" // sets all bits to appropriate startup configuration
#include "check_temperatures.c" // reads thermistors and acts on them
#include "read_external_buttons.c" // checks for any external buttons being pressed
#include "check_alarms.c" // checks for alarms
#include "safe_system.c" // performs actions to halt motion and ensure router is in a safe configuration
#include "enable_servos.c" // enables/disables servos halt bits and axes
#include "MPGServiceSmoothHardwareEncFilteredRev3_am.c" // MPG servicer
#include "ToolTableSet_am.c" //Tool setting after hitting toolsetter
#include "ServiceToolsetter.c"// Toolsetter servicer
#include "service_time_insensitive.c" // Flowmeter and other time-insensitive read tasks
#include "service_spindle.c" //Spindle speed and flow checks
#include "abs.c" //absolute value
#include "spindle_get_speed_from_adc.c" // turns spindle ADC counts to RPM
#include "update_velocity_DROs.c" //reads axis velocities and displays on screen
//#include "readout_status.c" // prints pertinant data to console and file on disk
//#include "pause_motion.c" // stops at a convenient point for routine tool changes, stock changes, etc, returns 1 when done
//#include "graceful_shutdown.c" // stops motion gracefully and readies system for power off, returns 1 when done
//#include "mpg_smoother_modified.c" // controls the MPG pendant
//uncomment when file exists enough to compile
// Load me into thread 7 so I can be large in kilobytes and keep running even if emergency stop called in SW
// This program runs to look for general machine state monitoring and can react to things like limit switches, external buttons, etc
// It should basically always be running to make sure it stops if a limit hits or such
// Special codes (eg, MPG control) run as separate programs called from either the CNC gui or from an external switch
// For the external switch case, it will kick off the program in another thread to run independently from this one
/* Dedicated M codes
M0 - Program Stop
M1 - Optional Program Stop
M2 - Program Stop, Rewind, Reset Interpreter Settings
M3 - Spindle On CW
M4 - Spindle On CCW
M5 - Spindle Off - Note Automatically called on Program Stop/Rewind
M6 - Tool Change (T variable is passed to the C program in the persist variable specified)
M7 - Mist On
M8 - Flood On
M9 - Mist and Flood Off
*/
/* basic structure of homing for reference:
if (!ReadBit(8)) // check for index mark
{
ch0->Position=0; // set current position to Zero
break;
}
*/
/* To do
Enable MPG controller to not move when job running (ie Kmotion CNC needs to set flag when jobs running)
Build program to check for servo output saturation and feedhold if so (so if one of the X axes loses itself stop entirely, other axes nice to have?)
Build program to home axes
Make notifications for when running into proximity sensor limits
Rename everything to test_control instead of TestControl
*/
float nexttime;
int servoAlarm = 0;
double T0 = 0; //used for the time-remaining computations
int stopping_state = -1;
main()
{
printf("Starting initialization tasks...\n");
nexttime = Time_sec()+DELTATIME; //for the time insensitive thread
// Configure all outputs appropriately
startup_configuration();
// Load up motor configurations
init_x_motors();
init_y_motor();
init_z_motor();
init_spindle();
enable_servos(0,1); // always disable servo inputs on startup
printf("Completed initialization tasks!\n");
DROLabel(MESSAGEMEM,MESSAGEVAR,"Completed initialization tasks!"); //KFLOP memory location, KMotionCNC variable (?), value
for(;;)
{
// Collect inputs
check_limit_switches(); // polls all proximity sensors and sends feedhold if found
read_external_buttons(); // looks for any external physical buttons being pressed
//check_alarms(); //doesn't do anything right now but looks to see if the DMMs still blip their alarm bits as they did previously before fixing grounding and adding RC filters
update_velocity_DROs();
//Service MPG
//ServiceMPG();
// Service spindle (check that commanded speed = actual speed to stop if bogged down
service_spindle();
// Check spindle flow rate and other time insensitive functions
nexttime = service_time_insensitive(nexttime);
//Service toolsetter
ServiceToolsetter();
// Perform actions
if (!ReadBit(MAINPOWERSTATUSBIT)) { // if don't see main power relay ...
if (!ReadBit(FEEDHOLDBIT)) { // ... and if this happened when we weren't in an intentional feedhold condition...
printf("Safe system from main power and feedhold!\n");
safe_system(); // ... perform emergency safing!
}
SetBit(FEEDHOLDBIT); // always feedhold
enable_servos(0,0); // ensure servos are disabled
servoAlarm = 0; // reset the servo alarm (servos power down with main power and reset)
}
// Start feedhold check
if(ReadBit(FEEDHOLDBIT)) { //if something set the feedhold bit
//StopCoordinatedMotion(); //perform the feedhold
//does hammering this every cycle do anything bad?
//Tests:
//stop coordinated motion G1 commands
//stop G0 commands
//stop long jog command
UpdateStoppingState(); // Update Stopping Status (only required for indep stopping)
if (stopping_state != CS0_StoppingState){
printf("CS0_StoppingState = %d\n",CS0_StoppingState);
}
stopping_state = CS0_StoppingState;
//extern int CS0_StoppingState; // emergency stop in progress, 0 = not stopping, 1=stopping coord motion, 2=stopping indep, 3=fully stopped, 4=ind stopped
if (CS0_StoppingState == 0) { //not stopping
StopCoordinatedMotion();
} else {
// motion is not coordinated e.g. G0 command or jog
//Jog(XAXIS,0);
//Jog(XAXISSLAVE,0);
//Jog(YAXIS,0);
//Jog(ZAXIS,0);
}
SetBit(FEEDHOLD_LAMP_SW); //turn on the feedhold lamp
}
if(!ReadBit(FEEDHOLDBIT)) {
ClearBit(FEEDHOLD_LAMP_SW); //turn off the feedhold lamp
}
// End feedhold check
// Look to see FETs are enabled and display "on" lamp if so
if(!ReadBit(X1MASTER_ENABLE) || !ReadBit(X2SLAVE_ENABLE) || !ReadBit(Z_ENABLE) || ReadBit(LEADSHINE_ENABLE)){ //if servos enabled
SetBit(SERVO_LAMP_SW); //turn on the programmable lamp
} else {
ClearBit(SERVO_LAMP_SW); //turn off the programmable lamp
}
// end servo enabled lamp
//Display time remaining for G-code
double TimeRemaining = CS0_TimeDownloaded - CS0_TimeExecuted - CS0_t;
char timeremainingtext[80];
if (TimeRemaining > 0.0) {// Print only with time remaining
sprintf(timeremainingtext,"%12.1f / %f",Time_sec() - T0, TimeRemaining);
//sprintf(timeremainingtext,"%12.6f\n\nTime Remaining = %12.1f\n",Time_sec() - T0, TimeRemaining);
} else {
T0 = Time_sec(); // Time stamp last time we weren't executing motion
}
DROLabel(TIMELEFTMEM,TIMELEFTVAR,timeremainingtext); //KFLOP memory location, KMotionCNC variable (?), value
// Finish perform actions
WaitNextTimeSlice();
}
return 0;
}
Andy