diff --git a/docs/src/config/python-interface.txt b/docs/src/config/python-interface.txt index e8b47d728e4..ec28f0a9d90 100644 --- a/docs/src/config/python-interface.txt +++ b/docs/src/config/python-interface.txt @@ -336,7 +336,9 @@ current XY rotation angle around Z axis. *settings*:: '(returns tuple of floats)' - current interpreter settings. settings[0] = -sequence number, settings[1] = feed rate, settings[2] = speed. +sequence number, settings[1] = feed rate, settings[2] = speed, +settings[3] = `G64 P` blend tolerance, +settings[4] = `G64 Q` naive CAM tolerance. *spindle*:: ' (returns tuple of dicts) ' - returns the current spindle status diff --git a/src/emc/motion/state_tag.h b/src/emc/motion/state_tag.h index 04fcf52a9cd..54b5f1e3264 100644 --- a/src/emc/motion/state_tag.h +++ b/src/emc/motion/state_tag.h @@ -62,7 +62,7 @@ typedef enum { /** - * Enum for various fields of state info that aren't binary. + * Enum for various fields of state info that are int type. * * WARNING: * @@ -87,6 +87,20 @@ typedef enum { GM_FIELD_MAX_FIELDS } StateField; + +/** + * Enum for indexing state tag `fields_float`, machine state float + * array: feed, speed, etc. + */ +typedef enum { + GM_FIELD_FLOAT_LINE_NUMBER, // eww + GM_FIELD_FLOAT_FEED, + GM_FIELD_FLOAT_SPEED, + GM_FIELD_FLOAT_PATH_TOLERANCE, + GM_FIELD_FLOAT_NAIVE_CAM_TOLERANCE, + GM_FIELD_FLOAT_MAX_FIELDS +} StateFieldFloat; + /** * Tag structure that is added to a motion segment so that motion has a copy of * the relevant interp state. @@ -99,9 +113,9 @@ typedef enum { */ struct state_tag_t { - // Machine settings - float feed; - float speed; + // Float-type machine settings: feed, speed, etc., indexed by the + // StateFieldFloat enum above + float fields_float[GM_FIELD_FLOAT_MAX_FIELDS]; // Any G / M code states that doesn't pack nicely into a single bit // These are an array mostly because it's easier to pass an diff --git a/src/emc/nml_intf/canon.hh b/src/emc/nml_intf/canon.hh index 2b745f38f4a..ea75c6e51aa 100644 --- a/src/emc/nml_intf/canon.hh +++ b/src/emc/nml_intf/canon.hh @@ -794,6 +794,9 @@ extern CANON_MOTION_MODE GET_EXTERNAL_MOTION_CONTROL_MODE(); // Returns the current motion path-following tolerance extern double GET_EXTERNAL_MOTION_CONTROL_TOLERANCE(); +// Returns the current motion naive CAM tolerance +extern double GET_EXTERNAL_MOTION_CONTROL_NAIVECAM_TOLERANCE(); + /* The interpreter is not using these six GET_EXTERNAL_ORIGIN functions // returns the current a-axis origin offset diff --git a/src/emc/rs274ngc/canonmodule.cc b/src/emc/rs274ngc/canonmodule.cc index 339b54ddb82..8598db1fbc0 100644 --- a/src/emc/rs274ngc/canonmodule.cc +++ b/src/emc/rs274ngc/canonmodule.cc @@ -136,6 +136,8 @@ BOOST_PYTHON_MODULE(emccanon) { def("GET_EXTERNAL_MOTION_CONTROL_MODE",&GET_EXTERNAL_MOTION_CONTROL_MODE); def("GET_EXTERNAL_MOTION_CONTROL_TOLERANCE",&GET_EXTERNAL_MOTION_CONTROL_TOLERANCE); def("SET_PARAMETER_FILE_NAME",&SET_PARAMETER_FILE_NAME); + def("GET_EXTERNAL_MOTION_CONTROL_NAIVECAM_TOLERANCE", + &GET_EXTERNAL_MOTION_CONTROL_NAIVECAM_TOLERANCE); def("GET_EXTERNAL_PARAMETER_FILE_NAME",&GET_EXTERNAL_PARAMETER_FILE_NAME); def("GET_EXTERNAL_PLANE",&GET_EXTERNAL_PLANE); def("GET_EXTERNAL_POCKETS_MAX",&GET_EXTERNAL_POCKETS_MAX); diff --git a/src/emc/rs274ngc/gcodemodule.cc b/src/emc/rs274ngc/gcodemodule.cc index 20d015bbac8..3d28d2801ff 100644 --- a/src/emc/rs274ngc/gcodemodule.cc +++ b/src/emc/rs274ngc/gcodemodule.cc @@ -498,6 +498,7 @@ void RIGID_TAP(int line_number, Py_XDECREF(result); } double GET_EXTERNAL_MOTION_CONTROL_TOLERANCE() { return 0.1; } +double GET_EXTERNAL_MOTION_CONTROL_NAIVECAM_TOLERANCE() { return 0.1; } double GET_EXTERNAL_PROBE_POSITION_X() { return _pos_x; } double GET_EXTERNAL_PROBE_POSITION_Y() { return _pos_y; } double GET_EXTERNAL_PROBE_POSITION_Z() { return _pos_z; } diff --git a/src/emc/rs274ngc/interp_base.hh b/src/emc/rs274ngc/interp_base.hh index 0587d78c827..82e0ce5a314 100644 --- a/src/emc/rs274ngc/interp_base.hh +++ b/src/emc/rs274ngc/interp_base.hh @@ -27,7 +27,7 @@ /* Size of certain arrays */ #define ACTIVE_G_CODES 17 #define ACTIVE_M_CODES 10 -#define ACTIVE_SETTINGS 3 +#define ACTIVE_SETTINGS 5 class InterpBase : boost::noncopyable { public: diff --git a/src/emc/rs274ngc/interp_convert.cc b/src/emc/rs274ngc/interp_convert.cc index b853339c30b..96cdedc75a1 100644 --- a/src/emc/rs274ngc/interp_convert.cc +++ b/src/emc/rs274ngc/interp_convert.cc @@ -1561,11 +1561,13 @@ already in force. */ -int Interp::convert_control_mode(int g_code, //!< g_code being executed (G_61, G61_1, || G_64) - double tolerance, //tolerance for the path following in G64 - double naivecam_tolerance, //tolerance for the naivecam - setup_pointer settings) //!< pointer to machine settings +int Interp::convert_control_mode( + int g_code, // g_code being executed (G_61, G61_1, G_64) + double tolerance_in, // tolerance for the path following in G64 + double naivecam_tolerance_in, // tolerance for the naivecam + setup_pointer settings) // pointer to machine settings { + double tolerance, naivecam_tolerance; CHKS((settings->cutter_comp_side), (_("Cannot change control mode with cutter radius compensation on"))); if (g_code == G_61) { @@ -1575,19 +1577,24 @@ int Interp::convert_control_mode(int g_code, //!< g_code being executed (G_6 SET_MOTION_CONTROL_MODE(CANON_EXACT_STOP, 0); settings->control_mode = CANON_EXACT_STOP; } else if (g_code == G_64) { - if (tolerance >= 0) { - SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, tolerance); - } else { - SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0); - } - if (naivecam_tolerance >= 0) { - SET_NAIVECAM_TOLERANCE(naivecam_tolerance); - } else if (tolerance >= 0) { - SET_NAIVECAM_TOLERANCE(tolerance); // if no naivecam_tolerance specified use same for both - } else { - SET_NAIVECAM_TOLERANCE(0); - } - settings->control_mode = CANON_CONTINUOUS; + if (tolerance_in >= 0) + tolerance = tolerance_in; + else + tolerance = 0; + settings->control_mode = CANON_CONTINUOUS; + settings->tolerance = tolerance; + SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, tolerance); + + if (naivecam_tolerance_in >= 0) + naivecam_tolerance = naivecam_tolerance_in; + else if (tolerance_in >= 0) + // if no naivecam_tolerance specified use same for both + naivecam_tolerance = tolerance_in; + else + naivecam_tolerance = 0; + settings->naivecam_tolerance = naivecam_tolerance; + SET_NAIVECAM_TOLERANCE(naivecam_tolerance); + } else ERS(NCE_BUG_CODE_NOT_G61_G61_1_OR_G64); return INTERP_OK; @@ -2708,43 +2715,48 @@ int Interp::convert_length_units(int g_code, //!< g_code being executed (mus /* - * given two double arrays representing interpreter settings as stored in - * _setup.active_settings, construct a G-code sequence to synchronize their state. + * given two int arrays and two double arrays representing interpreter + * settings as stored in _setup.active_g_codes and + * _setup.active_settings, construct a G-code sequence to synchronize + * their state. */ -int Interp::gen_settings(double *current, double *saved, std::string &cmd) +int Interp::gen_settings( + int *int_current, int *int_saved, // G codes + double *float_current, double *float_saved, // S, F, other + std::string &cmd) // command buffer { - int i; + int i, val; + int g64_changed = 0; char buf[LINELEN]; + + // F, S for (i = 0; i < ACTIVE_SETTINGS; i++) { - if (saved[i] != current[i]) { + if (float_saved[i] != float_current[i]) { switch (i) { - case 0: break; // sequence_number - no point in restoring - case 1: - snprintf(buf,sizeof(buf)," F%.1f", saved[i]); + case GM_FIELD_FLOAT_LINE_NUMBER: + // sequence_number - no point in restoring + break; + case GM_FIELD_FLOAT_FEED: + snprintf(buf,sizeof(buf)," F%.1f", float_saved[i]); cmd += buf; break; - case 2: - snprintf(buf,sizeof(buf)," S%.0f", saved[i]); + case GM_FIELD_FLOAT_SPEED: + snprintf(buf,sizeof(buf)," S%.0f", float_saved[i]); cmd += buf; break; + case GM_FIELD_FLOAT_PATH_TOLERANCE: + case GM_FIELD_FLOAT_NAIVE_CAM_TOLERANCE: + // G64 special case; see below + g64_changed = 1; + break; } } } - return INTERP_OK; -} - -/* - * given two int arrays representing interpreter settings as stored in - * _setup.active_g_codes, construct a G-code sequence to synchronize their state. - */ -int Interp::gen_g_codes(int *current, int *saved, std::string &cmd) -{ - int i, val; - char buf[LINELEN]; + // G codes for (i = 0; i < ACTIVE_G_CODES; i++) { - val = saved[i]; - if (val != current[i]) { + val = int_saved[i]; + if (val != int_current[i]) { switch (i) { case 0: @@ -2768,7 +2780,6 @@ int Interp::gen_g_codes(int *current, int *saved, std::string &cmd) case 8: // - coordinate system case 9: // - tool offset (G43/G49) case 10: // - retract mode - case 11: // - control mode case 13: // - spindle mode case 14: // - ijk distance mode case 15: // - lathe diameter mode @@ -2785,12 +2796,50 @@ int Interp::gen_g_codes(int *current, int *saved, std::string &cmd) cmd += buf; } else { // so complain rather loudly - MSG("------ gen_g_codes BUG: index %d = -1!!\n",i); + MSG("------ gen_settings BUG: index %d = -1!!\n",i); } break; + case 11: // - control mode + // Special case, since G64 requires P and Q flags + // FIXME what about when P or Q changes, even though still G64? + if (val == G_64) + // G64 special case; see below + g64_changed = 1; + else if (val == G_61) { + snprintf(buf,sizeof(buf)," G61"); + cmd += buf; + } else if (val == G_61_1) { + snprintf(buf,sizeof(buf)," G61.1"); + cmd += buf; + } else + MSG("------ gen_settings BUG: index %d = -1!!\n",i); + break; } } } + + + // Special case for restoring G64: `cmd` may contain a `G64` if + // current int settings is `G61` or if current float settings + // contain different `G64 P* Q*` args; in these cases, only add a + // single `G64` command + if ((int_saved[11] == G_64) && g64_changed) { + if (float_saved[GM_FIELD_FLOAT_PATH_TOLERANCE] < 0) + // No P, Q args + snprintf(buf,sizeof(buf)," G64"); + else if ( + float_saved[GM_FIELD_FLOAT_NAIVE_CAM_TOLERANCE] < 0) + // Only P arg + snprintf(buf,sizeof(buf)," G64 P%f", + float_saved[GM_FIELD_FLOAT_PATH_TOLERANCE]); + else // Both P, Q args + snprintf( + buf,sizeof(buf)," G64 P%f Q%f", + float_saved[GM_FIELD_FLOAT_PATH_TOLERANCE], + float_saved[GM_FIELD_FLOAT_NAIVE_CAM_TOLERANCE]); + cmd += buf; + } + return INTERP_OK; } @@ -2852,12 +2901,14 @@ int Interp::gen_restore_cmd(int *current_g, StateTag const &saved, std::string &cmd) { + int res; // A local copy of the saved settings, unpacked from a state tag int saved_g[ACTIVE_G_CODES]; int saved_m[ACTIVE_M_CODES]; double saved_settings[ACTIVE_SETTINGS]; //Extract saved state to local vectors + // FIXME Use saved_settings to store state tag floats, incl. in int res_unpack = active_modes(saved_g, saved_m, saved_settings, saved); if (res_unpack != INTERP_OK) { logStateTags("gen_restore_cmd() error %d: failed to unpack state tag", @@ -2880,17 +2931,14 @@ int Interp::gen_restore_cmd(int *current_g, cmd.c_str()); } - int res_settings = gen_settings(current_settings, saved_settings, cmd); - //M codes should not be restored during an abort - int res_m = 0; - int res_g = gen_g_codes(current_g, saved_g, cmd); - - if (res_settings || res_m || res_g) { - logStateTags("gen_restore_cmd(): error restoring " - "settings (%d) or G codes (%d)", - res_settings, res_g); + if ((res = gen_settings( + current_g, saved_g, current_settings, saved_settings, cmd))) { + logStateTags("gen_restore_cmd(): error restoring settings (%d)", + res); return INTERP_ERROR; } + // M codes should not be restored during an abort with gen_m_codes() + return INTERP_OK; } @@ -2952,9 +3000,16 @@ int Interp::restore_settings(setup_pointer settings, snprintf(buf,sizeof(buf), "G%d",settings->sub_context[from_level].saved_g_codes[5]/10); CHKS(execute(buf) != INTERP_OK, _("M7x: restore_settings G20/G21 failed: '%s'"), cmd.c_str()); } - gen_settings((double *)settings->active_settings, (double *)settings->sub_context[from_level].saved_settings,cmd); - gen_m_codes((int *) settings->active_m_codes, (int *)settings->sub_context[from_level].saved_m_codes,cmd); - gen_g_codes((int *)settings->active_g_codes, (int *)settings->sub_context[from_level].saved_g_codes,cmd); + gen_settings( + (int *)settings->active_g_codes, + (int *)settings->sub_context[from_level].saved_g_codes, + (double *)settings->active_settings, + (double *)settings->sub_context[from_level].saved_settings, + cmd); + gen_m_codes( + (int *) settings->active_m_codes, + (int *)settings->sub_context[from_level].saved_m_codes, + cmd); if (!cmd.empty()) { // the sequence can be multiline, separated by nl diff --git a/src/emc/rs274ngc/interp_internal.hh b/src/emc/rs274ngc/interp_internal.hh index a80675c3e12..feecc598bf7 100644 --- a/src/emc/rs274ngc/interp_internal.hh +++ b/src/emc/rs274ngc/interp_internal.hh @@ -681,6 +681,8 @@ struct setup char blocktext[LINELEN]; // linetext downcased, white space gone CANON_MOTION_MODE control_mode; // exact path or cutting mode + double tolerance; // G64 blending tolerance + double naivecam_tolerance; // G64 naive cam tolerance int current_pocket; // carousel slot number of current tool double current_x; // current X-axis position double current_y; // current Y-axis position diff --git a/src/emc/rs274ngc/interp_write.cc b/src/emc/rs274ngc/interp_write.cc index 6a5fe278f0e..aad7911c170 100644 --- a/src/emc/rs274ngc/interp_write.cc +++ b/src/emc/rs274ngc/interp_write.cc @@ -114,6 +114,7 @@ int Interp::write_g_codes(block_pointer block, //!< pointer to a block of RS27 settings->tool_offset.a || settings->tool_offset.b || settings->tool_offset.c || settings->tool_offset.u || settings->tool_offset.v || settings->tool_offset.w) ? G_43 : G_49; gez[10] = (settings->retract_mode == OLD_Z) ? G_98 : G_99; + // Three modes: G_64, G_61, G_61_1 or CANON_CONTINUOUS/EXACT_PATH/EXACT_STOP gez[11] = (settings->control_mode == CANON_CONTINUOUS) ? G_64 : (settings->control_mode == CANON_EXACT_PATH) ? G_61 : G_61_1; @@ -197,9 +198,11 @@ int Interp::write_settings(setup_pointer settings) //!< pointer to machine double *vals; vals = settings->active_settings; - vals[0] = settings->sequence_number; /* 0 sequence number */ - vals[1] = settings->feed_rate; /* 1 feed rate */ - vals[2] = settings->speed[0]; /* 2 spindle speed */ + vals[0] = settings->sequence_number; /* 0 sequence number */ + vals[1] = settings->feed_rate; /* 1 feed rate */ + vals[2] = settings->speed; /* 2 spindle speed */ + vals[3] = settings->tolerance; /* 3 blend tolerance */ + vals[4] = settings->naivecam_tolerance; /* 4 naive CAM tolerance */ return INTERP_OK; } @@ -279,10 +282,16 @@ int Interp::write_state_tag(block_pointer block, settings->tool_offset.w); state.flags[GM_FLAG_RETRACT_OLDZ] = (settings->retract_mode == OLD_Z); + state.flags[GM_FLAG_BLEND] = (settings->control_mode == CANON_CONTINUOUS); state.flags[GM_FLAG_EXACT_STOP] = (settings->control_mode == CANON_EXACT_STOP); + state.fields_float[GM_FIELD_FLOAT_PATH_TOLERANCE] = + settings->tolerance; + state.fields_float[GM_FIELD_FLOAT_NAIVE_CAM_TOLERANCE] = + settings->naivecam_tolerance; + state.flags[GM_FLAG_CSS_MODE] = (settings->spindle_mode == CONSTANT_RPM); state.flags[GM_FLAG_IJK_ABS] = @@ -312,8 +321,8 @@ int Interp::write_state_tag(block_pointer block, state.flags[GM_FLAG_FEED_HOLD] = (settings->feed_hold); - state.feed = settings->feed_rate; /* 1 feed rate */ - state.speed = settings->speed; /* 2 spindle speed */ + state.fields_float[GM_FIELD_FLOAT_FEED] = settings->feed_rate; + state.fields_float[GM_FIELD_FLOAT_SPEED] = settings->speed; return 0; } diff --git a/src/emc/rs274ngc/modal_state.cc b/src/emc/rs274ngc/modal_state.cc index 012dc6d1ba7..d90e6cb703f 100644 --- a/src/emc/rs274ngc/modal_state.cc +++ b/src/emc/rs274ngc/modal_state.cc @@ -27,8 +27,7 @@ StateTag::StateTag(): flags(0) { memset(fields,-1,sizeof(fields)); packed_flags = 0; - feed = 0.0; - speed = 0.0; + memset(fields_float,-1,sizeof(fields_float)); } StateTag::StateTag(struct state_tag_t const & basetag): diff --git a/src/emc/rs274ngc/rs274ngc_interp.hh b/src/emc/rs274ngc/rs274ngc_interp.hh index b19b4783b3a..00c37002734 100644 --- a/src/emc/rs274ngc/rs274ngc_interp.hh +++ b/src/emc/rs274ngc/rs274ngc_interp.hh @@ -471,8 +471,10 @@ int read_dollar(char *line, int *counter, block_pointer block, int save_settings(setup_pointer settings); int restore_settings(setup_pointer settings, int from_level); int restore_from_tag(StateTag const &tag); - int gen_settings(double *current, double *saved, std::string &cmd); - int gen_g_codes(int *current, int *saved, std::string &cmd); + int gen_settings( + int *int_current, int *int_saved, + double *float_current, double *float_saved, + std::string &cmd); int gen_m_codes(int *current, int *saved, std::string &cmd); int gen_restore_cmd(int *current_g, int *current_m, diff --git a/src/emc/rs274ngc/rs274ngc_pre.cc b/src/emc/rs274ngc/rs274ngc_pre.cc index 2cf3f46ad99..2403dc9d06a 100644 --- a/src/emc/rs274ngc/rs274ngc_pre.cc +++ b/src/emc/rs274ngc/rs274ngc_pre.cc @@ -2022,6 +2022,9 @@ int Interp::synch() _setup.current_x = GET_EXTERNAL_POSITION_X(); _setup.current_y = GET_EXTERNAL_POSITION_Y(); _setup.current_z = GET_EXTERNAL_POSITION_Z(); + _setup.control_mode = GET_EXTERNAL_MOTION_CONTROL_MODE(); + _setup.tolerance = GET_EXTERNAL_MOTION_CONTROL_TOLERANCE(); + _setup.naivecam_tolerance = GET_EXTERNAL_MOTION_CONTROL_NAIVECAM_TOLERANCE(); _setup.AA_current = GET_EXTERNAL_POSITION_A(); _setup.BB_current = GET_EXTERNAL_POSITION_B(); _setup.CC_current = GET_EXTERNAL_POSITION_C(); @@ -2156,6 +2159,8 @@ int Interp::active_modes(int *g_codes, double *settings, StateTag const &tag) { + int i; + // Pre-checks on fields if (!tag.is_valid()) { return INTERP_ERROR; @@ -2213,9 +2218,13 @@ int Interp::active_modes(int *g_codes, tag.flags[GM_FLAG_FEED_HOLD] ? 53 : -1; + // Copy float-type state + for (i=0; inextId = 0; tp->execId = 0; - struct state_tag_t tag = {0}; + struct state_tag_t tag = {{0}}; tp->execTag = tag; tp->motionType = 0; tp->termCond = TC_TERM_COND_PARABOLIC; @@ -533,7 +533,7 @@ int tpGetExecId(TP_STRUCT * const tp) struct state_tag_t tpGetExecTag(TP_STRUCT * const tp) { if (0 == tp) { - struct state_tag_t empty = {0}; + struct state_tag_t empty = {{0}}; return empty; } diff --git a/src/emc/usr_intf/axis/extensions/emcmodule.cc b/src/emc/usr_intf/axis/extensions/emcmodule.cc index ead051e8a86..c12f42d31cc 100644 --- a/src/emc/usr_intf/axis/extensions/emcmodule.cc +++ b/src/emc/usr_intf/axis/extensions/emcmodule.cc @@ -716,7 +716,7 @@ static PyGetSetDef Stat_getsetlist[] = { {(char*)"probed_position", (getter)Stat_probed}, {(char*)"settings", (getter)Stat_activesettings, (setter)NULL, (char*)"This is an array containing the Interp active settings: sequence number,\n" - "feed rate, and spindle speed." + "feed rate, spindle speed, and G64 blend and naive CAM tolerances." }, {(char*)"tool_offset", (getter)Stat_tool_offset}, {(char*)"tool_table", (getter)Stat_tool_table, (setter)NULL, diff --git a/tests/interp/compile/use-rs274.cc b/tests/interp/compile/use-rs274.cc index 5f3f8cfa826..5968bed1333 100644 --- a/tests/interp/compile/use-rs274.cc +++ b/tests/interp/compile/use-rs274.cc @@ -197,6 +197,7 @@ CANON_MOTION_MODE GET_EXTERNAL_MOTION_CONTROL_MODE() {} double GET_EXTERNAL_MOTION_CONTROL_TOLERANCE() {} extern void SET_PARAMETER_FILE_NAME(const char *name) {} +double GET_EXTERNAL_MOTION_CONTROL_NAIVECAM_TOLERANCE() {} void GET_EXTERNAL_PARAMETER_FILE_NAME(char *filename, int max_size) { snprintf(filename, max_size, "%s", "rs274ngc.var"); } diff --git a/tests/startup-state/test-ui.py b/tests/startup-state/test-ui.py index 18cd675fffa..ed7aa0136d2 100755 --- a/tests/startup-state/test-ui.py +++ b/tests/startup-state/test-ui.py @@ -310,6 +310,7 @@ def assert_axis_initialized(axis): assert(s.spindle[0]['override_enabled'] == True) assert(s.spindle[0]['speed'] == 0.0) assert(s.spindle[0]['override'] == 1.0) + assert(s.state == linuxcnc.STATE_ESTOP) assert(s.task_mode == linuxcnc.MODE_MANUAL)