Skip to content

Commit

Permalink
Changed kinematics API and implementations (corexy and wallplotter) t…
Browse files Browse the repository at this point in the history
…o allow backlash compensation. Ref [ESP32 issue 25](grblHAL/ESP32#25).

Fixed feed rate handling for corexy kinematics. Ref issue #147.
Fixed tool table/tool change bugs. Ref. [ioSender issue 228](terjeio/ioSender#228).
  • Loading branch information
terjeio committed Jun 12, 2022
1 parent 6d00f74 commit b55cca1
Show file tree
Hide file tree
Showing 22 changed files with 378 additions and 141 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ It has been written to complement grblHAL and has features such as proper keyboa

---

Latest build date is 20220325, see the [changelog](changelog.md) for details.
Latest build date is 20220612, see the [changelog](changelog.md) for details.
__NOTE:__ A settings reset will be performed on an update for versions earlier than 20211122. Backup and restore of settings is recommended.
__IMPORTANT!__ A new setting has been introduced for ganged axes motors in version 20211121.
I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured.
Expand Down
5 changes: 3 additions & 2 deletions alarms.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2017-2022 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Expand Down Expand Up @@ -43,7 +43,8 @@ PROGMEM static const alarm_detail_t alarm_detail[] = {
{ Alarm_Spindle, "Spindle at speed timeout. Clear before continuing." },
{ Alarm_HomingFailAutoSquaringApproach, "Homing fail. Could not find second limit switch for auto squared axis within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring." },
{ Alarm_SelftestFailed, "Power on selftest (POS) failed." },
{ Alarm_MotorFault, "Motor fault." }
{ Alarm_MotorFault, "Motor fault." },
{ Alarm_HomingFail, "Homing fail. Bad configuration." }
};

static alarm_details_t details = {
Expand Down
3 changes: 2 additions & 1 deletion alarms.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ typedef enum {
Alarm_HomingFailAutoSquaringApproach = 15,
Alarm_SelftestFailed = 16,
Alarm_MotorFault = 17,
Alarm_AlarmMax = Alarm_MotorFault
Alarm_HomingFail = 18,
Alarm_AlarmMax = Alarm_HomingFail
} alarm_code_t;

typedef struct {
Expand Down
20 changes: 20 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
## grblHAL changelog

20220612:

Core:

* Changed kinematics API and implementations (corexy and wallplotter) to allow backlash compensation. Ref [ESP32 issue 25](https://github.com/grblHAL/ESP32/issues/25).

* Fixed feed rate handling for corexy kinematics. Ref issue #147.

* Fixed tool table/tool change bugs. Ref. [ioSender issue 228](https://github.com/terjeio/ioSender/issues/228).

Drivers:

* iMXRT1062 : Fix for issue #38.

* STM32F4xx : Added missing code guard for boards not having a spindle direction pin. Improved UART channel assignment handling.

* STM32F7xx : Improved UART channel assignment handling.

* ESP32 : Added missing file \(corexy.c\) to filelist, fixed incorrect URL in readme.

20220416:

Drivers:
Expand Down
56 changes: 30 additions & 26 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ __NOTE:__ if switching to a level > 1 please reset non-volatile storage with \a

// Enable CoreXY kinematics. Use ONLY with CoreXY machines.
// IMPORTANT: If homing is enabled, you must reconfigure the homing cycle #defines above to
// #define HOMING_CYCLE_0 X_AXIS_BIT and #define HOMING_CYCLE_1 Y_AXIS_BIT
//#define HOMING_CYCLE_0 X_AXIS_BIT and #define HOMING_CYCLE_1 Y_AXIS_BIT
// NOTE: This configuration option alters the motion of the X and Y axes to principle of operation
// defined at (http://corexy.com/theory.html). Motors are assumed to positioned and wired exactly as
// described, if not, motions may move in strange directions. Grbl requires the CoreXY A and B motors
Expand Down Expand Up @@ -113,8 +113,8 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// ADVANCED CONFIGURATION OPTIONS:

// Enables code for debugging purposes. Not for general use and always in constant flux.
// #define DEBUG // Uncomment to enable. Default disabled.
// #define DEBUGOUT 0 // Uncomment to claim serial port with given instance number and add HAL entry point for debug output.
//#define DEBUG // Uncomment to enable. Default disabled.
//#define DEBUGOUT 0 // Uncomment to claim serial port with given instance number and add HAL entry point for debug output.

// Some status report data isn't necessary for realtime, only intermittently, because the values don't
// change often. The following macros configures how many times a status report needs to be called before
Expand Down Expand Up @@ -172,7 +172,7 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// value. This also ensures that a planned motion always completes and accounts for any floating-point
// round-off errors. Although not recommended, a lower value than 1.0 mm/min will likely work in smaller
// machines, perhaps to 0.1mm/min, but your success may vary based on multiple factors.
// #define MINIMUM_FEED_RATE 1.0f // (mm/min)
//#define MINIMUM_FEED_RATE 1.0f // (mm/min)

// Number of arc generation iterations by small angle approximation before exact arc trajectory
// correction with expensive sin() and cos() calculations. This parameter maybe decreased if there
Expand Down Expand Up @@ -208,19 +208,19 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// available RAM, like when re-compiling for MCU with ample amounts of RAM. Or decrease if the MCU begins to
// crash due to the lack of available RAM or if the CPU is having trouble keeping up with planning
// new incoming motions as they are executed.
// #define BLOCK_BUFFER_SIZE 36 // Uncomment to override default in planner.h.
//#define BLOCK_BUFFER_SIZE 36 // Uncomment to override default in planner.h.

// Governs the size of the intermediary step segment buffer between the step execution algorithm
// and the planner blocks. Each segment is set of steps executed at a constant velocity over a
// fixed time defined by ACCELERATION_TICKS_PER_SECOND. They are computed such that the planner
// block velocity profile is traced exactly. The size of this buffer governs how much step
// execution lead time there is for other Grbl processes have to compute and do their thing
// before having to come back and refill this buffer, currently at ~50msec of step moves.
// #define SEGMENT_BUFFER_SIZE 10 // Uncomment to override default in stepper.h.
//#define SEGMENT_BUFFER_SIZE 10 // Uncomment to override default in stepper.h.

// Configures the position after a probing cycle during Grbl's check mode. Disabled sets
// the position to the probe target, when enabled sets the position to the start position.
// #define SET_CHECK_MODE_PROBE_TO_START // Default disabled. Uncomment to enable.
//#define SET_CHECK_MODE_PROBE_TO_START // Default disabled. Uncomment to enable.

// Force Grbl to check the state of the hard limit switches when the processor detects a pin
// change inside the hard limit ISR routine. By default, Grbl will trigger the hard limits
Expand All @@ -230,7 +230,7 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// that the switches don't bounce, we recommend enabling this option. This will help prevent
// triggering a hard limit when the machine disengages from the switch.
// NOTE: This option has no effect if SOFTWARE_DEBOUNCE is enabled.
// #define HARD_LIMIT_FORCE_STATE_CHECK // Default disabled. Uncomment to enable.
//#define HARD_LIMIT_FORCE_STATE_CHECK // Default disabled. Uncomment to enable.

// Adjusts homing cycle search and locate scalars. These are the multipliers used by Grbl's
// homing cycle to ensure the limit switches are engaged and cleared through each phase of
Expand All @@ -239,8 +239,8 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// uses the homing pull-off distance setting times the LOCATE_SCALAR to pull-off and re-engage
// the limit switch.
// NOTE: Both of these values must be greater than 1.0 to ensure proper function.
// #define HOMING_AXIS_SEARCH_SCALAR 1.5f // Uncomment to override defaults in limits.c.
// #define HOMING_AXIS_LOCATE_SCALAR 10.0f // Uncomment to override defaults in limits.c.
//#define HOMING_AXIS_SEARCH_SCALAR 1.5f // Uncomment to override defaults in limits.c.
//#define HOMING_AXIS_LOCATE_SCALAR 10.0f // Uncomment to override defaults in limits.c.

// Enable the '$RST=*', '$RST=$', and '$RST=#' non-volatile storage restore commands. There are cases where
// these commands may be undesirable. Simply comment the desired macro to disable it.
Expand Down Expand Up @@ -268,7 +268,7 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// NOTE: If disabled and to ensure Grbl can never alter the build info line, you'll also need to enable
// the SETTING_RESTORE_ALL macro above and remove SETTINGS_RESTORE_BUILD_INFO from the mask.
// NOTE: See the included grblWrite_BuildInfo.ino example file to write this string seperately.
// #define DISABLE_BUILD_INFO_WRITE_COMMAND // '$I=' Default enabled. Uncomment to disable.
//#define DISABLE_BUILD_INFO_WRITE_COMMAND // '$I=' Default enabled. Uncomment to disable.

// Enables and configures Grbl's sleep mode feature. If the spindle or coolant are powered and Grbl
// is not actively moving or receiving any commands, a sleep timer will start. If any data or commands
Expand Down Expand Up @@ -372,11 +372,11 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// instead of ground.
// WARNING: When the pull-ups are disabled, this might require additional wiring with pull-down resistors!
// Please check driver code and/or documentation.
// #define DISABLE_LIMIT_BITS_PULL_UP_MASK AXES_BITMASK
// #define DISABLE_LIMIT_BITS_PULL_UP_MASK (X_AXIS_BIT|Y_AXIS_BIT)
// #define DISABLE_CONTROL_PINS_PULL_UP_MASK SIGNALS_BITMASK
// #define DISABLE_CONTROL_PINS_PULL_UP_MASK (SIGNALS_SAFETYDOOR_BIT|SIGNALS_RESET_BIT)
// #define DISABLE_PROBE_BIT_PULL_UP
//#define DISABLE_LIMIT_BITS_PULL_UP_MASK AXES_BITMASK
//#define DISABLE_LIMIT_BITS_PULL_UP_MASK (X_AXIS_BIT|Y_AXIS_BIT)
//#define DISABLE_CONTROL_PINS_PULL_UP_MASK SIGNALS_BITMASK
//#define DISABLE_CONTROL_PINS_PULL_UP_MASK (SIGNALS_SAFETYDOOR_BIT|SIGNALS_RESET_BIT)
//#define DISABLE_PROBE_BIT_PULL_UP

// If your machine has two limits switches wired in parallel to one axis, you will need to enable
// this feature. Since the two switches are sharing a single pin, there is no way for Grbl to tell
Expand All @@ -394,9 +394,13 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
//#define ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES // Default disabled. Uncomment to enable.

// Inverts logic of the stepper enable signal(s).
#if COMPATIBILITY_LEVEL <= 2
// NOTE: Not universally available for individual axes - check driver documentation.
// Specify at least X_AXIS_BIT if a common enable signal is used.
// #define INVERT_ST_ENABLE_MASK (X_AXIS_BIT|Y_AXIS_BIT|Z_AXIS_BIT) // Default disabled. Uncomment to enable.
//#define INVERT_ST_ENABLE_MASK (X_AXIS_BIT|Y_AXIS_BIT|Z_AXIS_BIT) // Default disabled. Uncomment to enable.
#else
//#define INVERT_ST_ENABLE_MASK 1 // Default disabled. Uncomment to enable.
#endif
// Mask to be OR'ed with stepper disable signal(s). Axes configured will not be disabled.
// NOTE: Not universally available for individual axes - check driver documentation.
// Specify at least X_AXIS_BIT if a common enable signal is used.
Expand All @@ -414,20 +418,20 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// normally-open (NO) switches on the specified pins, rather than the default normally-closed (NC) switches.
// NOTE: The first option will invert all control pins. The second option is an example of
// inverting only a few pins. See the start of this file for other signal definitions.
// #define INVERT_CONTROL_PIN_MASK SIGNALS_BITMASK // Default disabled. Uncomment to enable.
// #define INVERT_CONTROL_PIN_MASK (SIGNALS_SAFETYDOOR_BIT|SIGNALS_RESET_BIT) // Default disabled. Uncomment to enable.
// #define INVERT_LIMIT_BIT_MASK AXES_BITMASK // Default disabled. Uncomment to enable. Uncomment to enable.
// #define INVERT_LIMIT_BIT_MASK (X_AXIS_BIT|Y_AXIS_BIT) // Default disabled. Uncomment to enable.
//#define INVERT_CONTROL_PIN_MASK SIGNALS_BITMASK // Default disabled. Uncomment to enable.
//#define INVERT_CONTROL_PIN_MASK (SIGNALS_SAFETYDOOR_BIT|SIGNALS_RESET_BIT) // Default disabled. Uncomment to enable.
//#define INVERT_LIMIT_BIT_MASK AXES_BITMASK // Default disabled. Uncomment to enable. Uncomment to enable.
//#define INVERT_LIMIT_BIT_MASK (X_AXIS_BIT|Y_AXIS_BIT) // Default disabled. Uncomment to enable.
// For inverting the probe pin use DEFAULT_INVERT_PROBE_BIT in defaults.h

// Inverts the selected spindle output signals from active high to active low. Useful for some pre-built electronic boards.
// #define INVERT_SPINDLE_ENABLE_PIN 1 // Default disabled. Uncomment to enable.
// #define INVERT_SPINDLE_CCW_PIN 1 // Default disabled. Uncomment to enable. NOTE: not supported by all drivers.
// #define INVERT_SPINDLE_PWM_PIN 1 // Default disabled. Uncomment to enable. NOTE: not supported by all drivers.
//#define INVERT_SPINDLE_ENABLE_PIN 1 // Default disabled. Uncomment to enable.
//#define INVERT_SPINDLE_CCW_PIN 1 // Default disabled. Uncomment to enable. NOTE: not supported by all drivers.
//#define INVERT_SPINDLE_PWM_PIN 1 // Default disabled. Uncomment to enable. NOTE: not supported by all drivers.

// Inverts the selected coolant signals from active high to active low. Useful for some pre-built electronic boards.
// #define INVERT_COOLANT_FLOOD_PIN 1 // Default disabled. Uncomment to enable.
// #define INVERT_COOLANT_MIST_PIN 1 // Default disabled. Note: not supported by all drivers.
//#define INVERT_COOLANT_FLOOD_PIN 1 // Default disabled. Uncomment to enable.
//#define INVERT_COOLANT_MIST_PIN 1 // Default disabled. Note: not supported by all drivers.


// Used by variable spindle output only. This forces the PWM output to a minimum duty cycle when enabled.
Expand Down
2 changes: 2 additions & 0 deletions core_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ typedef bool (*on_probe_fixture_ptr)(tool_data_t *tool, bool at_g59_3, bool on);
typedef bool (*on_probe_start_ptr)(axes_signals_t axes, float *target, plan_line_data_t *pl_data);
typedef void (*on_probe_completed_ptr)(void);
typedef void (*on_toolchange_ack_ptr)(void);
typedef void (*on_jog_cancel_ptr)(sys_state_t state);
typedef bool (*on_spindle_select_ptr)(spindle_id_t spindle_id);
typedef status_code_t (*on_unknown_sys_command_ptr)(sys_state_t state, char *line); // return Status_Unhandled.
typedef status_code_t (*on_user_command_ptr)(char *line);
Expand Down Expand Up @@ -116,6 +117,7 @@ typedef struct {
on_probe_start_ptr on_probe_start;
on_probe_completed_ptr on_probe_completed;
on_toolchange_ack_ptr on_toolchange_ack; // Called from interrupt context.
on_jog_cancel_ptr on_jog_cancel; // Called from interrupt context.
on_laser_ppi_enable_ptr on_laser_ppi_enable;
on_spindle_select_ptr on_spindle_select;
// core entry points - set up by core before driver_init() is called.
Expand Down
97 changes: 71 additions & 26 deletions corexy.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2019 Terje Io
Copyright (c) 2019-2022 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
Expand All @@ -24,6 +24,8 @@

#ifdef COREXY

#include <math.h>

#include "settings.h"
#include "planner.h"
#include "kinematics.h"
Expand All @@ -45,37 +47,27 @@ inline static int32_t corexy_convert_to_b_motor_steps (int32_t *steps)
}

// Returns machine position of axis 'idx'. Must be sent a 'step' array.
static void corexy_convert_array_steps_to_mpos (float *position, int32_t *steps)
static float *corexy_convert_array_steps_to_mpos (float *position, int32_t *steps)
{
position[X_AXIS] = corexy_convert_to_a_motor_steps(steps) / settings.axis[X_AXIS].steps_per_mm;
position[Y_AXIS] = corexy_convert_to_b_motor_steps(steps) / settings.axis[Y_AXIS].steps_per_mm;
position[Z_AXIS] = steps[Z_AXIS] / settings.axis[Z_AXIS].steps_per_mm;

return position;
}

// Transform absolute position from cartesian coordinate system (mm) to corexy coordinate system (step)
static void corexy_target_to_steps (int32_t *target_steps, float *target)
// Transform position from cartesian coordinate system to corexy coordinate system
static inline float *transform_from_cartesian (float *target, float *position)
{
uint_fast8_t idx = N_AXIS;
int32_t a_steps, b_steps;
uint_fast8_t idx;

do {
switch(--idx) {
case X_AXIS:
a_steps = lroundf(target[idx] * settings.axis[idx].steps_per_mm);
break;

case Y_AXIS:
b_steps = lroundf(target[idx] * settings.axis[idx].steps_per_mm);
break;

default:
target_steps[idx] = lroundf(target[idx] * settings.axis[idx].steps_per_mm);
break;
}
} while(idx);
target[X_AXIS] = position[X_AXIS] + position[Y_AXIS];
target[Y_AXIS] = position[X_AXIS] - position[Y_AXIS];

for(idx = Z_AXIS; idx < N_AXIS; idx++)
target[idx] = position[idx];

target_steps[A_MOTOR] = a_steps + b_steps;
target_steps[B_MOTOR] = a_steps - b_steps;
return target;
}

static uint_fast8_t corexy_limits_get_axis_mask (uint_fast8_t idx)
Expand Down Expand Up @@ -151,16 +143,69 @@ static void corexy_limits_set_machine_positions (axes_signals_t cycle)
} while(idx);
}

static inline float get_distance (float *p0, float *p1)
{
uint_fast8_t idx = N_AXIS;
float distance = 0.0f;

do {
idx--;
distance += (p0[idx] - p1[idx]) * (p0[idx] - p1[idx]);
} while(idx);

return sqrtf(distance);
}

// 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 float trsf[N_AXIS];

if(init) {

iterations = 2;

transform_from_cartesian(trsf, target);

if(!pl_data->condition.rapid_motion) {

uint_fast8_t idx;
float cpos[N_AXIS];

cpos[X_AXIS] = (position[X_AXIS] + position[Y_AXIS]) * .5f;
cpos[Y_AXIS] = (position[X_AXIS] - position[Y_AXIS]) * .5f;
for(idx = Z_AXIS; idx < N_AXIS; idx++)
cpos[idx] = position[idx];

pl_data->feed_rate *= get_distance(trsf, position) / get_distance(target, cpos);
}
}

return iterations-- == 0 ? NULL : trsf;
}

static bool homing_cycle_validate (axes_signals_t cycle)
{
return (cycle.mask & (X_AXIS_BIT|Y_AXIS_BIT)) == 0 || cycle.mask < 3;
}

static float homing_cycle_get_feedrate (float feedrate, axes_signals_t cycle)
{
return feedrate * sqrtf(2.0f);
}

// Initialize API pointers for CoreXY kinematics
void corexy_init (void)
{
kinematics.limits_set_target_pos = corexy_limits_set_target_pos;
kinematics.limits_get_axis_mask = corexy_limits_get_axis_mask;
kinematics.limits_set_machine_positions = corexy_limits_set_machine_positions;
kinematics.plan_target_to_steps = corexy_target_to_steps;
kinematics.convert_array_steps_to_mpos = corexy_convert_array_steps_to_mpos;
kinematics.transform_from_cartesian = transform_from_cartesian;
kinematics.transform_steps_to_cartesian = corexy_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;
}

#endif

4 changes: 4 additions & 0 deletions defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,11 @@
#endif

#ifndef INVERT_ST_ENABLE_MASK
#if COMPATIBILITY_LEVEL <= 2
#define INVERT_ST_ENABLE_MASK AXES_BITMASK
#else
#define INVERT_ST_ENABLE_MASK 0
#endif
#endif

#ifndef INVERT_LIMIT_BIT_MASK
Expand Down
Loading

0 comments on commit b55cca1

Please sign in to comment.