diff --git a/CMakeLists.txt b/CMakeLists.txt index 1075d5d..891e718 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ target_sources(grbl INTERFACE ${CMAKE_CURRENT_LIST_DIR}/encoders.c ${CMAKE_CURRENT_LIST_DIR}/pid.c ${CMAKE_CURRENT_LIST_DIR}/fs_device.c + ${CMAKE_CURRENT_LIST_DIR}/kinematics/asymmetric_ganging.c ${CMAKE_CURRENT_LIST_DIR}/kinematics/corexy.c ${CMAKE_CURRENT_LIST_DIR}/kinematics/wall_plotter.c ${CMAKE_CURRENT_LIST_DIR}/kinematics/delta.c diff --git a/README.md b/README.md index 8792fde..b6b1425 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## grblHAL ## -Latest build date is 20260525, see the [changelog](changelog.md) for details. +Latest build date is 20260618, see the [changelog](changelog.md) for details. > [!NOTE] > A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended. @@ -89,4 +89,4 @@ G/M-codes not supported by [legacy Grbl](https://github.com/gnea/grbl/wiki) are Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes. --- -20260311 +20260618 diff --git a/changelog.md b/changelog.md index 0bd86b3..561dacb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,34 @@ ## grblHAL changelog +Build 20260618 + +Core: + +* Added kinematics for asymmetric \(differing step/mm\) ganged or auto squared axis, claims the highest number axis > Z for the second motor. + +* Ignore single block mode while executing startup code. Ref. issue [#963](https://github.com/grblHAL/core/issues/963). + +* For developers: added API call, `system_claim_axis()`, for claiming highest numbered axis > Z, hides its related settings. + +* Fixed a typo causing ganged Z compilation failure. + +* Fixed code guard. Ref. discussion [#968](https://github.com/grblHAL/core/discussions/968). + +Plugins: + +* Misc, MCP23017: added plugin for [MCP23017](https://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf) 16 channel I2C I/O expander, +compile time configurable for 8 channel input and output, 16 channel input or 16 channel output. + +Drivers: + +* RP2040: "hardened" neopixel code. + +* IMXRT1062: fixed typo causing compilation to fail if axis is remapped as C. Fixed incorrect function decorators in the core. Ref. issue #[965](https://github.com/grblHAL/core/issues/965). + +* STM32F7xx: fixed copy paste error affecting handling of AUX IRQ for pins 10 - 15. + +--- + Build 20260602 Core: diff --git a/config.h b/config.h index 2943d3f..060147b 100644 --- a/config.h +++ b/config.h @@ -120,15 +120,6 @@ generate a solution. //#define KINEMATICS_API // Uncomment to add HAL entry points for custom kinematics -/*! \def MASLOW_ROUTER -\brief Enable Maslow router kinematics. -Experimental - testing required and homing needs to be worked out. -*/ -#if !defined MASLOW_ROUTER || defined __DOXYGEN__ -// Enable Maslow router kinematics. -// Experimental - testing required and homing needs to be worked out. -#define MASLOW_ROUTER Off -#endif /*! \def WALL_PLOTTER \brief Enable wall plotter kinematics. @@ -159,7 +150,6 @@ Experimental - testing required and homing needs to be worked out. #define POLAR_ROBOT Off #endif - /*! \def COREXY \brief Enable CoreXY kinematics. Use ONLY with CoreXY machines.
__IMPORTANT:__ If homing is enabled, you must reconfigure the homing cycle \#defines above to @@ -173,6 +163,18 @@ have the same steps per mm internally. #define COREXY Off #endif +/*! \def ASYMMETRIC_GANGING +\brief Enable asymmetric ganging for X, Y or Z axis. +
To be used when the screw pitch is not equal. The highest numbered axis is claimed for the second motor. +*/ +//#define ASYMMETRIC_GANGING Y_AXIS // Uncomment to enable + +/*! \def ASYMMETRIC_AUTO_SQUARE +\brief Enable asymmetric ganging + auto squaring for X, Y or Z axis. +
To be used when the screw pitch is not equal. The highest numbered axis is claimed for the second motor. +*/ +//#define ASYMMETRIC_AUTO_SQUARE Y_AXIS // Uncomment to enable + /*! \def CHECK_MODE_DELAY \brief Add a short delay for each block processed in Check Mode to diff --git a/driver_opts.h b/driver_opts.h index 0cbf0ff..3e657c0 100644 --- a/driver_opts.h +++ b/driver_opts.h @@ -310,7 +310,11 @@ #define SPINDLE_DIR 0b100 #ifndef SPINDLE0_ENABLE -#define SPINDLE0_ENABLE DEFAULT_SPINDLE +#ifdef SPINDLE_ENABLE +#define SPINDLE0_ENABLE 0 +#else +#define SPINDLE0_ENABLE DEFAULT_SPINDLE +#endif #endif #ifndef SPINDLE1_ENABLE diff --git a/expanders_init.h b/expanders_init.h index bfa5176..c222179 100644 --- a/expanders_init.h +++ b/expanders_init.h @@ -31,7 +31,7 @@ extern void board_ports_init (void); // default is a weak function // I2C expanders -#if PCA9654E_ENABLE || MCP3221_ENABLE || MCP4725_ENABLE || FLEXGPIO_ENABLE +#if PCA9654E_ENABLE || MCP3221_ENABLE || MCP4725_ENABLE || MCP23017_ENABLE || FLEXGPIO_ENABLE #if defined(I2C_ENABLE) && !I2C_ENABLE #undef I2C_ENABLE @@ -53,6 +53,10 @@ extern void mcp4725_init (void); extern void pca9654e_init (void); #endif +#if MCP23017_ENABLE +extern void mcp23017_init (void); +#endif + // Third party I2C expander plugins goes after this line #if FLEXGPIO_ENABLE @@ -133,6 +137,10 @@ static inline void io_expanders_init (void) mcp4725_init(); #endif +#if MCP23017_ENABLE + mcp23017_init(); +#endif + #if R4SLS08_ENABLE r4sls08_init(); #endif diff --git a/grbl.h b/grbl.h index 4476586..79aedb6 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20260602 +#define GRBL_BUILD 20260618 #define GRBL_URL "https://github.com/grblHAL" @@ -86,7 +86,7 @@ #define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline #endif -#if (COREXY || WALL_PLOTTER || DELTA_ROBOT || POLAR_ROBOT || MASLOW_ROUTER) && !defined(KINEMATICS_API) +#if (COREXY || WALL_PLOTTER || DELTA_ROBOT || POLAR_ROBOT || ASYMMETRIC_GANGING || ASYMMETRIC_AUTO_SQUARE) && !defined(KINEMATICS_API) #define KINEMATICS_API #endif diff --git a/grbllib.c b/grbllib.c index 45cf831..c1ad5e1 100644 --- a/grbllib.c +++ b/grbllib.c @@ -45,22 +45,6 @@ #include "kinematics.h" #endif -#if COREXY -#include "kinematics/corexy.h" -#endif - -#if WALL_PLOTTER -#include "kinematics/wall_plotter.h" -#endif - -#if DELTA_ROBOT -#include "kinematics/delta.h" -#endif - -#if POLAR_ROBOT -#include "kinematics/polar.h" -#endif - static void task_execute (sys_state_t state); typedef union { @@ -357,21 +341,30 @@ FLASHMEM int grbl_enter (void) #endif #if COREXY + extern void corexy_init (void); corexy_init(); #endif #if WALL_PLOTTER + extern void wall_plotter_init (void); wall_plotter_init(); #endif #if DELTA_ROBOT + extern void delta_robot_init (void); delta_robot_init(); #endif #if POLAR_ROBOT + extern void polar_init (void); polar_init(); #endif +#if defined(ASYMMETRIC_GANGING) || defined(ASYMMETRIC_AUTO_SQUARE) + extern void asymmetric_ganging_init (void); + asymmetric_ganging_init(); +#endif + #if NVSDATA_BUFFER_ENABLE nvs_buffer_init(); #endif diff --git a/kinematics/asymmetric_ganging.c b/kinematics/asymmetric_ganging.c new file mode 100644 index 0000000..2734506 --- /dev/null +++ b/kinematics/asymmetric_ganging.c @@ -0,0 +1,346 @@ +/* + asymmetric_ganging.c - kinematics implementation for asymmetric ganging of two axis motors + + Part of grblHAL + + Copyright (c) 2026 Terje Io + + grblHAL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + grblHAL 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with grblHAL. If not, see . +*/ + +#include "../grbl.h" + +#if defined(ASYMMETRIC_GANGING) || defined(ASYMMETRIC_AUTO_SQUARE) + +#if N_AXIS <= 3 +#error "Kinematics for asymmetric ganging must have N_AXIS > 3" +#endif + +#include + +#include "../hal.h" +#include "../settings.h" +#include "../planner.h" +#include "../kinematics.h" + +#ifdef ASYMMETRIC_AUTO_SQUARE +#define PRIMARY_AXIS ASYMMETRIC_AUTO_SQUARE +#else +#define PRIMARY_AXIS ASYMMETRIC_GANGING +#endif +#define PRIMARY_AXIS_BIT (1 << PRIMARY_AXIS) +#define GANGED_AXIS (N_AXIS - 1) +#define GANGED_AXIS_BIT (1 << GANGED_AXIS) + +static on_report_options_ptr on_report_options; +static on_settings_changed_ptr on_settings_changed; +static stepper_get_ganged_ptr get_ganged_axes; + +#ifdef ASYMMETRIC_AUTO_SQUARE + +static axes_signals_t motor_disable = {0}; + +static stepper_disable_motors_ptr disable_motors; +static limits_get_state_ptr get_limits_state; +static home_get_state_ptr get_home_state; +static stepper_pulse_start_ptr pulse_start; + +static void onDisableMotors (axes_signals_t axes, squaring_mode_t mode) +{ + if(disable_motors) + disable_motors(axes, mode); + + if(!axes.bits) + motor_disable.bits = 0; + else if(axes.bits & (1 << PRIMARY_AXIS)) { +/* + if(mode == SquaringMode_A) + sys.homing_axis_lock.bits &= ~(1 << PRIMARY_AXIS); + else + sys.homing_axis_lock.bits &= ~GANGED_AXIS_BIT; +*/ + motor_disable.y = mode == SquaringMode_A; + if(mode == SquaringMode_B) + motor_disable.bits |= GANGED_AXIS_BIT; + else + motor_disable.bits &= ~GANGED_AXIS_BIT; + } +} + +static limit_signals_t onGetLimitsState (void) +{ + limit_signals_t limits = get_limits_state(); + + limits.min2.y = !!(limits.min.bits & GANGED_AXIS_BIT); + + return limits; +} + +/* +ISR_CODE static home_signals_t ISR_FUNC(onGetHomingState)(void) +{ + home_signals_t home = get_home_state(); + + if(home.a.bits && GANGED_AXIS_BIT) { + home.b.y = On; + home.a.bits &= ~GANGED_AXIS_BIT; + } + + return home; +} +*/ + +void ISR_CODE ISR_FUNC(onStepperPulse) (stepper_t *stepper) +{ + if(stepper->step_out.bits & motor_disable.bits) { + + if(motor_disable.bits & PRIMARY_AXIS_BIT) + stepper->step_out.bits &= ~PRIMARY_AXIS_BIT; + + if(motor_disable.bits & GANGED_AXIS_BIT) + stepper->step_out.bits &= ~GANGED_AXIS_BIT; + } + + pulse_start(stepper); +} + +static bool homing_cycle_validate (axes_signals_t cycle) +{ + return !(cycle.bits & PRIMARY_AXIS_BIT) || ((cycle.bits & PRIMARY_AXIS_BIT) && (cycle.bits & GANGED_AXIS_BIT)); +} + +static axes_signals_t onGetGangedAxes (bool auto_squared) +{ + axes_signals_t axes = {0}; + + if(get_ganged_axes) + axes = get_ganged_axes(auto_squared); + + axes.bits |= PRIMARY_AXIS_BIT; + + return axes; +} + +#else + +static bool homing_cycle_validate (axes_signals_t cycle) +{ + return true; +} + +static axes_signals_t onGetGangedAxes (bool auto_squared) +{ + axes_signals_t axes = {0}; + + if(get_ganged_axes) + axes = get_ganged_axes(auto_squared); + + if(!auto_squared) + axes.bits |= PRIMARY_AXIS_BIT; + + return axes; +} + + +#endif // ASYMMETRIC_AUTO_SQUARE + +static float *convert_array_steps_to_mpos (float *position, int32_t *steps) +{ + uint_fast8_t idx = N_AXIS; + do { + idx--; + position[idx] = steps[idx] / settings.axis[idx].steps_per_mm; + } while(idx); + + return position; +} + +// Transform position from cartesian coordinate system to corexy coordinate system +static inline float *transform_from_cartesian (float *target, float *position) +{ + memcpy(target, position, sizeof(coord_data_t)); + + target[GANGED_AXIS] = position[PRIMARY_AXIS]; + + return target; +} + +static uint_fast8_t get_axis_mask (uint_fast8_t idx) +{ + return bit(idx); +} + +static void set_target_pos (uint_fast8_t idx) // fn name? +{ + sys.position[idx] = 0; +} + +// Set machine positions for homed limit switches. Don't update non-homed axes. +// NOTE: settings.max_travel[] is stored as a negative value. +static void set_machine_positions (axes_signals_t cycle) +{ + limits_set_machine_positions(cycle, true); + + if(!settings.homing.flags.force_set_origin) + sys.position[GANGED_AXIS] = lroundf(sys.home_position[PRIMARY_AXIS] * settings.axis[GANGED_AXIS].steps_per_mm); +} + +// called from mc_line() to segment lines if not overridden, default implementation for pass-through +static float *kinematics_segment_line (float *target, float *position, plan_line_data_t *pl_data, bool init) +{ + static uint_fast8_t iterations; + static coord_data_t trsf; + + if(init) { + iterations = 2; + transform_from_cartesian(trsf.values, target); + } + + return iterations-- == 0 ? NULL : trsf.values; +} + +static float homing_cycle_get_feedrate (axes_signals_t cycle, float feedrate, homing_mode_t mode) +{ + return feedrate; +} + +static void onSettingsChanged (settings_t *settings, settings_changed_flags_t changed) +{ + uint_fast8_t idx = sizeof(settings->homing.cycle) / sizeof(axes_signals_t); + + on_settings_changed(settings, changed); + + float steps_per_mm = settings->axis[GANGED_AXIS].steps_per_mm; + + memcpy(&settings->axis[GANGED_AXIS], &settings->axis[PRIMARY_AXIS], sizeof(axis_settings_t)); + + settings->axis[GANGED_AXIS].steps_per_mm = steps_per_mm; + + do { + if(settings->homing.cycle[--idx].bits & PRIMARY_AXIS_BIT) + settings->homing.cycle[idx].bits |= GANGED_AXIS_BIT; + else if(settings->homing.cycle[idx].bits & GANGED_AXIS_BIT) + settings->homing.cycle[idx].bits &= GANGED_AXIS_BIT; + } while(idx); + + if(settings->steppers.enable_invert.bits & PRIMARY_AXIS_BIT) + settings->steppers.enable_invert.bits |= GANGED_AXIS_BIT; + else + settings->steppers.enable_invert.bits &= ~GANGED_AXIS_BIT; + + if(settings->steppers.dir_invert.bits & PRIMARY_AXIS_BIT) + settings->steppers.dir_invert.bits |= GANGED_AXIS_BIT; + else + settings->steppers.dir_invert.bits &= ~GANGED_AXIS_BIT; + + if(settings->steppers.step_invert.bits & PRIMARY_AXIS_BIT) + settings->steppers.step_invert.bits |= GANGED_AXIS_BIT; + else + settings->steppers.step_invert.bits &= ~GANGED_AXIS_BIT; + + if(settings->steppers.energize.bits & PRIMARY_AXIS_BIT) + settings->steppers.energize.bits |= GANGED_AXIS_BIT; + else + settings->steppers.energize.bits &= ~GANGED_AXIS_BIT; + + if(settings->homing.dir_mask.bits & PRIMARY_AXIS_BIT) + settings->homing.dir_mask.bits |= GANGED_AXIS_BIT; + else + settings->homing.dir_mask.bits &= ~GANGED_AXIS_BIT; + + settings->steppers.is_rotary.bits &= ~GANGED_AXIS_BIT; + +#ifdef ASYMMETRIC_AUTO_SQUARE + + if(settings->limits.invert.bits & PRIMARY_AXIS_BIT) + settings->limits.invert.bits |= GANGED_AXIS_BIT; + else + settings->limits.invert.bits &= ~GANGED_AXIS_BIT; + + if(hal.stepper.pulse_start != onStepperPulse) { + pulse_start = hal.stepper.pulse_start; + hal.stepper.pulse_start = onStepperPulse; + } + +#endif +} + +PROGMEM static const char label[] = { +#if PRIMARY_AXIS == X_AXIS + "Ganged X-motor travel resolution" +#elif PRIMARY_AXIS == Y_AXIS + "Ganged Y-motor travel resolution" +#elif PRIMARY_AXIS == Z_AXIS + "Ganged Z-motor travel resolution" +#endif +}; + +PROGMEM static const setting_detail_t axis_settings[] = { + { Setting_AxisStepsPerMM + GANGED_AXIS, Group_Axis0 + PRIMARY_AXIS, label, "step/mm", Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsLegacy, &settings.axis[GANGED_AXIS].steps_per_mm, NULL, NULL }, +}; + +static void report_options (bool newopt) +{ + on_report_options(newopt); + + if(!newopt) + hal.stream.write("[KINEMATICS:Asymmetric ganging v0.01]" ASCII_EOL); +} + +// Initialize API pointers for xxx kinematics +void asymmetric_ganging_init (void) +{ + static setting_details_t axis_setting_details = { + .is_core = true, + .settings = axis_settings, + .n_settings = sizeof(axis_settings) / sizeof(setting_detail_t), + .save = settings_write_global + }; + + system_claim_axis(); + kinematics.limits_set_target_pos = set_target_pos; + kinematics.limits_get_axis_mask = get_axis_mask; + kinematics.limits_set_machine_positions = set_machine_positions; + kinematics.transform_from_cartesian = transform_from_cartesian; + kinematics.transform_steps_to_cartesian = convert_array_steps_to_mpos; + kinematics.segment_line = kinematics_segment_line; + kinematics.homing_cycle_validate = homing_cycle_validate; + kinematics.homing_cycle_get_feedrate = homing_cycle_get_feedrate; + + settings_register(&axis_setting_details); + + on_report_options = grbl.on_report_options; + grbl.on_report_options = report_options; + + on_settings_changed = grbl.on_settings_changed; + grbl.on_settings_changed = onSettingsChanged; + + get_ganged_axes = hal.stepper.get_ganged; + hal.stepper.get_ganged = onGetGangedAxes; + +#ifdef ASYMMETRIC_AUTO_SQUARE + + get_limits_state = hal.limits.get_state; + hal.limits.get_state = onGetLimitsState; + + get_home_state = hal.homing.get_state; +// hal.homing.get_state = onGetHomingState; + + disable_motors = hal.stepper.disable_motors; + hal.stepper.disable_motors = onDisableMotors; + +#endif +} + +#endif // ASYMMETRIC_GANGING || ASYMMETRIC_AUTO_SQUARE diff --git a/kinematics/corexy.h b/kinematics/corexy.h deleted file mode 100644 index bdd37cd..0000000 --- a/kinematics/corexy.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - corexy.c - corexy kinematics implementation - - Part of grblHAL - - Copyright (c) 2019 Terje Io - Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC - - grblHAL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - grblHAL 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with grblHAL. If not, see . -*/ - -#ifndef _COREXY_H_ -#define _COREXY_H_ - -// Initialize HAL pointers for CoreXY kinematics -void corexy_init (void); - -#endif diff --git a/kinematics/delta.h b/kinematics/delta.h deleted file mode 100644 index 4b696b6..0000000 --- a/kinematics/delta.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - delta.c - delta kinematics implementation - - Part of grblHAL - - Copyright (c) 2023 Terje Io - - grblHAL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - grblHAL 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with grblHAL. If not, see . -*/ - -#ifndef _delta_H_ -#define _delta_H_ - -// Initialize HAL pointers for delta kinematics -void delta_robot_init (void); - -#endif diff --git a/kinematics/maslow.c b/kinematics/maslow.c deleted file mode 100644 index 811f549..0000000 --- a/kinematics/maslow.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - maslow.c - Maslow router kinematics implementation - - Part of grblHAL - - grblHAL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - grblHAL 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with grblHAL. If not, see . - - The basis for this code has been pulled from MaslowDue created by Larry D O'Cull. - - - Some portions of that package directly or indirectly has been pulled from from the Maslow CNC - firmware for Aduino Mega. Those parts are Copyright 2014-2017 Bar Smith. - - - It has been adapted for grblHAL by Terje Io. -*/ - -#include "../grbl.h" - -#if MASLOW_ROUTER - -#include - -#include "driver.h" - -#include "../settings.h" -#include "../planner.h" -#include "../nvs_buffer.h" -#include "../kinematics.h" -#include "../maslow.h" -#include "../report.h" - -#define A_MOTOR X_AXIS // Must be X_AXIS -#define B_MOTOR Y_AXIS // Must be Y_AXIS - -typedef struct { - float halfWidth; //Half the machine width - float halfHeight; //Half the machine height - float xCordOfMotor; - float xCordOfMotor_x4; - float xCordOfMotor_x2_pow; - float yCordOfMotor; - float height_to_bit; //distance between sled attach point and bit -} machine_t; - -static machine_t machine = {0}; - -uint_fast8_t selected_motor = A_MOTOR; -maslow_settings_t maslow; -maslow_hal_t maslow_hal = {0}; -static nvs_address_t nvs_address; - -static const maslow_settings_t maslow_defaults = { - .pid[A_MOTOR].Kp = MASLOW_A_KP, - .pid[A_MOTOR].Ki = MASLOW_A_KI, - .pid[A_MOTOR].Kd = MASLOW_A_KD, - .pid[A_MOTOR].Imax = MASLOW_A_IMAX, - - .pid[B_MOTOR].Kp = MASLOW_B_KP, - .pid[B_MOTOR].Ki = MASLOW_B_KI, - .pid[B_MOTOR].Kd = MASLOW_B_KD, - .pid[B_MOTOR].Imax = MASLOW_B_IMAX, - - .pid[Z_AXIS].Kp = MASLOW_Z_KP, - .pid[Z_AXIS].Ki = MASLOW_Z_KI, - .pid[Z_AXIS].Kd = MASLOW_Z_KD, - .pid[Z_AXIS].Imax = MASLOW_Z_IMAX, - - .chainOverSprocket = MASLOW_CHAINOVERSPROCKET, - .machineWidth = MASLOW_MACHINEWIDTH, - .machineHeight = MASLOW_MACHINEHEIGHT, - .distBetweenMotors = MASLOW_DISTBETWEENMOTORS, - - .motorOffsetY = MASLOW_MOTOROFFSETY, - .chainSagCorrection = MASLOW_CHAINSAGCORRECTION, - .leftChainTolerance = MASLOW_LEFTCHAINTOLERANCE, - .rightChainTolerance = MASLOW_RIGHTCHAINTOLERANCE, - .rotationDiskRadius = MASLOW_ROTATIONDISKRADIUS, - - .chainLength = MASLOW_CHAINLENGTH, - .sledHeight = MASLOW_SLEDHEIGHT, - .sledWidth = MASLOW_SLEDWIDTH, - - .XcorrScaling = MASLOW_ACORRSCALING, - .YcorrScaling = MASLOW_BCORRSCALING -}; - -static status_code_t set_axis_setting (setting_id_t setting, float value); -static float get_axis_setting (setting_id_t setting); -static void maslow_settings_load (void); -static void maslow_settings_restore (void); - -#define AXIS_OPTS { .subgroups = On, .iterations = 1 } - -static const setting_detail_t maslow_settings[] = { -#if maslow_MIXED_DRIVERS - { Setting_maslowDriver, Group_MotorDriver, "maslow driver", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_NonCore, &maslow.driver_enable.mask }, -#endif - { (setting_id_t)Maslow_ChainOverSprocket, Group_MotorDriver, "Chain over sprocket", NULL, Format_Integer, NULL, NULL, NULL, Setting_NonCore, &maslow.chainOverSprocket, NULL }, - { (setting_id_t)Maslow_MachineWidth, Group_MotorDriver, "Machine width", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.machineWidth, NULL }, - { (setting_id_t)Maslow_MachineHeight, Group_MotorDriver, "Machine height", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.machineHeight, NULL }, - { (setting_id_t)Maslow_DistBetweenMotors, Group_MotorDriver, "Distance between motors", "mm", Format_Decimal, NULL, NULL, NULL, Setting_NonCore, &maslow.distBetweenMotors, NULL }, - { (setting_id_t)Maslow_MotorOffsetY, Group_MotorDriver, "Motor offset Y", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.motorOffsetY, NULL }, - { (setting_id_t)Maslow_AcorrScaling, Group_MotorDriver, "Acorr Scaling", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.XcorrScaling, NULL }, - { (setting_id_t)Maslow_BcorrScaling, Group_MotorDriver, "BcorrScaling", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.XcorrScaling, NULL }, - { (setting_id_t)AxisSetting_MaslowKP, Group_Axis0, "-axis KP", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS }, - { (setting_id_t)AxisSetting_MaslowKI, Group_Axis0, "-axis KI", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS }, - { (setting_id_t)AxisSetting_MaslowKD, Group_Axis0, "-axis KIt", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS }, - { (setting_id_t)AxisSetting_MaslowIMax, Group_Axis0, "-axis I Max", "ma", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS } -}; - -static void maslow_settings_save (void) -{ - hal.nvs.memcpy_to_nvs(nvs_address, (uint8_t *)&maslow, sizeof(maslow_settings_t), true); -} - -static setting_details_t details = { - .settings = maslow_settings, - .n_settings = sizeof(maslow_settings) / sizeof(setting_detail_t), - .load = maslow_settings_load, - .save = maslow_settings_save, - .restore = maslow_settings_restore -}; - -static setting_details_t *on_get_settings (void) -{ - return &details; -} - -static status_code_t set_axis_setting (setting_id_t setting, float value) -{ - status_code_t status = Status_OK; - - if((setting_id_t)setting >= Setting_AxisSettingsBase && (setting_id_t)setting <= Setting_AxisSettingsMax) { - - uint_fast16_t base_idx = (uint_fast16_t)setting - (uint_fast16_t)Setting_AxisSettingsBase; - uint_fast8_t axis_idx = base_idx % AXIS_SETTINGS_INCREMENT; - - if(axis_idx < N_AXIS) switch((base_idx - axis_idx) / AXIS_SETTINGS_INCREMENT) { - - case AxisSetting_MaslowKP: - status = Status_OK; - maslow.pid[axis_idx].Kp = value; - break; - - case AxisSetting_MaslowKI: - status = Status_OK; - maslow.pid[axis_idx].Ki = value; - break; - - case AxisSetting_MaslowKD: - status = Status_OK; - maslow.pid[axis_idx].Kd = value; - break; - - case AxisSetting_MaslowIMax: - status = Status_OK; - maslow.pid[axis_idx].Imax = value; - - default: - status = Status_Unhandled; - break; - } - } - - return status; -} - -static float get_axis_setting (setting_id_t setting) -{ - float value = 0; - - if (setting >= Setting_AxisSettingsBase && setting <= Setting_AxisSettingsMax) { - - uint_fast16_t base_idx = (uint_fast16_t)setting - (uint_fast16_t)Setting_AxisSettingsBase; - uint_fast8_t axis_idx = base_idx % AXIS_SETTINGS_INCREMENT; - - if(axis_idx < N_AXIS) switch((base_idx - axis_idx) / AXIS_SETTINGS_INCREMENT) { - - case AxisSetting_MaslowKP: - value = maslow.pid[axis_idx].Kp; - break; - - case AxisSetting_MaslowKI: - value = maslow.pid[axis_idx].Ki; - break; - - case AxisSetting_MaslowKD: - value = maslow.pid[axis_idx].Kd; - break; - - case AxisSetting_MaslowIMax: - value = maslow.pid[axis_idx].Imax; - break; - } - } - - return value; -} - -static void maslow_settings_restore (void) -{ - memcpy(&maslow, &maslow_defaults, sizeof(maslow_settings_t)); - - hal.nvs.memcpy_to_nvs(hal.nvs.driver_area.address, (uint8_t *)&maslow, sizeof(maslow_settings_t), true); -} - -static void maslow_settings_load (void) -{ - if(hal.nvs.memcpy_from_nvs((uint8_t *)&maslow, nvs_address, sizeof(maslow_settings_t), true) != NVS_TransferResult_OK) - maslow_settings_restore(); -} - -/** End settings handling **/ - -void recomputeGeometry() -{ - /* - Some variables are computed on initialization for the geometry of the machine to reduce overhead, - calling this function regenerates those values. - */ - machine.halfWidth = (maslow.machineWidth / 2.0f); - machine.halfHeight = (maslow.machineHeight / 2.0f); - machine.xCordOfMotor = (maslow.distBetweenMotors / 2.0f); - machine.yCordOfMotor = (machine.halfHeight + maslow.motorOffsetY); - machine.xCordOfMotor_x4 = machine.xCordOfMotor * 4.0f; - machine.xCordOfMotor_x2_pow = powf((machine.xCordOfMotor * 2.0f), 2.0f); -} - -// limit motion to stay within table (in mm) -void verifyValidTarget (float* xTarget, float* yTarget) -{ - //If the target point is beyond one of the edges of the board, the machine stops at the edge - - recomputeGeometry(); -// no limits for now -// *xTarget = (*xTarget < -halfWidth) ? -halfWidth : (*xTarget > halfWidth) ? halfWidth : *xTarget; -// *yTarget = (*yTarget < -halfHeight) ? -halfHeight : (*yTarget > halfHeight) ? halfHeight : *yTarget; - -} - -// Maslow CNC calculation only. Returns x or y-axis "steps" based on Maslow motor steps. -// converts current position two-chain intersection (steps) into x / y cartesian in STEPS.. -static void maslow_convert_array_steps_to_mpos (float *position, int32_t *steps) -{ - float a_len = ((float)steps[A_MOTOR] / settings.axis[A_MOTOR].steps_per_mm); - float b_len = ((float)steps[B_MOTOR] / settings.axis[B_MOTOR].steps_per_mm); - - a_len = (machine.xCordOfMotor_x2_pow - powf(b_len, 2.0f) + powf(a_len, 2.0f)) / machine.xCordOfMotor_x4; - position[X_AXIS] = a_len - machine.xCordOfMotor; - a_len = maslow.distBetweenMotors - a_len; - position[Y_AXIS] = machine.yCordOfMotor - sqrtf(powf(b_len, 2.0f) - powf(a_len, 2.0f)); - position[Z_AXIS] = steps[Z_AXIS] / settings.axis[Z_AXIS].steps_per_mm; - -// back out any correction factor - position[X_AXIS] /= maslow.XcorrScaling; - position[Y_AXIS] /= maslow.YcorrScaling; -// -} - -// calculate left and right (A_MOTOR/B_MOTOR) chain lengths from X-Y cartesian coordinates (in mm) -// target is an absolute position in the frame -inline static void triangularInverse (int32_t *target_steps, float *target) -{ - //Confirm that the coordinates are on the table -// verifyValidTarget(&xTarget, &yTarget); - - // scale target (absolute position) by any correction factor - double xxx = (double)target[A_MOTOR] * (double)maslow.XcorrScaling; - double yyy = (double)target[B_MOTOR] * (double)maslow.YcorrScaling; - double yyp = pow((double)machine.yCordOfMotor - yyy, 2.0); - - //Calculate motor axes length to the bit - target_steps[A_MOTOR] = (int32_t)lround(sqrt(pow((double)machine.xCordOfMotor + xxx, 2.0f) + yyp) * settings.axis[A_MOTOR].steps_per_mm); - target_steps[B_MOTOR] = (int32_t)lround(sqrt(pow((double)machine.xCordOfMotor - xxx, 2.0f) + yyp) * settings.axis[B_MOTOR].steps_per_mm); -} - -// Transform absolute position from cartesian coordinate system (mm) to maslow coordinate system (step) -static void maslow_target_to_steps (int32_t *target_steps, float *target) -{ - uint_fast8_t idx = N_AXIS - 1; - - do { - target_steps[idx] = lroundf(target[idx] * settings.axis[idx].steps_per_mm); - } while(--idx > Y_AXIS); - - triangularInverse(target_steps, target); -} - -static uint_fast8_t maslow_limits_get_axis_mask (uint_fast8_t idx) -{ - return ((idx == A_MOTOR) || (idx == B_MOTOR)) ? (bit(X_AXIS) | bit(Y_AXIS)) : bit(idx); -} - -// MASLOW is circular in motion, so long lines must be divided up -static bool maslow_segment_line (float *target, plan_line_data_t *pl_data, bool init) -{ - static uint_fast16_t iterations; - static bool segmented; - static float delta[N_AXIS], segment_target[N_AXIS]; -// static plan_line_data_t plan; - - uint_fast8_t idx = N_AXIS; - - if(init) { - - float max_delta = 0.0f; - - do { - idx--; - delta[idx] = target[idx] - gc_state.position[idx]; - max_delta = max(max_delta, fabsf(delta[idx])); - } while(idx); - - if((segmented = !(pl_data->condition.rapid_motion || pl_data->condition.jog_motion) && - max_delta > MAX_SEG_LENGTH_MM && !(delta[X_AXIS] == 0.0f && delta[Y_AXIS] == 0.0f))) { - - idx = N_AXIS; - iterations = (uint_fast16_t)ceilf(max_delta / MAX_SEG_LENGTH_MM); - - memcpy(segment_target, gc_state.position, sizeof(segment_target)); -// memcpy(&plan, pl_data, sizeof(plan_line_data_t)); - - do { - delta[--idx] /= (float)iterations; - target[idx] = gc_state.position[idx]; - } while(idx); - - } else - iterations = 1; - - iterations++; // return at least one iteration - - } else { - - iterations--; - - if(segmented && iterations) do { - idx--; - segment_target[idx] += delta[idx]; - target[idx] = segment_target[idx]; -// memcpy(pl_data, &plan, sizeof(plan_line_data_t)); - } while(idx); - - } - - return iterations != 0; -} - -static void maslow_limits_set_target_pos (uint_fast8_t idx) // fn name? -{ - /* - int32_t axis_position; - float position[3]; - maslow_convert_array_steps_to_mpos(position, sys.position); - - float aCl,bCl; // set initial chain lengths to table center when $HOME - void triangularInverse(float ,float , float* , float* ); - - x_axis.axis_Position = 0; - x_axis.target = 0; - x_axis.target_PS = 0; - x_axis.Integral = 0; - y_axis.axis_Position = 0; - y_axis.target = 0; - y_axis.target_PS = 0; - y_axis.Integral = 0; - z_axis.axis_Position = 0; - z_axis.target = 0; - z_axis.target_PS = 0; - z_axis.Integral = 0; - set_axis_position = 0; // force to center of table -- its a Maslow thing - - triangularInverse((float)(set_axis_position), (float)(set_axis_position), &aCl, &bCl); - sys.position[A_MOTOR] = (int32_t) lround(aCl * settings.steps_per_mm[A_MOTOR]); - sys.position[B_MOTOR] = (int32_t) lround(bCl * settings.steps_per_mm[B_MOTOR]); - sys.position[Z_AXIS] = set_axis_position; - - store_current_machine_pos(); // reset all the way out to stored space - sys.step_control = STEP_CONTROL_NORMAL_OP; // Return step control to normal operation. - return; - - sys.position[idx] = set_axis_position; - - switch(idx) { - case X_AXIS: - axis_position = system_convert_maslow_to_y_axis_steps(sys.position); - sys.position[A_MOTOR] = axis_position; - sys.position[B_MOTOR] = -axis_position; - break; - case Y_AXIS: - sys.position[A_MOTOR] = sys.position[B_MOTOR] = system_convert_maslow_to_x_axis_steps(sys.position); - break; - default: - sys.position[idx] = 0; - break; - } - */ -} - -// Set machine positions for homed limit switches. Don't update non-homed axes. -// NOTE: settings.max_travel[] is stored as a negative value. -static void maslow_limits_set_machine_positions (axes_signals_t cycle) -{ - /* - * uint_fast8_t idx = N_AXIS; - - if(settings.homing.flags.force_set_origin) { - if (cycle.mask & bit(--idx)) do { - switch(--idx) { - case X_AXIS: - sys.position[A_MOTOR] = system_convert_maslow_to_y_axis_steps(sys.position); - sys.position[B_MOTOR] = - sys.position[A_MOTOR]; - break; - case Y_AXIS: - sys.position[A_MOTOR] = system_convert_maslow_to_x_axis_steps(sys.position); - sys.position[B_MOTOR] = sys.position[A_MOTOR]; - break; - default: - sys.position[idx] = 0; - break; - } - } while (idx); - } else do { - - coord_data_t *pulloff = limits_homing_pulloff(NULL); - - if (cycle.mask & bit(--idx)) { - int32_t off_axis_position; - int32_t set_axis_position = bit_istrue(settings.homing.dir_mask.value, bit(idx)) - ? lroundf((settings.max_travel[idx] + pulloff->values[idx]) * settings.steps_per_mm[idx]) - : lroundf(-pulloff->values[idx] * settings.steps_per_mm[idx]); - switch(idx) { - case X_AXIS: - off_axis_position = system_convert_maslow_to_y_axis_steps(sys.position); - sys.position[A_MOTOR] = set_axis_position + off_axis_position; - sys.position[B_MOTOR] = set_axis_position - off_axis_position; - break; - case Y_AXIS: - off_axis_position = system_convert_maslow_to_x_axis_steps(sys.position); - sys.position[A_MOTOR] = off_axis_position + set_axis_position; - sys.position[B_MOTOR] = off_axis_position - set_axis_position; - break; - default: - sys.position[idx] = set_axis_position; - break; - } - } - } while(idx); - */ -} - -// TODO: format output in grbl fashion: [...] -status_code_t maslow_tuning (sys_state_t state, char *line) -{ - status_code_t retval = Status_OK; - - if(line[1] == 'M') switch(line[2]) { - - case 'C': // commit driver setting changes to non-volatile storage - settings_dirty.is_dirty = settings_dirty.driver_settings = true; - break; - - case 'X': - selected_motor = A_MOTOR; - hal.stream.write("X-Axis Selected" ASCII_EOL); - break; - - case 'Y': - selected_motor = B_MOTOR; - hal.stream.write("Y-Axis Selected" ASCII_EOL); - break; - - case 'Z': - selected_motor = Z_AXIS; - if(maslow_hal.get_debug_data(selected_motor)) - hal.stream.write("Z-Axis Selected" ASCII_EOL); - else { - selected_motor = A_MOTOR; - hal.stream.write("Z-Axis is not PID controlled, switched to A motor" ASCII_EOL); - } - break; - - case 'G': - maslow_hal.pos_enable(true); - break; - - case 'R': // reset current position - maslow_hal.reset_pid(selected_motor); - break; - - case '+': // Move - maslow_hal.move(selected_motor, 10000); - break; - - case '-': // Move - maslow_hal.move(selected_motor, -10000); - break; - - case '*': // Move - maslow_hal.move(selected_motor, 10); - break; - - case '/': // Move - maslow_hal.move(selected_motor, -10); - break; - - case 'I': - case 'M': - case 'D': - case 'P': - case 'S': - case 'A':; - if(line[3] == '=' && line[4] != '\0') { - float parameter; - uint_fast8_t counter = 4; - - if(!read_float(line, &counter, ¶meter)) - retval = Status_BadNumberFormat; - - else switch(line[2]) { - - case 'P': - maslow.pid[selected_motor].Kp = parameter; - hal.stream.write("Kp == "); - hal.stream.write(ftoa(maslow.pid[selected_motor].Kp, 3)); - hal.stream.write(ASCII_EOL); - break; - - case 'D': - maslow.pid[selected_motor].Kd = parameter; - hal.stream.write("Kd == "); - hal.stream.write(ftoa(maslow.pid[selected_motor].Kd, 3)); - hal.stream.write(ASCII_EOL); - break; - - case 'I': - maslow.pid[selected_motor].Ki = parameter; - hal.stream.write("Ki == "); - hal.stream.write(ftoa(maslow.pid[selected_motor].Ki, 3)); - hal.stream.write(ASCII_EOL); - maslow_hal.pid_settings_changed(selected_motor); - break; - - case 'M': - maslow.pid[selected_motor].Imax = parameter; - hal.stream.write("Imax == "); - hal.stream.write(ftoa(maslow.pid[selected_motor].Imax, 3)); - hal.stream.write(ASCII_EOL); - maslow_hal.pid_settings_changed(selected_motor); - break; - - case 'S': - { - maslow_hal.tuning_enable(true); - int32_t sz = maslow_hal.set_step_size(selected_motor, (int32_t)parameter); - hal.stream.write("S == "); - hal.stream.write(ftoa((float)sz, 0)); - hal.stream.write(ASCII_EOL); - } - break; - - case 'A': // test kinematics - from X,Y mm to A,B steps back to X,Y mm - { - float xyz[N_AXIS]; - int32_t abz[N_AXIS]; - recomputeGeometry(); - xyz[X_AXIS] = parameter; - if(line[counter++] == ',' && line[counter] != '\0') { - if(!read_float(line, &counter, &xyz[Y_AXIS])) - retval = Status_BadNumberFormat; - } else - retval = Status_BadNumberFormat; - - if(retval == Status_OK) { - - triangularInverse(abz, xyz); - hal.stream.write("[KINEMATICSTRANSFORM: X,Y = "); - hal.stream.write(ftoa(xyz[X_AXIS], 3)); - hal.stream.write(","); - hal.stream.write(ftoa(xyz[Y_AXIS], 3)); - hal.stream.write(" -> A,B steps: "); - hal.stream.write(uitoa((uint32_t)abz[A_MOTOR])); - hal.stream.write(","); - hal.stream.write(uitoa((uint32_t)abz[B_MOTOR])); - - maslow_convert_array_steps_to_mpos(xyz, abz); - hal.stream.write(" -> X,Y = "); - hal.stream.write(ftoa(xyz[X_AXIS], 3)); - hal.stream.write(","); - hal.stream.write(ftoa(xyz[Y_AXIS], 3)); - hal.stream.write("]" ASCII_EOL); - } - } - break; - } - } else - retval = Status_BadNumberFormat; - break; - - default: - { - maslow_debug_t *debug = maslow_hal.get_debug_data(selected_motor); - - hal.stream.write("[AXISPID:"); - hal.stream.write(axis_letter[selected_motor]); - hal.stream.write(": Kp = "); - hal.stream.write(ftoa(maslow.pid[selected_motor].Kp, 3)); - hal.stream.write(" Ki = "); - hal.stream.write(ftoa(maslow.pid[selected_motor].Ki, 3)); - hal.stream.write(" Kd = "); - hal.stream.write(ftoa(maslow.pid[selected_motor].Kd, 3)); - hal.stream.write(" Imax = "); - hal.stream.write(ftoa(maslow.pid[selected_motor].Imax, 3)); - - hal.stream.write("]\r\n[PIDDATA:err="); - hal.stream.write(ftoa(debug->Error, 0)); - hal.stream.write("\t\ti="); - hal.stream.write(ftoa(debug->Integral, 0)); - hal.stream.write("\tiT="); - hal.stream.write(ftoa(debug->iterm, 0)); - hal.stream.write("\td="); - hal.stream.write(ftoa(debug->DiffTerm, 0)); - // hal.stream.write("\tV="); - // hal.stream.write(ftoa(debug->totalSpeed, 0)); - hal.stream.write("\txCMD="); - hal.stream.write(ftoa(debug->speed, 0)); - // hal.stream.write("\tyCMD="); - // hal.stream.write(uitoa(motor[Y_AXIS]->speed)); - // hal.stream.write("\tzCMD="); - // hal.stream.write(uitoa(motor[Z_AXIS]->speed)); - hal.stream.write("]" ASCII_EOL); - } - break; - } else - retval = Status_Unhandled; - - return retval; -} - -// Initialize API pointers & machine parameters for Maslow router kinematics -bool maslow_init (void) -{ - float xy[2] = {0.0f, 0.0f}; - - if((nvs_address = nvs_alloc(sizeof(maslow_settings_t)))) { - - details.on_get_settings = grbl.on_get_settings; - grbl.on_get_settings = on_get_settings; - - recomputeGeometry(); - triangularInverse(sys.position, xy); - - selected_motor = A_MOTOR; - - kinematics.limits_set_target_pos = maslow_limits_set_target_pos; - kinematics.limits_get_axis_mask = maslow_limits_get_axis_mask; - kinematics.limits_set_machine_positions = maslow_limits_set_machine_positions; - kinematics.plan_target_to_steps = maslow_target_to_steps; - kinematics.convert_array_steps_to_mpos = maslow_convert_array_steps_to_mpos; - kinematics.segment_line = maslow_segment_line; - - grbl.on_unknown_sys_command = maslow_tuning; - } - - return nvs_address != 0; -} - -#endif - diff --git a/kinematics/maslow.h b/kinematics/maslow.h deleted file mode 100644 index 61fe64b..0000000 --- a/kinematics/maslow.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - maslow.h - Maslow router kinematics implementation - - Part of grblHAL - - Grbl is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Grbl 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grbl. If not, see . - - The basis for this code has been pulled from MaslowDue created by Larry D O'Cull. - - - Some portions of that package directly or indirectly has been pulled from from the Maslow CNC - firmware for Aduino Mega. Those parts are Copyright 2014-2017 Bar Smith. - - - It has been adapted for grbl by Terje Io. - - *** TO BE COMPLETED *** - -*/ - -#include "../grbl.h" - -#ifndef _MASLOW_H_ -#define _MASLOW_H_ - -#define FP_SCALING 1024.0f -#define SPROCKET_RADIUS_MM (10.1f) -#define MAX_SEG_LENGTH_MM 2.0f /* long lines must be segmented due to circular motion */ - - // PID position loop factors X: Kp = 25000 Ki = 15000 Kd = 22000 Imax = 5000 - // 14.000 fixed point arithmetic S13.10 -#ifdef DRIVER_TLE5206 - #define MASLOW_A_KP 10.0f - #define MASLOW_A_KI 21.0f - #define MASLOW_A_KD 18.0f - #define MASLOW_A_IMAX 5000 - - #define MASLOW_B_KP 10.0f - #define MASLOW_B_KI 21.0f - #define MASLOW_B_KD 18.0f - #define MASLOW_B_IMAX 5000 - - #define MASLOW_Z_KP 10.0f - #define MASLOW_Z_KI 21.0f - #define MASLOW_Z_KD 17.0f - #define MASLOW_Z_IMAX 5000 -#else - #define MASLOW_A_KP 22.0f - #define MASLOW_A_KI 17.0f - #define MASLOW_A_KD 20.0f - #define MASLOW_A_IMAX 5000 - - #define MASLOW_B_KP 22.0f - #define MASLOW_B_KI 17.0f - #define MASLOW_B_KD 20.0f - #define MASLOW_B_IMAX 5000 - - #define MASLOW_Z_KP 20.0f - #define MASLOW_Z_KI 17.0f - #define MASLOW_Z_KD 18.0f - #define MASLOW_Z_IMAX 5000 -#endif - -#define MASLOW_MACHINEWIDTH 2400.0f -#define MASLOW_MACHINEHEIGHT 1200.0f -#define MASLOW_DISTBETWEENMOTORS 3000.0f -#define MASLOW_MOTOROFFSETY 600.0f -#define MASLOW_CHAINLENGTH 3000.0f -#define MASLOW_CHAINOVERSPROCKET 0 -#define MASLOW_CHAINSAGCORRECTION 59.504839f -#define MASLOW_LEFTCHAINTOLERANCE 0.0f -#define MASLOW_RIGHTCHAINTOLERANCE 0.0f -#define MASLOW_ROTATIONDISKRADIUS 104.3f -#define MASLOW_SLEDHEIGHT 139.0f -#define MASLOW_SLEDWIDTH 310.0f -#define MASLOW_ACORRSCALING 1.003922f -#define MASLOW_BCORRSCALING 1.002611f - -typedef enum { - Maslow_ChainOverSprocket = 260, - Maslow_MachineWidth, - Maslow_MachineHeight, - Maslow_DistBetweenMotors, - Maslow_MotorOffsetY, - Maslow_AcorrScaling, - Maslow_BcorrScaling, - Maslow_SettingMax, -} maslow_setting_t; - -typedef enum { - AxisSetting_MaslowKP = 10, - AxisSetting_MaslowKI, - AxisSetting_MaslowKD, - AxisSetting_MaslowIMax, - AxisSetting_MaslowMaxSetting -} maslow_axis_setting_t; - -typedef struct { - float Kp; - float Ki; - float Kd; - float Imax; -} maslow_pid_coefficients_t; - -typedef struct { - maslow_pid_coefficients_t pid[N_AXIS]; - - uint32_t chainOverSprocket; - float machineWidth; /* Maslow specific settings */ - float machineHeight; - float distBetweenMotors; - float motorOffsetY; - float chainSagCorrection; - float leftChainTolerance; - float rightChainTolerance; - float rotationDiskRadius; - float chainLength; - float sledHeight; - float sledWidth; - - float XcorrScaling; - float YcorrScaling; -} maslow_settings_t; - -typedef struct { - float Error; - float Integral; - float iterm; - float DiffTerm; - float speed; -} maslow_debug_t; - -typedef struct { - maslow_settings_t settings; - void (*pid_settings_changed)(uint_fast8_t idx); - void (*move)(uint_fast8_t idx, int_fast16_t distance); - void (*reset_pid)(uint_fast8_t idx); - void (*pos_enable)(bool enable); - void (*tuning_enable)(bool enable); - int32_t (*set_step_size)(uint_fast8_t idx, int32_t step_size); - maslow_debug_t *(*get_debug_data)(uint_fast8_t idx); -} maslow_hal_t; - -extern maslow_hal_t maslow_hal; - -// Initialize HAL pointers for Maslow Router kinematics -bool maslow_init (void); -static status_code_t maslow_tuning (uint_fast16_t state, char *line); - -#endif diff --git a/kinematics/polar.h b/kinematics/polar.h deleted file mode 100644 index 715e6c0..0000000 --- a/kinematics/polar.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - corexy.c - polar kinematics implementation - - Part of grblHAL - - Copyright (c) 2023 Terje Io - - grblHAL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - grblHAL 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with grblHAL. If not, see . -*/ - -#ifndef _POLAR_H_ -#define _POLAR_H_ - -// Initialize HAL pointers for Polar kinematics -void polar_init (void); - -#endif // _POLAR_H_ diff --git a/kinematics/wall_plotter.h b/kinematics/wall_plotter.h deleted file mode 100644 index 5242a70..0000000 --- a/kinematics/wall_plotter.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - wall_plotter.h - wall plotter kinematics implementation - - Part of grblHAL - - Copyright (c) 2019 Terje Io - - grblHAL is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - grblHAL 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with grblHAL. If not, see . -*/ - -#ifndef _WALL_PLOTTER_H_ -#define _WALL_PLOTTER_H_ - -// Initialize HAL pointers for Wall Plotter kinematics -void wall_plotter_init (void); - -#endif diff --git a/machine_limits.c b/machine_limits.c index cbe2ae2..92c96e7 100644 --- a/machine_limits.c +++ b/machine_limits.c @@ -139,8 +139,6 @@ FLASHMEM void limits_set_work_envelope (void) } while(idx); } -#ifndef KINEMATICS_API - // Set machine positions for homed limit switches. Don't update non-homed axes. // NOTE: settings.max_travel[] is stored as a negative value. FLASHMEM void limits_set_machine_positions (axes_signals_t cycle, bool add_pulloff) @@ -164,8 +162,6 @@ FLASHMEM void limits_set_machine_positions (axes_signals_t cycle, bool add_pullo } while(idx); } -#endif - // Set, get homing pulloff FLASHMEM coord_data_t *limits_homing_pulloff (coord_data_t *distance) { @@ -204,11 +200,12 @@ FLASHMEM static bool limits_pull_off (axes_signals_t axis, coord_data_t *distanc plan_data.feed_rate = settings.axis[0].homing_seek_rate * sqrtf(n_axis); // Adjust so individual axes all move at pull-off rate. plan_data.condition.coolant = gc_state.modal.coolant; + // Bypass mc_line(). Directly plan homing motion. #ifdef KINEMATICS_API coord_data_t k_target; - plan_buffer_line(kinematics.transform_from_cartesian(k_target.values, target.values), &plan_data); // Bypass mc_line(). Directly plan homing motion.; + plan_buffer_line(kinematics.transform_from_cartesian(k_target.values, target.values), &plan_data); #else - plan_buffer_line(target.values, &plan_data); // Bypass mc_line(). Directly plan homing motion. + plan_buffer_line(target.values, &plan_data); #endif sys.step_control.flags = 0; // Clear existing flags and @@ -419,7 +416,7 @@ FLASHMEM static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_squ idx = N_AXIS; do { idx--; - if ((axislock.mask & step_pin[idx]) && (homing_state.mask & bit(idx))) { + if((axislock.mask & step_pin[idx]) && (homing_state.mask & bit(idx))) { #ifdef KINEMATICS_API axislock.mask &= ~kinematics.limits_get_axis_mask(idx); #else @@ -432,7 +429,7 @@ FLASHMEM static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_squ sys.homing_axis_lock.mask = axislock.mask; - if (autosquare_check && abs(initial_trigger_position - sys.position[dual_motor_axis]) > autosquare_fail_distance) { + if(autosquare_check && abs(initial_trigger_position - sys.position[dual_motor_axis]) > autosquare_fail_distance) { system_set_exec_alarm(Alarm_HomingFailAutoSquaringApproach); mc_reset(); protocol_execute_realtime(); @@ -523,9 +520,11 @@ FLASHMEM static bool homing_cycle (axes_signals_t cycle, axes_signals_t auto_squ if(auto_square.mask && settings.axis[dual_motor_axis].dual_axis_offset != 0.0f) { hal.stepper.disable_motors(auto_square, settings.axis[dual_motor_axis].dual_axis_offset < 0.0f ? SquaringMode_B : SquaringMode_A); distance.values[dual_motor_axis] = fabs(settings.axis[dual_motor_axis].dual_axis_offset); +#if defined(ASYMMETRIC_GANGING) || defined(ASYMMETRIC_AUTO_SQUARE) + auto_square.mask |= (1 << (N_AXIS - 1)); +#endif if(!limits_pull_off(auto_square, &distance, 1.0f)) return false; - hal.stepper.disable_motors((axes_signals_t){0}, SquaringMode_Both); } // The active cycle axes should now be homed and machine limits have been located. By @@ -615,6 +614,8 @@ FLASHMEM status_code_t limits_go_home (axes_signals_t cycle) if((auto_squared.mask & homing_signals_select(hal.homing.get_state(), (axes_signals_t){0}, SquaringMode_Both).mask) && !limits_pull_off(auto_square, &homing_pulloff, HOMING_AXIS_LOCATE_SCALAR)) return Status_LimitsEngaged; // Auto squaring with limit switch asserted is not allowed. + + hal.stepper.disable_motors((axes_signals_t){0}, SquaringMode_Both); } return grbl.home_machine(cycle, auto_square) ? Status_OK : Status_Unhandled; diff --git a/motor_pins.h b/motor_pins.h index bb1decb..c089769 100644 --- a/motor_pins.h +++ b/motor_pins.h @@ -474,7 +474,7 @@ #define Z2_STEP_PORT MOTOR_IO(Z2_MOTOR_IDX, _STEP_PORT) #define Z2_STEP_PIN MOTOR_IO(Z2_MOTOR_IDX, _STEP_PIN) -#define Z2_STEP_BIT (1<< 3 @@ -108,7 +108,7 @@ static char *get_axis_values_inches (float *axis_values) #endif else strcat(buf, ftoa(axis_values[idx] * INCH_PER_MM, N_DECIMAL_COORDVALUE_INCH)); - if (idx < (N_AXIS - 1)) + if (idx < (system_n_axis() - 1)) strcat(buf, ","); } @@ -691,7 +691,7 @@ FLASHMEM void report_ngc_parameters (void) static inline bool is_g92_active (void) { bool active = false; - uint_fast32_t idx = N_AXIS; + uint_fast32_t idx = system_n_axis(); do { idx--; @@ -959,7 +959,7 @@ FLASHMEM void report_build_info (char *line, bool extended) hal.stream.write(uitoa(hal.rx_buffer_size)); if(extended) { hal.stream.write(","); - hal.stream.write(uitoa((uint32_t)N_AXIS)); + hal.stream.write(uitoa((uint32_t)system_n_axis())); hal.stream.write(","); hal.stream.write(uitoa(grbl.tool_table.n_tools)); } @@ -971,12 +971,12 @@ FLASHMEM void report_build_info (char *line, bool extended) nvs_io_t *nvs = nvs_buffer_get_physical(); atc_status_t atc = hal.tool.atc_get_state(); - strcat(strcpy(buf, "[AXS:"), uitoa(N_AXIS)); + strcat(strcpy(buf, "[AXS:"), uitoa((uint32_t)system_n_axis())); append = &buf[6]; *append++ = ':'; - for(idx = 0; idx < N_AXIS; idx++) + for(idx = 0; idx < system_n_axis(); idx++) *append++ = *axis_letter[idx]; *append = '\0'; @@ -1267,7 +1267,7 @@ void report_realtime_status (stream_write_ptr stream_write, status_report_tracki // Calculate distance-to-go in current block (i.e., difference between target / end-of-block) and current position) plan_block_t *cur_block = plan_get_current_block(); if((report->flags.distance_to_go = !!cur_block)) { - for(idx = 0; idx < N_AXIS; idx++) { + for(idx = 0; idx < system_n_axis(); idx++) { dist_remaining[idx] = cur_block->target_mm[idx] - print_position[idx]; } } @@ -1275,7 +1275,7 @@ void report_realtime_status (stream_write_ptr stream_write, status_report_tracki if(!settings.status_report.machine_position) { // Apply work coordinate offsets and tool length offset to current position. - for(idx = 0; idx < N_AXIS; idx++) { + for(idx = 0; idx < system_n_axis(); idx++) { wco[idx] = gc_get_offset(idx, true); print_position[idx] -= wco[idx]; } @@ -1433,7 +1433,7 @@ void report_realtime_status (stream_write_ptr stream_write, status_report_tracki if(report->flags.wco) { if(settings.status_report.machine_position) { - for(idx = 0; idx < N_AXIS; idx++) + for(idx = 0; idx < system_n_axis(); idx++) wco[idx] = gc_get_offset(idx, true); } stream_write("|WCO:"); diff --git a/settings.c b/settings.c index abaa6f2..dc8fafb 100644 --- a/settings.c +++ b/settings.c @@ -57,7 +57,7 @@ const settings_restore_t settings_all = { .driver_parameters = SETTINGS_RESTORE_DRIVER_PARAMETERS }; -PROGMEM const settings_t defaults = { +PROGMEM static const settings_t defaults = { .version.id = SETTINGS_VERSION, .version.build = (GRBL_BUILD - 20000000UL), @@ -399,7 +399,7 @@ PROGMEM const settings_t defaults = { static bool group_is_available (const setting_group_detail_t *group) { - return true; + return group->id < Group_XAxis || group->id > Group_WAxis || group->id < Group_Axis0 + system_n_axis(); } PROGMEM static const setting_group_detail_t setting_group_detail [] = { @@ -582,27 +582,164 @@ static void homing_pulloff_init (float pulloff) limits_homing_pulloff(&distance); } +FLASHMEM static status_code_t set_axis_mask (setting_id_t id, uint_fast16_t value) +{ + status_code_t status = Status_OK; + + value &= AXES_BITMASK; + + switch(id) { + + case Setting_StepInvertMask: + settings.steppers.step_invert.mask = value; + break; + + case Setting_DirInvertMask: + settings.steppers.dir_invert.mask = value; + break; + + case Setting_InvertStepperEnable: #if COMPATIBILITY_LEVEL > 2 - -static status_code_t set_enable_invert_mask (setting_id_t id, uint_fast16_t int_value) -{ - settings.steppers.enable_invert.mask = int_value ? 0 : AXES_BITMASK; - - return Status_OK; -} - + settings.steppers.enable_invert.mask = value ? 0 : AXES_BITMASK; +#else + settings.steppers.enable_invert.mask = value; #endif + break; + case Setting_LimitPinsInvertMask: #if COMPATIBILITY_LEVEL > 1 + settings.steppers.enable_invert.mask = value ? 0 : AXES_BITMASK; +#else + settings.steppers.enable_invert.mask = value; +#endif + break; -static status_code_t set_limits_invert_mask (setting_id_t id, uint_fast16_t int_value) -{ - settings.limits.invert.mask = (int_value ? ~(DEFAULT_LIMIT_SIGNALS_INVERT_MASK) : DEFAULT_LIMIT_SIGNALS_INVERT_MASK) & AXES_BITMASK; + case Setting_LimitPullUpDisableMask: + settings.limits.disable_pullup.mask = value; + break; - return Status_OK; + case Setting_HomingDirMask: + settings.homing.dir_mask.value = value; + break; + + case Setting_SteppersEnergize: + settings.steppers.energize.mask = value; + break; + + case Setting_HomingCycle_1: + case Setting_HomingCycle_2: + case Setting_HomingCycle_3: + case Setting_HomingCycle_4: + case Setting_HomingCycle_5: + case Setting_HomingCycle_6: + settings.homing.cycle[id - Setting_HomingCycle_1].mask = value; + break; + + case Setting_HomePinsInvertMask: + settings.home_invert.mask = value; + break; + + case Setting_MotorWarningsEnable: + settings.motor_warning_enable.mask = value; + break; + + case Setting_MotorWarningsInvert: + settings.motor_warning_invert.mask = value; + break; + + case Setting_MotorFaultsEnable: + settings.motor_fault_enable.mask = value; + break; + + case Setting_MotorFaultsInvert: + settings.motor_fault_invert.mask = value; + break; + + default: + // Should never enter here + break; + } + + return status; } +FLASHMEM static uint32_t get_axis_mask (setting_id_t id, uint_fast16_t int_value) +{ + uint32_t value = 0; + + switch(id) { + + case Setting_StepInvertMask: + value = settings.steppers.step_invert.mask; + break; + + case Setting_DirInvertMask: + value = settings.steppers.dir_invert.mask; + break; + + case Setting_InvertStepperEnable: +#if COMPATIBILITY_LEVEL > 2 + value = !!settings.steppers.enable_invert.mask; +#else + value = settings.steppers.enable_invert.mask; #endif + break; + + case Setting_LimitPinsInvertMask: +#if COMPATIBILITY_LEVEL > 1 + value = settings.steppers.enable_invert.mask == DEFAULT_LIMIT_SIGNALS_INVERT_MASK ? 0 : 1; +#else + value = settings.steppers.enable_invert.mask; +#endif + break; + + case Setting_LimitPullUpDisableMask: + value = settings.limits.disable_pullup.mask; + break; + + case Setting_HomingDirMask: + value = settings.homing.dir_mask.value; + break; + + case Setting_SteppersEnergize: + value = settings.steppers.energize.mask; + break; + + case Setting_HomingCycle_1: + case Setting_HomingCycle_2: + case Setting_HomingCycle_3: + case Setting_HomingCycle_4: + case Setting_HomingCycle_5: + case Setting_HomingCycle_6: + value = settings.homing.cycle[id - Setting_HomingCycle_1].mask & system_axis_mask(); + break; + + case Setting_HomePinsInvertMask: + value = settings.home_invert.mask; + break; + + case Setting_MotorWarningsEnable: + value = settings.motor_warning_enable.mask; + break; + + case Setting_MotorWarningsInvert: + value = settings.motor_warning_invert.mask; + break; + + case Setting_MotorFaultsEnable: + value = settings.motor_fault_enable.mask; + break; + + case Setting_MotorFaultsInvert: + value = settings.motor_fault_invert.mask; + break; + + default: + break; + } + + return value & system_axis_mask(); +} static status_code_t validate_pulse_width (float max_rate, float steps_per_mm, float pulse_width) { @@ -622,7 +759,7 @@ static status_code_t set_pulse_width (setting_id_t id, float value) do { idx--; #if N_AXIS > 3 - if(bit_isfalse(settings.steppers.is_rotary.mask, bit(idx))) + if(system_n_axis() > 3 && bit_isfalse(settings.steppers.is_rotary.mask, bit(idx))) #endif status = validate_pulse_width(settings.axis[idx].max_rate, settings.axis[idx].steps_per_mm, value); } while(idx && status == Status_OK); @@ -663,15 +800,6 @@ static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_v return Status_OK; } -static status_code_t set_stepper_energize_mask (setting_id_t id, uint_fast16_t int_value) -{ - settings.steppers.energize.mask = int_value; - - hal.stepper.enable(settings.steppers.energize, true); - - return Status_OK; -} - static status_code_t set_report_interval (setting_id_t setting, uint_fast16_t int_value) { if((settings.report_interval = int_value) == 0) @@ -993,14 +1121,6 @@ static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_v #endif // NO_SAFETY_DOOR_SUPPORT -static status_code_t set_homing_cycle (setting_id_t id, uint_fast16_t int_value) -{ - settings.homing.cycle[id - Setting_HomingCycle_1].mask = int_value; - limits_set_homing_axes(); - - return Status_OK; -} - static status_code_t set_homing_pulloff (setting_id_t id, float value) { settings.homing.pulloff = value; @@ -1012,7 +1132,7 @@ static status_code_t set_homing_pulloff (setting_id_t id, float value) static status_code_t set_homing_feedrates (setting_id_t id, float value) { - uint_fast8_t idx = N_AXIS; + uint_fast8_t idx = system_n_axis(); if(!settings.homing.flags.per_axis_feedrates) switch(id) { @@ -1516,18 +1636,6 @@ FLASHMEM static uint32_t get_int (setting_id_t id) switch(id) { -#if COMPATIBILITY_LEVEL > 2 - case Setting_InvertStepperEnable: - value = settings.steppers.enable_invert.mask ? 0 : 1; - break; -#endif - -#if COMPATIBILITY_LEVEL > 1 - case Setting_LimitPinsInvertMask: - value = settings.limits.invert.mask == DEFAULT_LIMIT_SIGNALS_INVERT_MASK ? 0 : 1; - break; -#endif - case Setting_SpindlePWMOptions: value = settings.pwm_spindle.flags.pwm_disable ? 0 @@ -1538,6 +1646,10 @@ FLASHMEM static uint32_t get_int (setting_id_t id) (settings.pwm_spindle.flags.ignore_delays ? 0b10000 : 0)); break; + case Setting_HomingDirMask: + value = settings.homing.dir_mask.mask & system_axis_mask(); + break; + case Setting_Mode: value = settings.mode; break; @@ -1620,15 +1732,6 @@ FLASHMEM static uint32_t get_int (setting_id_t id) value = settings.parking.flags.value; break; - case Setting_HomingCycle_1: - case Setting_HomingCycle_2: - case Setting_HomingCycle_3: - case Setting_HomingCycle_4: - case Setting_HomingCycle_5: - case Setting_HomingCycle_6: - value = settings.homing.cycle[id - Setting_HomingCycle_1].mask; - break; - case Setting_RestoreOverrides: value = settings.flags.restore_overrides; break; @@ -1959,6 +2062,24 @@ FLASHMEM static bool is_setting_available (const setting_detail_t *setting, uint available = spindle_get_caps(false).variable; break; +#if N_AXIS > 3 + case Setting_HomingCycle_4: + case Settings_RotaryAxes: + case Setting_RotaryWrap: + available = system_n_axis() > 3; + break; +#endif +#if N_AXIS > 4 + case Setting_HomingCycle_5: + available = system_n_axis() > 4; + break; +#endif +#if N_AXIS > 5 + case Setting_HomingCycle_6: + available = system_n_axis() > 5; + break; +#endif + case Setting_SleepEnable: available = SLEEP_DURATION > 0.0f; break; @@ -2156,17 +2277,17 @@ FLASHMEM static void _settings_write_global (void) PROGMEM static const setting_detail_t setting_detail[] = { { Setting_PulseMicroseconds, Group_Stepper, "Step pulse time", "microseconds", Format_Decimal, "#0.0", step_us_min, NULL, Setting_IsLegacyFn, set_pulse_width, get_float, NULL }, { Setting_StepperIdleLockTime, Group_Stepper, "Step idle delay", "milliseconds", Format_Int16, "####0", NULL, "65535", Setting_IsLegacy, &settings.steppers.idle_lock_time, NULL, NULL }, - { Setting_StepInvertMask, Group_Stepper, "Step pulse invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.step_invert.mask, NULL, NULL }, - { Setting_DirInvertMask, Group_Stepper, "Step direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.dir_invert.mask, NULL, NULL }, + { Setting_StepInvertMask, Group_Stepper, "Step pulse invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL }, + { Setting_DirInvertMask, Group_Stepper, "Step direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL }, #if COMPATIBILITY_LEVEL <= 2 - { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable output(s)", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.enable_invert.mask, NULL, NULL }, + { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable output(s)", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL }, #else - { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable output", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_enable_invert_mask, get_int, NULL }, + { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable output", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL }, #endif #if COMPATIBILITY_LEVEL <= 1 - { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.limits.invert.mask, NULL, NULL }, + { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL }, #else - { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_limits_invert_mask, get_int, NULL }, + { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit inputs", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL }, #endif { Setting_InvertProbePin, Group_Probing, "Invert probe inputs", NULL, Format_Bitfield, probe_signals, NULL, NULL, Setting_IsLegacyFn, set_probe_invert, get_int, is_setting_available }, { Setting_SpindlePWMBehaviour, Group_Spindle, "Deprecated", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_pwm_mode, get_int, is_setting_available }, @@ -2184,7 +2305,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_CoolantInvertMask, Group_Coolant, "Invert coolant outputs", NULL, Format_Bitfield, coolant_signals, NULL, NULL, Setting_IsExtended, &settings.coolant.invert.mask, NULL, NULL }, { Setting_SpindleInvertMask, Group_Spindle, "Invert spindle signals", NULL, Format_Bitfield, spindle_signals, NULL, NULL, Setting_IsExtendedFn, set_spindle_invert, get_int, is_setting_available, { .reboot_required = On } }, { Setting_ControlPullUpDisableMask, Group_ControlSignals, "Pullup disable control inputs", NULL, Format_Bitfield, control_signals, NULL, NULL, Setting_IsExtendedFn, set_control_disable_pullup, get_int, is_setting_available }, - { Setting_LimitPullUpDisableMask, Group_Limits, "Pullup disable limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.limits.disable_pullup.mask, NULL, NULL }, + { Setting_LimitPullUpDisableMask, Group_Limits, "Pullup disable limit inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL }, { Setting_ProbePullUpDisable, Group_Probing, "Pullup disable probe inputs", NULL, Format_Bitfield, probe_signals, NULL, NULL, Setting_IsLegacyFn, set_probe_disable_pullup, get_int, is_setting_available }, { Setting_SoftLimitsEnable, Group_Limits, "Soft limits enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_soft_limits_enable, get_int, NULL }, #if COMPATIBILITY_LEVEL <= 1 @@ -2201,7 +2322,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { #else { Setting_HomingEnable, Group_Homing, "Homing cycle enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_homing_enable, get_int, NULL }, #endif - { Setting_HomingDirMask, Group_Homing, "Homing direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.homing.dir_mask.value, NULL, NULL }, + { Setting_HomingDirMask, Group_Homing, "Homing direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacyFn, set_axis_mask, get_axis_mask, NULL }, { Setting_HomingFeedRate, Group_Homing, "Homing locate feed rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsLegacyFn, set_homing_feedrates, get_float, NULL }, { Setting_HomingSeekRate, Group_Homing, "Homing search seek rate", "mm/min", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsLegacyFn, set_homing_feedrates, get_float, NULL }, { Setting_HomingDebounceDelay, Group_Homing, "Homing switch debounce delay", "milliseconds", Format_Int16, "##0", NULL, NULL, Setting_IsLegacy, &settings.homing.debounce_delay, NULL, NULL }, @@ -2217,24 +2338,24 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_PWMOffValue, Group_Spindle, "Spindle PWM off value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.pwm_spindle.pwm_off_value, NULL, is_setting_available }, { Setting_PWMMinValue, Group_Spindle, "Spindle PWM min value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.pwm_spindle.pwm_min_value, NULL, is_setting_available }, { Setting_PWMMaxValue, Group_Spindle, "Spindle PWM max value", "percent", Format_Decimal, "##0.0", NULL, "100", Setting_IsExtended, &settings.pwm_spindle.pwm_max_value, NULL, is_setting_available }, - { Setting_SteppersEnergize, Group_Stepper, "Steppers to keep enabled", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_stepper_energize_mask, get_int, NULL }, + { Setting_SteppersEnergize, Group_Stepper, "Steppers to keep enabled", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL }, { Setting_SpindlePPR, Group_Spindle, "Spindle pulses per revolution (PPR)", NULL, Format_Int16, "###0", NULL, NULL, Setting_IsExtended, &settings.spindle.ppr, NULL, is_setting_available, { .reboot_required = On } }, { Setting_EnableLegacyRTCommands, Group_General, "Enable legacy RT commands", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_enable_legacy_rt_commands, get_int, NULL }, { Setting_JogSoftLimited, Group_Jogging, "Limit jog commands", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_jog_soft_limited, get_int, NULL }, { Setting_ParkingEnable, Group_SafetyDoor, "Parking cycle", NULL, Format_XBitfield, "Enable,Deactivate upon init,Enable parking override control", NULL, NULL, Setting_IsExtendedFn, set_parking_enable, get_int, NULL }, { Setting_ParkingAxis, Group_SafetyDoor, "Parking axis", NULL, Format_RadioButtons, "X,Y,Z", NULL, NULL, Setting_IsExtended, &settings.parking.axis, NULL, NULL }, { Setting_HomingLocateCycles, Group_Homing, "Homing passes", NULL, Format_Int8, "##0", "1", "128", Setting_IsExtended, &settings.homing.locate_cycles, NULL, NULL }, - { Setting_HomingCycle_1, Group_Homing, "Axes homing, first phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, - { Setting_HomingCycle_2, Group_Homing, "Axes homing, second phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, - { Setting_HomingCycle_3, Group_Homing, "Axes homing, third phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, + { Setting_HomingCycle_1, Group_Homing, "Axes homing, first phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL }, + { Setting_HomingCycle_2, Group_Homing, "Axes homing, second phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL }, + { Setting_HomingCycle_3, Group_Homing, "Axes homing, third phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, NULL }, #if N_AXIS > 3 - { Setting_HomingCycle_4, Group_Homing, "Axes homing, fourth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, + { Setting_HomingCycle_4, Group_Homing, "Axes homing, fourth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available }, #endif #if N_AXIS > 4 - { Setting_HomingCycle_5, Group_Homing, "Axes homing, fifth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, + { Setting_HomingCycle_5, Group_Homing, "Axes homing, fifth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available }, #endif #if N_AXIS > 5 - { Setting_HomingCycle_6, Group_Homing, "Axes homing, sixth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_homing_cycle, get_int, NULL }, + { Setting_HomingCycle_6, Group_Homing, "Axes homing, sixth phase", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available }, #endif { Setting_ParkingPulloutIncrement, Group_SafetyDoor, "Parking pull-out distance", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.pullout_increment, NULL, NULL }, { Setting_ParkingPulloutRate, Group_SafetyDoor, "Parking pull-out rate", "mm/min", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.pullout_rate, NULL, NULL }, @@ -2291,7 +2412,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_DisableG92Persistence, Group_General, "Disable G92 persistence", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_g92_disable_persistence, get_int, NULL }, #endif #if N_AXIS > 3 - { Settings_RotaryAxes, Group_Stepper, "Rotary axes", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_axes, get_int, NULL }, + { Settings_RotaryAxes, Group_Stepper, "Rotary axes", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_axes, get_int, is_setting_available }, #endif { Setting_DoorSpindleOnDelay, Group_SafetyDoor, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, NULL, { .allow_null = On } }, { Setting_DoorCoolantOnDelay, Group_SafetyDoor, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, NULL, { .allow_null = On } }, @@ -2312,16 +2433,16 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_RGB_StripLengt0, Group_AuxPorts, "LED strip 1 length", NULL, Format_Int8, "##0", NULL, "255", Setting_NonCore, &settings.rgb_strip.length0, NULL, is_setting_available }, { Setting_RGB_StripLengt1, Group_AuxPorts, "LED strip 2 length", NULL, Format_Int8, "##0", NULL, "255", Setting_NonCore, &settings.rgb_strip.length1, NULL, is_setting_available }, #if N_AXIS > 3 - { Setting_RotaryWrap, Group_Stepper, "Fast rotary go to G28", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_wrap_axes, get_int, NULL }, + { Setting_RotaryWrap, Group_Stepper, "Fast rotary go to G28", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_wrap_axes, get_int, is_setting_available }, #endif { Setting_SpindleOffDelay, Group_Spindle, "Spindle off delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtendedFn, set_float, get_float, is_setting_available, { .allow_null = On } }, { Setting_FSOptions, Group_General, "File systems options", NULL, Format_Bitfield, fs_options, NULL, NULL, Setting_IsExtended, &settings.fs_options.mask, NULL, is_setting_available }, - { Setting_HomePinsInvertMask, Group_Limits, "Invert home inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.home_invert.mask, NULL, is_setting_available }, + { Setting_HomePinsInvertMask, Group_Limits, "Invert home inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available }, { Setting_CoolantOnDelay, Group_Coolant, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtendedFn, set_float, get_float, is_setting_available, { .allow_null = On } }, - { Setting_MotorWarningsEnable, Group_Stepper, "Motor warning inputs enable", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.motor_warning_enable, NULL, is_setting_available }, - { Setting_MotorWarningsInvert, Group_Stepper, "Invert motor warning inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.motor_warning_invert, NULL, is_setting_available }, - { Setting_MotorFaultsEnable, Group_Stepper, "Motor fault inputs enable", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.motor_fault_enable, NULL, is_setting_available }, - { Setting_MotorFaultsInvert, Group_Stepper, "Invert motor fault inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.motor_fault_invert, NULL, is_setting_available }, + { Setting_MotorWarningsEnable, Group_Stepper, "Motor warning inputs enable", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available }, + { Setting_MotorWarningsInvert, Group_Stepper, "Invert motor warning inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available }, + { Setting_MotorFaultsEnable, Group_Stepper, "Motor fault inputs enable", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available }, + { Setting_MotorFaultsInvert, Group_Stepper, "Invert motor fault inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtendedFn, set_axis_mask, get_axis_mask, is_setting_available }, { Setting_ResetActions, Group_General, "Reset actions", NULL, Format_Bitfield, "Clear homed status if position was lost,Clear offsets (except G92),Clear rapids override,Clear feed override", NULL, NULL, Setting_IsExtendedFn, set_reset_actions, get_int, NULL }, { Setting_StepperEnableDelay, Group_Stepper, "Stepper enable delay", "ms", Format_Int16, "##0", NULL, "500", Setting_IsExtended, &settings.stepper_enable_delay, NULL, NULL }, { Setting_SubroutineOptions, Group_General, "Subroutine options", NULL, Format_Bitfield, "Prescan for internal M98 subroutines", NULL, NULL, Setting_IsExtendedFn, set_suboptions, get_int, is_setting_available } @@ -2897,7 +3018,7 @@ FLASHMEM bool settings_iterator (const setting_detail_t *setting, setting_output uint_fast8_t axis_idx = 0; - for(axis_idx = 0; axis_idx < N_AXIS; axis_idx++) { + for(axis_idx = 0; axis_idx < system_n_axis(); axis_idx++) { if(setting->is_available == NULL || setting->is_available(setting, axis_idx)) { @@ -3210,7 +3331,7 @@ FLASHMEM static status_code_t setting_validate_me_uint (const setting_detail_t * break; case Format_AxisMask: - if(value >= (1 << N_AXIS)) + if(value >= (1 << system_n_axis())) status = Status_SettingValueOutOfRange; break; @@ -3416,6 +3537,25 @@ FLASHMEM status_code_t settings_store_setting (setting_id_t id, char *svalue) machine_mode_changed = false; set->on_changed(&settings, changed); + + switch(setting->id) { + + case Setting_SteppersEnergize: + hal.stepper.enable(settings.steppers.energize, true); + break; + + case Setting_HomingCycle_1: + case Setting_HomingCycle_2: + case Setting_HomingCycle_3: + case Setting_HomingCycle_4: + case Setting_HomingCycle_5: + case Setting_HomingCycle_6: + limits_set_homing_axes(); + break; + + default: + break; + } } } @@ -3570,7 +3710,7 @@ FLASHMEM void settings_init (void) setting_remove_elements(Setting_DoorOptions, ((!settings.parking.flags.enabled || hal.signals_cap.safety_door_ajar) << 1) | hal.signals_cap.safety_door_ajar, true); #endif #if N_AXIS > 3 - for(idx = 3; idx < N_AXIS; idx++) + for(idx = 3; idx < system_n_axis(); idx++) *(rotary_axes + (idx - 3) * 7) = *axis_letter[idx]; #endif diff --git a/system.c b/system.c index a9d3580..6fea714 100644 --- a/system.c +++ b/system.c @@ -33,6 +33,8 @@ #include "kinematics.h" #endif +static uint8_t n_axis = N_AXIS; + /*! \internal \brief Simple hypotenuse computation function. \param x length \param y height @@ -43,6 +45,27 @@ inline static float hypot_f (float x, float y) return sqrtf(x * x + y * y); } +FLASHMEM uint8_t system_claim_axis (void) +{ + return n_axis > 3 ? n_axis-- : 0; +} + +uint8_t system_n_axis (void) +{ + return n_axis; +} + +FLASHMEM uint8_t system_axis_mask (void) +{ + uint8_t axis_mask = 0; + uint_fast32_t idx = n_axis; + + while(idx--) + axis_mask = (axis_mask << 1) | 1; + + return axis_mask; +} + void system_init_switches (void) { control_signals_t signals = hal.control.get_state(); @@ -165,6 +188,8 @@ FLASHMEM void system_execute_startup (void *data) uint_fast8_t idx; char line[sizeof(stored_line_t)]; + bool single_block = sys.flags.single_block; + sys.flags.single_block = Off; // Disable single block mode when executing startup code. for(idx = 0; idx < N_STARTUP_LINE; idx++) { if(!settings_read_startup_line(idx, line)) @@ -176,6 +201,8 @@ FLASHMEM void system_execute_startup (void *data) } while((block = strtok(NULL, "|"))); } } + + sys.flags.single_block = single_block; } } diff --git a/system.h b/system.h index 8a4a0bd..70b8473 100644 --- a/system.h +++ b/system.h @@ -319,6 +319,10 @@ typedef struct sys_commands_str { extern system_t sys; +uint8_t system_n_axis (void); +uint8_t system_axis_mask (void); +uint8_t system_claim_axis (void); + status_code_t system_execute_line (char *line); void system_execute_startup (void *data); void system_flag_wco_change (void);