From: Joseph Coffland Date: Wed, 6 Jul 2016 11:42:52 +0000 (-0700) Subject: Clean up X-Git-Url: https://git.buildbotics.com/?a=commitdiff_plain;h=5a93198f6ad1538a51b71e42649907ddde366e04;p=bbctrl-firmware Clean up --- diff --git a/src/axes.c b/src/axes.c index 93684d1..fb727ba 100644 --- a/src/axes.c +++ b/src/axes.c @@ -26,7 +26,7 @@ \******************************************************************************/ -#include "canonical_machine.h" +#include "machine.h" uint8_t get_axis_mode(int axis) { diff --git a/src/canonical_machine.c b/src/canonical_machine.c deleted file mode 100644 index 9f06ac8..0000000 --- a/src/canonical_machine.c +++ /dev/null @@ -1,1289 +0,0 @@ -/******************************************************************************\ - - This file is part of the Buildbotics firmware. - - Copyright (c) 2015 - 2016 Buildbotics LLC - Copyright (c) 2010 - 2015 Alden S. Hart, Jr. - Copyright (c) 2012 - 2015 Rob Giseburt - All rights reserved. - - This file ("the software") is free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License, - version 2 as published by the Free Software Foundation. You should - have received a copy of the GNU General Public License, version 2 - along with the software. If not, see . - - The software is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the software. If not, see - . - - For information regarding this software email: - "Joseph Coffland" - -\******************************************************************************/ - -/* This code is a loose implementation of Kramer, Proctor and Messina's - * canonical machining functions as described in the NIST RS274/NGC v3 - * - * The canonical machine is the layer between the Gcode parser and - * the motion control code for a specific robot. It keeps state and - * executes commands - passing the stateless commands to the motion - * planning layer. - * - * Synchronizing command execution - * - * "Synchronous commands" are commands that affect the runtime need - * to be synchronized with movement. Examples include G4 dwells, - * program stops and ends, and most M commands. These are queued - * into the planner queue and execute from the queue. Synchronous - * commands work like this: - * - * - Call the cm_xxx_xxx() function which will do any input - * validation and return an error if it detects one. - * - * - The cm_ function calls mp_queue_command(). Arguments are a - * callback to the _exec_...() function, which is the runtime - * execution routine, and any arguments that are needed by the - * runtime. See typedef for *exec in planner.h for details - * - * - mp_queue_command() stores the callback and the args in a - planner buffer. - * - * - When planner execution reaches the buffer it executes the - * callback w/ the args. Take careful note that the callback - * executes under an interrupt, so beware of variables that may - * need to be volatile. - * - * Note: - The synchronous command execution mechanism uses 2 - * vectors in the bf buffer to store and return values for the - * callback. It's obvious, but impractical to pass the entire bf - * buffer to the callback as some of these commands are actually - * executed locally and have no buffer. - */ - -#include "canonical_machine.h" - -#include "config.h" -#include "stepper.h" -#include "spindle.h" -#include "coolant.h" -#include "switch.h" -#include "hardware.h" -#include "util.h" -#include "usart.h" // for serial queue flush -#include "estop.h" - -#include "plan/planner.h" -#include "plan/buffer.h" -#include "plan/feedhold.h" -#include "plan/dwell.h" -#include "plan/command.h" -#include "plan/arc.h" -#include "plan/line.h" - -#include -#include -#include -#include - - -cmSingleton_t cm = { - // Offsets - .offset = { - {}, // ABSOLUTE_COORDS - - {0, 0, 0, 0, 0, 0}, // G54 - {X_TRAVEL_MAX / 2, Y_TRAVEL_MAX / 2, 0, 0, 0, 0}, // G55 - {0, 0, 0, 0, 0, 0}, // G56 - {0, 0, 0, 0, 0, 0}, // G57 - {0, 0, 0, 0, 0, 0}, // G58 - {0, 0, 0, 0, 0, 0}, // G59 - }, - - // Axes - .a = { - { - .axis_mode = X_AXIS_MODE, - .velocity_max = X_VELOCITY_MAX, - .feedrate_max = X_FEEDRATE_MAX, - .travel_min = X_TRAVEL_MIN, - .travel_max = X_TRAVEL_MAX, - .jerk_max = X_JERK_MAX, - .jerk_homing = X_JERK_HOMING, - .junction_dev = X_JUNCTION_DEVIATION, - .search_velocity = X_SEARCH_VELOCITY, - .latch_velocity = X_LATCH_VELOCITY, - .latch_backoff = X_LATCH_BACKOFF, - .zero_backoff = X_ZERO_BACKOFF, - }, { - .axis_mode = Y_AXIS_MODE, - .velocity_max = Y_VELOCITY_MAX, - .feedrate_max = Y_FEEDRATE_MAX, - .travel_min = Y_TRAVEL_MIN, - .travel_max = Y_TRAVEL_MAX, - .jerk_max = Y_JERK_MAX, - .jerk_homing = Y_JERK_HOMING, - .junction_dev = Y_JUNCTION_DEVIATION, - .search_velocity = Y_SEARCH_VELOCITY, - .latch_velocity = Y_LATCH_VELOCITY, - .latch_backoff = Y_LATCH_BACKOFF, - .zero_backoff = Y_ZERO_BACKOFF, - }, { - .axis_mode = Z_AXIS_MODE, - .velocity_max = Z_VELOCITY_MAX, - .feedrate_max = Z_FEEDRATE_MAX, - .travel_min = Z_TRAVEL_MIN, - .travel_max = Z_TRAVEL_MAX, - .jerk_max = Z_JERK_MAX, - .jerk_homing = Z_JERK_HOMING, - .junction_dev = Z_JUNCTION_DEVIATION, - .search_velocity = Z_SEARCH_VELOCITY, - .latch_velocity = Z_LATCH_VELOCITY, - .latch_backoff = Z_LATCH_BACKOFF, - .zero_backoff = Z_ZERO_BACKOFF, - }, { - .axis_mode = A_AXIS_MODE, - .velocity_max = A_VELOCITY_MAX, - .feedrate_max = A_FEEDRATE_MAX, - .travel_min = A_TRAVEL_MIN, - .travel_max = A_TRAVEL_MAX, - .jerk_max = A_JERK_MAX, - .jerk_homing = A_JERK_HOMING, - .junction_dev = A_JUNCTION_DEVIATION, - .radius = A_RADIUS, - .search_velocity = A_SEARCH_VELOCITY, - .latch_velocity = A_LATCH_VELOCITY, - .latch_backoff = A_LATCH_BACKOFF, - .zero_backoff = A_ZERO_BACKOFF, - }, { - .axis_mode = B_AXIS_MODE, - .velocity_max = B_VELOCITY_MAX, - .feedrate_max = B_FEEDRATE_MAX, - .travel_min = B_TRAVEL_MIN, - .travel_max = B_TRAVEL_MAX, - .jerk_max = B_JERK_MAX, - .junction_dev = B_JUNCTION_DEVIATION, - .radius = B_RADIUS, - }, { - .axis_mode = C_AXIS_MODE, - .velocity_max = C_VELOCITY_MAX, - .feedrate_max = C_FEEDRATE_MAX, - .travel_min = C_TRAVEL_MIN, - .travel_max = C_TRAVEL_MAX, - .jerk_max = C_JERK_MAX, - .junction_dev = C_JUNCTION_DEVIATION, - .radius = C_RADIUS, - } - }, - - .combined_state = COMBINED_READY, - .machine_state = MACHINE_READY, - - // State - .gm = {.motion_mode = MOTION_MODE_CANCEL_MOTION_MODE}, - .gn = {0}, - .gf = {0}, -}; - - -// Command execution callbacks from planner queue -static void _exec_offset(float *value, float *flag); -static void _exec_change_tool(float *value, float *flag); -static void _exec_select_tool(float *value, float *flag); -static void _exec_mist_coolant_control(float *value, float *flag); -static void _exec_flood_coolant_control(float *value, float *flag); -static void _exec_absolute_origin(float *value, float *flag); -static void _exec_program_finalize(float *value, float *flag); - -// Canonical Machine State functions - -/// Combines raw states into something a user might want to see -cmCombinedState_t cm_get_combined_state() { - if (cm.cycle_state == CYCLE_OFF) cm.combined_state = cm.machine_state; - else if (cm.cycle_state == CYCLE_PROBE) cm.combined_state = COMBINED_PROBE; - else if (cm.cycle_state == CYCLE_HOMING) cm.combined_state = COMBINED_HOMING; - else { - if (cm.motion_state == MOTION_RUN) cm.combined_state = COMBINED_RUN; - if (cm.motion_state == MOTION_HOLD) cm.combined_state = COMBINED_HOLD; - } - - if (cm.machine_state == MACHINE_SHUTDOWN) - cm.combined_state = COMBINED_SHUTDOWN; - - return cm.combined_state; -} - -uint32_t cm_get_line() {return cm.gm.line;} -cmMachineState_t cm_get_machine_state() {return cm.machine_state;} -cmCycleState_t cm_get_cycle_state() {return cm.cycle_state;} -cmMotionState_t cm_get_motion_state() {return cm.motion_state;} -cmFeedholdState_t cm_get_hold_state() {return cm.hold_state;} -cmHomingState_t cm_get_homing_state() {return cm.homing_state;} -cmMotionMode_t cm_get_motion_mode() {return cm.gm.motion_mode;} -cmCoordSystem_t cm_get_coord_system() {return cm.gm.coord_system;} -cmUnitsMode_t cm_get_units_mode() {return cm.gm.units_mode;} -cmCanonicalPlane_t cm_get_select_plane() {return cm.gm.select_plane;} -cmPathControlMode_t cm_get_path_control() {return cm.gm.path_control;} -cmDistanceMode_t cm_get_distance_mode() {return cm.gm.distance_mode;} -cmFeedRateMode_t cm_get_feed_rate_mode() {return cm.gm.feed_rate_mode;} -uint8_t cm_get_tool() {return cm.gm.tool;} -cmSpindleMode_t cm_get_spindle_mode() {return cm.gm.spindle_mode;} -bool cm_get_runtime_busy() {return mp_get_runtime_busy();} -float cm_get_feed_rate() {return cm.gm.feed_rate;} - - -void cm_set_machine_state(cmMachineState_t machine_state) { - cm.machine_state = machine_state; -} - - -void cm_set_motion_state(cmMotionState_t motion_state) { - cm.motion_state = motion_state; -} - - -void cm_set_motion_mode(cmMotionMode_t motion_mode) { - cm.gm.motion_mode = motion_mode; -} - - -void cm_set_spindle_mode(cmSpindleMode_t spindle_mode) { - cm.gm.spindle_mode = spindle_mode; -} - - -void cm_set_spindle_speed_parameter(float speed) {cm.gm.spindle_speed = speed;} -void cm_set_tool_number(uint8_t tool) {cm.gm.tool = tool;} - - -void cm_set_absolute_override(bool absolute_override) { - cm.gm.absolute_override = absolute_override; - // must reset offsets if you change absolute override - cm_set_work_offsets(); -} - - -void cm_set_model_line(uint32_t line) {cm.gm.line = line;} - - -/* Jerk functions - * - * Jerk values can be rather large, often in the billions. This makes - * for some pretty big numbers for people to deal with. Jerk values - * are stored in the system in truncated format; values are divided by - * 1,000,000 then reconstituted before use. - * - * The axis_jerk() functions expect the jerk in divided-by 1,000,000 form - */ - -/// returns jerk for an axis -float cm_get_axis_jerk(uint8_t axis) { - return cm.a[axis].jerk_max; -} - - -/// sets the jerk for an axis, including recirpcal and cached values -void cm_set_axis_jerk(uint8_t axis, float jerk) { - cm.a[axis].jerk_max = jerk; - cm.a[axis].recip_jerk = 1 / (jerk * JERK_MULTIPLIER); -} - - -/* Coordinate systems and offsets - * - * Functions to get, set and report coordinate systems and work offsets - * These functions are not part of the NIST defined functions - */ -/* - * Notes on Coordinate System and Offset functions - * - * All positional information in the canonical machine is kept as - * absolute coords and in canonical units (mm). The offsets are only - * used to translate in and out of canonical form during - * interpretation and response. - * - * Managing the coordinate systems & offsets is somewhat complicated. - * The following affect offsets: - * - coordinate system selected. 1-9 correspond to G54-G59 - * - absolute override: forces current move to be interpreted in machine - * coordinates: G53 (system 0) - * - G92 offsets are added "on top of" the coord system offsets -- - * if origin_offset_enable - * - G28 and G30 moves; these are run in absolute coordinates - * - * The offsets themselves are considered static, are kept in cm, and are - * supposed to be persistent. - * - * To reduce complexity and data load the following is done: - * - Full data for coordinates/offsets is only accessible by the canonical - * machine, not the downstream - * - Resolved set of coord and G92 offsets, with per-move exceptions can - * be captured as "work_offsets" - * - The core gcode context (gm) only knows about the active coord system - * and the work offsets - */ - -/* Return the currently active coordinate offset for an axis - * - * Takes G5x, G92 and absolute override into account to return the - * active offset for this move - * - * This function is typically used to evaluate and set offsets, as - * opposed to cm_get_work_offset() which merely returns what's in the - * work_offset[] array. - */ -float cm_get_active_coord_offset(uint8_t axis) { - if (cm.gm.absolute_override) return 0; // no offset in absolute override mode - float offset = cm.offset[cm.gm.coord_system][axis]; - - if (cm.origin_offset_enable) - offset += cm.origin_offset[axis]; // includes G5x and G92 components - - return offset; -} - - -/// Return a coord offset -float cm_get_work_offset(uint8_t axis) { - return cm.ms.work_offset[axis]; -} - - -// Capture coord offsets from the model into absolute values -void cm_set_work_offsets() { - for (int axis = 0; axis < AXES; axis++) - cm.ms.work_offset[axis] = cm_get_active_coord_offset(axis); -} - - -/* Get position of axis in absolute coordinates - * - * NOTE: Machine position is always returned in mm mode. No units conversion - * is performed - */ -float cm_get_absolute_position(uint8_t axis) { - return cm.position[axis]; -} - - -/* Return work position in prevailing units (mm/inch) and with all offsets - * applied. - * - * NOTE: This function only works after the gcode_state struct has had the - * work_offsets setup by calling cm_get_model_coord_offset_vector() first. - */ -float cm_get_work_position(uint8_t axis) { - float position = cm.position[axis] - cm_get_active_coord_offset(axis); - - if (cm.gm.units_mode == INCHES) position /= MM_PER_INCH; - - return position; -} - - -/* Critical helpers - * - * Core functions supporting the canonical machining functions - * These functions are not part of the NIST defined functions - */ - -/* Perform final operations for a traverse or feed - * - * These routines set the point position in the gcode model. - * - * Note: As far as the canonical machine is concerned the final - * position of a Gcode block (move) is achieved as soon as the move is - * planned and the move target becomes the new model position. In - * reality the planner will (in all likelihood) have only just queued - * the move for later execution, and the real tool position is still - * close to the starting point. - */ -void cm_finalize_move() { - copy_vector(cm.position, cm.ms.target); // update model position - - // if in ivnerse time mode reset feed rate so next block requires an - // explicit feed rate setting - if (cm.gm.feed_rate_mode == INVERSE_TIME_MODE && - cm.gm.motion_mode == MOTION_MODE_STRAIGHT_FEED) - cm.gm.feed_rate = 0; -} - - -/* Compute optimal and minimum move times into the gcode_state - * - * "Minimum time" is the fastest the move can be performed given - * the velocity constraints on each participating axis - regardless - * of the feed rate requested. The minimum time is the time limited - * by the rate-limiting axis. The minimum time is needed to compute - * the optimal time and is recorded for possible feed override - * computation. - * - * "Optimal time" is either the time resulting from the requested - * feed rate or the minimum time if the requested feed rate is not - * achievable. Optimal times for traverses are always the minimum - * time. - * - * The gcode state must have targets set prior by having - * cm_set_target(). Axis modes are taken into account by this. - * - * The following times are compared and the longest is returned: - * - G93 inverse time (if G93 is active) - * - time for coordinated move at requested feed rate - * - time that the slowest axis would require for the move - * - * Sets the following variables in the gcode_state struct - * - move_time is set to optimal time - * - * NIST RS274NGC_v3 Guidance - * - * The following is verbatim text from NIST RS274NGC_v3. As I - * interpret A for moves that combine both linear and rotational - * movement, the feed rate should apply to the XYZ movement, with - * the rotational axis (or axes) timed to start and end at the same - * time the linear move is performed. It is possible under this - * case for the rotational move to rate-limit the linear move. - * - * 2.1.2.5 Feed Rate - * - * The rate at which the controlled point or the axes move is - * nominally a steady rate which may be set by the user. In the - * Interpreter, the interpretation of the feed rate is as follows - * unless inverse time feed rate mode is being used in the - * RS274/NGC view (see Section 3.5.19). The canonical machining - * functions view of feed rate, as described in Section 4.3.5.1, - * has conditions under which the set feed rate is applied - * differently, but none of these is used in the Interpreter. - * - * A. For motion involving one or more of the X, Y, and Z axes - * (with or without simultaneous rotational axis motion), the - * feed rate means length units per minute along the programmed - * XYZ path, as if the rotational axes were not moving. - * - * B. For motion of one rotational axis with X, Y, and Z axes not - * moving, the feed rate means degrees per minute rotation of - * the rotational axis. - * - * C. For motion of two or three rotational axes with X, Y, and Z - * axes not moving, the rate is applied as follows. Let dA, dB, - * and dC be the angles in degrees through which the A, B, and - * C axes, respectively, must move. Let D = sqrt(dA^2 + dB^2 + - * dC^2). Conceptually, D is a measure of total angular motion, - * using the usual Euclidean metric. Let T be the amount of - * time required to move through D degrees at the current feed - * rate in degrees per minute. The rotational axes should be - * moved in coordinated linear motion so that the elapsed time - * from the start to the end of the motion is T plus any time - * required for acceleration or deceleration. - */ -void cm_calc_move_time(const float axis_length[], const float axis_square[]) { - float inv_time = 0; // inverse time if doing a feed in G93 mode - float xyz_time = 0; // linear coordinated move at requested feed - float abc_time = 0; // rotary coordinated move at requested feed - float max_time = 0; // time required for the rate-limiting axis - float tmp_time = 0; // used in computation - - // compute times for feed motion - if (cm.gm.motion_mode != MOTION_MODE_STRAIGHT_TRAVERSE) { - if (cm.gm.feed_rate_mode == INVERSE_TIME_MODE) { - // feed rate was un-inverted to minutes by cm_set_feed_rate() - inv_time = cm.gm.feed_rate; - cm.gm.feed_rate_mode = UNITS_PER_MINUTE_MODE; - - } else { - // compute length of linear move in millimeters. Feed rate is provided as - // mm/min - xyz_time = sqrt(axis_square[AXIS_X] + axis_square[AXIS_Y] + - axis_square[AXIS_Z]) / cm.gm.feed_rate; - - // if no linear axes, compute length of multi-axis rotary move in degrees. - // Feed rate is provided as degrees/min - if (fp_ZERO(xyz_time)) - abc_time = sqrt(axis_square[AXIS_A] + axis_square[AXIS_B] + - axis_square[AXIS_C]) / cm.gm.feed_rate; - } - } - - for (uint8_t axis = 0; axis < AXES; axis++) { - if (cm.gm.motion_mode == MOTION_MODE_STRAIGHT_TRAVERSE) - tmp_time = fabs(axis_length[axis]) / cm.a[axis].velocity_max; - - else // MOTION_MODE_STRAIGHT_FEED - tmp_time = fabs(axis_length[axis]) / cm.a[axis].feedrate_max; - - max_time = max(max_time, tmp_time); - } - - cm.ms.move_time = max4(inv_time, max_time, xyz_time, abc_time); -} - - -/// Set endpoint position from final runtime position -void cm_update_model_position_from_runtime() { - copy_vector(cm.position, mr.ms.target); -} - - -/* Set target vector in GM model - * - * This is a core routine. It handles: - * - conversion of linear units to internal canonical form (mm) - * - conversion of relative mode to absolute (internal canonical form) - * - translation of work coordinates to machine coordinates (internal - * canonical form) - * - computation and application of axis modes as so: - * - * DISABLED - Incoming value is ignored. Target value is not changed - * ENABLED - Convert axis values to canonical format and store as target - * INHIBITED - Same processing as ENABLED, but axis will not actually be run - * RADIUS - ABC axis value is provided in Gcode block in linear units - * - Target is set to degrees based on axis' Radius value - * - Radius mode is only processed for ABC axes. Application to - * XYZ is ignored. - * - * Target coordinates are provided in target[] - * Axes that need processing are signaled in flag[] - */ - -// ESTEE: _calc_ABC is a fix to workaround a gcc compiler bug wherein it runs -// out of spill registers we moved this block into its own function so that we -// get a fresh stack push -// ALDEN: This shows up in avr-gcc 4.7.0 and avr-libc 1.8.0 -static float _calc_ABC(uint8_t axis, float target[], float flag[]) { - if (cm.a[axis].axis_mode == AXIS_STANDARD || - cm.a[axis].axis_mode == AXIS_INHIBITED) - return target[axis]; // no mm conversion - it's in degrees - - return TO_MILLIMETERS(target[axis]) * 360 / (2 * M_PI * cm.a[axis].radius); -} - - -void cm_set_model_target(float target[], float flag[]) { - float tmp = 0; - - // process XYZABC for lower modes - for (int axis = AXIS_X; axis <= AXIS_Z; axis++) { - if (fp_FALSE(flag[axis]) || cm.a[axis].axis_mode == AXIS_DISABLED) - continue; // skip axis if not flagged for update or its disabled - - else if (cm.a[axis].axis_mode == AXIS_STANDARD || - cm.a[axis].axis_mode == AXIS_INHIBITED) { - if (cm.gm.distance_mode == ABSOLUTE_MODE) - cm.ms.target[axis] = - cm_get_active_coord_offset(axis) + TO_MILLIMETERS(target[axis]); - else cm.ms.target[axis] += TO_MILLIMETERS(target[axis]); - } - } - - // FYI: The ABC loop below relies on the XYZ loop having been run first - for (int axis = AXIS_A; axis <= AXIS_C; axis++) { - if (fp_FALSE(flag[axis]) || cm.a[axis].axis_mode == AXIS_DISABLED) - continue; // skip axis if not flagged for update or its disabled - else tmp = _calc_ABC(axis, target, flag); - - if (cm.gm.distance_mode == ABSOLUTE_MODE) - // sacidu93's fix to Issue #22 - cm.ms.target[axis] = tmp + cm_get_active_coord_offset(axis); - else cm.ms.target[axis] += tmp; - } -} - - -/* Return error code if soft limit is exceeded - * - * Must be called with target properly set in GM struct. Best done - * after cm_set_model_target(). - * - * Tests for soft limit for any homed axis if min and max are - * different values. You can set min and max to 0,0 to disable soft - * limits for an axis. Also will not test a min or a max if the value - * is < -1000000 (negative one million). This allows a single end to - * be tested w/the other disabled, should that requirement ever arise. - */ -stat_t cm_test_soft_limits(float target[]) { -#ifdef SOFT_LIMIT_ENABLE - for (int axis = 0; axis < AXES; axis++) { - if (!cm.homed[axis]) continue; // don't test axes that are not homed - - if (fp_EQ(cm.a[axis].travel_min, cm.a[axis].travel_max)) continue; - - if (cm.a[axis].travel_min > DISABLE_SOFT_LIMIT && - target[axis] < cm.a[axis].travel_min) - return STAT_SOFT_LIMIT_EXCEEDED; - - if (cm.a[axis].travel_max > DISABLE_SOFT_LIMIT && - target[axis] > cm.a[axis].travel_max) - return STAT_SOFT_LIMIT_EXCEEDED; - } -#endif - - return STAT_OK; -} - - -/* Canonical machining functions - * Values are passed in pre-unit_converted state (from gn structure) - * All operations occur on gm (current model state) - * - * These are organized by section number (x.x.x) in the order they are - * found in NIST RS274 NGCv3 - */ - -// Initialization and Termination (4.3.2) - -void canonical_machine_init() { - // Init 1/jerk - for (uint8_t axis = 0; axis < AXES; axis++) - cm.a[axis].recip_jerk = 1 / (cm.a[axis].jerk_max * JERK_MULTIPLIER); - - // Set gcode defaults - cm_set_units_mode(GCODE_DEFAULT_UNITS); - cm_set_coord_system(GCODE_DEFAULT_COORD_SYSTEM); - cm_set_plane(GCODE_DEFAULT_PLANE); - cm_set_path_control(GCODE_DEFAULT_PATH_CONTROL); - cm_set_distance_mode(GCODE_DEFAULT_DISTANCE_MODE); - cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE); // always the default - - // Sub-system inits - cm_spindle_init(); - coolant_init(); -} - - -/// Alarm state; send an exception report and stop processing input -stat_t cm_alarm(const char *location, stat_t code) { - status_message_P(location, STAT_LEVEL_ERROR, code, "ALARM"); - estop_trigger(); - return code; -} - - -/// Clear soft alarm -stat_t cm_clear() { - if (cm.cycle_state == CYCLE_OFF) - cm.machine_state = MACHINE_PROGRAM_STOP; - else cm.machine_state = MACHINE_CYCLE; - - return STAT_OK; -} - - -// Representation (4.3.3) -// -// Affect the Gcode model only (asynchronous) -// These functions assume input validation occurred upstream. - -/// G17, G18, G19 select axis plane -void cm_set_plane(cmCanonicalPlane_t plane) {cm.gm.select_plane = plane;} - - -/// G20, G21 -void cm_set_units_mode(cmUnitsMode_t mode) {cm.gm.units_mode = mode;} - - -/// G90, G91 -void cm_set_distance_mode(cmDistanceMode_t mode) {cm.gm.distance_mode = mode;} - - -/* G10 L2 Pn, delayed persistence - * - * This function applies the offset to the GM model. You can also - * use $g54x - $g59c config functions to change offsets. - * - * It also does not reset the work_offsets which may be - * accomplished by calling cm_set_work_offsets() immediately - * afterwards. - */ -void cm_set_coord_offsets(cmCoordSystem_t coord_system, float offset[], - float flag[]) { - if (coord_system < G54 || coord_system > COORD_SYSTEM_MAX) - return; // you can't set G53 - - for (int axis = 0; axis < AXES; axis++) - if (fp_TRUE(flag[axis])) - cm.offset[coord_system][axis] = TO_MILLIMETERS(offset[axis]); -} - - -// Representation functions that affect gcode model and are queued to planner -// (synchronous) - -/// G54-G59 -void cm_set_coord_system(cmCoordSystem_t coord_system) { - cm.gm.coord_system = coord_system; - - // pass coordinate system in value[0] element - float value[AXES] = {coord_system}; - // second vector (flags) is not used, so fake it - mp_queue_command(_exec_offset, value, value); -} - - -static void _exec_offset(float *value, float *flag) { - // coordinate system is passed in value[0] element - uint8_t coord_system = value[0]; - float offsets[AXES]; - - for (int axis = 0; axis < AXES; axis++) - offsets[axis] = cm.offset[coord_system][axis] + - cm.origin_offset[axis] * (cm.origin_offset_enable ? 1 : 0); - - mp_set_runtime_work_offset(offsets); - cm_set_work_offsets(); // set work offsets in the Gcode model -} - - -/* Set the position of a single axis in the model, planner and runtime - * - * This command sets an axis/axes to a position provided as an argument. - * This is useful for setting origins for homing, probing, and other operations. - * - * !!!!! DO NOT CALL THIS FUNCTION WHILE IN A MACHINING CYCLE !!!!! - * - * More specifically, do not call this function if there are any moves - * in the planner or if the runtime is moving. The system must be - * quiescent or you will introduce positional errors. This is true - * because the planned / running moves have a different reference - * frame than the one you are now going to set. These functions should - * only be called during initialization sequences and during cycles - * (such as homing cycles) when you know there are no more moves in - * the planner and that all motion has stopped. Use - * cm_get_runtime_busy() to be sure the system is quiescent. - */ -void cm_set_position(int axis, float position) { - // TODO: Interlock involving runtime_busy test - cm.position[axis] = position; - cm.ms.target[axis] = position; - mp_set_planner_position(axis, position); - mp_set_runtime_position(axis, position); - mp_set_steps_to_runtime_position(); -} - - -// G28.3 functions and support - -/* G28.3 - model, planner and queue to runtime - * - * Takes a vector of origins (presumably 0's, but not necessarily) and - * applies them to all axes where the corresponding position in the - * flag vector is true (1). - * - * This is a 2 step process. The model and planner contexts are set - * immediately, the runtime command is queued and synchronized with - * the planner queue. This includes the runtime position and the step - * recording done by the encoders. At that point any axis that is set - * is also marked as homed. - */ -void cm_set_absolute_origin(float origin[], float flag[]) { - float value[AXES]; - - for (int axis = 0; axis < AXES; axis++) - if (fp_TRUE(flag[axis])) { - value[axis] = TO_MILLIMETERS(origin[axis]); - cm.position[axis] = value[axis]; // set model position - cm.ms.target[axis] = value[axis]; // reset model target - mp_set_planner_position(axis, value[axis]); // set mm position - } - - mp_queue_command(_exec_absolute_origin, value, flag); -} - - -static void _exec_absolute_origin(float *value, float *flag) { - for (int axis = 0; axis < AXES; axis++) - if (fp_TRUE(flag[axis])) { - mp_set_runtime_position(axis, value[axis]); - cm.homed[axis] = true; // G28.3 is not considered homed until here - } - - mp_set_steps_to_runtime_position(); -} - - -/* G92's behave according to NIST 3.5.18 & LinuxCNC G92 - * http://linuxcnc.org/docs/html/gcode/gcode.html#sec:G92-G92.1-G92.2-G92.3 - */ - -/// G92 -void cm_set_origin_offsets(float offset[], float flag[]) { - // set offsets in the Gcode model extended context - cm.origin_offset_enable = true; - for (int axis = 0; axis < AXES; axis++) - if (fp_TRUE(flag[axis])) - cm.origin_offset[axis] = cm.position[axis] - - cm.offset[cm.gm.coord_system][axis] - TO_MILLIMETERS(offset[axis]); - - // now pass the offset to the callback - setting the coordinate system also - // applies the offsets - // pass coordinate system in value[0] element - float value[AXES] = {cm.gm.coord_system}; - mp_queue_command(_exec_offset, value, value); // second vector is not used -} - - -/// G92.1 -void cm_reset_origin_offsets() { - cm.origin_offset_enable = false; - for (int axis = 0; axis < AXES; axis++) - cm.origin_offset[axis] = 0; - - float value[AXES] = {cm.gm.coord_system}; - mp_queue_command(_exec_offset, value, value); -} - - -/// G92.2 -void cm_suspend_origin_offsets() { - cm.origin_offset_enable = false; - float value[AXES] = {cm.gm.coord_system}; - mp_queue_command(_exec_offset, value, value); -} - - -/// G92.3 -void cm_resume_origin_offsets() { - cm.origin_offset_enable = true; - float value[AXES] = {cm.gm.coord_system}; - mp_queue_command(_exec_offset, value, value); -} - - -// Free Space Motion (4.3.4) - -/// G0 linear rapid -stat_t cm_straight_traverse(float target[], float flags[]) { - cm.gm.motion_mode = MOTION_MODE_STRAIGHT_TRAVERSE; - cm_set_model_target(target, flags); - - // test soft limits - stat_t status = cm_test_soft_limits(cm.ms.target); - if (status != STAT_OK) return CM_ALARM(status); - - // prep and plan the move - cm_set_work_offsets(&cm.gm); // capture fully resolved offsets to the state - cm_cycle_start(); // required for homing & other cycles - cm.ms.line = cm.gm.line; // copy line number - mp_aline(&cm.ms); // send the move to the planner - cm_finalize_move(); - - return STAT_OK; -} - - -/// G28.1 -void cm_set_g28_position() {copy_vector(cm.g28_position, cm.position);} - - -/// G28 -stat_t cm_goto_g28_position(float target[], float flags[]) { - cm_set_absolute_override(true); - - // move through intermediate point, or skip - cm_straight_traverse(target, flags); - - // make sure you have an available buffer - mp_wait_for_buffer(); - - // execute actual stored move - float f[] = {1, 1, 1, 1, 1, 1}; - return cm_straight_traverse(cm.g28_position, f); -} - - -/// G30.1 -void cm_set_g30_position() {copy_vector(cm.g30_position, cm.position);} - - -/// G30 -stat_t cm_goto_g30_position(float target[], float flags[]) { - cm_set_absolute_override(true); - - // move through intermediate point, or skip - cm_straight_traverse(target, flags); - - // make sure you have an available buffer - mp_wait_for_buffer(); - - // execute actual stored move - float f[] = {1, 1, 1, 1, 1, 1}; - return cm_straight_traverse(cm.g30_position, f); -} - - -// Machining Attributes (4.3.5) - -/// F parameter -/// Normalize feed rate to mm/min or to minutes if in inverse time mode -void cm_set_feed_rate(float feed_rate) { - if (cm.gm.feed_rate_mode == INVERSE_TIME_MODE) - // normalize to minutes (active for this gcode block only) - cm.gm.feed_rate = 1 / feed_rate; - - else cm.gm.feed_rate = TO_MILLIMETERS(feed_rate); -} - - -/// G93, G94 See cmFeedRateMode -void cm_set_feed_rate_mode(cmFeedRateMode_t mode) {cm.gm.feed_rate_mode = mode;} - - -/// G61, G61.1, G64 -void cm_set_path_control(cmPathControlMode_t mode) {cm.gm.path_control = mode;} - - -// Machining Functions (4.3.6) See arc.c - -/// G4, P parameter (seconds) -stat_t cm_dwell(float seconds) { - return mp_dwell(seconds); -} - - -/// G1 -stat_t cm_straight_feed(float target[], float flags[]) { - // trap zero feed rate condition - if (cm.gm.feed_rate_mode != INVERSE_TIME_MODE && fp_ZERO(cm.gm.feed_rate)) - return STAT_GCODE_FEEDRATE_NOT_SPECIFIED; - - cm.gm.motion_mode = MOTION_MODE_STRAIGHT_FEED; - cm_set_model_target(target, flags); - - // test soft limits - stat_t status = cm_test_soft_limits(cm.ms.target); - if (status != STAT_OK) return CM_ALARM(status); - - // prep and plan the move - cm_set_work_offsets(&cm.gm); // capture the fully resolved offsets to state - cm_cycle_start(); // required for homing & other cycles - cm.ms.line = cm.gm.line; // copy line number - status = mp_aline(&cm.ms); // send the move to the planner - cm_finalize_move(); - - return status; -} - - -// Spindle Functions (4.3.7) see spindle.c, spindle.h - -/* Tool Functions (4.3.8) - * - * Note: These functions don't actually do anything for now, and there's a bug - * where T and M in different blocks don't work correctly - */ - -/// T parameter -void cm_select_tool(uint8_t tool_select) { - float value[AXES] = {tool_select}; - mp_queue_command(_exec_select_tool, value, value); -} - - -static void _exec_select_tool(float *value, float *flag) { - cm.gm.tool_select = value[0]; -} - - -/// M6 This might become a complete tool change cycle -void cm_change_tool(uint8_t tool_change) { - float value[AXES] = {cm.gm.tool_select}; - mp_queue_command(_exec_change_tool, value, value); -} - - -static void _exec_change_tool(float *value, float *flag) { - cm.gm.tool = (uint8_t)value[0]; -} - - -// Miscellaneous Functions (4.3.9) -/// M7 -void cm_mist_coolant_control(bool mist_coolant) { - float value[AXES] = {mist_coolant}; - mp_queue_command(_exec_mist_coolant_control, value, value); -} - - -static void _exec_mist_coolant_control(float *value, float *flag) { - coolant_set_mist(cm.gm.mist_coolant = value[0]); -} - - -/// M8, M9 -void cm_flood_coolant_control(bool flood_coolant) { - float value[AXES] = {flood_coolant}; - mp_queue_command(_exec_flood_coolant_control, value, value); -} - - -static void _exec_flood_coolant_control(float *value, float *flag) { - cm.gm.flood_coolant = value[0]; - - coolant_set_flood(value[0]); - if (!value[0]) coolant_set_mist(false); // M9 special function -} - - -/* Override enables are kind of a mess in Gcode. This is an attempt to sort - * them out. See - * http://www.linuxcnc.org/docs/2.4/html/gcode_main.html#sec:M50:-Feed-Override - */ - -/// M48, M49 -void cm_override_enables(bool flag) { - cm.gm.feed_rate_override_enable = flag; - cm.gm.traverse_override_enable = flag; - cm.gm.spindle_override_enable = flag; -} - - -/// M50 -void cm_feed_rate_override_enable(bool flag) { - if (fp_TRUE(cm.gf.parameter) && fp_ZERO(cm.gn.parameter)) - cm.gm.feed_rate_override_enable = false; - else cm.gm.feed_rate_override_enable = true; -} - - -/// M50.1 -void cm_feed_rate_override_factor(bool flag) { - cm.gm.feed_rate_override_enable = flag; - cm.gm.feed_rate_override_factor = cm.gn.parameter; -} - - -/// M50.2 -void cm_traverse_override_enable(bool flag) { - if (fp_TRUE(cm.gf.parameter) && fp_ZERO(cm.gn.parameter)) - cm.gm.traverse_override_enable = false; - else cm.gm.traverse_override_enable = true; -} - - -/// M51 -void cm_traverse_override_factor(bool flag) { - cm.gm.traverse_override_enable = flag; - cm.gm.traverse_override_factor = cm.gn.parameter; -} - - -/// M51.1 -void cm_spindle_override_enable(bool flag) { - if (fp_TRUE(cm.gf.parameter) && fp_ZERO(cm.gn.parameter)) - cm.gm.spindle_override_enable = false; - else cm.gm.spindle_override_enable = true; -} - - -/// M50.1 -void cm_spindle_override_factor(bool flag) { - cm.gm.spindle_override_enable = flag; - cm.gm.spindle_override_factor = cm.gn.parameter; -} - - -void cm_message(const char *message) { - status_message_P(0, STAT_LEVEL_INFO, STAT_OK, PSTR("%s"), message); -} - - -/* Program Functions (4.3.10) - * - * This group implements stop, start, end, and hold. - * It is extended beyond the NIST spec to handle various situations. - * - * cm_program_stop and cm_optional_program_stop are synchronous Gcode - * commands that are received through the interpreter. They cause all motion - * to stop at the end of the current command, including spindle motion. - * - * Note that the stop occurs at the end of the immediately preceding command - * (i.e. the stop is queued behind the last command). - * - * cm_program_end is a stop that also resets the machine to initial state - */ - -/* Feedholds, queue flushes and cycles starts are all related. The request - * functions set flags for these. The sequencing callback interprets the flags - * according to the following rules: - * - * A feedhold request received during motion should be honored - * A feedhold request received during a feedhold should be ignored and reset - * A feedhold request received during a motion stop should be ignored and - * reset - * - * A queue flush request received during motion should be ignored but not - * reset - * A queue flush request received during a feedhold should be deferred until - * the feedhold enters a HOLD state (i.e. until deceleration is complete) - * A queue flush request received during a motion stop should be honored - * - * A cycle start request received during motion should be ignored and reset - * A cycle start request received during a feedhold should be deferred until - * the feedhold enters a HOLD state (i.e. until deceleration is complete) - * If a queue flush request is also present the queue flush should be done - * first - * A cycle start request received during a motion stop should be honored and - * should start to run anything in the planner queue - */ - - -/// Initiate a feedhold right now -void cm_request_feedhold() {cm.feedhold_requested = true;} -void cm_request_queue_flush() {cm.queue_flush_requested = true;} -void cm_request_cycle_start() {cm.cycle_start_requested = true;} - - -/// Process feedholds, cycle starts & queue flushes -void cm_feedhold_sequencing_callback() { - if (cm.feedhold_requested) { - if (cm.motion_state == MOTION_RUN && cm.hold_state == FEEDHOLD_OFF) { - cm_set_motion_state(MOTION_HOLD); - cm.hold_state = FEEDHOLD_SYNC; // invokes hold from aline execution - } - - cm.feedhold_requested = false; - } - - if (cm.queue_flush_requested) { - if ((cm.motion_state == MOTION_STOP || - (cm.motion_state == MOTION_HOLD && cm.hold_state == FEEDHOLD_HOLD)) && - !cm_get_runtime_busy()) { - cm.queue_flush_requested = false; - cm_queue_flush(); - } - } - - bool processing = - cm.hold_state == FEEDHOLD_SYNC || - cm.hold_state == FEEDHOLD_PLAN || - cm.hold_state == FEEDHOLD_DECEL; - - if (cm.cycle_start_requested && !cm.queue_flush_requested && !processing) { - cm.cycle_start_requested = false; - cm.hold_state = FEEDHOLD_END_HOLD; - cm_cycle_start(); - mp_end_hold(); - } -} - - -stat_t cm_queue_flush() { - if (cm_get_runtime_busy()) return STAT_COMMAND_NOT_ACCEPTED; - - mp_flush_planner(); // flush planner queue - - // Note: The following uses low-level mp calls for absolute position. - for (int axis = 0; axis < AXES; axis++) - // set mm from mr - cm_set_position(axis, mp_get_runtime_absolute_position(axis)); - - float value[AXES] = {MACHINE_PROGRAM_STOP}; - _exec_program_finalize(value, value); // finalize now, not later - - return STAT_OK; -} - - -/* Program and cycle state functions - * - * cm_program_end() implements M2 and M30 - * The END behaviors are defined by NIST 3.6.1 are: - * 1. Axis offsets are set to zero (like G92.2) and origin offsets are set - * to the default (like G54) - * 2. Selected plane is set to CANON_PLANE_XY (like G17) - * 3. Distance mode is set to MODE_ABSOLUTE (like G90) - * 4. Feed rate mode is set to UNITS_PER_MINUTE (like G94) - * 5. Feed and speed overrides are set to ON (like M48) - * 6. Cutter compensation is turned off (like G40) - * 7. The spindle is stopped (like M5) - * 8. The current motion mode is set to G_1 (like G1) - * 9. Coolant is turned off (like M9) - * - * cm_program_end() implments things slightly differently: - * 1. Axis offsets are set to G92.1 CANCEL offsets - * (instead of using G92.2 SUSPEND Offsets) - * Set default coordinate system (uses $gco, not G54) - * 2. Selected plane is set to default plane ($gpl) - * (instead of setting it to G54) - * 3. Distance mode is set to MODE_ABSOLUTE (like G90) - * 4. Feed rate mode is set to UNITS_PER_MINUTE (like G94) - * 5. Not implemented - * 6. Not implemented - * 7. The spindle is stopped (like M5) - * 8. Motion mode is canceled like G80 (not set to G1) - * 9. Coolant is turned off (like M9) - * + Default INCHES or MM units mode is restored ($gun) - */ -static void _exec_program_finalize(float *value, float *flag) { - cm.machine_state = (uint8_t)value[0]; - cm_set_motion_state(MOTION_STOP); - if (cm.cycle_state == CYCLE_MACHINING) - cm.cycle_state = CYCLE_OFF; // don't end cycle if homing, probing, etc. - - cm.hold_state = FEEDHOLD_OFF; // end feedhold (if in feed hold) - cm.cycle_start_requested = false; // cancel any pending cycle start request - mp_zero_segment_velocity(); // for reporting purposes - - // perform the following resets if it's a program END - if (cm.machine_state == MACHINE_PROGRAM_END) { - cm_reset_origin_offsets(); // G92.1 - we do G91.1 instead of G92.2 - cm_set_coord_system(GCODE_DEFAULT_COORD_SYSTEM); - cm_set_plane(GCODE_DEFAULT_PLANE); - cm_set_distance_mode(GCODE_DEFAULT_DISTANCE_MODE); - cm_spindle_control(SPINDLE_OFF); // M5 - cm_flood_coolant_control(false); // M9 - cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE); // G94 - cm_set_motion_mode(MOTION_MODE_CANCEL_MOTION_MODE); - } -} - - -/// Do a cycle start right now -void cm_cycle_start() { - cm.machine_state = MACHINE_CYCLE; - - // don't (re)start homing, probe or other canned cycles - if (cm.cycle_state == CYCLE_OFF) cm.cycle_state = CYCLE_MACHINING; -} - - -/// Do a cycle end right now -void cm_cycle_end() { - if (cm.cycle_state != CYCLE_OFF) { - float value[AXES] = {MACHINE_PROGRAM_STOP}; - _exec_program_finalize(value, value); - } -} - - - -/// M0 Queue a program stop -void cm_program_stop() { - float value[AXES] = {MACHINE_PROGRAM_STOP}; - mp_queue_command(_exec_program_finalize, value, value); -} - - -/// M1 -void cm_optional_program_stop() { - float value[AXES] = {MACHINE_PROGRAM_STOP}; - mp_queue_command(_exec_program_finalize, value, value); -} - - -/// M2, M30 -void cm_program_end() { - float value[AXES] = {MACHINE_PROGRAM_END}; - mp_queue_command(_exec_program_finalize, value, value); -} - - -/// return ASCII char for axis given the axis number -char cm_get_axis_char(int8_t axis) { - char axis_char[] = "XYZABC"; - if (axis < 0 || axis > AXES) return ' '; - return axis_char[axis]; -} diff --git a/src/canonical_machine.h b/src/canonical_machine.h deleted file mode 100644 index dc23e38..0000000 --- a/src/canonical_machine.h +++ /dev/null @@ -1,568 +0,0 @@ -/******************************************************************************\ - - This file is part of the Buildbotics firmware. - - Copyright (c) 2015 - 2016 Buildbotics LLC - Copyright (c) 2010 - 2015 Alden S. Hart, Jr. - All rights reserved. - - This file ("the software") is free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License, - version 2 as published by the Free Software Foundation. You should - have received a copy of the GNU General Public License, version 2 - along with the software. If not, see . - - The software is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the software. If not, see - . - - For information regarding this software email: - "Joseph Coffland" - -\******************************************************************************/ - -#pragma once - - -#include "config.h" -#include "status.h" - -#include -#include - - -#define TO_MILLIMETERS(a) (cm.gm.units_mode == INCHES ? (a) * MM_PER_INCH : a) - -#define DISABLE_SOFT_LIMIT -1000000 - - - -/* Machine state model - * - * The following main variables track canonical machine state and state - * transitions. - * - cm.machine_state - overall state of machine and program execution - * - cm.cycle_state - what cycle the machine is executing (or none) - * - cm.motion_state - state of movement - * - * Allowed states and combined states: - * - * MACHINE STATE CYCLE STATE MOTION_STATE COMBINED_STATE (FYI) - * ------------- ------------ ------------- -------------------- - * MACHINE_UNINIT na na (U) - * MACHINE_READY CYCLE_OFF MOTION_STOP (ROS) RESET-OFF-STOP - * MACHINE_PROG_STOP CYCLE_OFF MOTION_STOP (SOS) STOP-OFF-STOP - * MACHINE_PROG_END CYCLE_OFF MOTION_STOP (EOS) END-OFF-STOP - * - * MACHINE_CYCLE CYCLE_STARTED MOTION_STOP (CSS) CYCLE-START-STOP - * MACHINE_CYCLE CYCLE_STARTED MOTION_RUN (CSR) CYCLE-START-RUN - * MACHINE_CYCLE CYCLE_STARTED MOTION_HOLD (CSH) CYCLE-START-HOLD - * MACHINE_CYCLE CYCLE_STARTED MOTION_END_HOLD (CSE) CYCLE-START-END_HOLD - * - * MACHINE_CYCLE CYCLE_HOMING MOTION_STOP (CHS) CYCLE-HOMING-STOP - * MACHINE_CYCLE CYCLE_HOMING MOTION_RUN (CHR) CYCLE-HOMING-RUN - * MACHINE_CYCLE CYCLE_HOMING MOTION_HOLD (CHH) CYCLE-HOMING-HOLD - * MACHINE_CYCLE CYCLE_HOMING MOTION_END_HOLD (CHE) CYCLE-HOMING-END_HOLD - */ - -/// check alignment with messages in config.c / msg_stat strings -typedef enum { - COMBINED_INITIALIZING, // machine is initializing - COMBINED_READY, // machine is ready for use. Also null move STOP state - COMBINED_ALARM, // machine in soft alarm state - COMBINED_PROGRAM_STOP, // program stop or no more blocks - COMBINED_PROGRAM_END, // program end - COMBINED_RUN, // motion is running - COMBINED_HOLD, // motion is holding - COMBINED_PROBE, // probe cycle active - COMBINED_CYCLE, // machine is running (cycling) - COMBINED_HOMING, // homing is treated as a cycle - COMBINED_SHUTDOWN, // machine in hard alarm state (shutdown) -} cmCombinedState_t; - - -typedef enum { - MACHINE_INITIALIZING, // machine is initializing - MACHINE_READY, // machine is ready for use - MACHINE_ALARM, // machine in soft alarm state - MACHINE_PROGRAM_STOP, // program stop or no more blocks - MACHINE_PROGRAM_END, // program end - MACHINE_CYCLE, // machine is running (cycling) - MACHINE_SHUTDOWN, // machine in hard alarm state (shutdown) -} cmMachineState_t; - - -typedef enum { - CYCLE_OFF, // machine is idle - CYCLE_MACHINING, // in normal machining cycle - CYCLE_PROBE, // in probe cycle - CYCLE_HOMING, // homing is treated as a specialized cycle -} cmCycleState_t; - - -typedef enum { - MOTION_STOP, // motion has stopped - MOTION_RUN, // machine is in motion - MOTION_HOLD // feedhold in progress -} cmMotionState_t; - - -typedef enum { // feedhold_state machine - FEEDHOLD_OFF, // no feedhold in effect - FEEDHOLD_SYNC, // start hold - sync to latest aline segment - FEEDHOLD_PLAN, // replan blocks for feedhold - FEEDHOLD_DECEL, // decelerate to hold point - FEEDHOLD_HOLD, // holding - FEEDHOLD_END_HOLD // end hold (transient state to OFF) -} cmFeedholdState_t; - - -typedef enum { // applies to cm.homing_state - HOMING_NOT_HOMED, // machine is not homed (0=false) - HOMING_HOMED, // machine is homed (1=true) - HOMING_WAITING // machine waiting to be homed -} cmHomingState_t; - - -typedef enum { // applies to cm.probe_state - PROBE_FAILED, // probe reached endpoint without triggering - PROBE_SUCCEEDED, // probe was triggered, cm.probe_results has position - PROBE_WAITING, // probe is waiting to be started -} cmProbeState_t; - - -/* The difference between NextAction and MotionMode is that NextAction is - * used by the current block, and may carry non-modal commands, whereas - * MotionMode persists across blocks (as G modal group 1) - */ - -/// these are in order to optimized CASE statement -typedef enum { - NEXT_ACTION_DEFAULT, // Must be zero (invokes motion modes) - NEXT_ACTION_SEARCH_HOME, // G28.2 homing cycle - NEXT_ACTION_SET_ABSOLUTE_ORIGIN, // G28.3 origin set - NEXT_ACTION_HOMING_NO_SET, // G28.4 homing cycle no coord setting - NEXT_ACTION_SET_G28_POSITION, // G28.1 set position in abs coordinates - NEXT_ACTION_GOTO_G28_POSITION, // G28 go to machine position - NEXT_ACTION_SET_G30_POSITION, // G30.1 - NEXT_ACTION_GOTO_G30_POSITION, // G30 - NEXT_ACTION_SET_COORD_DATA, // G10 - NEXT_ACTION_SET_ORIGIN_OFFSETS, // G92 - NEXT_ACTION_RESET_ORIGIN_OFFSETS, // G92.1 - NEXT_ACTION_SUSPEND_ORIGIN_OFFSETS, // G92.2 - NEXT_ACTION_RESUME_ORIGIN_OFFSETS, // G92.3 - NEXT_ACTION_DWELL, // G4 - NEXT_ACTION_STRAIGHT_PROBE // G38.2 -} cmNextAction_t; - - -typedef enum { // G Modal Group 1 - MOTION_MODE_STRAIGHT_TRAVERSE, // G0 - straight traverse - MOTION_MODE_STRAIGHT_FEED, // G1 - straight feed - MOTION_MODE_CW_ARC, // G2 - clockwise arc feed - MOTION_MODE_CCW_ARC, // G3 - counter-clockwise arc feed - MOTION_MODE_CANCEL_MOTION_MODE, // G80 - MOTION_MODE_STRAIGHT_PROBE, // G38.2 - MOTION_MODE_CANNED_CYCLE_81, // G81 - drilling - MOTION_MODE_CANNED_CYCLE_82, // G82 - drilling with dwell - MOTION_MODE_CANNED_CYCLE_83, // G83 - peck drilling - MOTION_MODE_CANNED_CYCLE_84, // G84 - right hand tapping - MOTION_MODE_CANNED_CYCLE_85, // G85 - boring, no dwell, feed out - MOTION_MODE_CANNED_CYCLE_86, // G86 - boring, spindle stop, rapid out - MOTION_MODE_CANNED_CYCLE_87, // G87 - back boring - MOTION_MODE_CANNED_CYCLE_88, // G88 - boring, spindle stop, manual out - MOTION_MODE_CANNED_CYCLE_89, // G89 - boring, dwell, feed out -} cmMotionMode_t; - - -typedef enum { // Used for detecting gcode errors. See NIST section 3.4 - MODAL_GROUP_G0, // {G10,G28,G28.1,G92} non-modal axis commands - MODAL_GROUP_G1, // {G0,G1,G2,G3,G80} motion - MODAL_GROUP_G2, // {G17,G18,G19} plane selection - MODAL_GROUP_G3, // {G90,G91} distance mode - MODAL_GROUP_G5, // {G93,G94} feed rate mode - MODAL_GROUP_G6, // {G20,G21} units - MODAL_GROUP_G7, // {G40,G41,G42} cutter radius compensation - MODAL_GROUP_G8, // {G43,G49} tool length offset - MODAL_GROUP_G9, // {G98,G99} return mode in canned cycles - MODAL_GROUP_G12, // {G54,G55,G56,G57,G58,G59} coordinate system selection - MODAL_GROUP_G13, // {G61,G61.1,G64} path control mode - MODAL_GROUP_M4, // {M0,M1,M2,M30,M60} stopping - MODAL_GROUP_M6, // {M6} tool change - MODAL_GROUP_M7, // {M3,M4,M5} spindle turning - MODAL_GROUP_M8, // {M7,M8,M9} coolant - MODAL_GROUP_M9, // {M48,M49} speed/feed override switches -} cmModalGroup_t; - -#define MODAL_GROUP_COUNT (MODAL_GROUP_M9 + 1) - -// Note 1: Our G0 omits G4,G30,G53,G92.1,G92.2,G92.3 as these have no axis -// components to error check - -typedef enum { // canonical plane - translates to: - // axis_0 axis_1 axis_2 - CANON_PLANE_XY, // G17 X Y Z - CANON_PLANE_XZ, // G18 X Z Y - CANON_PLANE_YZ // G19 Y Z X -} cmCanonicalPlane_t; - - -typedef enum { - INCHES, // G20 - MILLIMETERS, // G21 - DEGREES // ABC axes (this value used for displays only) -} cmUnitsMode_t; - - -typedef enum { - ABSOLUTE_COORDS, // machine coordinate system - G54, // G54 coordinate system - G55, // G55 coordinate system - G56, // G56 coordinate system - G57, // G57 coordinate system - G58, // G58 coordinate system - G59 // G59 coordinate system -} cmCoordSystem_t; - -#define COORD_SYSTEM_MAX G59 // set this manually to the last one - -/// G Modal Group 13 -typedef enum { - /// G61 - hits corners but does not stop if it does not need to. - PATH_EXACT_PATH, - PATH_EXACT_STOP, // G61.1 - stops at all corners - PATH_CONTINUOUS // G64 and typically the default mode -} cmPathControlMode_t; - - -typedef enum { - ABSOLUTE_MODE, // G90 - INCREMENTAL_MODE // G91 -} cmDistanceMode_t; - - -typedef enum { - INVERSE_TIME_MODE, // G93 - UNITS_PER_MINUTE_MODE, // G94 - UNITS_PER_REVOLUTION_MODE // G95 (unimplemented) -} cmFeedRateMode_t; - - -typedef enum { - ORIGIN_OFFSET_SET, // G92 - set origin offsets - ORIGIN_OFFSET_CANCEL, // G92.1 - zero out origin offsets - ORIGIN_OFFSET_SUSPEND, // G92.2 - do not apply offsets, but preserve values - ORIGIN_OFFSET_RESUME // G92.3 - resume application of the suspended offsets -} cmOriginOffset_t; - - -typedef enum { - PROGRAM_STOP, - PROGRAM_END -} cmProgramFlow_t; - - -/// spindle state settings -typedef enum { - SPINDLE_OFF, - SPINDLE_CW, - SPINDLE_CCW -} cmSpindleMode_t; - - -/// mist and flood coolant states -typedef enum { - COOLANT_OFF, // all coolant off - COOLANT_ON, // request coolant on or indicate both coolants are on - COOLANT_MIST, // indicates mist coolant on - COOLANT_FLOOD // indicates flood coolant on -} cmCoolantState_t; - - -/// used for spindle and arc dir -typedef enum { - DIRECTION_CW, - DIRECTION_CCW -} cmDirection_t; - - -/// axis modes (ordered: see _cm_get_feed_time()) -typedef enum { - AXIS_DISABLED, // kill axis - AXIS_STANDARD, // axis in coordinated motion w/standard behaviors - AXIS_INHIBITED, // axis is computed but not activated - AXIS_RADIUS, // rotary axis calibrated to circumference - AXIS_MODE_MAX -} cmAxisMode_t; // ordering must be preserved. - - -/* Gcode model - The following GCodeModel/GCodeInput structs are used: - * - * - gm is the core Gcode model state. It keeps the internal gcode - * state model in normalized, canonical form. All values are unit - * converted (to mm) and in the machine coordinate system - * (absolute coordinate system). Gm is owned by the canonical - * machine layer and should be accessed only through cm_ routines. - * - * - gn is used by the gcode interpreter and is re-initialized for - * each gcode block.It accepts data in the new gcode block in the - * formats present in the block (pre-normalized forms). During - * initialization some state elements are necessarily restored - * from gm. - * - * - gf is used by the gcode parser interpreter to hold flags for any - * data that has changed in gn during the parse. cm.gf.target[] - * values are also used by the canonical machine during - * set_target(). - */ - - -typedef struct { - int32_t line; // gcode block line number - float target[AXES]; // XYZABC where the move should go - float work_offset[AXES]; // offset from work coordinate system - float move_time; // optimal time for move given axis constraints -} MoveState_t; - - -/// Gcode model state -typedef struct GCodeState { - uint32_t line; // Gcode block line number - - uint8_t tool; // Tool after T and M6 - uint8_t tool_select; // T - sets this value - - float feed_rate; // F - in mm/min or inverse time mode - cmFeedRateMode_t feed_rate_mode; - float feed_rate_override_factor; // 1.0000 x F feed rate. - bool feed_rate_override_enable; // M48, M49 - float traverse_override_factor; // 1.0000 x traverse rate - bool traverse_override_enable; - - float spindle_speed; // in RPM - cmSpindleMode_t spindle_mode; - float spindle_override_factor; // 1.0000 x S spindle speed - bool spindle_override_enable; // true = override enabled - - cmMotionMode_t motion_mode; // Group 1 modal motion - cmCanonicalPlane_t select_plane; // G17, G18, G19 - cmUnitsMode_t units_mode; // G20, G21 - cmCoordSystem_t coord_system; // G54-G59 - select coordinate system 1-9 - bool absolute_override; // G53 true = move in machine coordinates - cmPathControlMode_t path_control; // G61 - cmDistanceMode_t distance_mode; // G91 - cmDistanceMode_t arc_distance_mode; // G91.1 - - bool mist_coolant; // true = mist on (M7), false = off (M9) - bool flood_coolant; // true = flood on (M8), false = off (M9) - - cmNextAction_t next_action; // handles G group 1 moves & non-modals - cmProgramFlow_t program_flow; // used only by the gcode_parser - - // unimplemented gcode parameters - // float cutter_radius; // D - cutter radius compensation (0 is off) - // float cutter_length; // H - cutter length compensation (0 is off) - - // Used for input only - float target[AXES]; // XYZABC where the move should go - bool override_enables; // feed and spindle enable - bool tool_change; // M6 tool change flag - - float parameter; // P - dwell time in sec, G10 coord select - - float arc_radius; // R - radius value in arc radius mode - float arc_offset[3]; // IJK - used by arc commands -} GCodeState_t; - - -typedef struct cmAxis { - cmAxisMode_t axis_mode; - float feedrate_max; // max velocity in mm/min or deg/min - float velocity_max; // max velocity in mm/min or deg/min - float travel_max; // max work envelope for soft limits - float travel_min; // min work envelope for soft limits - float jerk_max; // max jerk (Jm) in mm/min^3 divided by 1 million - float jerk_homing; // homing jerk (Jh) in mm/min^3 divided by 1 million - float recip_jerk; // reciprocal of current jerk value - with million - float junction_dev; // aka cornering delta - float radius; // radius in mm for rotary axis modes - float search_velocity; // homing search velocity - float latch_velocity; // homing latch velocity - float latch_backoff; // backoff from switches prior to homing latch movement - float zero_backoff; // backoff from switches for machine zero -} AxisConfig_t; - - -typedef struct cmSingleton { // struct to manage cm globals and cycles - // coordinate systems and offsets absolute (G53) + G54,G55,G56,G57,G58,G59 - float offset[COORDS + 1][AXES]; - float origin_offset[AXES]; // G92 offsets - bool origin_offset_enable; // G92 offsets enabled/disabled - - float position[AXES]; // model position (not used in gn or gf) - float g28_position[AXES]; // stored machine position for G28 - float g30_position[AXES]; // stored machine position for G30 - - // settings for axes X,Y,Z,A B,C - AxisConfig_t a[AXES]; - - cmCombinedState_t combined_state; // combination of states for display - cmMachineState_t machine_state; - cmCycleState_t cycle_state; - cmMotionState_t motion_state; - cmFeedholdState_t hold_state; // hold: feedhold sub-state machine - cmHomingState_t homing_state; // home: homing cycle sub-state machine - bool homed[AXES]; // individual axis homing flags - - cmProbeState_t probe_state; - float probe_results[AXES]; // probing results - - bool feedhold_requested; // feedhold character received - bool queue_flush_requested; // queue flush character received - bool cycle_start_requested; // cycle start character received - - // Model states - MoveState_t ms; - GCodeState_t gm; // core gcode model state - GCodeState_t gn; // gcode input values - GCodeState_t gf; // gcode input flags -} cmSingleton_t; - - -extern cmSingleton_t cm; // canonical machine controller singleton - - -// Model state getters and setters -uint32_t cm_get_line(); -cmCombinedState_t cm_get_combined_state(); -cmMachineState_t cm_get_machine_state(); -cmCycleState_t cm_get_cycle_state(); -cmMotionState_t cm_get_motion_state(); -cmFeedholdState_t cm_get_hold_state(); -cmHomingState_t cm_get_homing_state(); -cmMotionMode_t cm_get_motion_mode(); -cmCoordSystem_t cm_get_coord_system(); -cmUnitsMode_t cm_get_units_mode(); -cmCanonicalPlane_t cm_get_select_plane(); -cmPathControlMode_t cm_get_path_control(); -cmDistanceMode_t cm_get_distance_mode(); -cmFeedRateMode_t cm_get_feed_rate_mode(); -uint8_t cm_get_tool(); -cmSpindleMode_t cm_get_spindle_mode(); -bool cm_get_runtime_busy(); -float cm_get_feed_rate(); - -void cm_set_machine_state(cmMachineState_t machine_state); -void cm_set_motion_state(cmMotionState_t motion_state); -void cm_set_motion_mode(cmMotionMode_t motion_mode); -void cm_set_spindle_mode(cmSpindleMode_t spindle_mode); -void cm_set_spindle_speed_parameter(float speed); -void cm_set_tool_number(uint8_t tool); -void cm_set_absolute_override(bool absolute_override); -void cm_set_model_line(uint32_t line); - -float cm_get_axis_jerk(uint8_t axis); -void cm_set_axis_jerk(uint8_t axis, float jerk); - -// Coordinate systems and offsets -float cm_get_active_coord_offset(uint8_t axis); -float cm_get_work_offset(uint8_t axis); -void cm_set_work_offsets(); -float cm_get_absolute_position(uint8_t axis); -float cm_get_work_position(uint8_t axis); - -// Critical helpers -void cm_calc_move_time(const float axis_length[], const float axis_square[]); -void cm_update_model_position_from_runtime(); -void cm_finalize_move(); -stat_t cm_deferred_write_callback(); -void cm_set_model_target(float target[], float flag[]); -stat_t cm_test_soft_limits(float target[]); - -// Canonical machining functions defined by NIST [organized by NIST Gcode doc] - -// Initialization and termination (4.3.2) -void canonical_machine_init(); -/// enter alarm state. returns same status code -stat_t cm_alarm(const char *location, stat_t status); -stat_t cm_clear(); - -#define CM_ALARM(CODE) cm_alarm(STATUS_LOCATION, CODE) - -// Representation (4.3.3) -void cm_set_plane(cmCanonicalPlane_t plane); -void cm_set_units_mode(cmUnitsMode_t mode); -void cm_set_distance_mode(cmDistanceMode_t mode); -void cm_set_coord_offsets(cmCoordSystem_t coord_system, float offset[], - float flag[]); - -void cm_set_position(int axis, float position); -void cm_set_absolute_origin(float origin[], float flag[]); - -void cm_set_coord_system(cmCoordSystem_t coord_system); -void cm_set_origin_offsets(float offset[], float flag[]); -void cm_reset_origin_offsets(); -void cm_suspend_origin_offsets(); -void cm_resume_origin_offsets(); - -// Free Space Motion (4.3.4) -stat_t cm_straight_traverse(float target[], float flags[]); -void cm_set_g28_position(); -stat_t cm_goto_g28_position(float target[], float flags[]); -void cm_set_g30_position(); -stat_t cm_goto_g30_position(float target[], float flags[]); - -// Machining Attributes (4.3.5) -void cm_set_feed_rate(float feed_rate); -void cm_set_feed_rate_mode(cmFeedRateMode_t mode); -void cm_set_path_control(cmPathControlMode_t mode); - -// Machining Functions (4.3.6) -stat_t cm_straight_feed(float target[], float flags[]); -stat_t cm_arc_feed(float target[], float flags[], - float i, float j, float k, - float radius, uint8_t motion_mode); -stat_t cm_dwell(float seconds); - -// Spindle Functions (4.3.7) see spindle.h - -// Tool Functions (4.3.8) -void cm_select_tool(uint8_t tool); -void cm_change_tool(uint8_t tool); - -// Miscellaneous Functions (4.3.9) -void cm_mist_coolant_control(bool mist_coolant); -void cm_flood_coolant_control(bool flood_coolant); - -void cm_override_enables(bool flag); -void cm_feed_rate_override_enable(bool flag); -void cm_feed_rate_override_factor(bool flag); -void cm_traverse_override_enable(bool flag); -void cm_traverse_override_factor(bool flag); -void cm_spindle_override_enable(bool flag); -void cm_spindle_override_factor(bool flag); - -void cm_message(const char *message); - -// Program Functions (4.3.10) -void cm_request_feedhold(); -void cm_request_queue_flush(); -void cm_request_cycle_start(); - -void cm_feedhold_sequencing_callback(); -stat_t cm_queue_flush(); - -void cm_cycle_start(); -void cm_cycle_end(); -void cm_feedhold(); -void cm_program_stop(); -void cm_optional_program_stop(); -void cm_program_end(); - -// Cycles -char cm_get_axis_char(int8_t axis); diff --git a/src/config.h b/src/config.h index 124c4c9..e737bd7 100644 --- a/src/config.h +++ b/src/config.h @@ -169,7 +169,7 @@ typedef enum { #define VELOCITY_MAX 13000 // mm/min #define FEEDRATE_MAX VELOCITY_MAX -#define X_AXIS_MODE AXIS_STANDARD // See canonical_machine.h +#define X_AXIS_MODE AXIS_STANDARD // See machine.h #define X_VELOCITY_MAX VELOCITY_MAX // G0 max velocity in mm/min #define X_FEEDRATE_MAX FEEDRATE_MAX // G1 max feed rate in mm/min #define X_TRAVEL_MIN 0 // minimum travel for soft limits @@ -265,7 +265,7 @@ typedef enum { // Gcode defaults #define GCODE_DEFAULT_UNITS MILLIMETERS // MILLIMETERS or INCHES -#define GCODE_DEFAULT_PLANE CANON_PLANE_XY // See canonical_machine.h +#define GCODE_DEFAULT_PLANE PLANE_XY // See machine.h #define GCODE_DEFAULT_COORD_SYSTEM G54 // G54, G55, G56, G57, G58 or G59 #define GCODE_DEFAULT_PATH_CONTROL PATH_CONTINUOUS #define GCODE_DEFAULT_DISTANCE_MODE ABSOLUTE_MODE diff --git a/src/gcode_parser.c b/src/gcode_parser.c index 340ed0b..d00e2dd 100644 --- a/src/gcode_parser.c +++ b/src/gcode_parser.c @@ -28,7 +28,7 @@ #include "gcode_parser.h" -#include "canonical_machine.h" +#include "machine.h" #include "spindle.h" #include "probing.h" #include "homing.h" @@ -195,7 +195,7 @@ static stat_t _validate_gcode_block() { /* Execute parsed block * - * Conditionally (based on whether a flag is set in gf) call the canonical + * Conditionally (based on whether a flag is set in gf) call the * machining functions in order of execution as per RS274NGC_3 table 8 * (below, with modifications): * @@ -228,7 +228,7 @@ static stat_t _validate_gcode_block() { * 21. stop and end (M0, M1, M2, M30, M60) * * Values in gn are in original units and should not be unit converted prior - * to calling the canonical functions (which do the unit conversions) + * to calling the machine functions (which do the unit conversions) */ static stat_t _execute_gcode_block() { stat_t status = STAT_OK; @@ -378,9 +378,9 @@ static stat_t _parse_gcode_block(char *buf) { case 4: SET_NON_MODAL(next_action, NEXT_ACTION_DWELL); case 10: SET_MODAL(MODAL_GROUP_G0, next_action, NEXT_ACTION_SET_COORD_DATA); - case 17: SET_MODAL(MODAL_GROUP_G2, select_plane, CANON_PLANE_XY); - case 18: SET_MODAL(MODAL_GROUP_G2, select_plane, CANON_PLANE_XZ); - case 19: SET_MODAL(MODAL_GROUP_G2, select_plane, CANON_PLANE_YZ); + case 17: SET_MODAL(MODAL_GROUP_G2, select_plane, PLANE_XY); + case 18: SET_MODAL(MODAL_GROUP_G2, select_plane, PLANE_XZ); + case 19: SET_MODAL(MODAL_GROUP_G2, select_plane, PLANE_YZ); case 20: SET_MODAL(MODAL_GROUP_G6, units_mode, INCHES); case 21: SET_MODAL(MODAL_GROUP_G6, units_mode, MILLIMETERS); case 28: diff --git a/src/homing.c b/src/homing.c index acded39..a9efd44 100644 --- a/src/homing.c +++ b/src/homing.c @@ -26,7 +26,7 @@ \******************************************************************************/ -#include "canonical_machine.h" +#include "machine.h" #include "switch.h" #include "util.h" #include "report.h" diff --git a/src/huanyang.h b/src/huanyang.h index 60d5bbf..fce7aa0 100644 --- a/src/huanyang.h +++ b/src/huanyang.h @@ -27,7 +27,7 @@ #pragma once -#include "canonical_machine.h" +#include "machine.h" void huanyang_init(); diff --git a/src/machine.c b/src/machine.c new file mode 100644 index 0000000..cdbe35b --- /dev/null +++ b/src/machine.c @@ -0,0 +1,1291 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2016 Buildbotics LLC + Copyright (c) 2010 - 2015 Alden S. Hart, Jr. + Copyright (c) 2012 - 2015 Rob Giseburt + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + +/* This code is a loose implementation of Kramer, Proctor and Messina's + * machining functions as described in the NIST RS274/NGC v3 + * + * The machine is the layer between the Gcode parser and + * the motion control code for a specific robot. It keeps state and + * executes commands - passing the stateless commands to the motion + * planning layer. + * + * Synchronizing command execution + * + * "Synchronous commands" are commands that affect the runtime need + * to be synchronized with movement. Examples include G4 dwells, + * program stops and ends, and most M commands. These are queued + * into the planner queue and execute from the queue. Synchronous + * commands work like this: + * + * - Call the cm_xxx_xxx() function which will do any input + * validation and return an error if it detects one. + * + * - The cm_ function calls mp_queue_command(). Arguments are a + * callback to the _exec_...() function, which is the runtime + * execution routine, and any arguments that are needed by the + * runtime. See typedef for *exec in planner.h for details + * + * - mp_queue_command() stores the callback and the args in a + planner buffer. + * + * - When planner execution reaches the buffer it executes the + * callback w/ the args. Take careful note that the callback + * executes under an interrupt, so beware of variables that may + * need to be volatile. + * + * Note: - The synchronous command execution mechanism uses 2 + * vectors in the bf buffer to store and return values for the + * callback. It's obvious, but impractical to pass the entire bf + * buffer to the callback as some of these commands are actually + * executed locally and have no buffer. + */ + +#include "machine.h" + +#include "config.h" +#include "stepper.h" +#include "spindle.h" +#include "coolant.h" +#include "switch.h" +#include "hardware.h" +#include "util.h" +#include "usart.h" // for serial queue flush +#include "estop.h" + +#include "plan/planner.h" +#include "plan/buffer.h" +#include "plan/feedhold.h" +#include "plan/dwell.h" +#include "plan/command.h" +#include "plan/arc.h" +#include "plan/line.h" + +#include +#include +#include +#include + + +cmSingleton_t cm = { + // Offsets + .offset = { + {}, // ABSOLUTE_COORDS + + {0, 0, 0, 0, 0, 0}, // G54 + {X_TRAVEL_MAX / 2, Y_TRAVEL_MAX / 2, 0, 0, 0, 0}, // G55 + {0, 0, 0, 0, 0, 0}, // G56 + {0, 0, 0, 0, 0, 0}, // G57 + {0, 0, 0, 0, 0, 0}, // G58 + {0, 0, 0, 0, 0, 0}, // G59 + }, + + // Axes + .a = { + { + .axis_mode = X_AXIS_MODE, + .velocity_max = X_VELOCITY_MAX, + .feedrate_max = X_FEEDRATE_MAX, + .travel_min = X_TRAVEL_MIN, + .travel_max = X_TRAVEL_MAX, + .jerk_max = X_JERK_MAX, + .jerk_homing = X_JERK_HOMING, + .junction_dev = X_JUNCTION_DEVIATION, + .search_velocity = X_SEARCH_VELOCITY, + .latch_velocity = X_LATCH_VELOCITY, + .latch_backoff = X_LATCH_BACKOFF, + .zero_backoff = X_ZERO_BACKOFF, + }, { + .axis_mode = Y_AXIS_MODE, + .velocity_max = Y_VELOCITY_MAX, + .feedrate_max = Y_FEEDRATE_MAX, + .travel_min = Y_TRAVEL_MIN, + .travel_max = Y_TRAVEL_MAX, + .jerk_max = Y_JERK_MAX, + .jerk_homing = Y_JERK_HOMING, + .junction_dev = Y_JUNCTION_DEVIATION, + .search_velocity = Y_SEARCH_VELOCITY, + .latch_velocity = Y_LATCH_VELOCITY, + .latch_backoff = Y_LATCH_BACKOFF, + .zero_backoff = Y_ZERO_BACKOFF, + }, { + .axis_mode = Z_AXIS_MODE, + .velocity_max = Z_VELOCITY_MAX, + .feedrate_max = Z_FEEDRATE_MAX, + .travel_min = Z_TRAVEL_MIN, + .travel_max = Z_TRAVEL_MAX, + .jerk_max = Z_JERK_MAX, + .jerk_homing = Z_JERK_HOMING, + .junction_dev = Z_JUNCTION_DEVIATION, + .search_velocity = Z_SEARCH_VELOCITY, + .latch_velocity = Z_LATCH_VELOCITY, + .latch_backoff = Z_LATCH_BACKOFF, + .zero_backoff = Z_ZERO_BACKOFF, + }, { + .axis_mode = A_AXIS_MODE, + .velocity_max = A_VELOCITY_MAX, + .feedrate_max = A_FEEDRATE_MAX, + .travel_min = A_TRAVEL_MIN, + .travel_max = A_TRAVEL_MAX, + .jerk_max = A_JERK_MAX, + .jerk_homing = A_JERK_HOMING, + .junction_dev = A_JUNCTION_DEVIATION, + .radius = A_RADIUS, + .search_velocity = A_SEARCH_VELOCITY, + .latch_velocity = A_LATCH_VELOCITY, + .latch_backoff = A_LATCH_BACKOFF, + .zero_backoff = A_ZERO_BACKOFF, + }, { + .axis_mode = B_AXIS_MODE, + .velocity_max = B_VELOCITY_MAX, + .feedrate_max = B_FEEDRATE_MAX, + .travel_min = B_TRAVEL_MIN, + .travel_max = B_TRAVEL_MAX, + .jerk_max = B_JERK_MAX, + .junction_dev = B_JUNCTION_DEVIATION, + .radius = B_RADIUS, + }, { + .axis_mode = C_AXIS_MODE, + .velocity_max = C_VELOCITY_MAX, + .feedrate_max = C_FEEDRATE_MAX, + .travel_min = C_TRAVEL_MIN, + .travel_max = C_TRAVEL_MAX, + .jerk_max = C_JERK_MAX, + .junction_dev = C_JUNCTION_DEVIATION, + .radius = C_RADIUS, + } + }, + + .combined_state = COMBINED_READY, + .machine_state = MACHINE_READY, + + // State + .gm = {.motion_mode = MOTION_MODE_CANCEL_MOTION_MODE}, + .gn = {0}, + .gf = {0}, +}; + + +// Command execution callbacks from planner queue +static void _exec_offset(float *value, float *flag); +static void _exec_change_tool(float *value, float *flag); +static void _exec_select_tool(float *value, float *flag); +static void _exec_mist_coolant_control(float *value, float *flag); +static void _exec_flood_coolant_control(float *value, float *flag); +static void _exec_absolute_origin(float *value, float *flag); +static void _exec_program_finalize(float *value, float *flag); + +// Machine State functions + +/// Combines raw states into something a user might want to see +cmCombinedState_t cm_get_combined_state() { + if (cm.cycle_state == CYCLE_OFF) cm.combined_state = cm.machine_state; + else if (cm.cycle_state == CYCLE_PROBE) cm.combined_state = COMBINED_PROBE; + else if (cm.cycle_state == CYCLE_HOMING) cm.combined_state = COMBINED_HOMING; + else { + if (cm.motion_state == MOTION_RUN) cm.combined_state = COMBINED_RUN; + if (cm.motion_state == MOTION_HOLD) cm.combined_state = COMBINED_HOLD; + } + + if (cm.machine_state == MACHINE_SHUTDOWN) + cm.combined_state = COMBINED_SHUTDOWN; + + return cm.combined_state; +} + +uint32_t cm_get_line() {return cm.gm.line;} +cmMachineState_t cm_get_machine_state() {return cm.machine_state;} +cmCycleState_t cm_get_cycle_state() {return cm.cycle_state;} +cmMotionState_t cm_get_motion_state() {return cm.motion_state;} +cmFeedholdState_t cm_get_hold_state() {return cm.hold_state;} +cmHomingState_t cm_get_homing_state() {return cm.homing_state;} +cmMotionMode_t cm_get_motion_mode() {return cm.gm.motion_mode;} +cmCoordSystem_t cm_get_coord_system() {return cm.gm.coord_system;} +cmUnitsMode_t cm_get_units_mode() {return cm.gm.units_mode;} +cmPlane_t cm_get_select_plane() {return cm.gm.select_plane;} +cmPathControlMode_t cm_get_path_control() {return cm.gm.path_control;} +cmDistanceMode_t cm_get_distance_mode() {return cm.gm.distance_mode;} +cmFeedRateMode_t cm_get_feed_rate_mode() {return cm.gm.feed_rate_mode;} +uint8_t cm_get_tool() {return cm.gm.tool;} +cmSpindleMode_t cm_get_spindle_mode() {return cm.gm.spindle_mode;} +bool cm_get_runtime_busy() {return mp_get_runtime_busy();} +float cm_get_feed_rate() {return cm.gm.feed_rate;} + + +void cm_set_machine_state(cmMachineState_t machine_state) { + cm.machine_state = machine_state; +} + + +void cm_set_motion_state(cmMotionState_t motion_state) { + cm.motion_state = motion_state; +} + + +void cm_set_motion_mode(cmMotionMode_t motion_mode) { + cm.gm.motion_mode = motion_mode; +} + + +void cm_set_spindle_mode(cmSpindleMode_t spindle_mode) { + cm.gm.spindle_mode = spindle_mode; +} + + +void cm_set_spindle_speed_parameter(float speed) {cm.gm.spindle_speed = speed;} +void cm_set_tool_number(uint8_t tool) {cm.gm.tool = tool;} + + +void cm_set_absolute_override(bool absolute_override) { + cm.gm.absolute_override = absolute_override; + // must reset offsets if you change absolute override + cm_set_work_offsets(); +} + + +void cm_set_model_line(uint32_t line) {cm.gm.line = line;} + + +/* Jerk functions + * + * Jerk values can be rather large, often in the billions. This makes + * for some pretty big numbers for people to deal with. Jerk values + * are stored in the system in truncated format; values are divided by + * 1,000,000 then reconstituted before use. + * + * The axis_jerk() functions expect the jerk in divided-by 1,000,000 form + */ + +/// returns jerk for an axis +float cm_get_axis_jerk(uint8_t axis) { + return cm.a[axis].jerk_max; +} + + +/// sets the jerk for an axis, including recirpcal and cached values +void cm_set_axis_jerk(uint8_t axis, float jerk) { + cm.a[axis].jerk_max = jerk; + cm.a[axis].recip_jerk = 1 / (jerk * JERK_MULTIPLIER); +} + + +/* Coordinate systems and offsets + * + * Functions to get, set and report coordinate systems and work offsets + * These functions are not part of the NIST defined functions + */ +/* + * Notes on Coordinate System and Offset functions + * + * All positional information in the machine is kept as + * absolute coords and in canonical units (mm). The offsets are only + * used to translate in and out of canonical form during + * interpretation and response. + * + * Managing the coordinate systems & offsets is somewhat complicated. + * The following affect offsets: + * - coordinate system selected. 1-9 correspond to G54-G59 + * - absolute override: forces current move to be interpreted in machine + * coordinates: G53 (system 0) + * - G92 offsets are added "on top of" the coord system offsets -- + * if origin_offset_enable + * - G28 and G30 moves; these are run in absolute coordinates + * + * The offsets themselves are considered static, are kept in cm, and are + * supposed to be persistent. + * + * To reduce complexity and data load the following is done: + * - Full data for coordinates/offsets is only accessible by the + * machine, not the downstream + * - Resolved set of coord and G92 offsets, with per-move exceptions can + * be captured as "work_offsets" + * - The core gcode context (gm) only knows about the active coord system + * and the work offsets + */ + +/* Return the currently active coordinate offset for an axis + * + * Takes G5x, G92 and absolute override into account to return the + * active offset for this move + * + * This function is typically used to evaluate and set offsets, as + * opposed to cm_get_work_offset() which merely returns what's in the + * work_offset[] array. + */ +float cm_get_active_coord_offset(uint8_t axis) { + if (cm.gm.absolute_override) return 0; // no offset in absolute override mode + float offset = cm.offset[cm.gm.coord_system][axis]; + + if (cm.origin_offset_enable) + offset += cm.origin_offset[axis]; // includes G5x and G92 components + + return offset; +} + + +/// Return a coord offset +float cm_get_work_offset(uint8_t axis) { + return cm.ms.work_offset[axis]; +} + + +// Capture coord offsets from the model into absolute values +void cm_set_work_offsets() { + for (int axis = 0; axis < AXES; axis++) + cm.ms.work_offset[axis] = cm_get_active_coord_offset(axis); +} + + +/* Get position of axis in absolute coordinates + * + * NOTE: Machine position is always returned in mm mode. No units conversion + * is performed + */ +float cm_get_absolute_position(uint8_t axis) { + return cm.position[axis]; +} + + +/* Return work position in prevailing units (mm/inch) and with all offsets + * applied. + * + * NOTE: This function only works after the gcode_state struct has had the + * work_offsets setup by calling cm_get_model_coord_offset_vector() first. + */ +float cm_get_work_position(uint8_t axis) { + float position = cm.position[axis] - cm_get_active_coord_offset(axis); + + if (cm.gm.units_mode == INCHES) position /= MM_PER_INCH; + + return position; +} + + +/* Critical helpers + * + * Core functions supporting the machining functions + * These functions are not part of the NIST defined functions + */ + +/* Perform final operations for a traverse or feed + * + * These routines set the point position in the gcode model. + * + * Note: As far as the machine is concerned the final + * position of a Gcode block (move) is achieved as soon as the move is + * planned and the move target becomes the new model position. In + * reality the planner will (in all likelihood) have only just queued + * the move for later execution, and the real tool position is still + * close to the starting point. + */ +void cm_finalize_move() { + copy_vector(cm.position, cm.ms.target); // update model position + + // if in ivnerse time mode reset feed rate so next block requires an + // explicit feed rate setting + if (cm.gm.feed_rate_mode == INVERSE_TIME_MODE && + cm.gm.motion_mode == MOTION_MODE_STRAIGHT_FEED) + cm.gm.feed_rate = 0; +} + + +/* Compute optimal and minimum move times into the gcode_state + * + * "Minimum time" is the fastest the move can be performed given + * the velocity constraints on each participating axis - regardless + * of the feed rate requested. The minimum time is the time limited + * by the rate-limiting axis. The minimum time is needed to compute + * the optimal time and is recorded for possible feed override + * computation. + * + * "Optimal time" is either the time resulting from the requested + * feed rate or the minimum time if the requested feed rate is not + * achievable. Optimal times for traverses are always the minimum + * time. + * + * The gcode state must have targets set prior by having + * cm_set_target(). Axis modes are taken into account by this. + * + * The following times are compared and the longest is returned: + * - G93 inverse time (if G93 is active) + * - time for coordinated move at requested feed rate + * - time that the slowest axis would require for the move + * + * Sets the following variables in the gcode_state struct + * - move_time is set to optimal time + * + * NIST RS274NGC_v3 Guidance + * + * The following is verbatim text from NIST RS274NGC_v3. As I + * interpret A for moves that combine both linear and rotational + * movement, the feed rate should apply to the XYZ movement, with + * the rotational axis (or axes) timed to start and end at the same + * time the linear move is performed. It is possible under this + * case for the rotational move to rate-limit the linear move. + * + * 2.1.2.5 Feed Rate + * + * The rate at which the controlled point or the axes move is + * nominally a steady rate which may be set by the user. In the + * Interpreter, the interpretation of the feed rate is as follows + * unless inverse time feed rate mode is being used in the + * RS274/NGC view (see Section 3.5.19). The machining + * functions view of feed rate, as described in Section 4.3.5.1, + * has conditions under which the set feed rate is applied + * differently, but none of these is used in the Interpreter. + * + * A. For motion involving one or more of the X, Y, and Z axes + * (with or without simultaneous rotational axis motion), the + * feed rate means length units per minute along the programmed + * XYZ path, as if the rotational axes were not moving. + * + * B. For motion of one rotational axis with X, Y, and Z axes not + * moving, the feed rate means degrees per minute rotation of + * the rotational axis. + * + * C. For motion of two or three rotational axes with X, Y, and Z + * axes not moving, the rate is applied as follows. Let dA, dB, + * and dC be the angles in degrees through which the A, B, and + * C axes, respectively, must move. Let D = sqrt(dA^2 + dB^2 + + * dC^2). Conceptually, D is a measure of total angular motion, + * using the usual Euclidean metric. Let T be the amount of + * time required to move through D degrees at the current feed + * rate in degrees per minute. The rotational axes should be + * moved in coordinated linear motion so that the elapsed time + * from the start to the end of the motion is T plus any time + * required for acceleration or deceleration. + */ +void cm_calc_move_time(const float axis_length[], const float axis_square[]) { + float inv_time = 0; // inverse time if doing a feed in G93 mode + float xyz_time = 0; // linear coordinated move at requested feed + float abc_time = 0; // rotary coordinated move at requested feed + float max_time = 0; // time required for the rate-limiting axis + float tmp_time = 0; // used in computation + + // compute times for feed motion + if (cm.gm.motion_mode != MOTION_MODE_STRAIGHT_TRAVERSE) { + if (cm.gm.feed_rate_mode == INVERSE_TIME_MODE) { + // feed rate was un-inverted to minutes by cm_set_feed_rate() + inv_time = cm.gm.feed_rate; + cm.gm.feed_rate_mode = UNITS_PER_MINUTE_MODE; + + } else { + // compute length of linear move in millimeters. Feed rate is provided as + // mm/min + xyz_time = sqrt(axis_square[AXIS_X] + axis_square[AXIS_Y] + + axis_square[AXIS_Z]) / cm.gm.feed_rate; + + // if no linear axes, compute length of multi-axis rotary move in degrees. + // Feed rate is provided as degrees/min + if (fp_ZERO(xyz_time)) + abc_time = sqrt(axis_square[AXIS_A] + axis_square[AXIS_B] + + axis_square[AXIS_C]) / cm.gm.feed_rate; + } + } + + for (uint8_t axis = 0; axis < AXES; axis++) { + if (cm.gm.motion_mode == MOTION_MODE_STRAIGHT_TRAVERSE) + tmp_time = fabs(axis_length[axis]) / cm.a[axis].velocity_max; + + else // MOTION_MODE_STRAIGHT_FEED + tmp_time = fabs(axis_length[axis]) / cm.a[axis].feedrate_max; + + max_time = max(max_time, tmp_time); + } + + cm.ms.move_time = max4(inv_time, max_time, xyz_time, abc_time); +} + + +/// Set endpoint position from final runtime position +void cm_update_model_position_from_runtime() { + copy_vector(cm.position, mr.ms.target); +} + + +/* Set target vector in GM model + * + * This is a core routine. It handles: + * - conversion of linear units to internal canonical form (mm) + * - conversion of relative mode to absolute (internal canonical form) + * - translation of work coordinates to machine coordinates (internal + * canonical form) + * - computation and application of axis modes as so: + * + * DISABLED - Incoming value is ignored. Target value is not changed + * ENABLED - Convert axis values to canonical format and store as target + * INHIBITED - Same processing as ENABLED, but axis will not actually be run + * RADIUS - ABC axis value is provided in Gcode block in linear units + * - Target is set to degrees based on axis' Radius value + * - Radius mode is only processed for ABC axes. Application to + * XYZ is ignored. + * + * Target coordinates are provided in target[] + * Axes that need processing are signaled in flag[] + */ + +// ESTEE: _calc_ABC is a fix to workaround a gcc compiler bug wherein it runs +// out of spill registers we moved this block into its own function so that we +// get a fresh stack push +// ALDEN: This shows up in avr-gcc 4.7.0 and avr-libc 1.8.0 +static float _calc_ABC(uint8_t axis, float target[], float flag[]) { + if (cm.a[axis].axis_mode == AXIS_STANDARD || + cm.a[axis].axis_mode == AXIS_INHIBITED) + return target[axis]; // no mm conversion - it's in degrees + + return TO_MILLIMETERS(target[axis]) * 360 / (2 * M_PI * cm.a[axis].radius); +} + + +void cm_set_model_target(float target[], float flag[]) { + float tmp = 0; + + // process XYZABC for lower modes + for (int axis = AXIS_X; axis <= AXIS_Z; axis++) { + if (fp_FALSE(flag[axis]) || cm.a[axis].axis_mode == AXIS_DISABLED) + continue; // skip axis if not flagged for update or its disabled + + else if (cm.a[axis].axis_mode == AXIS_STANDARD || + cm.a[axis].axis_mode == AXIS_INHIBITED) { + if (cm.gm.distance_mode == ABSOLUTE_MODE) + cm.ms.target[axis] = + cm_get_active_coord_offset(axis) + TO_MILLIMETERS(target[axis]); + else cm.ms.target[axis] += TO_MILLIMETERS(target[axis]); + } + } + + // FYI: The ABC loop below relies on the XYZ loop having been run first + for (int axis = AXIS_A; axis <= AXIS_C; axis++) { + if (fp_FALSE(flag[axis]) || cm.a[axis].axis_mode == AXIS_DISABLED) + continue; // skip axis if not flagged for update or its disabled + else tmp = _calc_ABC(axis, target, flag); + + if (cm.gm.distance_mode == ABSOLUTE_MODE) + // sacidu93's fix to Issue #22 + cm.ms.target[axis] = tmp + cm_get_active_coord_offset(axis); + else cm.ms.target[axis] += tmp; + } +} + + +/* Return error code if soft limit is exceeded + * + * Must be called with target properly set in GM struct. Best done + * after cm_set_model_target(). + * + * Tests for soft limit for any homed axis if min and max are + * different values. You can set min and max to 0,0 to disable soft + * limits for an axis. Also will not test a min or a max if the value + * is < -1000000 (negative one million). This allows a single end to + * be tested w/the other disabled, should that requirement ever arise. + */ +stat_t cm_test_soft_limits(float target[]) { +#ifdef SOFT_LIMIT_ENABLE + for (int axis = 0; axis < AXES; axis++) { + if (!cm.homed[axis]) continue; // don't test axes that are not homed + + if (fp_EQ(cm.a[axis].travel_min, cm.a[axis].travel_max)) continue; + + if (cm.a[axis].travel_min > DISABLE_SOFT_LIMIT && + target[axis] < cm.a[axis].travel_min) + return STAT_SOFT_LIMIT_EXCEEDED; + + if (cm.a[axis].travel_max > DISABLE_SOFT_LIMIT && + target[axis] > cm.a[axis].travel_max) + return STAT_SOFT_LIMIT_EXCEEDED; + } +#endif + + return STAT_OK; +} + + +/* machining functions + * Values are passed in pre-unit_converted state (from gn structure) + * All operations occur on gm (current model state) + * + * These are organized by section number (x.x.x) in the order they are + * found in NIST RS274 NGCv3 + */ + +// Initialization and Termination (4.3.2) + +void machine_init() { + // Init 1/jerk + for (uint8_t axis = 0; axis < AXES; axis++) + cm.a[axis].recip_jerk = 1 / (cm.a[axis].jerk_max * JERK_MULTIPLIER); + + // Set gcode defaults + cm_set_units_mode(GCODE_DEFAULT_UNITS); + cm_set_coord_system(GCODE_DEFAULT_COORD_SYSTEM); + cm_set_plane(GCODE_DEFAULT_PLANE); + cm_set_path_control(GCODE_DEFAULT_PATH_CONTROL); + cm_set_distance_mode(GCODE_DEFAULT_DISTANCE_MODE); + cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE); // always the default + + // Sub-system inits + cm_spindle_init(); + coolant_init(); +} + + +/// Alarm state; send an exception report and stop processing input +stat_t cm_alarm(const char *location, stat_t code) { + status_message_P(location, STAT_LEVEL_ERROR, code, "ALARM"); + estop_trigger(); + return code; +} + + +/// Clear soft alarm +stat_t cm_clear() { + if (cm.cycle_state == CYCLE_OFF) + cm.machine_state = MACHINE_PROGRAM_STOP; + else cm.machine_state = MACHINE_CYCLE; + + return STAT_OK; +} + + +// Representation (4.3.3) +// +// Affect the Gcode model only (asynchronous) +// These functions assume input validation occurred upstream. + +/// G17, G18, G19 select axis plane +void cm_set_plane(cmPlane_t plane) {cm.gm.select_plane = plane;} + + +/// G20, G21 +void cm_set_units_mode(cmUnitsMode_t mode) {cm.gm.units_mode = mode;} + + +/// G90, G91 +void cm_set_distance_mode(cmDistanceMode_t mode) {cm.gm.distance_mode = mode;} + + +/* G10 L2 Pn, delayed persistence + * + * This function applies the offset to the GM model. You can also + * use $g54x - $g59c config functions to change offsets. + * + * It also does not reset the work_offsets which may be + * accomplished by calling cm_set_work_offsets() immediately + * afterwards. + */ +void cm_set_coord_offsets(cmCoordSystem_t coord_system, float offset[], + float flag[]) { + if (coord_system < G54 || coord_system > COORD_SYSTEM_MAX) + return; // you can't set G53 + + for (int axis = 0; axis < AXES; axis++) + if (fp_TRUE(flag[axis])) + cm.offset[coord_system][axis] = TO_MILLIMETERS(offset[axis]); +} + + +// Representation functions that affect gcode model and are queued to planner +// (synchronous) + +/// G54-G59 +void cm_set_coord_system(cmCoordSystem_t coord_system) { + cm.gm.coord_system = coord_system; + + // pass coordinate system in value[0] element + float value[AXES] = {coord_system}; + // second vector (flags) is not used, so fake it + mp_queue_command(_exec_offset, value, value); +} + + +static void _exec_offset(float *value, float *flag) { + // coordinate system is passed in value[0] element + uint8_t coord_system = value[0]; + float offsets[AXES]; + + for (int axis = 0; axis < AXES; axis++) + offsets[axis] = cm.offset[coord_system][axis] + + cm.origin_offset[axis] * (cm.origin_offset_enable ? 1 : 0); + + mp_set_runtime_work_offset(offsets); + cm_set_work_offsets(); // set work offsets in the Gcode model +} + + +/* Set the position of a single axis in the model, planner and runtime + * + * This command sets an axis/axes to a position provided as an argument. + * This is useful for setting origins for homing, probing, and other operations. + * + * !!!!! DO NOT CALL THIS FUNCTION WHILE IN A MACHINING CYCLE !!!!! + * + * More specifically, do not call this function if there are any moves + * in the planner or if the runtime is moving. The system must be + * quiescent or you will introduce positional errors. This is true + * because the planned / running moves have a different reference + * frame than the one you are now going to set. These functions should + * only be called during initialization sequences and during cycles + * (such as homing cycles) when you know there are no more moves in + * the planner and that all motion has stopped. Use + * cm_get_runtime_busy() to be sure the system is quiescent. + */ +void cm_set_position(int axis, float position) { + // TODO: Interlock involving runtime_busy test + cm.position[axis] = position; + cm.ms.target[axis] = position; + mp_set_planner_position(axis, position); + mp_set_runtime_position(axis, position); + mp_set_steps_to_runtime_position(); +} + + +// G28.3 functions and support + +/* G28.3 - model, planner and queue to runtime + * + * Takes a vector of origins (presumably 0's, but not necessarily) and + * applies them to all axes where the corresponding position in the + * flag vector is true (1). + * + * This is a 2 step process. The model and planner contexts are set + * immediately, the runtime command is queued and synchronized with + * the planner queue. This includes the runtime position and the step + * recording done by the encoders. At that point any axis that is set + * is also marked as homed. + */ +void cm_set_absolute_origin(float origin[], float flag[]) { + float value[AXES]; + + for (int axis = 0; axis < AXES; axis++) + if (fp_TRUE(flag[axis])) { + value[axis] = TO_MILLIMETERS(origin[axis]); + cm.position[axis] = value[axis]; // set model position + cm.ms.target[axis] = value[axis]; // reset model target + mp_set_planner_position(axis, value[axis]); // set mm position + } + + mp_queue_command(_exec_absolute_origin, value, flag); +} + + +static void _exec_absolute_origin(float *value, float *flag) { + for (int axis = 0; axis < AXES; axis++) + if (fp_TRUE(flag[axis])) { + mp_set_runtime_position(axis, value[axis]); + cm.homed[axis] = true; // G28.3 is not considered homed until here + } + + mp_set_steps_to_runtime_position(); +} + + +/* G92's behave according to NIST 3.5.18 & LinuxCNC G92 + * http://linuxcnc.org/docs/html/gcode/gcode.html#sec:G92-G92.1-G92.2-G92.3 + */ + +/// G92 +void cm_set_origin_offsets(float offset[], float flag[]) { + // set offsets in the Gcode model extended context + cm.origin_offset_enable = true; + for (int axis = 0; axis < AXES; axis++) + if (fp_TRUE(flag[axis])) + cm.origin_offset[axis] = cm.position[axis] - + cm.offset[cm.gm.coord_system][axis] - TO_MILLIMETERS(offset[axis]); + + // now pass the offset to the callback - setting the coordinate system also + // applies the offsets + // pass coordinate system in value[0] element + float value[AXES] = {cm.gm.coord_system}; + mp_queue_command(_exec_offset, value, value); // second vector is not used +} + + +/// G92.1 +void cm_reset_origin_offsets() { + cm.origin_offset_enable = false; + for (int axis = 0; axis < AXES; axis++) + cm.origin_offset[axis] = 0; + + float value[AXES] = {cm.gm.coord_system}; + mp_queue_command(_exec_offset, value, value); +} + + +/// G92.2 +void cm_suspend_origin_offsets() { + cm.origin_offset_enable = false; + float value[AXES] = {cm.gm.coord_system}; + mp_queue_command(_exec_offset, value, value); +} + + +/// G92.3 +void cm_resume_origin_offsets() { + cm.origin_offset_enable = true; + float value[AXES] = {cm.gm.coord_system}; + mp_queue_command(_exec_offset, value, value); +} + + +// Free Space Motion (4.3.4) + +/// G0 linear rapid +stat_t cm_straight_traverse(float target[], float flags[]) { + cm.gm.motion_mode = MOTION_MODE_STRAIGHT_TRAVERSE; + cm_set_model_target(target, flags); + + // test soft limits + stat_t status = cm_test_soft_limits(cm.ms.target); + if (status != STAT_OK) return CM_ALARM(status); + + // prep and plan the move + cm_set_work_offsets(&cm.gm); // capture fully resolved offsets to the state + cm_cycle_start(); // required for homing & other cycles + cm.ms.line = cm.gm.line; // copy line number + mp_aline(&cm.ms); // send the move to the planner + cm_finalize_move(); + + return STAT_OK; +} + + +/// G28.1 +void cm_set_g28_position() {copy_vector(cm.g28_position, cm.position);} + + +/// G28 +stat_t cm_goto_g28_position(float target[], float flags[]) { + cm_set_absolute_override(true); + + // move through intermediate point, or skip + cm_straight_traverse(target, flags); + + // make sure you have an available buffer + mp_wait_for_buffer(); + + // execute actual stored move + float f[] = {1, 1, 1, 1, 1, 1}; + return cm_straight_traverse(cm.g28_position, f); +} + + +/// G30.1 +void cm_set_g30_position() {copy_vector(cm.g30_position, cm.position);} + + +/// G30 +stat_t cm_goto_g30_position(float target[], float flags[]) { + cm_set_absolute_override(true); + + // move through intermediate point, or skip + cm_straight_traverse(target, flags); + + // make sure you have an available buffer + mp_wait_for_buffer(); + + // execute actual stored move + float f[] = {1, 1, 1, 1, 1, 1}; + return cm_straight_traverse(cm.g30_position, f); +} + + +// Machining Attributes (4.3.5) + +/// F parameter +/// Normalize feed rate to mm/min or to minutes if in inverse time mode +void cm_set_feed_rate(float feed_rate) { + if (cm.gm.feed_rate_mode == INVERSE_TIME_MODE) + // normalize to minutes (active for this gcode block only) + cm.gm.feed_rate = 1 / feed_rate; + + else cm.gm.feed_rate = TO_MILLIMETERS(feed_rate); +} + + +/// G93, G94 See cmFeedRateMode +void cm_set_feed_rate_mode(cmFeedRateMode_t mode) {cm.gm.feed_rate_mode = mode;} + + +/// G61, G61.1, G64 +void cm_set_path_control(cmPathControlMode_t mode) {cm.gm.path_control = mode;} + + +// Machining Functions (4.3.6) See arc.c + +/// G4, P parameter (seconds) +stat_t cm_dwell(float seconds) { + return mp_dwell(seconds); +} + + +/// G1 +stat_t cm_straight_feed(float target[], float flags[]) { + // trap zero feed rate condition + if (cm.gm.feed_rate_mode != INVERSE_TIME_MODE && fp_ZERO(cm.gm.feed_rate)) + return STAT_GCODE_FEEDRATE_NOT_SPECIFIED; + + cm.gm.motion_mode = MOTION_MODE_STRAIGHT_FEED; + cm_set_model_target(target, flags); + + // test soft limits + stat_t status = cm_test_soft_limits(cm.ms.target); + if (status != STAT_OK) return CM_ALARM(status); + + // prep and plan the move + cm_set_work_offsets(&cm.gm); // capture the fully resolved offsets to state + cm_cycle_start(); // required for homing & other cycles + cm.ms.line = cm.gm.line; // copy line number + status = mp_aline(&cm.ms); // send the move to the planner + cm_finalize_move(); + + return status; +} + + +// Spindle Functions (4.3.7) see spindle.c, spindle.h + +/* Tool Functions (4.3.8) + * + * Note: These functions don't actually do anything for now, and there's a bug + * where T and M in different blocks don't work correctly + */ + +/// T parameter +void cm_select_tool(uint8_t tool_select) { + float value[AXES] = {tool_select}; + mp_queue_command(_exec_select_tool, value, value); +} + + +static void _exec_select_tool(float *value, float *flag) { + cm.gm.tool_select = value[0]; +} + + +/// M6 This might become a complete tool change cycle +void cm_change_tool(uint8_t tool_change) { + float value[AXES] = {cm.gm.tool_select}; + mp_queue_command(_exec_change_tool, value, value); +} + + +static void _exec_change_tool(float *value, float *flag) { + cm.gm.tool = (uint8_t)value[0]; +} + + +// Miscellaneous Functions (4.3.9) +/// M7 +void cm_mist_coolant_control(bool mist_coolant) { + float value[AXES] = {mist_coolant}; + mp_queue_command(_exec_mist_coolant_control, value, value); +} + + +static void _exec_mist_coolant_control(float *value, float *flag) { + coolant_set_mist(cm.gm.mist_coolant = value[0]); +} + + +/// M8, M9 +void cm_flood_coolant_control(bool flood_coolant) { + float value[AXES] = {flood_coolant}; + mp_queue_command(_exec_flood_coolant_control, value, value); +} + + +static void _exec_flood_coolant_control(float *value, float *flag) { + cm.gm.flood_coolant = value[0]; + + coolant_set_flood(value[0]); + if (!value[0]) coolant_set_mist(false); // M9 special function +} + + +/* Override enables are kind of a mess in Gcode. This is an attempt to sort + * them out. See + * http://www.linuxcnc.org/docs/2.4/html/gcode_main.html#sec:M50:-Feed-Override + */ + +/// M48, M49 +void cm_override_enables(bool flag) { + cm.gm.feed_rate_override_enable = flag; + cm.gm.traverse_override_enable = flag; + cm.gm.spindle_override_enable = flag; +} + + +/// M50 +void cm_feed_rate_override_enable(bool flag) { + if (fp_TRUE(cm.gf.parameter) && fp_ZERO(cm.gn.parameter)) + cm.gm.feed_rate_override_enable = false; + else cm.gm.feed_rate_override_enable = true; +} + + +/// M50.1 +void cm_feed_rate_override_factor(bool flag) { + cm.gm.feed_rate_override_enable = flag; + cm.gm.feed_rate_override_factor = cm.gn.parameter; +} + + +/// M50.2 +void cm_traverse_override_enable(bool flag) { + if (fp_TRUE(cm.gf.parameter) && fp_ZERO(cm.gn.parameter)) + cm.gm.traverse_override_enable = false; + else cm.gm.traverse_override_enable = true; +} + + +/// M51 +void cm_traverse_override_factor(bool flag) { + cm.gm.traverse_override_enable = flag; + cm.gm.traverse_override_factor = cm.gn.parameter; +} + + +/// M51.1 +void cm_spindle_override_enable(bool flag) { + if (fp_TRUE(cm.gf.parameter) && fp_ZERO(cm.gn.parameter)) + cm.gm.spindle_override_enable = false; + else cm.gm.spindle_override_enable = true; +} + + +/// M50.1 +void cm_spindle_override_factor(bool flag) { + cm.gm.spindle_override_enable = flag; + cm.gm.spindle_override_factor = cm.gn.parameter; +} + + +void cm_message(const char *message) { + status_message_P(0, STAT_LEVEL_INFO, STAT_OK, PSTR("%s"), message); +} + + +/* Program Functions (4.3.10) + * + * This group implements stop, start, end, and hold. + * It is extended beyond the NIST spec to handle various situations. + * + * cm_program_stop and cm_optional_program_stop are synchronous Gcode + * commands that are received through the interpreter. They cause all motion + * to stop at the end of the current command, including spindle motion. + * + * Note that the stop occurs at the end of the immediately preceding command + * (i.e. the stop is queued behind the last command). + * + * cm_program_end is a stop that also resets the machine to initial state + */ + +/* Feedholds, queue flushes and cycles starts are all related. The request + * functions set flags for these. The sequencing callback interprets the flags + * according to the following rules: + * + * A feedhold request received during motion should be honored + * A feedhold request received during a feedhold should be ignored and reset + * A feedhold request received during a motion stop should be ignored and + * reset + * + * A queue flush request received during motion should be ignored but not + * reset + * A queue flush request received during a feedhold should be deferred until + * the feedhold enters a HOLD state (i.e. until deceleration is complete) + * A queue flush request received during a motion stop should be honored + * + * A cycle start request received during motion should be ignored and reset + * A cycle start request received during a feedhold should be deferred until + * the feedhold enters a HOLD state (i.e. until deceleration is complete) + * If a queue flush request is also present the queue flush should be done + * first + * A cycle start request received during a motion stop should be honored and + * should start to run anything in the planner queue + */ + + +/// Initiate a feedhold right now +void cm_request_feedhold() {cm.feedhold_requested = true;} +void cm_request_queue_flush() {cm.queue_flush_requested = true;} +void cm_request_cycle_start() {cm.cycle_start_requested = true;} + + +/// Process feedholds, cycle starts & queue flushes +void cm_feedhold_callback() { + if (cm.feedhold_requested) { + if (cm.motion_state == MOTION_RUN && cm.hold_state == FEEDHOLD_OFF) { + cm_set_motion_state(MOTION_HOLD); + cm.hold_state = FEEDHOLD_SYNC; // invokes hold from aline execution + } + + cm.feedhold_requested = false; + } + + if (cm.queue_flush_requested) { + if ((cm.motion_state == MOTION_STOP || + (cm.motion_state == MOTION_HOLD && cm.hold_state == FEEDHOLD_HOLD)) && + !cm_get_runtime_busy()) { + cm.queue_flush_requested = false; + cm_queue_flush(); + } + } + + bool processing = + cm.hold_state == FEEDHOLD_SYNC || + cm.hold_state == FEEDHOLD_PLAN || + cm.hold_state == FEEDHOLD_DECEL; + + if (cm.cycle_start_requested && !cm.queue_flush_requested && !processing) { + cm.cycle_start_requested = false; + cm.hold_state = FEEDHOLD_END_HOLD; + cm_cycle_start(); + mp_end_hold(); + } + + mp_plan_hold_callback(); +} + + +stat_t cm_queue_flush() { + if (cm_get_runtime_busy()) return STAT_COMMAND_NOT_ACCEPTED; + + mp_flush_planner(); // flush planner queue + + // Note: The following uses low-level mp calls for absolute position. + for (int axis = 0; axis < AXES; axis++) + // set mm from mr + cm_set_position(axis, mp_get_runtime_absolute_position(axis)); + + float value[AXES] = {MACHINE_PROGRAM_STOP}; + _exec_program_finalize(value, value); // finalize now, not later + + return STAT_OK; +} + + +/* Program and cycle state functions + * + * cm_program_end() implements M2 and M30 + * The END behaviors are defined by NIST 3.6.1 are: + * 1. Axis offsets are set to zero (like G92.2) and origin offsets are set + * to the default (like G54) + * 2. Selected plane is set to PLANE_XY (like G17) + * 3. Distance mode is set to MODE_ABSOLUTE (like G90) + * 4. Feed rate mode is set to UNITS_PER_MINUTE (like G94) + * 5. Feed and speed overrides are set to ON (like M48) + * 6. Cutter compensation is turned off (like G40) + * 7. The spindle is stopped (like M5) + * 8. The current motion mode is set to G_1 (like G1) + * 9. Coolant is turned off (like M9) + * + * cm_program_end() implments things slightly differently: + * 1. Axis offsets are set to G92.1 CANCEL offsets + * (instead of using G92.2 SUSPEND Offsets) + * Set default coordinate system (uses $gco, not G54) + * 2. Selected plane is set to default plane ($gpl) + * (instead of setting it to G54) + * 3. Distance mode is set to MODE_ABSOLUTE (like G90) + * 4. Feed rate mode is set to UNITS_PER_MINUTE (like G94) + * 5. Not implemented + * 6. Not implemented + * 7. The spindle is stopped (like M5) + * 8. Motion mode is canceled like G80 (not set to G1) + * 9. Coolant is turned off (like M9) + * + Default INCHES or MM units mode is restored ($gun) + */ +static void _exec_program_finalize(float *value, float *flag) { + cm.machine_state = (uint8_t)value[0]; + cm_set_motion_state(MOTION_STOP); + if (cm.cycle_state == CYCLE_MACHINING) + cm.cycle_state = CYCLE_OFF; // don't end cycle if homing, probing, etc. + + cm.hold_state = FEEDHOLD_OFF; // end feedhold (if in feed hold) + cm.cycle_start_requested = false; // cancel any pending cycle start request + mp_zero_segment_velocity(); // for reporting purposes + + // perform the following resets if it's a program END + if (cm.machine_state == MACHINE_PROGRAM_END) { + cm_reset_origin_offsets(); // G92.1 - we do G91.1 instead of G92.2 + cm_set_coord_system(GCODE_DEFAULT_COORD_SYSTEM); + cm_set_plane(GCODE_DEFAULT_PLANE); + cm_set_distance_mode(GCODE_DEFAULT_DISTANCE_MODE); + cm_spindle_control(SPINDLE_OFF); // M5 + cm_flood_coolant_control(false); // M9 + cm_set_feed_rate_mode(UNITS_PER_MINUTE_MODE); // G94 + cm_set_motion_mode(MOTION_MODE_CANCEL_MOTION_MODE); + } +} + + +/// Do a cycle start right now +void cm_cycle_start() { + cm.machine_state = MACHINE_CYCLE; + + // don't (re)start homing, probe or other canned cycles + if (cm.cycle_state == CYCLE_OFF) cm.cycle_state = CYCLE_MACHINING; +} + + +/// Do a cycle end right now +void cm_cycle_end() { + if (cm.cycle_state != CYCLE_OFF) { + float value[AXES] = {MACHINE_PROGRAM_STOP}; + _exec_program_finalize(value, value); + } +} + + + +/// M0 Queue a program stop +void cm_program_stop() { + float value[AXES] = {MACHINE_PROGRAM_STOP}; + mp_queue_command(_exec_program_finalize, value, value); +} + + +/// M1 +void cm_optional_program_stop() { + float value[AXES] = {MACHINE_PROGRAM_STOP}; + mp_queue_command(_exec_program_finalize, value, value); +} + + +/// M2, M30 +void cm_program_end() { + float value[AXES] = {MACHINE_PROGRAM_END}; + mp_queue_command(_exec_program_finalize, value, value); +} + + +/// return ASCII char for axis given the axis number +char cm_get_axis_char(int8_t axis) { + char axis_char[] = "XYZABC"; + if (axis < 0 || axis > AXES) return ' '; + return axis_char[axis]; +} diff --git a/src/machine.h b/src/machine.h new file mode 100644 index 0000000..300c942 --- /dev/null +++ b/src/machine.h @@ -0,0 +1,568 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2016 Buildbotics LLC + Copyright (c) 2010 - 2015 Alden S. Hart, Jr. + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + +#pragma once + + +#include "config.h" +#include "status.h" + +#include +#include + + +#define TO_MILLIMETERS(a) (cm.gm.units_mode == INCHES ? (a) * MM_PER_INCH : a) + +#define DISABLE_SOFT_LIMIT -1000000 + + + +/* Machine state model + * + * The following main variables track machine state and state + * transitions. + * - cm.machine_state - overall state of machine and program execution + * - cm.cycle_state - what cycle the machine is executing (or none) + * - cm.motion_state - state of movement + * + * Allowed states and combined states: + * + * MACHINE STATE CYCLE STATE MOTION_STATE COMBINED_STATE (FYI) + * ------------- ------------ ------------- -------------------- + * MACHINE_UNINIT na na (U) + * MACHINE_READY CYCLE_OFF MOTION_STOP (ROS) RESET-OFF-STOP + * MACHINE_PROG_STOP CYCLE_OFF MOTION_STOP (SOS) STOP-OFF-STOP + * MACHINE_PROG_END CYCLE_OFF MOTION_STOP (EOS) END-OFF-STOP + * + * MACHINE_CYCLE CYCLE_STARTED MOTION_STOP (CSS) CYCLE-START-STOP + * MACHINE_CYCLE CYCLE_STARTED MOTION_RUN (CSR) CYCLE-START-RUN + * MACHINE_CYCLE CYCLE_STARTED MOTION_HOLD (CSH) CYCLE-START-HOLD + * MACHINE_CYCLE CYCLE_STARTED MOTION_END_HOLD (CSE) CYCLE-START-END_HOLD + * + * MACHINE_CYCLE CYCLE_HOMING MOTION_STOP (CHS) CYCLE-HOMING-STOP + * MACHINE_CYCLE CYCLE_HOMING MOTION_RUN (CHR) CYCLE-HOMING-RUN + * MACHINE_CYCLE CYCLE_HOMING MOTION_HOLD (CHH) CYCLE-HOMING-HOLD + * MACHINE_CYCLE CYCLE_HOMING MOTION_END_HOLD (CHE) CYCLE-HOMING-END_HOLD + */ + +/// check alignment with messages in config.c / msg_stat strings +typedef enum { + COMBINED_INITIALIZING, // machine is initializing + COMBINED_READY, // machine is ready for use. Also null move STOP state + COMBINED_ALARM, // machine in soft alarm state + COMBINED_PROGRAM_STOP, // program stop or no more blocks + COMBINED_PROGRAM_END, // program end + COMBINED_RUN, // motion is running + COMBINED_HOLD, // motion is holding + COMBINED_PROBE, // probe cycle active + COMBINED_CYCLE, // machine is running (cycling) + COMBINED_HOMING, // homing is treated as a cycle + COMBINED_SHUTDOWN, // machine in hard alarm state (shutdown) +} cmCombinedState_t; + + +typedef enum { + MACHINE_INITIALIZING, // machine is initializing + MACHINE_READY, // machine is ready for use + MACHINE_ALARM, // machine in soft alarm state + MACHINE_PROGRAM_STOP, // program stop or no more blocks + MACHINE_PROGRAM_END, // program end + MACHINE_CYCLE, // machine is running (cycling) + MACHINE_SHUTDOWN, // machine in hard alarm state (shutdown) +} cmMachineState_t; + + +typedef enum { + CYCLE_OFF, // machine is idle + CYCLE_MACHINING, // in normal machining cycle + CYCLE_PROBE, // in probe cycle + CYCLE_HOMING, // homing is treated as a specialized cycle +} cmCycleState_t; + + +typedef enum { + MOTION_STOP, // motion has stopped + MOTION_RUN, // machine is in motion + MOTION_HOLD // feedhold in progress +} cmMotionState_t; + + +typedef enum { // feedhold_state machine + FEEDHOLD_OFF, // no feedhold in effect + FEEDHOLD_SYNC, // start hold - sync to latest aline segment + FEEDHOLD_PLAN, // replan blocks for feedhold + FEEDHOLD_DECEL, // decelerate to hold point + FEEDHOLD_HOLD, // holding + FEEDHOLD_END_HOLD // end hold (transient state to OFF) +} cmFeedholdState_t; + + +typedef enum { // applies to cm.homing_state + HOMING_NOT_HOMED, // machine is not homed (0=false) + HOMING_HOMED, // machine is homed (1=true) + HOMING_WAITING // machine waiting to be homed +} cmHomingState_t; + + +typedef enum { // applies to cm.probe_state + PROBE_FAILED, // probe reached endpoint without triggering + PROBE_SUCCEEDED, // probe was triggered, cm.probe_results has position + PROBE_WAITING, // probe is waiting to be started +} cmProbeState_t; + + +/* The difference between NextAction and MotionMode is that NextAction is + * used by the current block, and may carry non-modal commands, whereas + * MotionMode persists across blocks (as G modal group 1) + */ + +/// these are in order to optimized CASE statement +typedef enum { + NEXT_ACTION_DEFAULT, // Must be zero (invokes motion modes) + NEXT_ACTION_SEARCH_HOME, // G28.2 homing cycle + NEXT_ACTION_SET_ABSOLUTE_ORIGIN, // G28.3 origin set + NEXT_ACTION_HOMING_NO_SET, // G28.4 homing cycle no coord setting + NEXT_ACTION_SET_G28_POSITION, // G28.1 set position in abs coordinates + NEXT_ACTION_GOTO_G28_POSITION, // G28 go to machine position + NEXT_ACTION_SET_G30_POSITION, // G30.1 + NEXT_ACTION_GOTO_G30_POSITION, // G30 + NEXT_ACTION_SET_COORD_DATA, // G10 + NEXT_ACTION_SET_ORIGIN_OFFSETS, // G92 + NEXT_ACTION_RESET_ORIGIN_OFFSETS, // G92.1 + NEXT_ACTION_SUSPEND_ORIGIN_OFFSETS, // G92.2 + NEXT_ACTION_RESUME_ORIGIN_OFFSETS, // G92.3 + NEXT_ACTION_DWELL, // G4 + NEXT_ACTION_STRAIGHT_PROBE // G38.2 +} cmNextAction_t; + + +typedef enum { // G Modal Group 1 + MOTION_MODE_STRAIGHT_TRAVERSE, // G0 - straight traverse + MOTION_MODE_STRAIGHT_FEED, // G1 - straight feed + MOTION_MODE_CW_ARC, // G2 - clockwise arc feed + MOTION_MODE_CCW_ARC, // G3 - counter-clockwise arc feed + MOTION_MODE_CANCEL_MOTION_MODE, // G80 + MOTION_MODE_STRAIGHT_PROBE, // G38.2 + MOTION_MODE_CANNED_CYCLE_81, // G81 - drilling + MOTION_MODE_CANNED_CYCLE_82, // G82 - drilling with dwell + MOTION_MODE_CANNED_CYCLE_83, // G83 - peck drilling + MOTION_MODE_CANNED_CYCLE_84, // G84 - right hand tapping + MOTION_MODE_CANNED_CYCLE_85, // G85 - boring, no dwell, feed out + MOTION_MODE_CANNED_CYCLE_86, // G86 - boring, spindle stop, rapid out + MOTION_MODE_CANNED_CYCLE_87, // G87 - back boring + MOTION_MODE_CANNED_CYCLE_88, // G88 - boring, spindle stop, manual out + MOTION_MODE_CANNED_CYCLE_89, // G89 - boring, dwell, feed out +} cmMotionMode_t; + + +typedef enum { // Used for detecting gcode errors. See NIST section 3.4 + MODAL_GROUP_G0, // {G10,G28,G28.1,G92} non-modal axis commands + MODAL_GROUP_G1, // {G0,G1,G2,G3,G80} motion + MODAL_GROUP_G2, // {G17,G18,G19} plane selection + MODAL_GROUP_G3, // {G90,G91} distance mode + MODAL_GROUP_G5, // {G93,G94} feed rate mode + MODAL_GROUP_G6, // {G20,G21} units + MODAL_GROUP_G7, // {G40,G41,G42} cutter radius compensation + MODAL_GROUP_G8, // {G43,G49} tool length offset + MODAL_GROUP_G9, // {G98,G99} return mode in canned cycles + MODAL_GROUP_G12, // {G54,G55,G56,G57,G58,G59} coordinate system selection + MODAL_GROUP_G13, // {G61,G61.1,G64} path control mode + MODAL_GROUP_M4, // {M0,M1,M2,M30,M60} stopping + MODAL_GROUP_M6, // {M6} tool change + MODAL_GROUP_M7, // {M3,M4,M5} spindle turning + MODAL_GROUP_M8, // {M7,M8,M9} coolant + MODAL_GROUP_M9, // {M48,M49} speed/feed override switches +} cmModalGroup_t; + +#define MODAL_GROUP_COUNT (MODAL_GROUP_M9 + 1) + +// Note 1: Our G0 omits G4,G30,G53,G92.1,G92.2,G92.3 as these have no axis +// components to error check + +typedef enum { // plane - translates to: + // axis_0 axis_1 axis_2 + PLANE_XY, // G17 X Y Z + PLANE_XZ, // G18 X Z Y + PLANE_YZ // G19 Y Z X +} cmPlane_t; + + +typedef enum { + INCHES, // G20 + MILLIMETERS, // G21 + DEGREES // ABC axes (this value used for displays only) +} cmUnitsMode_t; + + +typedef enum { + ABSOLUTE_COORDS, // machine coordinate system + G54, // G54 coordinate system + G55, // G55 coordinate system + G56, // G56 coordinate system + G57, // G57 coordinate system + G58, // G58 coordinate system + G59 // G59 coordinate system +} cmCoordSystem_t; + +#define COORD_SYSTEM_MAX G59 // set this manually to the last one + +/// G Modal Group 13 +typedef enum { + /// G61 - hits corners but does not stop if it does not need to. + PATH_EXACT_PATH, + PATH_EXACT_STOP, // G61.1 - stops at all corners + PATH_CONTINUOUS // G64 and typically the default mode +} cmPathControlMode_t; + + +typedef enum { + ABSOLUTE_MODE, // G90 + INCREMENTAL_MODE // G91 +} cmDistanceMode_t; + + +typedef enum { + INVERSE_TIME_MODE, // G93 + UNITS_PER_MINUTE_MODE, // G94 + UNITS_PER_REVOLUTION_MODE // G95 (unimplemented) +} cmFeedRateMode_t; + + +typedef enum { + ORIGIN_OFFSET_SET, // G92 - set origin offsets + ORIGIN_OFFSET_CANCEL, // G92.1 - zero out origin offsets + ORIGIN_OFFSET_SUSPEND, // G92.2 - do not apply offsets, but preserve values + ORIGIN_OFFSET_RESUME // G92.3 - resume application of the suspended offsets +} cmOriginOffset_t; + + +typedef enum { + PROGRAM_STOP, + PROGRAM_END +} cmProgramFlow_t; + + +/// spindle state settings +typedef enum { + SPINDLE_OFF, + SPINDLE_CW, + SPINDLE_CCW +} cmSpindleMode_t; + + +/// mist and flood coolant states +typedef enum { + COOLANT_OFF, // all coolant off + COOLANT_ON, // request coolant on or indicate both coolants are on + COOLANT_MIST, // indicates mist coolant on + COOLANT_FLOOD // indicates flood coolant on +} cmCoolantState_t; + + +/// used for spindle and arc dir +typedef enum { + DIRECTION_CW, + DIRECTION_CCW +} cmDirection_t; + + +/// axis modes (ordered: see _cm_get_feed_time()) +typedef enum { + AXIS_DISABLED, // kill axis + AXIS_STANDARD, // axis in coordinated motion w/standard behaviors + AXIS_INHIBITED, // axis is computed but not activated + AXIS_RADIUS, // rotary axis calibrated to circumference + AXIS_MODE_MAX +} cmAxisMode_t; // ordering must be preserved. + + +/* Gcode model - The following GCodeModel/GCodeInput structs are used: + * + * - gm is the core Gcode model state. It keeps the internal gcode + * state model in normalized, canonical form. All values are unit + * converted (to mm) and in the machine coordinate system + * (absolute coordinate system). Gm is owned by the machine layer and + * should be accessed only through cm_ routines. + * + * - gn is used by the gcode interpreter and is re-initialized for + * each gcode block.It accepts data in the new gcode block in the + * formats present in the block (pre-normalized forms). During + * initialization some state elements are necessarily restored + * from gm. + * + * - gf is used by the gcode parser interpreter to hold flags for any + * data that has changed in gn during the parse. cm.gf.target[] + * values are also used by the machine during + * set_target(). + */ + + +typedef struct { + int32_t line; // gcode block line number + float target[AXES]; // XYZABC where the move should go + float work_offset[AXES]; // offset from work coordinate system + float move_time; // optimal time for move given axis constraints +} MoveState_t; + + +/// Gcode model state +typedef struct GCodeState { + uint32_t line; // Gcode block line number + + uint8_t tool; // Tool after T and M6 + uint8_t tool_select; // T - sets this value + + float feed_rate; // F - in mm/min or inverse time mode + cmFeedRateMode_t feed_rate_mode; + float feed_rate_override_factor; // 1.0000 x F feed rate. + bool feed_rate_override_enable; // M48, M49 + float traverse_override_factor; // 1.0000 x traverse rate + bool traverse_override_enable; + + float spindle_speed; // in RPM + cmSpindleMode_t spindle_mode; + float spindle_override_factor; // 1.0000 x S spindle speed + bool spindle_override_enable; // true = override enabled + + cmMotionMode_t motion_mode; // Group 1 modal motion + cmPlane_t select_plane; // G17, G18, G19 + cmUnitsMode_t units_mode; // G20, G21 + cmCoordSystem_t coord_system; // G54-G59 - select coordinate system 1-9 + bool absolute_override; // G53 true = move in machine coordinates + cmPathControlMode_t path_control; // G61 + cmDistanceMode_t distance_mode; // G91 + cmDistanceMode_t arc_distance_mode; // G91.1 + + bool mist_coolant; // true = mist on (M7), false = off (M9) + bool flood_coolant; // true = flood on (M8), false = off (M9) + + cmNextAction_t next_action; // handles G group 1 moves & non-modals + cmProgramFlow_t program_flow; // used only by the gcode_parser + + // unimplemented gcode parameters + // float cutter_radius; // D - cutter radius compensation (0 is off) + // float cutter_length; // H - cutter length compensation (0 is off) + + // Used for input only + float target[AXES]; // XYZABC where the move should go + bool override_enables; // feed and spindle enable + bool tool_change; // M6 tool change flag + + float parameter; // P - dwell time in sec, G10 coord select + + float arc_radius; // R - radius value in arc radius mode + float arc_offset[3]; // IJK - used by arc commands +} GCodeState_t; + + +typedef struct cmAxis { + cmAxisMode_t axis_mode; + float feedrate_max; // max velocity in mm/min or deg/min + float velocity_max; // max velocity in mm/min or deg/min + float travel_max; // max work envelope for soft limits + float travel_min; // min work envelope for soft limits + float jerk_max; // max jerk (Jm) in mm/min^3 divided by 1 million + float jerk_homing; // homing jerk (Jh) in mm/min^3 divided by 1 million + float recip_jerk; // reciprocal of current jerk value - with million + float junction_dev; // aka cornering delta + float radius; // radius in mm for rotary axis modes + float search_velocity; // homing search velocity + float latch_velocity; // homing latch velocity + float latch_backoff; // backoff from switches prior to homing latch movement + float zero_backoff; // backoff from switches for machine zero +} AxisConfig_t; + + +typedef struct cmSingleton { // struct to manage cm globals and cycles + // coordinate systems and offsets absolute (G53) + G54,G55,G56,G57,G58,G59 + float offset[COORDS + 1][AXES]; + float origin_offset[AXES]; // G92 offsets + bool origin_offset_enable; // G92 offsets enabled/disabled + + float position[AXES]; // model position (not used in gn or gf) + float g28_position[AXES]; // stored machine position for G28 + float g30_position[AXES]; // stored machine position for G30 + + // settings for axes X,Y,Z,A B,C + AxisConfig_t a[AXES]; + + cmCombinedState_t combined_state; // combination of states for display + cmMachineState_t machine_state; + cmCycleState_t cycle_state; + cmMotionState_t motion_state; + cmFeedholdState_t hold_state; // hold: feedhold sub-state machine + cmHomingState_t homing_state; // home: homing cycle sub-state machine + bool homed[AXES]; // individual axis homing flags + + cmProbeState_t probe_state; + float probe_results[AXES]; // probing results + + bool feedhold_requested; // feedhold character received + bool queue_flush_requested; // queue flush character received + bool cycle_start_requested; // cycle start character received + + // Model states + MoveState_t ms; + GCodeState_t gm; // core gcode model state + GCodeState_t gn; // gcode input values + GCodeState_t gf; // gcode input flags +} cmSingleton_t; + + +extern cmSingleton_t cm; // machine controller singleton + + +// Model state getters and setters +uint32_t cm_get_line(); +cmCombinedState_t cm_get_combined_state(); +cmMachineState_t cm_get_machine_state(); +cmCycleState_t cm_get_cycle_state(); +cmMotionState_t cm_get_motion_state(); +cmFeedholdState_t cm_get_hold_state(); +cmHomingState_t cm_get_homing_state(); +cmMotionMode_t cm_get_motion_mode(); +cmCoordSystem_t cm_get_coord_system(); +cmUnitsMode_t cm_get_units_mode(); +cmPlane_t cm_get_select_plane(); +cmPathControlMode_t cm_get_path_control(); +cmDistanceMode_t cm_get_distance_mode(); +cmFeedRateMode_t cm_get_feed_rate_mode(); +uint8_t cm_get_tool(); +cmSpindleMode_t cm_get_spindle_mode(); +bool cm_get_runtime_busy(); +float cm_get_feed_rate(); + +void cm_set_machine_state(cmMachineState_t machine_state); +void cm_set_motion_state(cmMotionState_t motion_state); +void cm_set_motion_mode(cmMotionMode_t motion_mode); +void cm_set_spindle_mode(cmSpindleMode_t spindle_mode); +void cm_set_spindle_speed_parameter(float speed); +void cm_set_tool_number(uint8_t tool); +void cm_set_absolute_override(bool absolute_override); +void cm_set_model_line(uint32_t line); + +float cm_get_axis_jerk(uint8_t axis); +void cm_set_axis_jerk(uint8_t axis, float jerk); + +// Coordinate systems and offsets +float cm_get_active_coord_offset(uint8_t axis); +float cm_get_work_offset(uint8_t axis); +void cm_set_work_offsets(); +float cm_get_absolute_position(uint8_t axis); +float cm_get_work_position(uint8_t axis); + +// Critical helpers +void cm_calc_move_time(const float axis_length[], const float axis_square[]); +void cm_update_model_position_from_runtime(); +void cm_finalize_move(); +stat_t cm_deferred_write_callback(); +void cm_set_model_target(float target[], float flag[]); +stat_t cm_test_soft_limits(float target[]); + +// machining functions defined by NIST [organized by NIST Gcode doc] + +// Initialization and termination (4.3.2) +void machine_init(); +/// enter alarm state. returns same status code +stat_t cm_alarm(const char *location, stat_t status); +stat_t cm_clear(); + +#define CM_ALARM(CODE) cm_alarm(STATUS_LOCATION, CODE) + +// Representation (4.3.3) +void cm_set_plane(cmPlane_t plane); +void cm_set_units_mode(cmUnitsMode_t mode); +void cm_set_distance_mode(cmDistanceMode_t mode); +void cm_set_coord_offsets(cmCoordSystem_t coord_system, float offset[], + float flag[]); + +void cm_set_position(int axis, float position); +void cm_set_absolute_origin(float origin[], float flag[]); + +void cm_set_coord_system(cmCoordSystem_t coord_system); +void cm_set_origin_offsets(float offset[], float flag[]); +void cm_reset_origin_offsets(); +void cm_suspend_origin_offsets(); +void cm_resume_origin_offsets(); + +// Free Space Motion (4.3.4) +stat_t cm_straight_traverse(float target[], float flags[]); +void cm_set_g28_position(); +stat_t cm_goto_g28_position(float target[], float flags[]); +void cm_set_g30_position(); +stat_t cm_goto_g30_position(float target[], float flags[]); + +// Machining Attributes (4.3.5) +void cm_set_feed_rate(float feed_rate); +void cm_set_feed_rate_mode(cmFeedRateMode_t mode); +void cm_set_path_control(cmPathControlMode_t mode); + +// Machining Functions (4.3.6) +stat_t cm_straight_feed(float target[], float flags[]); +stat_t cm_arc_feed(float target[], float flags[], + float i, float j, float k, + float radius, uint8_t motion_mode); +stat_t cm_dwell(float seconds); + +// Spindle Functions (4.3.7) see spindle.h + +// Tool Functions (4.3.8) +void cm_select_tool(uint8_t tool); +void cm_change_tool(uint8_t tool); + +// Miscellaneous Functions (4.3.9) +void cm_mist_coolant_control(bool mist_coolant); +void cm_flood_coolant_control(bool flood_coolant); + +void cm_override_enables(bool flag); +void cm_feed_rate_override_enable(bool flag); +void cm_feed_rate_override_factor(bool flag); +void cm_traverse_override_enable(bool flag); +void cm_traverse_override_factor(bool flag); +void cm_spindle_override_enable(bool flag); +void cm_spindle_override_factor(bool flag); + +void cm_message(const char *message); + +// Program Functions (4.3.10) +void cm_request_feedhold(); +void cm_request_queue_flush(); +void cm_request_cycle_start(); + +void cm_feedhold_callback(); +stat_t cm_queue_flush(); + +void cm_cycle_start(); +void cm_cycle_end(); +void cm_feedhold(); +void cm_program_stop(); +void cm_optional_program_stop(); +void cm_program_end(); + +// Cycles +char cm_get_axis_char(int8_t axis); diff --git a/src/main.c b/src/main.c index c06e16b..936c1f3 100644 --- a/src/main.c +++ b/src/main.c @@ -28,7 +28,7 @@ \******************************************************************************/ #include "hardware.h" -#include "canonical_machine.h" +#include "machine.h" #include "stepper.h" #include "motor.h" #include "switch.h" @@ -43,7 +43,6 @@ #include "homing.h" #include "plan/planner.h" -#include "plan/buffer.h" #include "plan/arc.h" #include "plan/feedhold.h" @@ -67,7 +66,7 @@ int main() { motor_init(); // motors switch_init(); // switches planner_init(); // motion planning - canonical_machine_init(); // gcode machine + machine_init(); // gcode machine vars_init(); // configuration variables estop_init(); // emergency stop handler @@ -79,14 +78,12 @@ int main() { // main loop while (true) { hw_reset_handler(); // handle hard reset requests - cm_feedhold_sequencing_callback(); // feedhold state machine - mp_plan_hold_callback(); // plan a feedhold + cm_feedhold_callback(); // feedhold state machine cm_arc_callback(); // arc generation runs cm_homing_callback(); // G28.2 continuation cm_probe_callback(); // G38.2 continuation command_callback(); // process next command report_callback(); // report changes - wdt_reset(); } diff --git a/src/plan/arc.c b/src/plan/arc.c index 7782ae9..fec5842 100644 --- a/src/plan/arc.c +++ b/src/plan/arc.c @@ -27,7 +27,7 @@ \******************************************************************************/ /* This module actually contains some parts that belong ion the - * canonical machine, and other parts that belong at the motion planner + * machine, and other parts that belong at the motion planner * level, but the whole thing is treated as if it were part of the * motion planner. */ @@ -282,7 +282,7 @@ static stat_t _compute_arc() { // g18_correction is used to invert G18 XZ plane arcs for proper CW // orientation - float g18_correction = (cm.gm.select_plane == CANON_PLANE_XZ) ? -1 : 1; + float g18_correction = (cm.gm.select_plane == PLANE_XZ) ? -1 : 1; if (arc.full_circle) { // angular travel always starts as zero for full circles @@ -356,7 +356,7 @@ static stat_t _compute_arc() { } -/* Canonical machine entry point for arc +/* machine entry point for arc * * Generates an arc by queuing line segments to the move buffer. The arc is * approximated by generating a large number of tiny, linear arc_segments. @@ -390,7 +390,7 @@ stat_t cm_arc_feed(float target[], float flags[], // arc endpoints // specification Plane axis 0 and 1 are the arc plane, the linear axis is // normal to the arc plane. // G17 - the vast majority of arcs are in the G17 (XY) plane - if (cm.gm.select_plane == CANON_PLANE_XY) { + if (cm.gm.select_plane == PLANE_XY) { arc.plane_axis_0 = AXIS_X; arc.plane_axis_1 = AXIS_Y; arc.linear_axis = AXIS_Z; @@ -405,7 +405,7 @@ stat_t cm_arc_feed(float target[], float flags[], // arc endpoints // but error if k is present return STAT_ARC_SPECIFICATION_ERROR; - } else if (cm.gm.select_plane == CANON_PLANE_XZ) { // G18 + } else if (cm.gm.select_plane == PLANE_XZ) { // G18 arc.plane_axis_0 = AXIS_X; arc.plane_axis_1 = AXIS_Z; arc.linear_axis = AXIS_Y; @@ -415,7 +415,7 @@ stat_t cm_arc_feed(float target[], float flags[], // arc endpoints return STAT_ARC_AXIS_MISSING_FOR_SELECTED_PLANE; } else if (offset_j) return STAT_ARC_SPECIFICATION_ERROR; - } else if (cm.gm.select_plane == CANON_PLANE_YZ) { // G19 + } else if (cm.gm.select_plane == PLANE_YZ) { // G19 arc.plane_axis_0 = AXIS_Y; arc.plane_axis_1 = AXIS_Z; arc.linear_axis = AXIS_X; diff --git a/src/plan/buffer.h b/src/plan/buffer.h index 59da843..c05ab25 100644 --- a/src/plan/buffer.h +++ b/src/plan/buffer.h @@ -27,7 +27,7 @@ #pragma once -#include "canonical_machine.h" +#include "machine.h" #include "config.h" #include @@ -74,7 +74,7 @@ typedef struct mpBuffer { // See Planning Velocity Notes struct mpBuffer *nx; // pointer to next buffer bf_func_t bf_func; // callback to buffer exec function - cm_exec_t cm_func; // callback to canonical machine + cm_exec_t cm_func; // callback to machine float naive_move_time; diff --git a/src/plan/calibrate.c b/src/plan/calibrate.c index 1909b8e..b1833c8 100644 --- a/src/plan/calibrate.c +++ b/src/plan/calibrate.c @@ -30,7 +30,7 @@ #include "buffer.h" #include "motor.h" -#include "canonical_machine.h" +#include "machine.h" #include "planner.h" #include "stepper.h" #include "rtc.h" diff --git a/src/plan/command.c b/src/plan/command.c index 0bbd28e..545bd5f 100644 --- a/src/plan/command.c +++ b/src/plan/command.c @@ -31,7 +31,7 @@ * - A command is called by the Gcode interpreter (cm_, e.g. M code) * - cm_ function calls mp_queue_command which puts it in the planning queue * (bf buffer) which sets some parameters and registers a callback to the - * execution function in the canonical machine. + * execution function in the machine. * - When the planning queue gets to the function it calls _exec_command() * which loads a pointer to the bf buffer in stepper.c's next move. * - When the runtime gets to the end of the current activity (sending steps, @@ -47,7 +47,7 @@ #include "command.h" #include "buffer.h" -#include "canonical_machine.h" +#include "machine.h" #include "stepper.h" @@ -69,7 +69,7 @@ void mp_queue_command(cm_exec_t cm_exec, float *value, float *flag) { bf->move_type = MOVE_TYPE_COMMAND; bf->bf_func = _exec_command; // callback to planner queue exec function - bf->cm_func = cm_exec; // callback to canonical machine exec function + bf->cm_func = cm_exec; // callback to machine exec function // Store values and flags in planner buffer for (int axis = 0; axis < AXES; axis++) { diff --git a/src/plan/dwell.c b/src/plan/dwell.c index d543471..7e2305a 100644 --- a/src/plan/dwell.c +++ b/src/plan/dwell.c @@ -30,7 +30,7 @@ #include "dwell.h" #include "buffer.h" -#include "canonical_machine.h" +#include "machine.h" #include "stepper.h" diff --git a/src/plan/exec.c b/src/plan/exec.c index 4fc1af7..caa506b 100644 --- a/src/plan/exec.c +++ b/src/plan/exec.c @@ -765,7 +765,7 @@ stat_t mp_exec_aline(mpBuf_t *bf) { else if (mr.section == SECTION_TAIL) status = _exec_aline_tail(); else return CM_ALARM(STAT_INTERNAL_ERROR); // never supposed to get here - // Feedhold processing. Refer to canonical_machine.h for state machine + // Feedhold processing. Refer to machine.h for state machine // Catch the feedhold request and start the planning the hold if (cm.hold_state == FEEDHOLD_SYNC) cm.hold_state = FEEDHOLD_PLAN; diff --git a/src/plan/feedhold.h b/src/plan/feedhold.h index 1fbb6e8..007962d 100644 --- a/src/plan/feedhold.h +++ b/src/plan/feedhold.h @@ -27,7 +27,6 @@ #pragma once -#include "status.h" void mp_plan_hold_callback(); void mp_end_hold(); diff --git a/src/plan/jog.c b/src/plan/jog.c index c511196..1ca6908 100644 --- a/src/plan/jog.c +++ b/src/plan/jog.c @@ -31,7 +31,7 @@ #include "buffer.h" #include "stepper.h" #include "motor.h" -#include "canonical_machine.h" +#include "machine.h" #include "motor.h" #include "config.h" diff --git a/src/plan/line.c b/src/plan/line.c index bb25aa4..266599a 100644 --- a/src/plan/line.c +++ b/src/plan/line.c @@ -33,7 +33,7 @@ #include "exec.h" #include "buffer.h" #include "zoid.h" -#include "canonical_machine.h" +#include "machine.h" #include "stepper.h" #include "util.h" #include "report.h" diff --git a/src/plan/planner.c b/src/plan/planner.c index 9247b04..eac0e81 100644 --- a/src/plan/planner.c +++ b/src/plan/planner.c @@ -29,7 +29,7 @@ /* Planner Notes * - * The planner works below the canonical machine and above the + * The planner works below the machine and above the * motor mapping and stepper execution layers. A rudimentary * multitasking capability is implemented for long-running commands * such as lines, arcs, and dwells. These functions are coded as @@ -44,10 +44,10 @@ * mm), and runtime model (mr). These are designated as "model", * "planner" and "runtime" in function names. * - * The Gcode model is owned by the canonical machine and should + * The Gcode model is owned by the machine and should * only be accessed by cm_xxxx() functions. Data from the Gcode * model is transferred to the planner by the mp_xxx() functions - * called by the canonical machine. + * called by the machine. * * The planner should only use data in the planner model. When a * move (block) is ready for execution the planner data is @@ -61,7 +61,7 @@ #include "buffer.h" #include "arc.h" -#include "canonical_machine.h" +#include "machine.h" #include "stepper.h" #include "motor.h" diff --git a/src/plan/planner.h b/src/plan/planner.h index bf08ad3..bd46a68 100644 --- a/src/plan/planner.h +++ b/src/plan/planner.h @@ -30,7 +30,7 @@ #pragma once -#include "canonical_machine.h" // used for GCodeState_t +#include "machine.h" // used for GCodeState_t #include "util.h" diff --git a/src/probing.c b/src/probing.c index eae282f..c48c12c 100644 --- a/src/probing.c +++ b/src/probing.c @@ -26,7 +26,7 @@ \******************************************************************************/ -#include "canonical_machine.h" +#include "machine.h" #include "spindle.h" #include "switch.h" #include "util.h" diff --git a/src/pwm_spindle.h b/src/pwm_spindle.h index 48e7a6d..6e739b3 100644 --- a/src/pwm_spindle.h +++ b/src/pwm_spindle.h @@ -27,7 +27,7 @@ #pragma once -#include "canonical_machine.h" +#include "machine.h" void pwm_spindle_init(); diff --git a/src/spindle.h b/src/spindle.h index 8bb6fc0..0b78a2f 100644 --- a/src/spindle.h +++ b/src/spindle.h @@ -28,7 +28,7 @@ #pragma once -#include "canonical_machine.h" +#include "machine.h" void cm_spindle_init(); diff --git a/src/stepper.c b/src/stepper.c index 891c072..c597bf6 100644 --- a/src/stepper.c +++ b/src/stepper.c @@ -30,7 +30,7 @@ #include "stepper.h" #include "config.h" -#include "canonical_machine.h" +#include "machine.h" #include "plan/exec.h" #include "plan/command.h" #include "motor.h" diff --git a/src/switch.c b/src/switch.c index a08277b..9014f30 100644 --- a/src/switch.c +++ b/src/switch.c @@ -46,7 +46,7 @@ #include "switch.h" #include "hardware.h" -#include "canonical_machine.h" +#include "machine.h" #include "config.h" #include diff --git a/src/tmc2660.c b/src/tmc2660.c index 54082be..9bc92d7 100644 --- a/src/tmc2660.c +++ b/src/tmc2660.c @@ -30,7 +30,7 @@ #include "motor.h" #include "rtc.h" #include "cpp_magic.h" -#include "canonical_machine.h" +#include "machine.h" #include "plan/calibrate.h" #include