Added soft limits check for corexy kinematics, ref. discussion #536.

Added high level CANbus API for plugin use. Ref. issue #179.
This commit is contained in:
Terje Io
2024-07-07 06:55:24 +02:00
parent d4c9d21ab2
commit eb7610cd39
9 changed files with 316 additions and 5 deletions

View File

@@ -33,6 +33,7 @@ target_sources(grbl INTERFACE
${CMAKE_CURRENT_LIST_DIR}/regex.c
${CMAKE_CURRENT_LIST_DIR}/ioports.c
${CMAKE_CURRENT_LIST_DIR}/vfs.c
${CMAKE_CURRENT_LIST_DIR}/canbus.c
${CMAKE_CURRENT_LIST_DIR}/kinematics/corexy.c
${CMAKE_CURRENT_LIST_DIR}/kinematics/wall_plotter.c
${CMAKE_CURRENT_LIST_DIR}/kinematics/delta.c

View File

@@ -13,7 +13,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
---
Latest build date is 20240624, see the [changelog](changelog.md) for details.
Latest build date is 20240704, see the [changelog](changelog.md) for details.
__NOTE:__ Build 20240222 has moved the probe input to the ioPorts pool of inputs and will be allocated from it when configured.
The change is major and _potentially dangerous_, it may damage your probe, so please _verify correct operation_ after installing this, or later, builds.

209
canbus.c Normal file
View File

@@ -0,0 +1,209 @@
/*
canbus.c -
Part of grblHAL
Copyright (c) 2022 Jon Escombe
Copyright (c) 2024 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 <http://www.gnu.org/licenses/>.
*/
#include "hal.h"
#include "task.h"
#include "protocol.h"
#include "canbus.h"
#ifndef CANBUS_BUFFER_LEN
#define CANBUS_BUFFER_LEN 8
#endif
#ifndef CANBUS_BAUDRATE
#define CANBUS_BAUDRATE 0 // 125,000
#endif
typedef struct {
volatile canbus_message_t message;
can_rx_ptr callback;
} canbus_rx_message;
typedef struct {
volatile canbus_message_t message;
bool ext_id;
} canbus_tx_message;
typedef struct {
volatile uint8_t head;
volatile uint8_t tail;
volatile canbus_tx_message tx[CANBUS_BUFFER_LEN];
} canbus_tx_buffer_t;
typedef struct {
volatile uint8_t head;
volatile uint8_t tail;
volatile canbus_rx_message rx[CANBUS_BUFFER_LEN];
} canbus_rx_buffer_t;
static bool isEnabled = false;
static const uint32_t baud[] = { 125000, 250000, 500000, 1000000 };
static canbus_tx_buffer_t tx_buffer = {0};
static canbus_rx_buffer_t rx_buffer = {0};
// Weak implementations of low level functions to be provided by the driver
__attribute__((weak)) bool can_start (uint32_t baud, can_rx_enqueue_fn callback)
{
return false;
}
__attribute__((weak)) bool can_stop (void)
{
return false;
}
__attribute__((weak)) bool can_set_baud (uint32_t baud)
{
return false;
}
__attribute__((weak)) bool can_put (canbus_message_t msg, bool ext_id)
{
return false;
}
__attribute__((weak)) bool can_add_filter (uint32_t id, uint32_t mask, bool ext_id, can_rx_ptr callback)
{
return false;
}
// ---
ISR_CODE static bool ISR_FUNC(canbus_queue_rx)(canbus_message_t message, can_rx_ptr callback)
{
bool ok;
uint8_t next_head = (rx_buffer.head + 1) % CANBUS_BUFFER_LEN;
if((ok = next_head != rx_buffer.tail)) {
rx_buffer.rx[next_head].callback = callback;
rx_buffer.rx[next_head].message = message;
rx_buffer.head = next_head;
}
return ok;
}
// called every 1 ms
static void canbus_poll (void *data)
{
/* if have TX data, sends one message per iteration.. */
if(tx_buffer.head != tx_buffer.tail && can_put(tx_buffer.tx[tx_buffer.tail].message, tx_buffer.tx[tx_buffer.tail].ext_id))
tx_buffer.tail = (tx_buffer.tail + 1) % CANBUS_BUFFER_LEN;
/* if have RX data, process one message per iteration.. */
if(rx_buffer.head != rx_buffer.tail) {
if(rx_buffer.rx[rx_buffer.tail].callback)
rx_buffer.rx[rx_buffer.tail].callback(rx_buffer.rx[rx_buffer.tail].message);
rx_buffer.tail = (rx_buffer.tail + 1) % CANBUS_BUFFER_LEN;
}
}
static bool canbus_start (uint32_t baud)
{
if((isEnabled = can_start(baud, canbus_queue_rx)))
task_add_systick(canbus_poll, NULL);
return isEnabled;
}
static status_code_t canbus_set_baud (setting_id_t id, uint_fast16_t value)
{
settings.canbus_baud = value;
can_set_baud(baud[settings.canbus_baud]);
return can_set_baud(baud[settings.canbus_baud]) ? Status_OK : Status_SettingValueOutOfRange;
}
static uint32_t canbus_get_baud (setting_id_t setting)
{
return settings.canbus_baud < (sizeof(baud) / sizeof(uint32_t)) ? settings.canbus_baud : CANBUS_BAUDRATE;
}
static const setting_group_detail_t canbus_groups [] = {
{ Group_Root, Group_CANbus, "CAN bus"}
};
static const setting_detail_t canbus_setting_detail[] = {
{ Setting_CANbus_BaudRate, Group_CANbus, "CAN bus baud rate", NULL, Format_RadioButtons, "125000,250000,500000,1000000", NULL, NULL, Setting_NonCoreFn, canbus_set_baud, canbus_get_baud, NULL },
};
static void canbus_settings_restore (void)
{
settings.canbus_baud = CANBUS_BAUDRATE;
settings_write_global();
}
static void canbus_settings_load (void)
{
canbus_start(baud[canbus_get_baud(Setting_CANbus_BaudRate)]);
}
static setting_details_t setting_details = {
.groups = canbus_groups,
.n_groups = sizeof(canbus_groups) / sizeof(setting_group_detail_t),
.settings = canbus_setting_detail,
.n_settings = sizeof(canbus_setting_detail) / sizeof(setting_detail_t),
.save = settings_write_global,
.load = canbus_settings_load,
.restore = canbus_settings_restore
};
// Public API
bool canbus_enabled (void)
{
return isEnabled;
}
bool canbus_queue_tx (canbus_message_t message, bool ext_id)
{
bool ok;
uint8_t next_head = (tx_buffer.head + 1) % CANBUS_BUFFER_LEN;
if((ok = next_head != tx_buffer.tail)) {
tx_buffer.tx[tx_buffer.head].ext_id = ext_id;
tx_buffer.tx[tx_buffer.head].message = message;
tx_buffer.head = next_head;
}
return ok;
}
bool canbus_add_filter (uint32_t id, uint32_t mask, bool ext_id, can_rx_ptr callback)
{
return can_add_filter(id, mask, ext_id, callback);
}
void canbus_init (void)
{
static bool init_ok = false;
if(!init_ok) {
init_ok = true;
settings_register(&setting_details);
}
}

48
canbus.h Normal file
View File

@@ -0,0 +1,48 @@
/*
canbus.h -
Part of grblHAL
Copyright (c) 2022 Jon Escombe
Copyright (c) 2024 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _CANBUS_H_
#define _CANBUS_H_
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint32_t id;
uint8_t len;
uint8_t data[8];
} canbus_message_t;
typedef bool (*can_rx_ptr)(canbus_message_t);
typedef bool (*can_rx_enqueue_fn)(canbus_message_t msg, can_rx_ptr callback); // used internally by the driver
/*
* Function prototypes
*/
void canbus_init (void);
bool canbus_enabled (void);
bool canbus_queue_tx (canbus_message_t message, bool ext_id);
bool canbus_add_filter (uint32_t id, uint32_t mask, bool ext_id, can_rx_ptr callback);
#endif /* _CANBUS_H_ */

View File

@@ -1,5 +1,23 @@
## grblHAL changelog
<a name="20240704"/>Build 20240704
Core:
* Added high level CANbus API for plugin use. If driver/board combo provides the required lowlevel HAL API the `NEWOPT` string in the `$I` output will contain the `CAN` element when CAN is enabled.
Ref. [issue #179](https://github.com/grblHAL/STM32F4xx/issues/179).
* Added soft limits check for corexy kinematics, ref. [discussion #536](https://github.com/grblHAL/core/discussions/536).
Drivers:
* ESP32: fixed WebUI regression. Ref. [issue #116](https://github.com/grblHAL/ESP32/issues/116).
* STM32F7xx, STM32F4xx: Added lowlevel CANbus API and enabled it for some boards.
---
<a name="20240624"/>Build 20240624
Core:

2
grbl.h
View File

@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
#define GRBL_BUILD 20240624
#define GRBL_BUILD 20240704
#define GRBL_URL "https://github.com/grblHAL"

View File

@@ -37,6 +37,7 @@
#define B_MOTOR Y_AXIS // Must be Y_AXIS
static on_report_options_ptr on_report_options;
static travel_limits_ptr check_travel_limits;
// Returns x or y-axis "steps" based on CoreXY motor steps.
inline static int32_t corexy_convert_to_a_motor_steps (int32_t *steps)
@@ -77,12 +78,25 @@ static inline float *transform_from_cartesian (float *target, float *position)
return target;
}
// Transform position from motor (corexy) coordinate system to cartesian coordinate system
static inline float *transform_to_cartesian (float *target, float *position)
{
uint_fast8_t idx;
target[X_AXIS] = (position[X_AXIS] + position[Y_AXIS]) * 0.5f;
target[Y_AXIS] = (position[X_AXIS] - position[Y_AXIS]) * 0.5f;
for(idx = Z_AXIS; idx < N_AXIS; idx++)
target[idx] = position[idx];
return target;
}
static uint_fast8_t corexy_limits_get_axis_mask (uint_fast8_t idx)
{
return ((idx == A_MOTOR) || (idx == B_MOTOR)) ? (bit(X_AXIS) | bit(Y_AXIS)) : bit(idx);
}
static void corexy_limits_set_target_pos (uint_fast8_t idx) // fn name?
{
int32_t axis_position;
@@ -102,6 +116,19 @@ static void corexy_limits_set_target_pos (uint_fast8_t idx) // fn name?
}
}
// Checks and reports if target array exceeds machine travel limits. Returns false if check failed.
// NOTE: target for axes X and Y are in motor coordinates if is_cartesian is false.
static bool corexy_check_travel_limits (float *target, axes_signals_t axes, bool is_cartesian)
{
if(is_cartesian)
return check_travel_limits(target, axes, true);
float cartesian_coords[N_AXIS];
transform_to_cartesian(cartesian_coords, target);
return check_travel_limits(cartesian_coords, axes, true);
}
// Set machine positions for homed limit switches. Don't update non-homed axes.
// NOTE: settings.max_travel[] is stored as a negative value.
@@ -207,7 +234,7 @@ static void report_options (bool newopt)
on_report_options(newopt);
if(!newopt)
hal.stream.write("[KINEMATICS:CoreXY v2.00]" ASCII_EOL);
hal.stream.write("[KINEMATICS:CoreXY v2.01]" ASCII_EOL);
}
// Initialize API pointers for CoreXY kinematics
@@ -222,6 +249,9 @@ void corexy_init (void)
kinematics.homing_cycle_validate = homing_cycle_validate;
kinematics.homing_cycle_get_feedrate = homing_cycle_get_feedrate;
check_travel_limits = grbl.check_travel_limits;
grbl.check_travel_limits = corexy_check_travel_limits;
on_report_options = grbl.on_report_options;
grbl.on_report_options = report_options;
}

View File

@@ -38,6 +38,7 @@
#include "nvs_buffer.h"
#include "machine_limits.h"
#include "state_machine.h"
#include "canbus.h"
#include "regex.h"
#if ENABLE_SPINDLE_LINEARIZATION
@@ -985,6 +986,9 @@ void report_build_info (char *line, bool extended)
if(hal.rtc.get_datetime)
strcat(buf, "RTC,");
if(canbus_enabled())
strcat(buf, "CAN,");
#ifdef PID_LOG
strcat(buf, "PID,");
#endif

View File

@@ -779,7 +779,8 @@ typedef struct {
control_signals_t control_disable_pullup;
coolant_state_t coolant_invert;
axes_signals_t home_invert;
uint16_t hole_1;
uint8_t modbus_baud;
uint8_t canbus_baud;
spindle_settings_t spindle;
stepper_settings_t steppers;
reportmask_t status_report; // Mask to indicate desired report data.