mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-08-18 20:31:35 +02:00
Merge remote-tracking branch 'upstream/devt' into devt
This commit is contained in:
@@ -59,6 +59,19 @@ void machine_init() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converts Cartesian to motors with no motion control
|
||||||
|
static void cartesian_to_motors(float* position) {
|
||||||
|
float motors[MAX_N_AXIS];
|
||||||
|
|
||||||
|
motors[X_AXIS] = geometry_factor * position[X_AXIS] + position[Y_AXIS];
|
||||||
|
motors[Y_AXIS] = geometry_factor * position[X_AXIS] - position[Y_AXIS];
|
||||||
|
|
||||||
|
position[X_AXIS] = motors[X_AXIS];
|
||||||
|
position[Y_AXIS] = motors[Y_AXIS];
|
||||||
|
|
||||||
|
// Z and higher just pass through unchanged
|
||||||
|
}
|
||||||
|
|
||||||
// Cycle mask is 0 unless the user sends a single axis command like $HZ
|
// Cycle mask is 0 unless the user sends a single axis command like $HZ
|
||||||
// This will always return true to prevent the normal Grbl homing cycle
|
// This will always return true to prevent the normal Grbl homing cycle
|
||||||
bool user_defined_homing(uint8_t cycle_mask) {
|
bool user_defined_homing(uint8_t cycle_mask) {
|
||||||
@@ -135,7 +148,7 @@ bool user_defined_homing(uint8_t cycle_mask) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convert back to motor steps
|
// convert back to motor steps
|
||||||
inverse_kinematics(target);
|
cartesian_to_motors(target);
|
||||||
|
|
||||||
pl_data->feed_rate = homing_rate; // feed or seek rates
|
pl_data->feed_rate = homing_rate; // feed or seek rates
|
||||||
plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
|
plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
|
||||||
@@ -226,7 +239,7 @@ bool user_defined_homing(uint8_t cycle_mask) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convert to motors
|
// convert to motors
|
||||||
inverse_kinematics(target);
|
cartesian_to_motors(target);
|
||||||
// convert to steps
|
// convert to steps
|
||||||
for (axis = X_AXIS; axis <= Y_AXIS; axis++) {
|
for (axis = X_AXIS; axis <= Y_AXIS; axis++) {
|
||||||
sys_position[axis] = target[axis] * axis_settings[axis]->steps_per_mm->get();
|
sys_position[axis] = target[axis] * axis_settings[axis]->steps_per_mm->get();
|
||||||
@@ -242,24 +255,10 @@ bool user_defined_homing(uint8_t cycle_mask) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is used by Grbl convert Cartesian to motors
|
|
||||||
// this does not do any motion control
|
|
||||||
void inverse_kinematics(float* position) {
|
|
||||||
float motors[MAX_N_AXIS];
|
|
||||||
|
|
||||||
motors[X_AXIS] = geometry_factor * position[X_AXIS] + position[Y_AXIS];
|
|
||||||
motors[Y_AXIS] = geometry_factor * position[X_AXIS] - position[Y_AXIS];
|
|
||||||
|
|
||||||
position[X_AXIS] = motors[X_AXIS];
|
|
||||||
position[Y_AXIS] = motors[Y_AXIS];
|
|
||||||
|
|
||||||
// Z and higher just pass through unchanged
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inverse Kinematics calculates motor positions from real world cartesian positions
|
// Inverse Kinematics calculates motor positions from real world cartesian positions
|
||||||
// position is the current position
|
// position is the current position
|
||||||
// Breaking into segments is not needed with CoreXY, because it is a linear system.
|
// Breaking into segments is not needed with CoreXY, because it is a linear system.
|
||||||
void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) //The target and position are provided in MPos
|
bool inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) //The target and position are provided in MPos
|
||||||
{
|
{
|
||||||
float dx, dy, dz; // distances in each cartesian axis
|
float dx, dy, dz; // distances in each cartesian axis
|
||||||
float motors[MAX_N_AXIS];
|
float motors[MAX_N_AXIS];
|
||||||
@@ -288,7 +287,7 @@ void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* positio
|
|||||||
|
|
||||||
memcpy(last_motors, motors, sizeof(motors));
|
memcpy(last_motors, motors, sizeof(motors));
|
||||||
|
|
||||||
mc_line(motors, pl_data);
|
return mc_line(motors, pl_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// motors -> cartesian
|
// motors -> cartesian
|
||||||
@@ -314,7 +313,7 @@ void forward_kinematics(float* position) {
|
|||||||
// apply the forward kinemetics to the machine coordinates
|
// apply the forward kinemetics to the machine coordinates
|
||||||
// https://corexy.com/theory.html
|
// https://corexy.com/theory.html
|
||||||
//calc_fwd[X_AXIS] = 0.5 / geometry_factor * (position[X_AXIS] + position[Y_AXIS]);
|
//calc_fwd[X_AXIS] = 0.5 / geometry_factor * (position[X_AXIS] + position[Y_AXIS]);
|
||||||
calc_fwd[X_AXIS] = ((0.5 * (print_position[X_AXIS] + print_position[Y_AXIS]) * geometry_factor) - wco[X_AXIS]);
|
calc_fwd[X_AXIS] = ((0.5 * (print_position[X_AXIS] + print_position[Y_AXIS]) / geometry_factor) - wco[X_AXIS]);
|
||||||
calc_fwd[Y_AXIS] = ((0.5 * (print_position[X_AXIS] - print_position[Y_AXIS])) - wco[Y_AXIS]);
|
calc_fwd[Y_AXIS] = ((0.5 * (print_position[X_AXIS] - print_position[Y_AXIS])) - wco[Y_AXIS]);
|
||||||
|
|
||||||
for (int axis = 0; axis < n_axis; axis++) {
|
for (int axis = 0; axis < n_axis; axis++) {
|
||||||
@@ -336,9 +335,9 @@ void kinematics_post_homing() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is used used by Grbl soft limits to see if the range of the machine is exceeded.
|
// this is used used by Limits.cpp to see if the range of the machine is exceeded.
|
||||||
uint8_t kinematic_limits_check(float* target) {
|
bool limitsCheckTravel(float* target) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void user_m30() {}
|
void user_m30() {}
|
||||||
|
@@ -54,7 +54,6 @@ special things your machine needs at startup.
|
|||||||
void machine_init() {}
|
void machine_init() {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_CUSTOM_HOMING
|
|
||||||
/*
|
/*
|
||||||
user_defined_homing(uint8_t cycle_mask) is called at the begining of the normal Grbl_ESP32 homing
|
user_defined_homing(uint8_t cycle_mask) is called at the begining of the normal Grbl_ESP32 homing
|
||||||
sequence. If user_defined_homing(uint8_t cycle_mask) returns false, the rest of normal Grbl_ESP32
|
sequence. If user_defined_homing(uint8_t cycle_mask) returns false, the rest of normal Grbl_ESP32
|
||||||
@@ -66,9 +65,7 @@ bool user_defined_homing(uint8_t cycle_mask) {
|
|||||||
// True = done with homing, false = continue with normal Grbl_ESP32 homing
|
// True = done with homing, false = continue with normal Grbl_ESP32 homing
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_KINEMATICS
|
|
||||||
/*
|
/*
|
||||||
Inverse Kinematics converts X,Y,Z cartesian coordinate to the steps
|
Inverse Kinematics converts X,Y,Z cartesian coordinate to the steps
|
||||||
on your "joint" motors. It requires the following three functions:
|
on your "joint" motors. It requires the following three functions:
|
||||||
@@ -86,9 +83,9 @@ bool user_defined_homing(uint8_t cycle_mask) {
|
|||||||
pl_data = planner data (see the definition of this type to see what it is)
|
pl_data = planner data (see the definition of this type to see what it is)
|
||||||
position = an N_AXIS array of where the machine is starting from for this move
|
position = an N_AXIS array of where the machine is starting from for this move
|
||||||
*/
|
*/
|
||||||
void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) {
|
bool inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) {
|
||||||
// this simply moves to the target. Replace with your kinematics.
|
// this simply moves to the target. Replace with your kinematics.
|
||||||
mc_line(target, pl_data);
|
return mc_line(target, pl_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -97,8 +94,7 @@ void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* positio
|
|||||||
|
|
||||||
cycle_mask is a bit mask of the axes being homed this time.
|
cycle_mask is a bit mask of the axes being homed this time.
|
||||||
*/
|
*/
|
||||||
bool kinematics_pre_homing(uint8_t cycle_mask))
|
bool kinematics_pre_homing(uint8_t cycle_mask) {
|
||||||
{
|
|
||||||
return false; // finish normal homing cycle
|
return false; // finish normal homing cycle
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +102,15 @@ bool kinematics_pre_homing(uint8_t cycle_mask))
|
|||||||
kinematics_post_homing() is called at the end of normal homing
|
kinematics_post_homing() is called at the end of normal homing
|
||||||
*/
|
*/
|
||||||
void kinematics_post_homing() {}
|
void kinematics_post_homing() {}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_FWD_KINEMATICS
|
/*
|
||||||
|
limitsCheckTravel() is called to check soft limits
|
||||||
|
It returns true if the motion is outside the limit values
|
||||||
|
*/
|
||||||
|
bool limitsCheckTravel() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The status command uses forward_kinematics() to convert
|
The status command uses forward_kinematics() to convert
|
||||||
your motor positions to cartesian X,Y,Z... coordinates.
|
your motor positions to cartesian X,Y,Z... coordinates.
|
||||||
@@ -119,7 +121,6 @@ void forward_kinematics(float* position) {
|
|||||||
// position[X_AXIS] =
|
// position[X_AXIS] =
|
||||||
// position[Y_AXIS] =
|
// position[Y_AXIS] =
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_TOOL_CHANGE
|
#ifdef USE_TOOL_CHANGE
|
||||||
/*
|
/*
|
||||||
|
280
Grbl_Esp32/Custom/oled_basic.cpp
Normal file
280
Grbl_Esp32/Custom/oled_basic.cpp
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
oled_basic.cpp
|
||||||
|
Part of Grbl_ESP32
|
||||||
|
|
||||||
|
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
||||||
|
CPU. Do not use this with Grbl for atMega328P
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
|
This is a minimal implentation of a display as a test project.
|
||||||
|
It is designed to be used with a machine that has no easily accessible serial connection
|
||||||
|
It shows basic status and connection information.
|
||||||
|
|
||||||
|
When in alarm mode it will show the current Wifi/BT paramaters and status
|
||||||
|
Most machines will start in alarm mode (needs homing)
|
||||||
|
If the machine is running a job from SD it will show the progress
|
||||||
|
In other modes it will show state and 3 axis DROs
|
||||||
|
Thats All!
|
||||||
|
|
||||||
|
Library Infor:
|
||||||
|
https://github.com/ThingPulse/esp8266-oled-ssd1306
|
||||||
|
|
||||||
|
Install to PlatformIO with this typed at the terminal
|
||||||
|
platformio lib install 562
|
||||||
|
|
||||||
|
Add this to your machine definition file
|
||||||
|
#define DISPLAY_CODE_FILENAME "Custom/oled_basic.cpp"
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Include the correct display library
|
||||||
|
|
||||||
|
#include "SSD1306Wire.h"
|
||||||
|
#include "../src/WebUI/WebSettings.h"
|
||||||
|
|
||||||
|
#ifndef OLED_ADDRESS
|
||||||
|
# define OLED_ADDRESS 0x3c
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OLED_SDA
|
||||||
|
# define OLED_SDA GPIO_NUM_14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OLED_SCL
|
||||||
|
# define OLED_SCL GPIO_NUM_13
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OLED_GEOMETRY
|
||||||
|
# define OLED_GEOMETRY GEOMETRY_128_64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SSD1306Wire display(OLED_ADDRESS, OLED_SDA, OLED_SCL, OLED_GEOMETRY);
|
||||||
|
|
||||||
|
static TaskHandle_t displayUpdateTaskHandle = 0;
|
||||||
|
|
||||||
|
// This displays the status of the ESP32 Radios...BT, WiFi, etc
|
||||||
|
void displayRadioInfo() {
|
||||||
|
String radio_addr = "";
|
||||||
|
String radio_name = "";
|
||||||
|
String radio_status = "";
|
||||||
|
|
||||||
|
#ifdef ENABLE_BLUETOOTH
|
||||||
|
if (WebUI::wifi_radio_mode->get() == ESP_BT) {
|
||||||
|
radio_name = String("BT: ") + WebUI::bt_name->get();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_WIFI
|
||||||
|
if ((WiFi.getMode() == WIFI_MODE_STA) || (WiFi.getMode() == WIFI_MODE_APSTA)) {
|
||||||
|
radio_name = "STA: " + WiFi.SSID();
|
||||||
|
radio_addr = WiFi.localIP().toString();
|
||||||
|
} else if ((WiFi.getMode() == WIFI_MODE_AP) || (WiFi.getMode() == WIFI_MODE_APSTA)) {
|
||||||
|
radio_name = String("AP:") + WebUI::wifi_ap_ssid->get();
|
||||||
|
radio_addr = WiFi.softAPIP().toString();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIFI_OR_BLUETOOTH
|
||||||
|
if (WebUI::wifi_radio_mode->get() == ESP_RADIO_OFF) {
|
||||||
|
radio_name = "Radio Mode: None";
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
radio_name = "Radio Mode:Disabled";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display.setFont(ArialMT_Plain_10);
|
||||||
|
|
||||||
|
if (sys.state == State::Alarm) { // print below Alarm:
|
||||||
|
display.drawString(0, 18, radio_name);
|
||||||
|
display.drawString(0, 30, radio_addr);
|
||||||
|
|
||||||
|
} else { // print next to status
|
||||||
|
if (WebUI::wifi_radio_mode->get() == ESP_BT) {
|
||||||
|
display.drawString(55, 2, radio_name);
|
||||||
|
} else {
|
||||||
|
display.drawString(55, 2, radio_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Here changes begin Here changes begin Here changes begin Here changes begin Here changes begin
|
||||||
|
|
||||||
|
void draw_checkbox(int16_t x, int16_t y, int16_t width, int16_t height, bool checked) {
|
||||||
|
if (checked)
|
||||||
|
display.fillRect(x, y, width, height); // If log.0
|
||||||
|
else
|
||||||
|
display.drawRect(x, y, width, height); // If log.1
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayDRO() {
|
||||||
|
uint8_t oled_y_pos;
|
||||||
|
float print_position[MAX_N_AXIS];
|
||||||
|
//float wco[MAX_N_AXIS];
|
||||||
|
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display.setFont(ArialMT_Plain_10);
|
||||||
|
|
||||||
|
char axisVal[20];
|
||||||
|
|
||||||
|
display.drawString(80, 14, "L"); // Limit switch
|
||||||
|
|
||||||
|
auto n_axis = number_axis->get();
|
||||||
|
AxisMask lim_pin_state = limits_get_state();
|
||||||
|
ControlPins ctrl_pin_state = system_control_get_state();
|
||||||
|
bool prb_pin_state = probe_get_state();
|
||||||
|
|
||||||
|
if (bit_istrue(status_mask->get(), RtStatus::Position)) {
|
||||||
|
calc_mpos(print_position);
|
||||||
|
} else {
|
||||||
|
calc_wpos(print_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t axis = X_AXIS; axis < n_axis; axis++) {
|
||||||
|
oled_y_pos = 24 + (axis * 10);
|
||||||
|
|
||||||
|
String axis_letter = String(report_get_axis_letter(axis));
|
||||||
|
axis_letter += ":";
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display.drawString(0, oled_y_pos, axis_letter); // String('X') + ":");
|
||||||
|
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||||
|
snprintf(axisVal, 20 - 1, "%.3f", print_position[axis]);
|
||||||
|
display.drawString(60, oled_y_pos, axisVal);
|
||||||
|
|
||||||
|
if (limitsSwitchDefined(axis, 0)) { // olny draw the box if a switch has been defined
|
||||||
|
draw_checkbox(80, 27 + (axis * 10), 7, 7, bit_istrue(lim_pin_state, bit(axis)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oled_y_pos = 14;
|
||||||
|
|
||||||
|
if (PROBE_PIN != UNDEFINED_PIN) {
|
||||||
|
display.drawString(110, oled_y_pos, "P");
|
||||||
|
draw_checkbox(120, oled_y_pos + 3, 7, 7, prb_pin_state);
|
||||||
|
oled_y_pos += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONTROL_FEED_HOLD_PIN
|
||||||
|
display.drawString(110, oled_y_pos, "H");
|
||||||
|
draw_checkbox(120, oled_y_pos + 3, 7, 7, ctrl_pin_state.bit.feedHold);
|
||||||
|
oled_y_pos += 10;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONTROL_CYCLE_START_PIN
|
||||||
|
display.drawString(110, oled_y_pos, "S");
|
||||||
|
draw_checkbox(120, oled_y_pos + 3, 7, 7, ctrl_pin_state.bit.cycleStart);
|
||||||
|
oled_y_pos += 10;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONTROL_RESET_PIN
|
||||||
|
display.drawString(110, oled_y_pos, "R");
|
||||||
|
draw_checkbox(120, oled_y_pos + 3, 7, 7, ctrl_pin_state.bit.reset);
|
||||||
|
oled_y_pos += 10;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONTROL_SAFETY_DOOR_PIN
|
||||||
|
display.drawString(110, oled_y_pos, "D");
|
||||||
|
draw_checkbox(120, oled_y_pos + 3, 7, 7, ctrl_pin_state.bit.safetyDoor);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayUpdate(void* pvParameters) {
|
||||||
|
TickType_t xLastWakeTime;
|
||||||
|
const TickType_t xDisplayFrequency = 100; // in ticks (typically ms)
|
||||||
|
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||||
|
|
||||||
|
vTaskDelay(2500);
|
||||||
|
uint16_t sd_file_ticker = 0;
|
||||||
|
|
||||||
|
display.init();
|
||||||
|
display.flipScreenVertically();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
display.clear();
|
||||||
|
|
||||||
|
String state_string = "";
|
||||||
|
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display.setFont(ArialMT_Plain_16);
|
||||||
|
display.drawString(0, 0, report_state_text());
|
||||||
|
|
||||||
|
if (get_sd_state(false) == SDState::BusyPrinting) {
|
||||||
|
display.clear();
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
|
display.setFont(ArialMT_Plain_10);
|
||||||
|
state_string = "SD File";
|
||||||
|
for (int i = 0; i < sd_file_ticker % 10; i++) {
|
||||||
|
state_string += ".";
|
||||||
|
}
|
||||||
|
sd_file_ticker++;
|
||||||
|
display.drawString(63, 0, state_string);
|
||||||
|
|
||||||
|
char path[50];
|
||||||
|
sd_get_current_filename(path);
|
||||||
|
display.drawString(63, 12, path);
|
||||||
|
|
||||||
|
int progress = sd_report_perc_complete();
|
||||||
|
// draw the progress bar
|
||||||
|
display.drawProgressBar(0, 45, 120, 10, progress);
|
||||||
|
|
||||||
|
// draw the percentage as String
|
||||||
|
display.setFont(ArialMT_Plain_10);
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
|
display.drawString(64, 25, String(progress) + "%");
|
||||||
|
|
||||||
|
} else if (sys.state == State::Alarm) {
|
||||||
|
displayRadioInfo();
|
||||||
|
} else {
|
||||||
|
displayDRO();
|
||||||
|
displayRadioInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
|
||||||
|
vTaskDelayUntil(&xLastWakeTime, xDisplayFrequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_init() {
|
||||||
|
// Initialising the UI will init the display too.
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Init Basic OLED SDA:%s SCL:%s", pinName(OLED_SDA), pinName(OLED_SCL));
|
||||||
|
display.init();
|
||||||
|
|
||||||
|
display.flipScreenVertically();
|
||||||
|
|
||||||
|
display.clear();
|
||||||
|
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
|
display.setFont(ArialMT_Plain_10);
|
||||||
|
|
||||||
|
String mach_name = MACHINE_NAME;
|
||||||
|
// remove characters from the end until the string fits
|
||||||
|
while (display.getStringWidth(mach_name) > 128) {
|
||||||
|
mach_name = mach_name.substring(0, mach_name.length() - 1);
|
||||||
|
}
|
||||||
|
display.drawString(63, 0, mach_name);
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
|
||||||
|
xTaskCreatePinnedToCore(displayUpdate, // task
|
||||||
|
"displayUpdateTask", // name for task
|
||||||
|
4096, // size of task stack
|
||||||
|
NULL, // parameters
|
||||||
|
1, // priority
|
||||||
|
&displayUpdateTaskHandle,
|
||||||
|
CONFIG_ARDUINO_RUNNING_CORE // must run the task on same core
|
||||||
|
// core
|
||||||
|
);
|
||||||
|
}
|
@@ -135,23 +135,12 @@ bool user_defined_homing(uint8_t cycle_mask) { // true = do not continue with n
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function is used by Grbl
|
// This function is used by Grbl
|
||||||
void inverse_kinematics(float* position) {
|
bool inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) //The target and position are provided in MPos
|
||||||
float motor_angles[3];
|
|
||||||
|
|
||||||
read_settings();
|
|
||||||
delta_calcInverse(position, motor_angles);
|
|
||||||
position[0] = motor_angles[0];
|
|
||||||
position[1] = motor_angles[1];
|
|
||||||
position[2] = motor_angles[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is used by Grbl
|
|
||||||
void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) //The target and position are provided in MPos
|
|
||||||
{
|
{
|
||||||
float dx, dy, dz; // distances in each cartesian axis
|
float dx, dy, dz; // distances in each cartesian axis
|
||||||
float motor_angles[3];
|
float motor_angles[3];
|
||||||
|
|
||||||
float seg_target[3]; // The target of the current segment
|
float seg_target[3]; // The target of the current segment
|
||||||
float feed_rate = pl_data->feed_rate; // save original feed rate
|
float feed_rate = pl_data->feed_rate; // save original feed rate
|
||||||
bool show_error = true; // shows error once
|
bool show_error = true; // shows error once
|
||||||
|
|
||||||
@@ -210,7 +199,7 @@ void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* positio
|
|||||||
pl_data->feed_rate = (feed_rate * delta_distance / segment_dist);
|
pl_data->feed_rate = (feed_rate * delta_distance / segment_dist);
|
||||||
}
|
}
|
||||||
|
|
||||||
mc_line(motor_angles, pl_data);
|
return mc_line(motor_angles, pl_data);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (show_error) {
|
if (show_error) {
|
||||||
@@ -222,36 +211,35 @@ void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* positio
|
|||||||
// motor_angles[1],
|
// motor_angles[1],
|
||||||
// motor_angles[2]);
|
// motor_angles[2]);
|
||||||
show_error = false;
|
show_error = false;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is used used by Grbl soft limits to see if the range of the machine is exceeded.
|
// this is used used by Grbl soft limits to see if the range of the machine is exceeded.
|
||||||
uint8_t kinematic_limits_check(float* target) {
|
bool limitsCheckTravel(float* target) {
|
||||||
float motor_angles[3];
|
float motor_angles[3];
|
||||||
|
|
||||||
read_settings();
|
read_settings();
|
||||||
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Kin Soft Check %3.3f, %3.3f, %3.3f", target[0], target[1], target[2]);
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Kin Soft Check %3.3f, %3.3f, %3.3f", target[0], target[1], target[2]);
|
||||||
|
|
||||||
KinematicError status = delta_calcInverse(target, motor_angles);
|
switch (delta_calcInverse(target, motor_angles)) {
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case KinematicError::OUT_OF_RANGE:
|
case KinematicError::OUT_OF_RANGE:
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Kin target out of range");
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Kin target out of range");
|
||||||
break;
|
return true;
|
||||||
case KinematicError::ANGLE_TOO_NEGATIVE:
|
case KinematicError::ANGLE_TOO_NEGATIVE:
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Kin target max negative");
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Kin target max negative");
|
||||||
break;
|
return true;
|
||||||
case KinematicError::ANGLE_TOO_POSITIVE:
|
case KinematicError::ANGLE_TOO_POSITIVE:
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Kin target max positive");
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Kin target max positive");
|
||||||
break;
|
return true;
|
||||||
case KinematicError::NONE:
|
case KinematicError::NONE:
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (status == KinematicError::NONE);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// inverse kinematics: cartesian -> angles
|
// inverse kinematics: cartesian -> angles
|
||||||
|
@@ -85,7 +85,7 @@ void kinematics_post_homing() {
|
|||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) {
|
bool inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) {
|
||||||
//static float last_angle = 0;
|
//static float last_angle = 0;
|
||||||
//static float last_radius = 0;
|
//static float last_radius = 0;
|
||||||
float dx, dy, dz; // distances in each cartesian axis
|
float dx, dy, dz; // distances in each cartesian axis
|
||||||
@@ -111,6 +111,7 @@ void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* positio
|
|||||||
segment_count = ceil(dist / SEGMENT_LENGTH); // determine the number of segments we need ... round up so there is at least 1
|
segment_count = ceil(dist / SEGMENT_LENGTH); // determine the number of segments we need ... round up so there is at least 1
|
||||||
}
|
}
|
||||||
dist /= segment_count; // segment distance
|
dist /= segment_count; // segment distance
|
||||||
|
bool added = false;
|
||||||
for (uint32_t segment = 1; segment <= segment_count; segment++) {
|
for (uint32_t segment = 1; segment <= segment_count; segment++) {
|
||||||
// determine this segment's target
|
// determine this segment's target
|
||||||
seg_target[X_AXIS] = position[X_AXIS] + (dx / float(segment_count) * segment) - x_offset;
|
seg_target[X_AXIS] = position[X_AXIS] + (dx / float(segment_count) * segment) - x_offset;
|
||||||
@@ -141,9 +142,10 @@ void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* positio
|
|||||||
polar[Z_AXIS] += z_offset;
|
polar[Z_AXIS] += z_offset;
|
||||||
last_radius = polar[RADIUS_AXIS];
|
last_radius = polar[RADIUS_AXIS];
|
||||||
last_angle = polar[POLAR_AXIS];
|
last_angle = polar[POLAR_AXIS];
|
||||||
mc_line(polar, pl_data);
|
added = mc_line(polar, pl_data);
|
||||||
}
|
}
|
||||||
// TO DO don't need a feedrate for rapids
|
// TO DO don't need a feedrate for rapids
|
||||||
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -6,3 +6,7 @@
|
|||||||
#ifdef CUSTOM_CODE_FILENAME
|
#ifdef CUSTOM_CODE_FILENAME
|
||||||
# include CUSTOM_CODE_FILENAME
|
# include CUSTOM_CODE_FILENAME
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DISPLAY_CODE_FILENAME
|
||||||
|
# include DISPLAY_CODE_FILENAME
|
||||||
|
#endif
|
@@ -1287,11 +1287,12 @@ Error gc_execute_line(char* line, uint8_t client) {
|
|||||||
FAIL(Error::InvalidJogCommand);
|
FAIL(Error::InvalidJogCommand);
|
||||||
}
|
}
|
||||||
// Initialize planner data to current spindle and coolant modal state.
|
// Initialize planner data to current spindle and coolant modal state.
|
||||||
pl_data->spindle_speed = gc_state.spindle_speed;
|
pl_data->spindle_speed = gc_state.spindle_speed;
|
||||||
pl_data->spindle = gc_state.modal.spindle;
|
pl_data->spindle = gc_state.modal.spindle;
|
||||||
pl_data->coolant = gc_state.modal.coolant;
|
pl_data->coolant = gc_state.modal.coolant;
|
||||||
Error status = jog_execute(pl_data, &gc_block);
|
bool cancelledInflight = false;
|
||||||
if (status == Error::Ok) {
|
Error status = jog_execute(pl_data, &gc_block, &cancelledInflight);
|
||||||
|
if (status == Error::Ok && !cancelledInflight) {
|
||||||
memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz));
|
memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz));
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
@@ -1485,9 +1486,9 @@ Error gc_execute_line(char* line, uint8_t client) {
|
|||||||
// and absolute and incremental modes.
|
// and absolute and incremental modes.
|
||||||
pl_data->motion.rapidMotion = 1; // Set rapid motion flag.
|
pl_data->motion.rapidMotion = 1; // Set rapid motion flag.
|
||||||
if (axis_command != AxisCommand::None) {
|
if (axis_command != AxisCommand::None) {
|
||||||
mc_line_kins(gc_block.values.xyz, pl_data, gc_state.position);
|
inverse_kinematics(gc_block.values.xyz, pl_data, gc_state.position);
|
||||||
}
|
}
|
||||||
mc_line_kins(coord_data, pl_data, gc_state.position);
|
inverse_kinematics(coord_data, pl_data, gc_state.position);
|
||||||
memcpy(gc_state.position, coord_data, sizeof(gc_state.position));
|
memcpy(gc_state.position, coord_data, sizeof(gc_state.position));
|
||||||
break;
|
break;
|
||||||
case NonModal::SetHome0:
|
case NonModal::SetHome0:
|
||||||
@@ -1515,12 +1516,10 @@ Error gc_execute_line(char* line, uint8_t client) {
|
|||||||
if (axis_command == AxisCommand::MotionMode) {
|
if (axis_command == AxisCommand::MotionMode) {
|
||||||
GCUpdatePos gc_update_pos = GCUpdatePos::Target;
|
GCUpdatePos gc_update_pos = GCUpdatePos::Target;
|
||||||
if (gc_state.modal.motion == Motion::Linear) {
|
if (gc_state.modal.motion == Motion::Linear) {
|
||||||
//mc_line(gc_block.values.xyz, pl_data);
|
inverse_kinematics(gc_block.values.xyz, pl_data, gc_state.position);
|
||||||
mc_line_kins(gc_block.values.xyz, pl_data, gc_state.position);
|
|
||||||
} else if (gc_state.modal.motion == Motion::Seek) {
|
} else if (gc_state.modal.motion == Motion::Seek) {
|
||||||
pl_data->motion.rapidMotion = 1; // Set rapid motion flag.
|
pl_data->motion.rapidMotion = 1; // Set rapid motion flag.
|
||||||
//mc_line(gc_block.values.xyz, pl_data);
|
inverse_kinematics(gc_block.values.xyz, pl_data, gc_state.position);
|
||||||
mc_line_kins(gc_block.values.xyz, pl_data, gc_state.position);
|
|
||||||
} else if ((gc_state.modal.motion == Motion::CwArc) || (gc_state.modal.motion == Motion::CcwArc)) {
|
} else if ((gc_state.modal.motion == Motion::CwArc) || (gc_state.modal.motion == Motion::CcwArc)) {
|
||||||
mc_arc(gc_block.values.xyz,
|
mc_arc(gc_block.values.xyz,
|
||||||
pl_data,
|
pl_data,
|
||||||
|
@@ -30,7 +30,8 @@ void grbl_init() {
|
|||||||
WiFi.enableSTA(false);
|
WiFi.enableSTA(false);
|
||||||
WiFi.enableAP(false);
|
WiFi.enableAP(false);
|
||||||
WiFi.mode(WIFI_OFF);
|
WiFi.mode(WIFI_OFF);
|
||||||
serial_init(); // Setup serial baud rate and interrupts
|
client_init(); // Setup serial baud rate and interrupts
|
||||||
|
display_init();
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Grbl_ESP32 Ver %s Date %s", GRBL_VERSION, GRBL_VERSION_BUILD); // print grbl_esp32 verion info
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Grbl_ESP32 Ver %s Date %s", GRBL_VERSION, GRBL_VERSION_BUILD); // print grbl_esp32 verion info
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Compiled with ESP32 SDK:%s", ESP.getSdkVersion()); // print the SDK version
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Compiled with ESP32 SDK:%s", ESP.getSdkVersion()); // print the SDK version
|
||||||
// show the map name at startup
|
// show the map name at startup
|
||||||
@@ -39,7 +40,7 @@ void grbl_init() {
|
|||||||
#endif
|
#endif
|
||||||
settings_init(); // Load Grbl settings from non-volatile storage
|
settings_init(); // Load Grbl settings from non-volatile storage
|
||||||
stepper_init(); // Configure stepper pins and interrupt timers
|
stepper_init(); // Configure stepper pins and interrupt timers
|
||||||
system_ini(); // Configure pinout pins and pin-change interrupt (Renamed due to conflict with esp32 files)
|
system_ini(); // Configure pinout pins and pin-change interrupt (Renamed due to conflict with esp32 files)
|
||||||
init_motors();
|
init_motors();
|
||||||
memset(sys_position, 0, sizeof(sys_position)); // Clear machine position.
|
memset(sys_position, 0, sizeof(sys_position)); // Clear machine position.
|
||||||
machine_init(); // weak definition in Grbl.cpp does nothing
|
machine_init(); // weak definition in Grbl.cpp does nothing
|
||||||
@@ -92,8 +93,8 @@ static void reset_variables() {
|
|||||||
sys_rt_s_override = SpindleSpeedOverride::Default;
|
sys_rt_s_override = SpindleSpeedOverride::Default;
|
||||||
|
|
||||||
// Reset Grbl primary systems.
|
// Reset Grbl primary systems.
|
||||||
serial_reset_read_buffer(CLIENT_ALL); // Clear serial read buffer
|
client_reset_read_buffer(CLIENT_ALL);
|
||||||
gc_init(); // Set g-code parser to default state
|
gc_init(); // Set g-code parser to default state
|
||||||
spindle->stop();
|
spindle->stop();
|
||||||
coolant_init();
|
coolant_init();
|
||||||
limits_init();
|
limits_init();
|
||||||
@@ -104,6 +105,10 @@ static void reset_variables() {
|
|||||||
plan_sync_position();
|
plan_sync_position();
|
||||||
gc_sync_position();
|
gc_sync_position();
|
||||||
report_init_message(CLIENT_ALL);
|
report_init_message(CLIENT_ALL);
|
||||||
|
|
||||||
|
// used to keep track of a jog command sent to mc_line() so we can cancel it.
|
||||||
|
// this is needed if a jogCancel comes along after we have already parsed a jog and it is in-flight.
|
||||||
|
sys_pl_data_inflight = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_once() {
|
void run_once() {
|
||||||
@@ -116,6 +121,7 @@ void run_once() {
|
|||||||
|
|
||||||
void __attribute__((weak)) machine_init() {}
|
void __attribute__((weak)) machine_init() {}
|
||||||
|
|
||||||
|
void __attribute__((weak)) display_init() {}
|
||||||
/*
|
/*
|
||||||
setup() and loop() in the Arduino .ino implements this control flow:
|
setup() and loop() in the Arduino .ino implements this control flow:
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
// Grbl versioning system
|
// Grbl versioning system
|
||||||
const char* const GRBL_VERSION = "1.3a";
|
const char* const GRBL_VERSION = "1.3a";
|
||||||
const char* const GRBL_VERSION_BUILD = "20210311";
|
const char* const GRBL_VERSION_BUILD = "20210420";
|
||||||
|
|
||||||
//#include <sdkconfig.h>
|
//#include <sdkconfig.h>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
@@ -51,8 +51,9 @@ const char* const GRBL_VERSION_BUILD = "20210311";
|
|||||||
#include "Limits.h"
|
#include "Limits.h"
|
||||||
#include "MotionControl.h"
|
#include "MotionControl.h"
|
||||||
#include "Protocol.h"
|
#include "Protocol.h"
|
||||||
#include "Report.h"
|
#include "Uart.h"
|
||||||
#include "Serial.h"
|
#include "Serial.h"
|
||||||
|
#include "Report.h"
|
||||||
#include "Pins.h"
|
#include "Pins.h"
|
||||||
#include "Spindles/Spindle.h"
|
#include "Spindles/Spindle.h"
|
||||||
#include "Motors/Motors.h"
|
#include "Motors/Motors.h"
|
||||||
@@ -65,6 +66,8 @@ const char* const GRBL_VERSION_BUILD = "20210311";
|
|||||||
|
|
||||||
#include "UserOutput.h"
|
#include "UserOutput.h"
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
// Do not guard this because it is needed for local files too
|
// Do not guard this because it is needed for local files too
|
||||||
#include "SDCard.h"
|
#include "SDCard.h"
|
||||||
|
|
||||||
@@ -90,20 +93,18 @@ const char* const GRBL_VERSION_BUILD = "20210311";
|
|||||||
void grbl_init();
|
void grbl_init();
|
||||||
void run_once();
|
void run_once();
|
||||||
|
|
||||||
// Called if USE_MACHINE_INIT is defined
|
void machine_init(); // weak definition in Grbl.cpp
|
||||||
void machine_init();
|
void display_init(); // weak definition in Grbl.cpp
|
||||||
|
|
||||||
bool user_defined_homing(uint8_t cycle_mask); // weak definition in Limits.cpp
|
bool user_defined_homing(uint8_t cycle_mask); // weak definition in Limits.cpp
|
||||||
|
|
||||||
// Called if USE_KINEMATICS is defined
|
// weak definitions in MotionControl.cpp
|
||||||
|
bool inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position);
|
||||||
|
bool kinematics_pre_homing(uint8_t cycle_mask);
|
||||||
|
void kinematics_post_homing();
|
||||||
|
|
||||||
void inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position);
|
bool limitsCheckTravel(float* target); // weak in Limits.cpp; true if out of range
|
||||||
bool kinematics_pre_homing(uint8_t cycle_mask);
|
|
||||||
void kinematics_post_homing();
|
|
||||||
uint8_t kinematic_limits_check(float* target);
|
|
||||||
|
|
||||||
// Called if USE_FWD_KINEMATICS is defined
|
|
||||||
void inverse_kinematics(float* position); // used to return a converted value
|
|
||||||
void forward_kinematics(float* position); // weak definition in Report.cpp
|
void forward_kinematics(float* position); // weak definition in Report.cpp
|
||||||
|
|
||||||
// Called if MACRO_BUTTON_0_PIN or MACRO_BUTTON_1_PIN or MACRO_BUTTON_2_PIN is defined
|
// Called if MACRO_BUTTON_0_PIN or MACRO_BUTTON_1_PIN or MACRO_BUTTON_2_PIN is defined
|
||||||
|
@@ -48,6 +48,7 @@
|
|||||||
#include "WebUI/ESPResponse.h"
|
#include "WebUI/ESPResponse.h"
|
||||||
#include "Probe.h"
|
#include "Probe.h"
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
|
#include "Serial.h"
|
||||||
#include "Report.h"
|
#include "Report.h"
|
||||||
|
|
||||||
#include <FreeRTOS.h>
|
#include <FreeRTOS.h>
|
||||||
|
@@ -24,11 +24,13 @@
|
|||||||
#include "Grbl.h"
|
#include "Grbl.h"
|
||||||
|
|
||||||
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
||||||
Error jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block) {
|
// cancelledInflight will be set to true if was not added to parser due to a cancelJog.
|
||||||
|
Error jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block, bool* cancelledInflight) {
|
||||||
// Initialize planner data struct for jogging motions.
|
// Initialize planner data struct for jogging motions.
|
||||||
// NOTE: Spindle and coolant are allowed to fully function with overrides during a jog.
|
// NOTE: Spindle and coolant are allowed to fully function with overrides during a jog.
|
||||||
pl_data->feed_rate = gc_block->values.f;
|
pl_data->feed_rate = gc_block->values.f;
|
||||||
pl_data->motion.noFeedOverride = 1;
|
pl_data->motion.noFeedOverride = 1;
|
||||||
|
pl_data->is_jog = true;
|
||||||
#ifdef USE_LINE_NUMBERS
|
#ifdef USE_LINE_NUMBERS
|
||||||
pl_data->line_number = gc_block->values.n;
|
pl_data->line_number = gc_block->values.n;
|
||||||
#endif
|
#endif
|
||||||
@@ -37,12 +39,12 @@ Error jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block) {
|
|||||||
return Error::TravelExceeded;
|
return Error::TravelExceeded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Valid jog command. Plan, set state, and execute.
|
// Valid jog command. Plan, set state, and execute.
|
||||||
#ifndef USE_KINEMATICS
|
if (!inverse_kinematics(gc_block->values.xyz, pl_data, gc_state.position)) {
|
||||||
mc_line(gc_block->values.xyz, pl_data);
|
if (cancelledInflight)
|
||||||
#else // else use kinematics
|
*cancelledInflight = true;
|
||||||
inverse_kinematics(gc_block->values.xyz, pl_data, gc_state.position);
|
return Error::Ok;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
if (sys.state == State::Idle) {
|
if (sys.state == State::Idle) {
|
||||||
if (plan_get_current_block() != NULL) { // Check if there is a block to execute.
|
if (plan_get_current_block() != NULL) { // Check if there is a block to execute.
|
||||||
|
@@ -28,4 +28,5 @@
|
|||||||
const int JOG_LINE_NUMBER = 0;
|
const int JOG_LINE_NUMBER = 0;
|
||||||
|
|
||||||
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
||||||
Error jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block);
|
// cancelledInflight will be set to true if was not added to parser due to a cancelJog.
|
||||||
|
Error jog_execute(plan_line_data_t* pl_data, parser_block_t* gc_block, bool* cancelledInflight);
|
||||||
|
@@ -55,10 +55,12 @@ void IRAM_ATTR isr_limit_switches() {
|
|||||||
# ifdef HARD_LIMIT_FORCE_STATE_CHECK
|
# ifdef HARD_LIMIT_FORCE_STATE_CHECK
|
||||||
// Check limit pin state.
|
// Check limit pin state.
|
||||||
if (limits_get_state()) {
|
if (limits_get_state()) {
|
||||||
|
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Hard limits");
|
||||||
mc_reset(); // Initiate system kill.
|
mc_reset(); // Initiate system kill.
|
||||||
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
|
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Hard limits");
|
||||||
mc_reset(); // Initiate system kill.
|
mc_reset(); // Initiate system kill.
|
||||||
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
||||||
# endif
|
# endif
|
||||||
@@ -195,7 +197,8 @@ void limits_go_home(uint8_t cycle_mask) {
|
|||||||
|
|
||||||
if (sys_rt_exec_alarm != ExecAlarm::None) {
|
if (sys_rt_exec_alarm != ExecAlarm::None) {
|
||||||
motors_set_homing_mode(cycle_mask, false); // tell motors homing is done...failed
|
motors_set_homing_mode(cycle_mask, false); // tell motors homing is done...failed
|
||||||
mc_reset(); // Stop motors, if they are running.
|
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Homing fail");
|
||||||
|
mc_reset(); // Stop motors, if they are running.
|
||||||
protocol_execute_realtime();
|
protocol_execute_realtime();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@@ -351,6 +354,7 @@ void limits_soft_check(float* target) {
|
|||||||
}
|
}
|
||||||
} while (sys.state != State::Idle);
|
} while (sys.state != State::Idle);
|
||||||
}
|
}
|
||||||
|
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Soft limits");
|
||||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||||
sys_rt_exec_alarm = ExecAlarm::SoftLimit; // Indicate soft limit critical event
|
sys_rt_exec_alarm = ExecAlarm::SoftLimit; // Indicate soft limit critical event
|
||||||
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
|
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
|
||||||
@@ -367,7 +371,7 @@ void limitCheckTask(void* pvParameters) {
|
|||||||
AxisMask switch_state;
|
AxisMask switch_state;
|
||||||
switch_state = limits_get_state();
|
switch_state = limits_get_state();
|
||||||
if (switch_state) {
|
if (switch_state) {
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Limit Switch State %08d", switch_state);
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Debug, "Limit Switch State %08d", switch_state);
|
||||||
mc_reset(); // Initiate system kill.
|
mc_reset(); // Initiate system kill.
|
||||||
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
|
||||||
}
|
}
|
||||||
@@ -392,19 +396,24 @@ float limitsMinPosition(uint8_t axis) {
|
|||||||
|
|
||||||
// Checks and reports if target array exceeds machine travel limits.
|
// Checks and reports if target array exceeds machine travel limits.
|
||||||
// Return true if exceeding limits
|
// Return true if exceeding limits
|
||||||
bool limitsCheckTravel(float* target) {
|
// Set $<axis>/MaxTravel=0 to selectively remove an axis from soft limit checks
|
||||||
|
bool __attribute__((weak)) limitsCheckTravel(float* target) {
|
||||||
uint8_t idx;
|
uint8_t idx;
|
||||||
auto n_axis = number_axis->get();
|
auto n_axis = number_axis->get();
|
||||||
for (idx = 0; idx < n_axis; idx++) {
|
for (idx = 0; idx < n_axis; idx++) {
|
||||||
float max_mpos, min_mpos;
|
float max_mpos, min_mpos;
|
||||||
|
|
||||||
if (target[idx] < limitsMinPosition(idx) || target[idx] > limitsMaxPosition(idx)) {
|
if ((target[idx] < limitsMinPosition(idx) || target[idx] > limitsMaxPosition(idx)) && axis_settings[idx]->max_travel->get() > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool limitsSwitchDefined(uint8_t axis, uint8_t gang_index) {
|
||||||
|
return (limit_pins[axis][gang_index] != UNDEFINED_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
bool __attribute__((weak)) user_defined_homing(uint8_t cycle_mask) {
|
bool __attribute__((weak)) user_defined_homing(uint8_t cycle_mask) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -54,3 +54,6 @@ float limitsMinPosition(uint8_t axis);
|
|||||||
|
|
||||||
// Internal factor used by limits_soft_check
|
// Internal factor used by limits_soft_check
|
||||||
bool limitsCheckTravel(float* target);
|
bool limitsCheckTravel(float* target);
|
||||||
|
|
||||||
|
// check if a switch has been defined
|
||||||
|
bool limitsSwitchDefined(uint8_t axis, uint8_t gang_index);
|
||||||
|
@@ -30,8 +30,6 @@
|
|||||||
#define CUSTOM_CODE_FILENAME "../Custom/CoreXY.cpp"
|
#define CUSTOM_CODE_FILENAME "../Custom/CoreXY.cpp"
|
||||||
|
|
||||||
#define MIDTBOT // applies the geometry correction to the kinematics
|
#define MIDTBOT // applies the geometry correction to the kinematics
|
||||||
#define USE_KINEMATICS // there are kinematic equations for this machine
|
|
||||||
#define USE_FWD_KINEMATICS // report in cartesian
|
|
||||||
#define USE_MACHINE_INIT // There is some custom initialization for this machine
|
#define USE_MACHINE_INIT // There is some custom initialization for this machine
|
||||||
#define USE_CUSTOM_HOMING
|
#define USE_CUSTOM_HOMING
|
||||||
|
|
||||||
|
@@ -37,8 +37,6 @@
|
|||||||
#define POLAR_AXIS 1
|
#define POLAR_AXIS 1
|
||||||
|
|
||||||
#define SEGMENT_LENGTH 0.5 // segment length in mm
|
#define SEGMENT_LENGTH 0.5 // segment length in mm
|
||||||
#define USE_KINEMATICS
|
|
||||||
#define USE_FWD_KINEMATICS // report in cartesian
|
|
||||||
#define USE_M30
|
#define USE_M30
|
||||||
|
|
||||||
#define X_STEP_PIN GPIO_NUM_15
|
#define X_STEP_PIN GPIO_NUM_15
|
||||||
|
@@ -25,8 +25,6 @@
|
|||||||
|
|
||||||
// ================= Firmware Customization ===================
|
// ================= Firmware Customization ===================
|
||||||
|
|
||||||
#define USE_KINEMATICS // there are kinematic equations for this machine
|
|
||||||
#define USE_FWD_KINEMATICS // report in cartesian
|
|
||||||
#define USE_MACHINE_INIT // There is some custom initialization for this machine
|
#define USE_MACHINE_INIT // There is some custom initialization for this machine
|
||||||
|
|
||||||
// ================== Delta Geometry ===========================
|
// ================== Delta Geometry ===========================
|
||||||
|
@@ -41,8 +41,6 @@
|
|||||||
|
|
||||||
#define N_AXIS 3
|
#define N_AXIS 3
|
||||||
|
|
||||||
#define USE_KINEMATICS // there are kinematic equations for this machine
|
|
||||||
#define USE_FWD_KINEMATICS // report in cartesian
|
|
||||||
#define USE_MACHINE_INIT // There is some custom initialization for this machine
|
#define USE_MACHINE_INIT // There is some custom initialization for this machine
|
||||||
|
|
||||||
// ================== Delta Geometry ===========================
|
// ================== Delta Geometry ===========================
|
||||||
|
@@ -33,15 +33,6 @@
|
|||||||
|
|
||||||
SquaringMode ganged_mode = SquaringMode::Dual;
|
SquaringMode ganged_mode = SquaringMode::Dual;
|
||||||
|
|
||||||
// this allows kinematics to be used.
|
|
||||||
void mc_line_kins(float* target, plan_line_data_t* pl_data, float* position) {
|
|
||||||
#ifndef USE_KINEMATICS
|
|
||||||
mc_line(target, pl_data);
|
|
||||||
#else // else use kinematics
|
|
||||||
inverse_kinematics(target, pl_data, position);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
||||||
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
||||||
// (1 minute)/feed_rate time.
|
// (1 minute)/feed_rate time.
|
||||||
@@ -49,7 +40,11 @@ void mc_line_kins(float* target, plan_line_data_t* pl_data, float* position) {
|
|||||||
// segments, must pass through this routine before being passed to the planner. The seperation of
|
// segments, must pass through this routine before being passed to the planner. The seperation of
|
||||||
// mc_line and plan_buffer_line is done primarily to place non-planner-type functions from being
|
// mc_line and plan_buffer_line is done primarily to place non-planner-type functions from being
|
||||||
// in the planner and to let backlash compensation or canned cycle integration simple and direct.
|
// in the planner and to let backlash compensation or canned cycle integration simple and direct.
|
||||||
void mc_line(float* target, plan_line_data_t* pl_data) {
|
// returns true if line was submitted to planner, or false if intentionally dropped.
|
||||||
|
bool mc_line(float* target, plan_line_data_t* pl_data) {
|
||||||
|
bool submitted_result = false;
|
||||||
|
// store the plan data so it can be cancelled by the protocol system if needed
|
||||||
|
sys_pl_data_inflight = pl_data;
|
||||||
// If enabled, check for soft limit violations. Placed here all line motions are picked up
|
// If enabled, check for soft limit violations. Placed here all line motions are picked up
|
||||||
// from everywhere in Grbl.
|
// from everywhere in Grbl.
|
||||||
if (soft_limits->get()) {
|
if (soft_limits->get()) {
|
||||||
@@ -60,7 +55,8 @@ void mc_line(float* target, plan_line_data_t* pl_data) {
|
|||||||
}
|
}
|
||||||
// If in check gcode mode, prevent motion by blocking planner. Soft limits still work.
|
// If in check gcode mode, prevent motion by blocking planner. Soft limits still work.
|
||||||
if (sys.state == State::CheckMode) {
|
if (sys.state == State::CheckMode) {
|
||||||
return;
|
sys_pl_data_inflight = NULL;
|
||||||
|
return submitted_result;
|
||||||
}
|
}
|
||||||
// NOTE: Backlash compensation may be installed here. It will need direction info to track when
|
// NOTE: Backlash compensation may be installed here. It will need direction info to track when
|
||||||
// to insert a backlash line motion(s) before the intended line motion and will require its own
|
// to insert a backlash line motion(s) before the intended line motion and will require its own
|
||||||
@@ -80,7 +76,8 @@ void mc_line(float* target, plan_line_data_t* pl_data) {
|
|||||||
do {
|
do {
|
||||||
protocol_execute_realtime(); // Check for any run-time commands
|
protocol_execute_realtime(); // Check for any run-time commands
|
||||||
if (sys.abort) {
|
if (sys.abort) {
|
||||||
return; // Bail, if system abort.
|
sys_pl_data_inflight = NULL;
|
||||||
|
return submitted_result; // Bail, if system abort.
|
||||||
}
|
}
|
||||||
if (plan_check_full_buffer()) {
|
if (plan_check_full_buffer()) {
|
||||||
protocol_auto_cycle_start(); // Auto-cycle start when buffer is full.
|
protocol_auto_cycle_start(); // Auto-cycle start when buffer is full.
|
||||||
@@ -90,9 +87,25 @@ void mc_line(float* target, plan_line_data_t* pl_data) {
|
|||||||
} while (1);
|
} while (1);
|
||||||
// Plan and queue motion into planner buffer
|
// Plan and queue motion into planner buffer
|
||||||
// uint8_t plan_status; // Not used in normal operation.
|
// uint8_t plan_status; // Not used in normal operation.
|
||||||
plan_buffer_line(target, pl_data);
|
if (sys_pl_data_inflight == pl_data) {
|
||||||
|
plan_buffer_line(target, pl_data);
|
||||||
|
submitted_result = true;
|
||||||
|
}
|
||||||
|
sys_pl_data_inflight = NULL;
|
||||||
|
return submitted_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool __attribute__((weak)) inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position) {
|
||||||
|
return mc_line(target, pl_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __attribute__((weak)) kinematics_pre_homing(uint8_t cycle_mask) {
|
||||||
|
return false; // finish normal homing cycle
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((weak)) kinematics_post_homing() {}
|
||||||
|
|
||||||
|
void __attribute__((weak)) forward_kinematics(float* position) {}
|
||||||
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
||||||
// offset == offset from current xyz, axis_X defines circle plane in tool space, axis_linear is
|
// offset == offset from current xyz, axis_X defines circle plane in tool space, axis_linear is
|
||||||
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
|
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
|
||||||
@@ -117,14 +130,12 @@ void mc_arc(float* target,
|
|||||||
float rt_axis1 = target[axis_1] - center_axis1;
|
float rt_axis1 = target[axis_1] - center_axis1;
|
||||||
|
|
||||||
float previous_position[MAX_N_AXIS] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
|
float previous_position[MAX_N_AXIS] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
|
||||||
#ifdef USE_KINEMATICS
|
|
||||||
|
|
||||||
uint16_t n;
|
uint16_t n;
|
||||||
auto n_axis = number_axis->get();
|
auto n_axis = number_axis->get();
|
||||||
for (n = 0; n < n_axis; n++) {
|
for (n = 0; n < n_axis; n++) {
|
||||||
previous_position[n] = position[n];
|
previous_position[n] = position[n];
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
|
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
|
||||||
float angular_travel = atan2(r_axis0 * rt_axis1 - r_axis1 * rt_axis0, r_axis0 * rt_axis0 + r_axis1 * rt_axis1);
|
float angular_travel = atan2(r_axis0 * rt_axis1 - r_axis1 * rt_axis0, r_axis0 * rt_axis0 + r_axis1 * rt_axis1);
|
||||||
if (is_clockwise_arc) { // Correct atan2 output per direction
|
if (is_clockwise_arc) { // Correct atan2 output per direction
|
||||||
@@ -206,15 +217,11 @@ void mc_arc(float* target,
|
|||||||
position[axis_0] = center_axis0 + r_axis0;
|
position[axis_0] = center_axis0 + r_axis0;
|
||||||
position[axis_1] = center_axis1 + r_axis1;
|
position[axis_1] = center_axis1 + r_axis1;
|
||||||
position[axis_linear] += linear_per_segment;
|
position[axis_linear] += linear_per_segment;
|
||||||
#ifdef USE_KINEMATICS
|
|
||||||
pl_data->feed_rate = original_feedrate; // This restores the feedrate kinematics may have altered
|
pl_data->feed_rate = original_feedrate; // This restores the feedrate kinematics may have altered
|
||||||
mc_line_kins(position, pl_data, previous_position);
|
inverse_kinematics(position, pl_data, previous_position);
|
||||||
previous_position[axis_0] = position[axis_0];
|
previous_position[axis_0] = position[axis_0];
|
||||||
previous_position[axis_1] = position[axis_1];
|
previous_position[axis_1] = position[axis_1];
|
||||||
previous_position[axis_linear] = position[axis_linear];
|
previous_position[axis_linear] = position[axis_linear];
|
||||||
#else
|
|
||||||
mc_line(position, pl_data);
|
|
||||||
#endif
|
|
||||||
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
|
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
|
||||||
if (sys.abort) {
|
if (sys.abort) {
|
||||||
return;
|
return;
|
||||||
@@ -222,7 +229,7 @@ void mc_arc(float* target,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ensure last segment arrives at target location.
|
// Ensure last segment arrives at target location.
|
||||||
mc_line_kins(target, pl_data, previous_position);
|
inverse_kinematics(target, pl_data, previous_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute dwell in seconds.
|
// Execute dwell in seconds.
|
||||||
@@ -292,11 +299,9 @@ void mc_homing_cycle(uint8_t cycle_mask) {
|
|||||||
|
|
||||||
// This give kinematics a chance to do something before normal homing
|
// This give kinematics a chance to do something before normal homing
|
||||||
// if it returns true, the homing is canceled.
|
// if it returns true, the homing is canceled.
|
||||||
#ifdef USE_KINEMATICS
|
|
||||||
if (kinematics_pre_homing(cycle_mask)) {
|
if (kinematics_pre_homing(cycle_mask)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
// Check and abort homing cycle, if hard limits are already enabled. Helps prevent problems
|
// Check and abort homing cycle, if hard limits are already enabled. Helps prevent problems
|
||||||
// with machines with limits wired on both ends of travel to one limit pin.
|
// with machines with limits wired on both ends of travel to one limit pin.
|
||||||
// TODO: Move the pin-specific LIMIT_PIN call to Limits.cpp as a function.
|
// TODO: Move the pin-specific LIMIT_PIN call to Limits.cpp as a function.
|
||||||
@@ -366,10 +371,8 @@ void mc_homing_cycle(uint8_t cycle_mask) {
|
|||||||
// Sync gcode parser and planner positions to homed position.
|
// Sync gcode parser and planner positions to homed position.
|
||||||
gc_sync_position();
|
gc_sync_position();
|
||||||
plan_sync_position();
|
plan_sync_position();
|
||||||
#ifdef USE_KINEMATICS
|
|
||||||
// This give kinematics a chance to do something after normal homing
|
// This give kinematics a chance to do something after normal homing
|
||||||
kinematics_post_homing();
|
kinematics_post_homing();
|
||||||
#endif
|
|
||||||
// If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
|
// If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
|
||||||
limits_init();
|
limits_init();
|
||||||
}
|
}
|
||||||
@@ -412,7 +415,7 @@ GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t par
|
|||||||
}
|
}
|
||||||
// Setup and queue probing motion. Auto cycle-start should not start the cycle.
|
// Setup and queue probing motion. Auto cycle-start should not start the cycle.
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Found");
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Found");
|
||||||
mc_line_kins(target, pl_data, gc_state.position);
|
inverse_kinematics(target, pl_data, gc_state.position);
|
||||||
// Activate the probing state monitor in the stepper module.
|
// Activate the probing state monitor in the stepper module.
|
||||||
sys_probe_state = Probe::Active;
|
sys_probe_state = Probe::Active;
|
||||||
// Perform probing cycle. Wait here until probe is triggered or motion completes.
|
// Perform probing cycle. Wait here until probe is triggered or motion completes.
|
||||||
@@ -499,6 +502,7 @@ void mc_override_ctrl_update(uint8_t override_state) {
|
|||||||
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
|
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
|
||||||
// realtime abort command and hard limits. So, keep to a minimum.
|
// realtime abort command and hard limits. So, keep to a minimum.
|
||||||
void mc_reset() {
|
void mc_reset() {
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Debug, "mc_reset()");
|
||||||
// Only this function can set the system reset. Helps prevent multiple kill calls.
|
// Only this function can set the system reset. Helps prevent multiple kill calls.
|
||||||
if (!sys_rt_exec_state.bit.reset) {
|
if (!sys_rt_exec_state.bit.reset) {
|
||||||
sys_rt_exec_state.bit.reset = true;
|
sys_rt_exec_state.bit.reset = true;
|
||||||
|
@@ -35,8 +35,8 @@ const int PARKING_MOTION_LINE_NUMBER = 0;
|
|||||||
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
||||||
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
||||||
// (1 minute)/feed_rate time.
|
// (1 minute)/feed_rate time.
|
||||||
void mc_line_kins(float* target, plan_line_data_t* pl_data, float* position);
|
bool inverse_kinematics(float* target, plan_line_data_t* pl_data, float* position);
|
||||||
void mc_line(float* target, plan_line_data_t* pl_data);
|
bool mc_line(float* target, plan_line_data_t* pl_data); // returns true if line was submitted to planner
|
||||||
|
|
||||||
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
||||||
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
|
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "Motor.h"
|
#include "Motor.h"
|
||||||
#include "StandardStepper.h"
|
#include "StandardStepper.h"
|
||||||
|
#include "../Uart.h"
|
||||||
|
|
||||||
#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper
|
#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ const double TRINAMIC_UART_FCLK = 12700000.0; // Internal clock Approx (Hz) use
|
|||||||
# define TMC_UART_TX UNDEFINED_PIN
|
# define TMC_UART_TX UNDEFINED_PIN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern HardwareSerial tmc_serial;
|
extern Uart tmc_serial;
|
||||||
|
|
||||||
namespace Motors {
|
namespace Motors {
|
||||||
|
|
||||||
@@ -75,6 +76,9 @@ namespace Motors {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class TrinamicUartDriver : public StandardStepper {
|
class TrinamicUartDriver : public StandardStepper {
|
||||||
|
private:
|
||||||
|
static bool _uart_started;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TrinamicUartDriver(uint8_t axis_index,
|
TrinamicUartDriver(uint8_t axis_index,
|
||||||
uint8_t step_pin,
|
uint8_t step_pin,
|
||||||
@@ -128,4 +132,4 @@ namespace Motors {
|
|||||||
// void config_message() override;
|
// void config_message() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -26,10 +26,12 @@
|
|||||||
|
|
||||||
#include <TMCStepper.h>
|
#include <TMCStepper.h>
|
||||||
|
|
||||||
HardwareSerial tmc_serial(TMC_UART);
|
Uart tmc_serial(TMC_UART);
|
||||||
|
|
||||||
namespace Motors {
|
namespace Motors {
|
||||||
|
|
||||||
|
bool TrinamicUartDriver::_uart_started = false;
|
||||||
|
|
||||||
TrinamicUartDriver* TrinamicUartDriver::List = NULL; // a static ist of all drivers for stallguard reporting
|
TrinamicUartDriver* TrinamicUartDriver::List = NULL; // a static ist of all drivers for stallguard reporting
|
||||||
|
|
||||||
/* HW Serial Constructor. */
|
/* HW Serial Constructor. */
|
||||||
@@ -41,9 +43,11 @@ namespace Motors {
|
|||||||
_r_sense = r_sense;
|
_r_sense = r_sense;
|
||||||
this->addr = addr;
|
this->addr = addr;
|
||||||
|
|
||||||
uart_set_pin(TMC_UART, TMC_UART_TX, TMC_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
if (!_uart_started) {
|
||||||
tmc_serial.begin(115200, SERIAL_8N1, TMC_UART_RX, TMC_UART_TX);
|
tmc_serial.setPins(TMC_UART_TX, TMC_UART_RX);
|
||||||
tmc_serial.setRxBufferSize(128);
|
tmc_serial.begin(115200, Uart::Data::Bits8, Uart::Stop::Bits1, Uart::Parity::None);
|
||||||
|
_uart_started = true;
|
||||||
|
}
|
||||||
hw_serial_init();
|
hw_serial_init();
|
||||||
|
|
||||||
link = List;
|
link = List;
|
||||||
@@ -231,7 +235,7 @@ namespace Motors {
|
|||||||
tmcstepper->en_spreadCycle(false);
|
tmcstepper->en_spreadCycle(false);
|
||||||
tmcstepper->pwm_autoscale(false);
|
tmcstepper->pwm_autoscale(false);
|
||||||
tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0));
|
tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0));
|
||||||
tmcstepper->SGTHRS(constrain(axis_settings[_axis_index]->stallguard->get(),0,255));
|
tmcstepper->SGTHRS(constrain(axis_settings[_axis_index]->stallguard->get(), 0, 255));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Unknown Trinamic mode:d", _mode);
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Unknown Trinamic mode:d", _mode);
|
||||||
@@ -394,4 +398,4 @@ namespace Motors {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -91,6 +91,7 @@ typedef struct {
|
|||||||
#ifdef USE_LINE_NUMBERS
|
#ifdef USE_LINE_NUMBERS
|
||||||
int32_t line_number; // Desired line number to report when executing.
|
int32_t line_number; // Desired line number to report when executing.
|
||||||
#endif
|
#endif
|
||||||
|
bool is_jog; // true if this was generated due to a jog command
|
||||||
} plan_line_data_t;
|
} plan_line_data_t;
|
||||||
|
|
||||||
// Initialize and reset the motion plan subsystem
|
// Initialize and reset the motion plan subsystem
|
||||||
|
@@ -192,6 +192,7 @@ Error toggle_check_mode(const char* value, WebUI::AuthenticationLevel auth_level
|
|||||||
// is idle and ready, regardless of alarm locks. This is mainly to keep things
|
// is idle and ready, regardless of alarm locks. This is mainly to keep things
|
||||||
// simple and consistent.
|
// simple and consistent.
|
||||||
if (sys.state == State::CheckMode) {
|
if (sys.state == State::CheckMode) {
|
||||||
|
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Check mode");
|
||||||
mc_reset();
|
mc_reset();
|
||||||
report_feedback_message(Message::Disabled);
|
report_feedback_message(Message::Disabled);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -103,7 +103,7 @@ bool can_park() {
|
|||||||
GRBL PRIMARY LOOP:
|
GRBL PRIMARY LOOP:
|
||||||
*/
|
*/
|
||||||
void protocol_main_loop() {
|
void protocol_main_loop() {
|
||||||
serial_reset_read_buffer(CLIENT_ALL);
|
client_reset_read_buffer(CLIENT_ALL);
|
||||||
empty_lines();
|
empty_lines();
|
||||||
//uint8_t client = CLIENT_SERIAL; // default client
|
//uint8_t client = CLIENT_SERIAL; // default client
|
||||||
// Perform some machine checks to make sure everything is good to go.
|
// Perform some machine checks to make sure everything is good to go.
|
||||||
@@ -135,7 +135,7 @@ void protocol_main_loop() {
|
|||||||
// Primary loop! Upon a system abort, this exits back to main() to reset the system.
|
// Primary loop! Upon a system abort, this exits back to main() to reset the system.
|
||||||
// This is also where Grbl idles while waiting for something to do.
|
// This is also where Grbl idles while waiting for something to do.
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
uint8_t c;
|
int c;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
#ifdef ENABLE_SD_CARD
|
#ifdef ENABLE_SD_CARD
|
||||||
if (SD_ready_next) {
|
if (SD_ready_next) {
|
||||||
@@ -157,7 +157,7 @@ void protocol_main_loop() {
|
|||||||
uint8_t client = CLIENT_SERIAL;
|
uint8_t client = CLIENT_SERIAL;
|
||||||
char* line;
|
char* line;
|
||||||
for (client = 0; client < CLIENT_COUNT; client++) {
|
for (client = 0; client < CLIENT_COUNT; client++) {
|
||||||
while ((c = serial_read(client)) != SERIAL_NO_DATA) {
|
while ((c = client_read(client)) != -1) {
|
||||||
Error res = add_char_to_line(c, client);
|
Error res = add_char_to_line(c, client);
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case Error::Ok:
|
case Error::Ok:
|
||||||
@@ -567,6 +567,12 @@ static void protocol_exec_rt_suspend() {
|
|||||||
if (sys.abort) {
|
if (sys.abort) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// if a jogCancel comes in and we have a jog "in-flight" (parsed and handed over to mc_line()),
|
||||||
|
// then we need to cancel it before it reaches the planner. otherwise we may try to move way out of
|
||||||
|
// normal bounds, especially with senders that issue a series of jog commands before sending a cancel.
|
||||||
|
if (sys.suspend.bit.jogCancel && sys_pl_data_inflight != NULL && ((plan_line_data_t*)sys_pl_data_inflight)->is_jog) {
|
||||||
|
sys_pl_data_inflight = NULL;
|
||||||
|
}
|
||||||
// Block until initial hold is complete and the machine has stopped motion.
|
// Block until initial hold is complete and the machine has stopped motion.
|
||||||
if (sys.suspend.bit.holdComplete) {
|
if (sys.suspend.bit.holdComplete) {
|
||||||
// Parking manager. Handles de/re-energizing, switch state checks, and parking motions for
|
// Parking manager. Handles de/re-energizing, switch state checks, and parking motions for
|
||||||
|
@@ -54,30 +54,8 @@ EspClass esp;
|
|||||||
#endif
|
#endif
|
||||||
const int DEFAULTBUFFERSIZE = 64;
|
const int DEFAULTBUFFERSIZE = 64;
|
||||||
|
|
||||||
// this is a generic send function that everything should use, so interfaces could be added (Bluetooth, etc)
|
|
||||||
void grbl_send(uint8_t client, const char* text) {
|
void grbl_send(uint8_t client, const char* text) {
|
||||||
if (client == CLIENT_INPUT) {
|
client_write(client, text);
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef ENABLE_BLUETOOTH
|
|
||||||
if (WebUI::SerialBT.hasClient() && (client == CLIENT_BT || client == CLIENT_ALL)) {
|
|
||||||
WebUI::SerialBT.print(text);
|
|
||||||
//delay(10); // possible fix for dropped characters
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_OUT)
|
|
||||||
if (client == CLIENT_WEBUI || client == CLIENT_ALL) {
|
|
||||||
WebUI::Serial2Socket.write((const uint8_t*)text, strlen(text));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
|
|
||||||
if (client == CLIENT_TELNET || client == CLIENT_ALL) {
|
|
||||||
WebUI::telnet_server.write((const uint8_t*)text, strlen(text));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (client == CLIENT_SERIAL || client == CLIENT_ALL) {
|
|
||||||
Serial.print(text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a formating version of the grbl_send(CLIENT_ALL,...) function that work like printf
|
// This is a formating version of the grbl_send(CLIENT_ALL,...) function that work like printf
|
||||||
@@ -291,13 +269,13 @@ std::map<Message, const char*> MessageText = {
|
|||||||
// NOTE: For interfaces, messages are always placed within brackets. And if silent mode
|
// NOTE: For interfaces, messages are always placed within brackets. And if silent mode
|
||||||
// is installed, the message number codes are less than zero.
|
// is installed, the message number codes are less than zero.
|
||||||
void report_feedback_message(Message message) { // ok to send to all clients
|
void report_feedback_message(Message message) { // ok to send to all clients
|
||||||
#if defined (ENABLE_SD_CARD)
|
#if defined(ENABLE_SD_CARD)
|
||||||
if (message == Message::SdFileQuit) {
|
if (message == Message::SdFileQuit) {
|
||||||
grbl_notifyf("SD print canceled", "Reset during SD file at line: %d", sd_get_current_line_number());
|
grbl_notifyf("SD print canceled", "Reset during SD file at line: %d", sd_get_current_line_number());
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Reset during SD file at line: %d", sd_get_current_line_number());
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Reset during SD file at line: %d", sd_get_current_line_number());
|
||||||
|
|
||||||
} else
|
} else
|
||||||
#endif //ENABLE_SD_CARD
|
#endif //ENABLE_SD_CARD
|
||||||
{
|
{
|
||||||
auto it = MessageText.find(message);
|
auto it = MessageText.find(message);
|
||||||
if (it != MessageText.end()) {
|
if (it != MessageText.end()) {
|
||||||
@@ -592,82 +570,52 @@ void report_echo_line_received(char* line, uint8_t client) {
|
|||||||
grbl_sendf(client, "[echo: %s]\r\n", line);
|
grbl_sendf(client, "[echo: %s]\r\n", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate the position for status reports.
|
||||||
|
// float print_position = returned position
|
||||||
|
// float wco = returns the work coordinate offset
|
||||||
|
// bool wpos = true for work position compensation
|
||||||
|
void report_calc_status_position(float* print_position, float* wco, bool wpos) {
|
||||||
|
int32_t current_position[MAX_N_AXIS]; // Copy current state of the system position variable
|
||||||
|
memcpy(current_position, sys_position, sizeof(sys_position));
|
||||||
|
system_convert_array_steps_to_mpos(print_position, current_position);
|
||||||
|
|
||||||
|
//float wco[MAX_N_AXIS];
|
||||||
|
if (wpos || (sys.report_wco_counter == 0)) {
|
||||||
|
auto n_axis = number_axis->get();
|
||||||
|
for (uint8_t idx = 0; idx < n_axis; idx++) {
|
||||||
|
// Apply work coordinate offsets and tool length offset to current position.
|
||||||
|
wco[idx] = gc_state.coord_system[idx] + gc_state.coord_offset[idx];
|
||||||
|
if (idx == TOOL_LENGTH_OFFSET_AXIS) {
|
||||||
|
wco[idx] += gc_state.tool_length_offset;
|
||||||
|
}
|
||||||
|
if (wpos) {
|
||||||
|
print_position[idx] -= wco[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_kinematics(print_position); // a weak definition does nothing. Users can provide strong version
|
||||||
|
}
|
||||||
|
|
||||||
// Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
|
// Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
|
||||||
// and the actual location of the CNC machine. Users may change the following function to their
|
// and the actual location of the CNC machine. Users may change the following function to their
|
||||||
// specific needs, but the desired real-time data report must be as short as possible. This is
|
// specific needs, but the desired real-time data report must be as short as possible. This is
|
||||||
// requires as it minimizes the computational overhead and allows grbl to keep running smoothly,
|
// requires as it minimizes the computational overhead and allows grbl to keep running smoothly,
|
||||||
// especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
|
// especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
|
||||||
void report_realtime_status(uint8_t client) {
|
void report_realtime_status(uint8_t client) {
|
||||||
uint8_t idx;
|
|
||||||
int32_t current_position[MAX_N_AXIS]; // Copy current state of the system position variable
|
|
||||||
memcpy(current_position, sys_position, sizeof(sys_position));
|
|
||||||
float print_position[MAX_N_AXIS];
|
float print_position[MAX_N_AXIS];
|
||||||
char status[200];
|
char status[200];
|
||||||
char temp[MAX_N_AXIS * 20];
|
char temp[MAX_N_AXIS * 20];
|
||||||
system_convert_array_steps_to_mpos(print_position, current_position);
|
|
||||||
// Report current machine state and sub-states
|
|
||||||
strcpy(status, "<");
|
strcpy(status, "<");
|
||||||
switch (sys.state) {
|
strcat(status, report_state_text());
|
||||||
case State::Idle:
|
|
||||||
strcat(status, "Idle");
|
// Report position
|
||||||
break;
|
|
||||||
case State::Cycle:
|
|
||||||
strcat(status, "Run");
|
|
||||||
break;
|
|
||||||
case State::Hold:
|
|
||||||
if (!(sys.suspend.bit.jogCancel)) {
|
|
||||||
strcat(status, "Hold:");
|
|
||||||
strcat(status, sys.suspend.bit.holdComplete ? "0" : "1"); // Ready to resume
|
|
||||||
break;
|
|
||||||
} // Continues to print jog state during jog cancel.
|
|
||||||
case State::Jog:
|
|
||||||
strcat(status, "Jog");
|
|
||||||
break;
|
|
||||||
case State::Homing:
|
|
||||||
strcat(status, "Home");
|
|
||||||
break;
|
|
||||||
case State::Alarm:
|
|
||||||
strcat(status, "Alarm");
|
|
||||||
break;
|
|
||||||
case State::CheckMode:
|
|
||||||
strcat(status, "Check");
|
|
||||||
break;
|
|
||||||
case State::SafetyDoor:
|
|
||||||
strcat(status, "Door:");
|
|
||||||
if (sys.suspend.bit.initiateRestore) {
|
|
||||||
strcat(status, "3"); // Restoring
|
|
||||||
} else {
|
|
||||||
if (sys.suspend.bit.retractComplete) {
|
|
||||||
strcat(status, sys.suspend.bit.safetyDoorAjar ? "1" : "0"); // Door ajar
|
|
||||||
// Door closed and ready to resume
|
|
||||||
} else {
|
|
||||||
strcat(status, "2"); // Retracting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case State::Sleep:
|
|
||||||
strcat(status, "Sleep");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
float wco[MAX_N_AXIS];
|
|
||||||
if (bit_isfalse(status_mask->get(), RtStatus::Position) || (sys.report_wco_counter == 0)) {
|
|
||||||
auto n_axis = number_axis->get();
|
|
||||||
for (idx = 0; idx < n_axis; idx++) {
|
|
||||||
// Apply work coordinate offsets and tool length offset to current position.
|
|
||||||
wco[idx] = gc_state.coord_system[idx] + gc_state.coord_offset[idx];
|
|
||||||
if (idx == TOOL_LENGTH_OFFSET_AXIS) {
|
|
||||||
wco[idx] += gc_state.tool_length_offset;
|
|
||||||
}
|
|
||||||
if (bit_isfalse(status_mask->get(), RtStatus::Position)) {
|
|
||||||
print_position[idx] -= wco[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
forward_kinematics(print_position); // a weak definition does nothing. Users can provide strong version
|
|
||||||
// Report machine position
|
|
||||||
if (bit_istrue(status_mask->get(), RtStatus::Position)) {
|
if (bit_istrue(status_mask->get(), RtStatus::Position)) {
|
||||||
|
calc_mpos(print_position);
|
||||||
strcat(status, "|MPos:");
|
strcat(status, "|MPos:");
|
||||||
} else {
|
} else {
|
||||||
|
calc_wpos(print_position);
|
||||||
strcat(status, "|WPos:");
|
strcat(status, "|WPos:");
|
||||||
}
|
}
|
||||||
report_util_axis_values(print_position, temp);
|
report_util_axis_values(print_position, temp);
|
||||||
@@ -688,7 +636,7 @@ void report_realtime_status(uint8_t client) {
|
|||||||
}
|
}
|
||||||
# endif //ENABLE_BLUETOOTH
|
# endif //ENABLE_BLUETOOTH
|
||||||
if (client == CLIENT_SERIAL) {
|
if (client == CLIENT_SERIAL) {
|
||||||
bufsize = serial_get_rx_buffer_available(CLIENT_SERIAL);
|
bufsize = client_get_rx_buffer_available(CLIENT_SERIAL);
|
||||||
}
|
}
|
||||||
sprintf(temp, "|Bf:%d,%d", plan_get_block_buffer_available(), bufsize);
|
sprintf(temp, "|Bf:%d,%d", plan_get_block_buffer_available(), bufsize);
|
||||||
strcat(status, temp);
|
strcat(status, temp);
|
||||||
@@ -793,7 +741,7 @@ void report_realtime_status(uint8_t client) {
|
|||||||
sys.report_ovr_counter = 1; // Set override on next report.
|
sys.report_ovr_counter = 1; // Set override on next report.
|
||||||
}
|
}
|
||||||
strcat(status, "|WCO:");
|
strcat(status, "|WCO:");
|
||||||
report_util_axis_values(wco, temp);
|
report_util_axis_values(get_wco(), temp);
|
||||||
strcat(status, temp);
|
strcat(status, temp);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -913,6 +861,54 @@ void report_hex_msg(uint8_t* buf, const char* prefix, int len) {
|
|||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "%s", report);
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "%s", report);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* report_state_text() {
|
||||||
|
static char state[10];
|
||||||
|
|
||||||
|
switch (sys.state) {
|
||||||
|
case State::Idle:
|
||||||
|
strcpy(state, "Idle");
|
||||||
|
break;
|
||||||
|
case State::Cycle:
|
||||||
|
strcpy(state, "Run");
|
||||||
|
break;
|
||||||
|
case State::Hold:
|
||||||
|
if (!(sys.suspend.bit.jogCancel)) {
|
||||||
|
sys.suspend.bit.holdComplete ? strcpy(state, "Hold:0") : strcpy(state, "Hold:1");
|
||||||
|
break;
|
||||||
|
} // Continues to print jog state during jog cancel.
|
||||||
|
case State::Jog:
|
||||||
|
strcpy(state, "Jog");
|
||||||
|
break;
|
||||||
|
case State::Homing:
|
||||||
|
strcpy(state, "Home");
|
||||||
|
break;
|
||||||
|
case State::Alarm:
|
||||||
|
strcpy(state, "Alarm");
|
||||||
|
break;
|
||||||
|
case State::CheckMode:
|
||||||
|
strcpy(state, "Check");
|
||||||
|
break;
|
||||||
|
case State::SafetyDoor:
|
||||||
|
strcpy(state, "Door:");
|
||||||
|
if (sys.suspend.bit.initiateRestore) {
|
||||||
|
strcat(state, "3"); // Restoring
|
||||||
|
} else {
|
||||||
|
if (sys.suspend.bit.retractComplete) {
|
||||||
|
sys.suspend.bit.safetyDoorAjar ? strcat(state, "1") : strcat(state, "0");
|
||||||
|
; // Door ajar
|
||||||
|
// Door closed and ready to resume
|
||||||
|
} else {
|
||||||
|
strcat(state, "2"); // Retracting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case State::Sleep:
|
||||||
|
strcpy(state, "Sleep");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
char report_get_axis_letter(uint8_t axis) {
|
char report_get_axis_letter(uint8_t axis) {
|
||||||
switch (axis) {
|
switch (axis) {
|
||||||
case X_AXIS:
|
case X_AXIS:
|
||||||
@@ -960,4 +956,37 @@ void reportTaskStackSize(UBaseType_t& saved) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void calc_mpos(float* print_position) {
|
||||||
|
int32_t current_position[MAX_N_AXIS]; // Copy current state of the system position variable
|
||||||
|
memcpy(current_position, sys_position, sizeof(sys_position));
|
||||||
|
system_convert_array_steps_to_mpos(print_position, current_position);
|
||||||
|
forward_kinematics(print_position); // a weak definition does nothing. Users can provide strong version
|
||||||
|
}
|
||||||
|
|
||||||
|
void calc_wpos(float* print_position) {
|
||||||
|
int32_t current_position[MAX_N_AXIS]; // Copy current state of the system position variable
|
||||||
|
memcpy(current_position, sys_position, sizeof(sys_position));
|
||||||
|
system_convert_array_steps_to_mpos(print_position, current_position);
|
||||||
|
|
||||||
|
float* wco = get_wco();
|
||||||
|
auto n_axis = number_axis->get();
|
||||||
|
for (int idx = 0; idx < n_axis; idx++) {
|
||||||
|
print_position[idx] -= wco[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_kinematics(print_position); // a weak definition does nothing. Users can provide strong version
|
||||||
|
}
|
||||||
|
float* get_wco() {
|
||||||
|
static float wco[MAX_N_AXIS];
|
||||||
|
auto n_axis = number_axis->get();
|
||||||
|
for (int idx = 0; idx < n_axis; idx++) {
|
||||||
|
// Apply work coordinate offsets and tool length offset to current position.
|
||||||
|
wco[idx] = gc_state.coord_system[idx] + gc_state.coord_offset[idx];
|
||||||
|
if (idx == TOOL_LENGTH_OFFSET_AXIS) {
|
||||||
|
wco[idx] += gc_state.tool_length_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wco;
|
||||||
|
}
|
||||||
|
|
||||||
void __attribute__((weak)) forward_kinematics(float* position) {} // This version does nothing. Make your own to do something with it
|
void __attribute__((weak)) forward_kinematics(float* position) {} // This version does nothing. Make your own to do something with it
|
||||||
|
@@ -92,6 +92,9 @@ void report_grbl_settings(uint8_t client, uint8_t show_extended);
|
|||||||
// Prints an echo of the pre-parsed line received right before execution.
|
// Prints an echo of the pre-parsed line received right before execution.
|
||||||
void report_echo_line_received(char* line, uint8_t client);
|
void report_echo_line_received(char* line, uint8_t client);
|
||||||
|
|
||||||
|
// calculate the postion for status reports
|
||||||
|
void report_calc_status_position(float* print_position, float* wco, bool wpos);
|
||||||
|
|
||||||
// Prints realtime status report
|
// Prints realtime status report
|
||||||
void report_realtime_status(uint8_t client);
|
void report_realtime_status(uint8_t client);
|
||||||
|
|
||||||
@@ -122,10 +125,14 @@ void report_machine_type(uint8_t client);
|
|||||||
void report_hex_msg(char* buf, const char* prefix, int len);
|
void report_hex_msg(char* buf, const char* prefix, int len);
|
||||||
void report_hex_msg(uint8_t* buf, const char* prefix, int len);
|
void report_hex_msg(uint8_t* buf, const char* prefix, int len);
|
||||||
|
|
||||||
char report_get_axis_letter(uint8_t axis);
|
char report_get_axis_letter(uint8_t axis);
|
||||||
|
|
||||||
char* reportAxisLimitsMsg(uint8_t axis);
|
char* reportAxisLimitsMsg(uint8_t axis);
|
||||||
char* reportAxisNameMsg(uint8_t axis);
|
char* reportAxisNameMsg(uint8_t axis);
|
||||||
char* reportAxisNameMsg(uint8_t axis, uint8_t dual_axis);
|
char* reportAxisNameMsg(uint8_t axis, uint8_t dual_axis);
|
||||||
|
|
||||||
void reportTaskStackSize(UBaseType_t& saved);
|
void reportTaskStackSize(UBaseType_t& saved);
|
||||||
|
|
||||||
|
char* report_state_text();
|
||||||
|
float* get_wco();
|
||||||
|
void calc_mpos(float* print_position);
|
||||||
|
void calc_wpos(float* print_position);
|
||||||
|
@@ -57,15 +57,26 @@
|
|||||||
|
|
||||||
#include "Grbl.h"
|
#include "Grbl.h"
|
||||||
|
|
||||||
|
// Define this to use the Arduino serial (UART) driver instead
|
||||||
|
// of the one in Uart.cpp, which uses the ESP-IDF UART driver.
|
||||||
|
// This is for regression testing, and can be removed after
|
||||||
|
// testing is complete.
|
||||||
|
// #define REVERT_TO_ARDUINO_SERIAL
|
||||||
|
|
||||||
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
static TaskHandle_t serialCheckTaskHandle = 0;
|
static TaskHandle_t clientCheckTaskHandle = 0;
|
||||||
|
|
||||||
WebUI::InputBuffer client_buffer[CLIENT_COUNT]; // create a buffer for each client
|
WebUI::InputBuffer client_buffer[CLIENT_COUNT]; // create a buffer for each client
|
||||||
|
|
||||||
// Returns the number of bytes available in a client buffer.
|
// Returns the number of bytes available in a client buffer.
|
||||||
uint8_t serial_get_rx_buffer_available(uint8_t client) {
|
uint8_t client_get_rx_buffer_available(uint8_t client) {
|
||||||
return client_buffer[client].availableforwrite();
|
#ifdef REVERT_TO_ARDUINO_SERIAL
|
||||||
|
return 128 - Serial.available();
|
||||||
|
#else
|
||||||
|
return 128 - Uart0.available();
|
||||||
|
#endif
|
||||||
|
// return client_buffer[client].availableforwrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
void heapCheckTask(void* pvParameters) {
|
void heapCheckTask(void* pvParameters) {
|
||||||
@@ -85,75 +96,84 @@ void heapCheckTask(void* pvParameters) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_init() {
|
void client_init() {
|
||||||
#ifdef DEBUG_REPORT_HEAP_SIZE
|
#ifdef DEBUG_REPORT_HEAP_SIZE
|
||||||
// For a 2000-word stack, uxTaskGetStackHighWaterMark reports 288 words available
|
// For a 2000-word stack, uxTaskGetStackHighWaterMark reports 288 words available
|
||||||
xTaskCreatePinnedToCore(heapCheckTask, "heapTask", 2000, NULL, 1, NULL, 1);
|
xTaskCreatePinnedToCore(heapCheckTask, "heapTask", 2000, NULL, 1, NULL, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Serial.begin(BAUD_RATE);
|
#ifdef REVERT_TO_ARDUINO_SERIAL
|
||||||
Serial.setRxBufferSize(256);
|
Serial.begin(BAUD_RATE, SERIAL_8N1, 3, 1, false);
|
||||||
// reset all buffers
|
client_reset_read_buffer(CLIENT_ALL);
|
||||||
serial_reset_read_buffer(CLIENT_ALL);
|
Serial.write("\r\n"); // create some white space after ESP32 boot info
|
||||||
grbl_send(CLIENT_SERIAL, "\r\n"); // create some white space after ESP32 boot info
|
#else
|
||||||
serialCheckTaskHandle = 0;
|
Uart0.setPins(1, 3); // Tx 1, Rx 3 - standard hardware pins
|
||||||
|
Uart0.begin(BAUD_RATE, Uart::Data::Bits8, Uart::Stop::Bits1, Uart::Parity::None);
|
||||||
|
|
||||||
|
client_reset_read_buffer(CLIENT_ALL);
|
||||||
|
Uart0.write("\r\n"); // create some white space after ESP32 boot info
|
||||||
|
#endif
|
||||||
|
clientCheckTaskHandle = 0;
|
||||||
// create a task to check for incoming data
|
// create a task to check for incoming data
|
||||||
// For a 4096-word stack, uxTaskGetStackHighWaterMark reports 244 words available
|
// For a 4096-word stack, uxTaskGetStackHighWaterMark reports 244 words available
|
||||||
// after WebUI attaches.
|
// after WebUI attaches.
|
||||||
xTaskCreatePinnedToCore(serialCheckTask, // task
|
xTaskCreatePinnedToCore(clientCheckTask, // task
|
||||||
"serialCheckTask", // name for task
|
"clientCheckTask", // name for task
|
||||||
4096, // size of task stack
|
4096, // size of task stack
|
||||||
NULL, // parameters
|
NULL, // parameters
|
||||||
1, // priority
|
1, // priority
|
||||||
&serialCheckTaskHandle,
|
&clientCheckTaskHandle,
|
||||||
SUPPORT_TASK_CORE // must run the task on same core
|
SUPPORT_TASK_CORE // must run the task on same core
|
||||||
// core
|
// core
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this task runs and checks for data on all interfaces
|
static uint8_t getClientChar(uint8_t* data) {
|
||||||
// REaltime stuff is acted upon, then characters are added to the appropriate buffer
|
int res;
|
||||||
void serialCheckTask(void* pvParameters) {
|
#ifdef REVERT_TO_ARDUINO_SERIAL
|
||||||
uint8_t data = 0;
|
if (client_buffer[CLIENT_SERIAL].availableforwrite() && (res = Serial.read()) != -1) {
|
||||||
uint8_t client = CLIENT_ALL; // who sent the data
|
#else
|
||||||
static UBaseType_t uxHighWaterMark = 0;
|
if (client_buffer[CLIENT_SERIAL].availableforwrite() && (res = Uart0.read()) != -1) {
|
||||||
while (true) { // run continuously
|
#endif
|
||||||
while (any_client_has_data()) {
|
*data = res;
|
||||||
if (Serial.available()) {
|
return CLIENT_SERIAL;
|
||||||
client = CLIENT_SERIAL;
|
}
|
||||||
data = Serial.read();
|
if (WebUI::inputBuffer.available()) {
|
||||||
} else if (WebUI::inputBuffer.available()) {
|
*data = WebUI::inputBuffer.read();
|
||||||
client = CLIENT_INPUT;
|
return CLIENT_INPUT;
|
||||||
data = WebUI::inputBuffer.read();
|
}
|
||||||
} else {
|
//currently is wifi or BT but better to prepare both can be live
|
||||||
//currently is wifi or BT but better to prepare both can be live
|
|
||||||
#ifdef ENABLE_BLUETOOTH
|
#ifdef ENABLE_BLUETOOTH
|
||||||
if (WebUI::SerialBT.hasClient() && WebUI::SerialBT.available()) {
|
if (WebUI::SerialBT.hasClient()) {
|
||||||
client = CLIENT_BT;
|
if ((res = WebUI::SerialBT.read()) != -1) {
|
||||||
data = WebUI::SerialBT.read();
|
*data = res;
|
||||||
|
return CLIENT_BT;
|
||||||
// Serial.write(data); // echo all data to serial.
|
}
|
||||||
} else {
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
||||||
if (WebUI::Serial2Socket.available()) {
|
if (WebUI::Serial2Socket.available()) {
|
||||||
client = CLIENT_WEBUI;
|
*data = WebUI::Serial2Socket.read();
|
||||||
data = WebUI::Serial2Socket.read();
|
return CLIENT_WEBUI;
|
||||||
} else {
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
|
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
|
||||||
if (WebUI::telnet_server.available()) {
|
if (WebUI::telnet_server.available()) {
|
||||||
client = CLIENT_TELNET;
|
*data = WebUI::telnet_server.read();
|
||||||
data = WebUI::telnet_server.read();
|
return CLIENT_TELNET;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
return CLIENT_ALL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_BLUETOOTH
|
// this task runs and checks for data on all interfaces
|
||||||
}
|
// REaltime stuff is acted upon, then characters are added to the appropriate buffer
|
||||||
#endif
|
void clientCheckTask(void* pvParameters) {
|
||||||
}
|
uint8_t data = 0;
|
||||||
|
uint8_t client; // who sent the data
|
||||||
|
static UBaseType_t uxHighWaterMark = 0;
|
||||||
|
while (true) { // run continuously
|
||||||
|
while ((client = getClientChar(&data)) != CLIENT_ALL) {
|
||||||
// Pick off realtime command characters directly from the serial stream. These characters are
|
// Pick off realtime command characters directly from the serial stream. These characters are
|
||||||
// not passed into the main buffer, but these set system state flag bits for realtime execution.
|
// not passed into the main buffer, but these set system state flag bits for realtime execution.
|
||||||
if (is_realtime_command(data)) {
|
if (is_realtime_command(data)) {
|
||||||
@@ -161,7 +181,7 @@ void serialCheckTask(void* pvParameters) {
|
|||||||
} else {
|
} else {
|
||||||
#if defined(ENABLE_SD_CARD)
|
#if defined(ENABLE_SD_CARD)
|
||||||
if (get_sd_state(false) < SDState::Busy) {
|
if (get_sd_state(false) < SDState::Busy) {
|
||||||
#endif //ENABLE_SD_CARD
|
#endif //ENABLE_SD_CARD
|
||||||
vTaskEnterCritical(&myMutex);
|
vTaskEnterCritical(&myMutex);
|
||||||
client_buffer[client].write(data);
|
client_buffer[client].write(data);
|
||||||
vTaskExitCritical(&myMutex);
|
vTaskExitCritical(&myMutex);
|
||||||
@@ -172,7 +192,7 @@ void serialCheckTask(void* pvParameters) {
|
|||||||
grbl_msg_sendf(client, MsgLevel::Info, "SD card job running");
|
grbl_msg_sendf(client, MsgLevel::Info, "SD card job running");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //ENABLE_SD_CARD
|
#endif //ENABLE_SD_CARD
|
||||||
}
|
}
|
||||||
} // if something available
|
} // if something available
|
||||||
WebUI::COMMANDS::handle();
|
WebUI::COMMANDS::handle();
|
||||||
@@ -194,7 +214,7 @@ void serialCheckTask(void* pvParameters) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_reset_read_buffer(uint8_t client) {
|
void client_reset_read_buffer(uint8_t client) {
|
||||||
for (uint8_t client_num = 0; client_num < CLIENT_COUNT; client_num++) {
|
for (uint8_t client_num = 0; client_num < CLIENT_COUNT; client_num++) {
|
||||||
if (client == client_num || client == CLIENT_ALL) {
|
if (client == client_num || client == CLIENT_ALL) {
|
||||||
client_buffer[client_num].begin();
|
client_buffer[client_num].begin();
|
||||||
@@ -202,38 +222,12 @@ void serial_reset_read_buffer(uint8_t client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes one byte to the TX serial buffer. Called by main program.
|
// Fetches the first byte in the client read buffer. Called by protocol loop.
|
||||||
void serial_write(uint8_t data) {
|
int client_read(uint8_t client) {
|
||||||
Serial.write((char)data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetches the first byte in the serial read buffer. Called by protocol loop.
|
|
||||||
uint8_t serial_read(uint8_t client) {
|
|
||||||
uint8_t data;
|
|
||||||
vTaskEnterCritical(&myMutex);
|
vTaskEnterCritical(&myMutex);
|
||||||
if (client_buffer[client].available()) {
|
int data = client_buffer[client].read();
|
||||||
data = client_buffer[client].read();
|
vTaskExitCritical(&myMutex);
|
||||||
vTaskExitCritical(&myMutex);
|
return data;
|
||||||
//Serial.write((char)data);
|
|
||||||
return data;
|
|
||||||
} else {
|
|
||||||
vTaskExitCritical(&myMutex);
|
|
||||||
return SERIAL_NO_DATA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool any_client_has_data() {
|
|
||||||
return (Serial.available() || WebUI::inputBuffer.available()
|
|
||||||
#ifdef ENABLE_BLUETOOTH
|
|
||||||
|| (WebUI::SerialBT.hasClient() && WebUI::SerialBT.available())
|
|
||||||
#endif
|
|
||||||
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
|
||||||
|| WebUI::Serial2Socket.available()
|
|
||||||
#endif
|
|
||||||
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
|
|
||||||
|| WebUI::telnet_server.available()
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks to see if a character is a realtime character
|
// checks to see if a character is a realtime character
|
||||||
@@ -249,6 +243,7 @@ bool is_realtime_command(uint8_t data) {
|
|||||||
void execute_realtime_command(Cmd command, uint8_t client) {
|
void execute_realtime_command(Cmd command, uint8_t client) {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case Cmd::Reset:
|
case Cmd::Reset:
|
||||||
|
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Cmd::Reset");
|
||||||
mc_reset(); // Call motion control reset routine.
|
mc_reset(); // Call motion control reset routine.
|
||||||
break;
|
break;
|
||||||
case Cmd::StatusReport:
|
case Cmd::StatusReport:
|
||||||
@@ -350,3 +345,32 @@ void execute_realtime_command(Cmd command, uint8_t client) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void client_write(uint8_t client, const char* text) {
|
||||||
|
if (client == CLIENT_INPUT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_BLUETOOTH
|
||||||
|
if (WebUI::SerialBT.hasClient() && (client == CLIENT_BT || client == CLIENT_ALL)) {
|
||||||
|
WebUI::SerialBT.print(text);
|
||||||
|
//delay(10); // possible fix for dropped characters
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_OUT)
|
||||||
|
if (client == CLIENT_WEBUI || client == CLIENT_ALL) {
|
||||||
|
WebUI::Serial2Socket.write((const uint8_t*)text, strlen(text));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
|
||||||
|
if (client == CLIENT_TELNET || client == CLIENT_ALL) {
|
||||||
|
WebUI::telnet_server.write((const uint8_t*)text, strlen(text));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (client == CLIENT_SERIAL || client == CLIENT_ALL) {
|
||||||
|
#ifdef REVERT_TO_ARDUINO_SERIAL
|
||||||
|
Serial.write(text);
|
||||||
|
#else
|
||||||
|
Uart0.write(text);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Grbl.h"
|
#include "stdint.h"
|
||||||
|
|
||||||
#ifndef RX_BUFFER_SIZE
|
#ifndef RX_BUFFER_SIZE
|
||||||
# define RX_BUFFER_SIZE 256
|
# define RX_BUFFER_SIZE 256
|
||||||
@@ -33,24 +33,22 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const float SERIAL_NO_DATA = 0xff;
|
|
||||||
|
|
||||||
// a task to read for incoming data from serial port
|
// a task to read for incoming data from serial port
|
||||||
void serialCheckTask(void* pvParameters);
|
void clientCheckTask(void* pvParameters);
|
||||||
|
|
||||||
|
void client_write(uint8_t client, const char* text);
|
||||||
|
|
||||||
void serial_write(uint8_t data);
|
|
||||||
// Fetches the first byte in the serial read buffer. Called by main program.
|
// Fetches the first byte in the serial read buffer. Called by main program.
|
||||||
uint8_t serial_read(uint8_t client);
|
int client_read(uint8_t client);
|
||||||
|
|
||||||
// See if the character is an action command like feedhold or jogging. If so, do the action and return true
|
// See if the character is an action command like feedhold or jogging. If so, do the action and return true
|
||||||
uint8_t check_action_command(uint8_t data);
|
uint8_t check_action_command(uint8_t data);
|
||||||
|
|
||||||
void serial_init();
|
void client_init();
|
||||||
void serial_reset_read_buffer(uint8_t client);
|
void client_reset_read_buffer(uint8_t client);
|
||||||
|
|
||||||
// Returns the number of bytes available in the RX serial buffer.
|
// Returns the number of bytes available in the RX serial buffer.
|
||||||
uint8_t serial_get_rx_buffer_available(uint8_t client);
|
uint8_t client_get_rx_buffer_available(uint8_t client);
|
||||||
|
|
||||||
void execute_realtime_command(Cmd command, uint8_t client);
|
void execute_realtime_command(Cmd command, uint8_t client);
|
||||||
bool any_client_has_data();
|
|
||||||
bool is_realtime_command(uint8_t data);
|
bool is_realtime_command(uint8_t data);
|
||||||
|
@@ -301,7 +301,7 @@ void make_settings() {
|
|||||||
}
|
}
|
||||||
for (axis = MAX_N_AXIS - 1; axis >= 0; axis--) {
|
for (axis = MAX_N_AXIS - 1; axis >= 0; axis--) {
|
||||||
def = &axis_defaults[axis];
|
def = &axis_defaults[axis];
|
||||||
auto setting = new FloatSetting(GRBL, WG, makeGrblName(axis, 130), makename(def->name, "MaxTravel"), def->max_travel, 1.0, 100000.0);
|
auto setting = new FloatSetting(GRBL, WG, makeGrblName(axis, 130), makename(def->name, "MaxTravel"), def->max_travel, 0, 100000.0);
|
||||||
setting->setAxis(axis);
|
setting->setAxis(axis);
|
||||||
axis_settings[axis]->max_travel = setting;
|
axis_settings[axis]->max_travel = setting;
|
||||||
}
|
}
|
||||||
|
@@ -28,17 +28,10 @@
|
|||||||
managed to piece together.
|
managed to piece together.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <driver/uart.h>
|
|
||||||
|
|
||||||
namespace Spindles {
|
namespace Spindles {
|
||||||
void H2A::default_modbus_settings(uart_config_t& uart) {
|
H2A::H2A() : VFD() {
|
||||||
// sets the uart to 19200 8E1
|
_baudrate = 19200;
|
||||||
VFD::default_modbus_settings(uart);
|
_parity = Uart::Parity::Even;
|
||||||
|
|
||||||
uart.baud_rate = 19200;
|
|
||||||
uart.data_bits = UART_DATA_8_BITS;
|
|
||||||
uart.parity = UART_PARITY_EVEN;
|
|
||||||
uart.stop_bits = UART_STOP_BITS_1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void H2A::direction_command(SpindleState mode, ModbusCommand& data) {
|
void H2A::direction_command(SpindleState mode, ModbusCommand& data) {
|
||||||
|
@@ -24,8 +24,6 @@
|
|||||||
namespace Spindles {
|
namespace Spindles {
|
||||||
class H2A : public VFD {
|
class H2A : public VFD {
|
||||||
protected:
|
protected:
|
||||||
void default_modbus_settings(uart_config_t& uart) override;
|
|
||||||
|
|
||||||
void direction_command(SpindleState mode, ModbusCommand& data) override;
|
void direction_command(SpindleState mode, ModbusCommand& data) override;
|
||||||
void set_speed_command(uint32_t rpm, ModbusCommand& data) override;
|
void set_speed_command(uint32_t rpm, ModbusCommand& data) override;
|
||||||
|
|
||||||
@@ -36,5 +34,8 @@ namespace Spindles {
|
|||||||
|
|
||||||
bool supports_actual_rpm() const override { return true; }
|
bool supports_actual_rpm() const override { return true; }
|
||||||
bool safety_polling() const override { return false; }
|
bool safety_polling() const override { return false; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
H2A();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -149,15 +149,10 @@
|
|||||||
If the frequency is -say- 25 Hz, Huanyang wants us to send 2500 (eg. 25.00 Hz).
|
If the frequency is -say- 25 Hz, Huanyang wants us to send 2500 (eg. 25.00 Hz).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <driver/uart.h>
|
|
||||||
|
|
||||||
namespace Spindles {
|
namespace Spindles {
|
||||||
void Huanyang::default_modbus_settings(uart_config_t& uart) {
|
Huanyang::Huanyang() : VFD() {
|
||||||
// sets the uart to 9600 8N1
|
// Baud rate is set in the PD164 setting. If it is not 9600, add, for example,
|
||||||
VFD::default_modbus_settings(uart);
|
// _baudrate = 19200;
|
||||||
|
|
||||||
// uart.baud_rate = 9600;
|
|
||||||
// Baud rate is set in the PD164 setting.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Huanyang::direction_command(SpindleState mode, ModbusCommand& data) {
|
void Huanyang::direction_command(SpindleState mode, ModbusCommand& data) {
|
||||||
|
@@ -35,8 +35,6 @@ namespace Spindles {
|
|||||||
|
|
||||||
void updateRPM();
|
void updateRPM();
|
||||||
|
|
||||||
void default_modbus_settings(uart_config_t& uart) override;
|
|
||||||
|
|
||||||
void direction_command(SpindleState mode, ModbusCommand& data) override;
|
void direction_command(SpindleState mode, ModbusCommand& data) override;
|
||||||
void set_speed_command(uint32_t rpm, ModbusCommand& data) override;
|
void set_speed_command(uint32_t rpm, ModbusCommand& data) override;
|
||||||
|
|
||||||
@@ -45,5 +43,8 @@ namespace Spindles {
|
|||||||
response_parser get_current_rpm(ModbusCommand& data) override;
|
response_parser get_current_rpm(ModbusCommand& data) override;
|
||||||
|
|
||||||
bool supports_actual_rpm() const override { return true; }
|
bool supports_actual_rpm() const override { return true; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Huanyang();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,7 @@
|
|||||||
#include "H2ASpindle.h"
|
#include "H2ASpindle.h"
|
||||||
#include "BESCSpindle.h"
|
#include "BESCSpindle.h"
|
||||||
#include "10vSpindle.h"
|
#include "10vSpindle.h"
|
||||||
|
#include "YL620Spindle.h"
|
||||||
|
|
||||||
namespace Spindles {
|
namespace Spindles {
|
||||||
// An instance of each type of spindle is created here.
|
// An instance of each type of spindle is created here.
|
||||||
@@ -51,6 +52,7 @@ namespace Spindles {
|
|||||||
H2A h2a;
|
H2A h2a;
|
||||||
BESC besc;
|
BESC besc;
|
||||||
_10v _10v;
|
_10v _10v;
|
||||||
|
YL620 yl620;
|
||||||
|
|
||||||
void Spindle::select() {
|
void Spindle::select() {
|
||||||
switch (static_cast<SpindleType>(spindle_type->get())) {
|
switch (static_cast<SpindleType>(spindle_type->get())) {
|
||||||
@@ -78,6 +80,9 @@ namespace Spindles {
|
|||||||
case SpindleType::H2A:
|
case SpindleType::H2A:
|
||||||
spindle = &h2a;
|
spindle = &h2a;
|
||||||
break;
|
break;
|
||||||
|
case SpindleType::YL620:
|
||||||
|
spindle = &yl620;
|
||||||
|
break;
|
||||||
case SpindleType::NONE:
|
case SpindleType::NONE:
|
||||||
default:
|
default:
|
||||||
spindle = &null;
|
spindle = &null;
|
||||||
|
@@ -38,6 +38,7 @@ enum class SpindleType : int8_t {
|
|||||||
BESC,
|
BESC,
|
||||||
_10V,
|
_10V,
|
||||||
H2A,
|
H2A,
|
||||||
|
YL620,
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "../Grbl.h"
|
#include "../Grbl.h"
|
||||||
|
@@ -42,11 +42,12 @@
|
|||||||
// be plenty: assuming 9600 8N1, that's roughly 250 chars. A message of 2x16 chars with 4x4
|
// be plenty: assuming 9600 8N1, that's roughly 250 chars. A message of 2x16 chars with 4x4
|
||||||
// chars buffering is just 40 chars.
|
// chars buffering is just 40 chars.
|
||||||
|
|
||||||
const uart_port_t VFD_RS485_UART_PORT = UART_NUM_2; // hard coded for this port right now
|
const int VFD_RS485_UART_PORT = 2; // hard coded for this port right now
|
||||||
const int VFD_RS485_BUF_SIZE = 127;
|
const int VFD_RS485_BUF_SIZE = 127;
|
||||||
const int VFD_RS485_QUEUE_SIZE = 10; // numv\ber of commands that can be queued up.
|
const int VFD_RS485_QUEUE_SIZE = 10; // numv\ber of commands that can be queued up.
|
||||||
const int RESPONSE_WAIT_MILLIS = 1000; // how long to wait for a response in milliseconds
|
const int RESPONSE_WAIT_MILLIS = 1000; // how long to wait for a response in milliseconds
|
||||||
const int VFD_RS485_POLL_RATE = 250; // in milliseconds between commands
|
const int VFD_RS485_POLL_RATE = 250; // in milliseconds between commands
|
||||||
|
const TickType_t response_ticks = RESPONSE_WAIT_MILLIS / portTICK_PERIOD_MS; // in milliseconds between commands
|
||||||
|
|
||||||
// OK to change these
|
// OK to change these
|
||||||
// #define them in your machine definition file if you want different values
|
// #define them in your machine definition file if you want different values
|
||||||
@@ -55,9 +56,48 @@ const int VFD_RS485_POLL_RATE = 250; // in milliseconds between comma
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Spindles {
|
namespace Spindles {
|
||||||
|
Uart _uart(VFD_RS485_UART_PORT);
|
||||||
QueueHandle_t VFD::vfd_cmd_queue = nullptr;
|
QueueHandle_t VFD::vfd_cmd_queue = nullptr;
|
||||||
TaskHandle_t VFD::vfd_cmdTaskHandle = nullptr;
|
TaskHandle_t VFD::vfd_cmdTaskHandle = nullptr;
|
||||||
|
|
||||||
|
VFD::VFD() :
|
||||||
|
_txd_pin(
|
||||||
|
#ifdef VFD_RS485_TXD_PIN
|
||||||
|
VFD_RS485_TXD_PIN
|
||||||
|
#else
|
||||||
|
-1
|
||||||
|
#endif
|
||||||
|
),
|
||||||
|
_rxd_pin(
|
||||||
|
#ifdef VFD_RS485_RXD_PIN
|
||||||
|
VFD_RS485_RXD_PIN
|
||||||
|
#else
|
||||||
|
-1
|
||||||
|
#endif
|
||||||
|
),
|
||||||
|
_rts_pin(
|
||||||
|
#ifdef VFD_RS485_RTS_PIN
|
||||||
|
VFD_RS485_RTS_PIN
|
||||||
|
#else
|
||||||
|
-1
|
||||||
|
#endif
|
||||||
|
),
|
||||||
|
_baudrate(
|
||||||
|
#ifdef VFD_RS485_BAUD_RATE
|
||||||
|
VFD_RS485_BAUD_RATE
|
||||||
|
#else
|
||||||
|
9600
|
||||||
|
#endif
|
||||||
|
),
|
||||||
|
_dataBits(Uart::Data::Bits8), _stopBits(Uart::Stop::Bits1), _parity(
|
||||||
|
#ifdef VFD_RS485_PARITY
|
||||||
|
VFD_RS485_PARITY
|
||||||
|
#else
|
||||||
|
Uart::Parity::None
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
// The communications task
|
// The communications task
|
||||||
void VFD::vfd_cmd_task(void* pvParameters) {
|
void VFD::vfd_cmd_task(void* pvParameters) {
|
||||||
static bool unresponsive = false; // to pop off a message once each time it becomes unresponsive
|
static bool unresponsive = false; // to pop off a message once each time it becomes unresponsive
|
||||||
@@ -145,16 +185,15 @@ namespace Spindles {
|
|||||||
int retry_count = 0;
|
int retry_count = 0;
|
||||||
for (; retry_count < MAX_RETRIES; ++retry_count) {
|
for (; retry_count < MAX_RETRIES; ++retry_count) {
|
||||||
// Flush the UART:
|
// Flush the UART:
|
||||||
uart_flush(VFD_RS485_UART_PORT);
|
_uart.flush();
|
||||||
|
|
||||||
// Write the data:
|
// Write the data:
|
||||||
uart_write_bytes(VFD_RS485_UART_PORT, reinterpret_cast<const char*>(next_cmd.msg), next_cmd.tx_length);
|
_uart.write(reinterpret_cast<const char*>(next_cmd.msg), next_cmd.tx_length);
|
||||||
uart_wait_tx_done(VFD_RS485_UART_PORT, RESPONSE_WAIT_MILLIS / portTICK_PERIOD_MS);
|
_uart.flushTxTimed(response_ticks);
|
||||||
|
|
||||||
// Read the response
|
// Read the response
|
||||||
uint16_t read_length = 0;
|
uint16_t read_length = 0;
|
||||||
uint16_t current_read =
|
uint16_t current_read = _uart.readBytes(rx_message, next_cmd.rx_length, response_ticks);
|
||||||
uart_read_bytes(VFD_RS485_UART_PORT, rx_message, next_cmd.rx_length, RESPONSE_WAIT_MILLIS / portTICK_PERIOD_MS);
|
|
||||||
read_length += current_read;
|
read_length += current_read;
|
||||||
|
|
||||||
// Apparently some Huanyang report modbus errors in the correct way, and the rest not. Sigh.
|
// Apparently some Huanyang report modbus errors in the correct way, and the rest not. Sigh.
|
||||||
@@ -165,10 +204,7 @@ namespace Spindles {
|
|||||||
|
|
||||||
while (read_length < next_cmd.rx_length && current_read > 0) {
|
while (read_length < next_cmd.rx_length && current_read > 0) {
|
||||||
// Try to read more; we're not there yet...
|
// Try to read more; we're not there yet...
|
||||||
current_read = uart_read_bytes(VFD_RS485_UART_PORT,
|
current_read = _uart.readBytes(rx_message + read_length, next_cmd.rx_length - read_length, response_ticks);
|
||||||
rx_message + read_length,
|
|
||||||
next_cmd.rx_length - read_length,
|
|
||||||
RESPONSE_WAIT_MILLIS / portTICK_PERIOD_MS);
|
|
||||||
read_length += current_read;
|
read_length += current_read;
|
||||||
}
|
}
|
||||||
if (current_read < 0) {
|
if (current_read < 0) {
|
||||||
@@ -257,13 +293,6 @@ namespace Spindles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ================== Class methods ==================================
|
// ================== Class methods ==================================
|
||||||
void VFD::default_modbus_settings(uart_config_t& uart) {
|
|
||||||
// Default is 9600 8N1, which is sane for most VFD's:
|
|
||||||
uart.baud_rate = 9600;
|
|
||||||
uart.data_bits = UART_DATA_8_BITS;
|
|
||||||
uart.parity = UART_PARITY_DISABLE;
|
|
||||||
uart.stop_bits = UART_STOP_BITS_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VFD::init() {
|
void VFD::init() {
|
||||||
vfd_ok = false; // initialize
|
vfd_ok = false; // initialize
|
||||||
@@ -281,38 +310,16 @@ namespace Spindles {
|
|||||||
|
|
||||||
// this allows us to init() again later.
|
// this allows us to init() again later.
|
||||||
// If you change certain settings, init() gets called agian
|
// If you change certain settings, init() gets called agian
|
||||||
uart_driver_delete(VFD_RS485_UART_PORT);
|
// uart_driver_delete(VFD_RS485_UART_PORT);
|
||||||
|
|
||||||
uart_config_t uart_config;
|
if (_uart.setPins(_txd_pin, _rxd_pin, _rts_pin)) {
|
||||||
default_modbus_settings(uart_config);
|
|
||||||
|
|
||||||
// Overwrite with user defined defines:
|
|
||||||
#ifdef VFD_RS485_BAUD_RATE
|
|
||||||
uart_config.baud_rate = VFD_RS485_BAUD_RATE;
|
|
||||||
#endif
|
|
||||||
#ifdef VFD_RS485_PARITY
|
|
||||||
uart_config.parity = VFD_RS485_PARITY;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
|
||||||
uart_config.rx_flow_ctrl_thresh = 122;
|
|
||||||
|
|
||||||
if (uart_param_config(VFD_RS485_UART_PORT, &uart_config) != ESP_OK) {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart parameters failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uart_set_pin(VFD_RS485_UART_PORT, _txd_pin, _rxd_pin, _rts_pin, UART_PIN_NO_CHANGE) != ESP_OK) {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart pin config failed");
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart pin config failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uart_driver_install(VFD_RS485_UART_PORT, VFD_RS485_BUF_SIZE * 2, 0, 0, NULL, 0) != ESP_OK) {
|
_uart.begin(_baudrate, _dataBits, _stopBits, _parity);
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart driver install failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uart_set_mode(VFD_RS485_UART_PORT, UART_MODE_RS485_HALF_DUPLEX) != ESP_OK) {
|
if (_uart.setHalfDuplex()) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart set half duplex failed");
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart set half duplex failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -349,26 +356,20 @@ namespace Spindles {
|
|||||||
bool VFD::get_pins_and_settings() {
|
bool VFD::get_pins_and_settings() {
|
||||||
bool pins_settings_ok = true;
|
bool pins_settings_ok = true;
|
||||||
|
|
||||||
#ifdef VFD_RS485_TXD_PIN
|
if (_txd_pin == -1) {
|
||||||
_txd_pin = VFD_RS485_TXD_PIN;
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_TXD_PIN");
|
||||||
#else
|
pins_settings_ok = false;
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_TXD_PIN");
|
}
|
||||||
pins_settings_ok = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VFD_RS485_RXD_PIN
|
if (_rxd_pin == -1) {
|
||||||
_rxd_pin = VFD_RS485_RXD_PIN;
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_RXD_PIN");
|
||||||
#else
|
pins_settings_ok = false;
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_RXD_PIN");
|
}
|
||||||
pins_settings_ok = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VFD_RS485_RTS_PIN
|
if (_rts_pin == -1) {
|
||||||
_rts_pin = VFD_RS485_RTS_PIN;
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_RTS_PIN");
|
||||||
#else
|
pins_settings_ok = false;
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_RTS_PIN");
|
}
|
||||||
pins_settings_ok = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (laser_mode->get()) {
|
if (laser_mode->get()) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "VFD spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart");
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "VFD spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart");
|
||||||
@@ -564,9 +565,12 @@ namespace Spindles {
|
|||||||
ModbusCommand rpm_cmd;
|
ModbusCommand rpm_cmd;
|
||||||
rpm_cmd.msg[0] = VFD_RS485_ADDR;
|
rpm_cmd.msg[0] = VFD_RS485_ADDR;
|
||||||
|
|
||||||
|
|
||||||
set_speed_command(rpm, rpm_cmd);
|
set_speed_command(rpm, rpm_cmd);
|
||||||
|
|
||||||
|
// Sometimes sync_rpm is retained between different set_speed_command's. We don't want that - we want
|
||||||
|
// spindle sync to kick in after we set the speed. This forces that.
|
||||||
|
_sync_rpm = UINT32_MAX;
|
||||||
|
|
||||||
rpm_cmd.critical = (rpm == 0);
|
rpm_cmd.critical = (rpm == 0);
|
||||||
|
|
||||||
if (xQueueSend(vfd_cmd_queue, &rpm_cmd, 0) != pdTRUE) {
|
if (xQueueSend(vfd_cmd_queue, &rpm_cmd, 0) != pdTRUE) {
|
||||||
@@ -576,7 +580,12 @@ namespace Spindles {
|
|||||||
return rpm;
|
return rpm;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFD::stop() { set_mode(SpindleState::Disable, true); }
|
void VFD::stop() {
|
||||||
|
#ifdef VFD_DEBUG_MODE
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Debug, "VFD::stop()");
|
||||||
|
#endif
|
||||||
|
set_mode(SpindleState::Disable, true);
|
||||||
|
}
|
||||||
|
|
||||||
// state is cached rather than read right now to prevent delays
|
// state is cached rather than read right now to prevent delays
|
||||||
SpindleState VFD::get_state() { return _current_state; }
|
SpindleState VFD::get_state() { return _current_state; }
|
||||||
|
@@ -20,11 +20,12 @@
|
|||||||
*/
|
*/
|
||||||
#include "Spindle.h"
|
#include "Spindle.h"
|
||||||
|
|
||||||
#include <driver/uart.h>
|
#include "../Uart.h"
|
||||||
|
|
||||||
// #define VFD_DEBUG_MODE
|
// #define VFD_DEBUG_MODE
|
||||||
|
|
||||||
namespace Spindles {
|
namespace Spindles {
|
||||||
|
extern Uart _uart;
|
||||||
|
|
||||||
class VFD : public Spindle {
|
class VFD : public Spindle {
|
||||||
private:
|
private:
|
||||||
@@ -34,9 +35,9 @@ namespace Spindles {
|
|||||||
bool set_mode(SpindleState mode, bool critical);
|
bool set_mode(SpindleState mode, bool critical);
|
||||||
bool get_pins_and_settings();
|
bool get_pins_and_settings();
|
||||||
|
|
||||||
uint8_t _txd_pin;
|
int _txd_pin;
|
||||||
uint8_t _rxd_pin;
|
int _rxd_pin;
|
||||||
uint8_t _rts_pin;
|
int _rts_pin;
|
||||||
|
|
||||||
uint32_t _current_rpm = 0;
|
uint32_t _current_rpm = 0;
|
||||||
bool _task_running = false;
|
bool _task_running = false;
|
||||||
@@ -57,8 +58,6 @@ namespace Spindles {
|
|||||||
uint8_t msg[VFD_RS485_MAX_MSG_SIZE];
|
uint8_t msg[VFD_RS485_MAX_MSG_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void default_modbus_settings(uart_config_t& uart);
|
|
||||||
|
|
||||||
// Commands:
|
// Commands:
|
||||||
virtual void direction_command(SpindleState mode, ModbusCommand& data) = 0;
|
virtual void direction_command(SpindleState mode, ModbusCommand& data) = 0;
|
||||||
virtual void set_speed_command(uint32_t rpm, ModbusCommand& data) = 0;
|
virtual void set_speed_command(uint32_t rpm, ModbusCommand& data) = 0;
|
||||||
@@ -73,8 +72,14 @@ namespace Spindles {
|
|||||||
virtual bool supports_actual_rpm() const { return false; }
|
virtual bool supports_actual_rpm() const { return false; }
|
||||||
virtual bool safety_polling() const { return true; }
|
virtual bool safety_polling() const { return true; }
|
||||||
|
|
||||||
|
// The constructor sets these
|
||||||
|
int _baudrate;
|
||||||
|
Uart::Data _dataBits;
|
||||||
|
Uart::Stop _stopBits;
|
||||||
|
Uart::Parity _parity;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VFD() = default;
|
VFD();
|
||||||
VFD(const VFD&) = delete;
|
VFD(const VFD&) = delete;
|
||||||
VFD(VFD&&) = delete;
|
VFD(VFD&&) = delete;
|
||||||
VFD& operator=(const VFD&) = delete;
|
VFD& operator=(const VFD&) = delete;
|
||||||
|
232
Grbl_Esp32/src/Spindles/YL620Spindle.cpp
Normal file
232
Grbl_Esp32/src/Spindles/YL620Spindle.cpp
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
#include "YL620Spindle.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
YL620Spindle.cpp
|
||||||
|
|
||||||
|
This is for a Yalang YL620/YL620-A VFD based spindle to be controlled via RS485 Modbus RTU.
|
||||||
|
|
||||||
|
Part of Grbl_ESP32
|
||||||
|
2021 - Marco Wagner
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
WARNING!!!!
|
||||||
|
VFDs are very dangerous. They have high voltages and are very powerful
|
||||||
|
Remove power before changing bits.
|
||||||
|
|
||||||
|
=============================================================================================================
|
||||||
|
|
||||||
|
Configuration required for the YL620
|
||||||
|
|
||||||
|
Parameter number Description Value
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
P00.00 Main frequency 400.00Hz (match to your spindle)
|
||||||
|
P00.01 Command source 3
|
||||||
|
|
||||||
|
P03.00 RS485 Baud rate 3 (9600)
|
||||||
|
P03.01 RS485 address 1
|
||||||
|
P03.02 RS485 protocol 2
|
||||||
|
P03.08 Frequency given lower limit 100.0Hz (match to your spindle cooling-type)
|
||||||
|
|
||||||
|
===============================================================================================================
|
||||||
|
|
||||||
|
RS485 communication is standard Modbus RTU
|
||||||
|
|
||||||
|
Therefore, the following operation codes are relevant:
|
||||||
|
0x03: read single holding register
|
||||||
|
0x06: write single holding register
|
||||||
|
|
||||||
|
Holding register address Description
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
0x0000 main frequency
|
||||||
|
0x0308 frequency given lower limit
|
||||||
|
|
||||||
|
0x2000 command register (further information below)
|
||||||
|
0x2001 Modbus485 frequency command (x0.1Hz => 2500 = 250.0Hz)
|
||||||
|
|
||||||
|
0x200A Target frequency
|
||||||
|
0x200B Output frequency
|
||||||
|
0x200C Output current
|
||||||
|
|
||||||
|
|
||||||
|
Command register at holding address 0x2000
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
bit 1:0 b00: No function
|
||||||
|
b01: shutdown command
|
||||||
|
b10: start command
|
||||||
|
b11: Jog command
|
||||||
|
bit 3:2 reserved
|
||||||
|
bit 5:4 b00: No function
|
||||||
|
b01: Forward command
|
||||||
|
b10: Reverse command
|
||||||
|
b11: change direction
|
||||||
|
bit 7:6 b00: No function
|
||||||
|
b01: reset an error flag
|
||||||
|
b10: reset all error flags
|
||||||
|
b11: reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
YL620::YL620() : VFD() {}
|
||||||
|
|
||||||
|
void YL620::direction_command(SpindleState mode, ModbusCommand& data) {
|
||||||
|
// NOTE: data length is excluding the CRC16 checksum.
|
||||||
|
data.tx_length = 6;
|
||||||
|
data.rx_length = 6;
|
||||||
|
|
||||||
|
// data.msg[0] is omitted (modbus address is filled in later)
|
||||||
|
data.msg[1] = 0x06; // 06: write output register
|
||||||
|
data.msg[2] = 0x20; // 0x2000: command register address
|
||||||
|
data.msg[3] = 0x00;
|
||||||
|
|
||||||
|
data.msg[4] = 0x00; // High-Byte of command always 0x00
|
||||||
|
switch (mode) {
|
||||||
|
case SpindleState::Cw:
|
||||||
|
data.msg[5] = 0x12; // Start in forward direction
|
||||||
|
break;
|
||||||
|
case SpindleState::Ccw:
|
||||||
|
data.msg[5] = 0x22; // Start in reverse direction
|
||||||
|
break;
|
||||||
|
default: // SpindleState::Disable
|
||||||
|
data.msg[5] = 0x01; // Disable spindle
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void YL620::set_speed_command(uint32_t rpm, ModbusCommand& data) {
|
||||||
|
// NOTE: data length is excluding the CRC16 checksum.
|
||||||
|
data.tx_length = 6;
|
||||||
|
data.rx_length = 6;
|
||||||
|
|
||||||
|
// We have to know the max RPM before we can set the current RPM:
|
||||||
|
auto max_rpm = this->_max_rpm;
|
||||||
|
auto max_frequency = this->_maxFrequency;
|
||||||
|
|
||||||
|
uint16_t freqFromRPM = (uint16_t(rpm) * uint16_t(max_frequency)) / uint16_t(max_rpm);
|
||||||
|
|
||||||
|
#ifdef VFD_DEBUG_MODE
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "For %d RPM the output frequency is set to %d Hz*10", int(rpm), int(freqFromRPM));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
data.msg[1] = 0x06;
|
||||||
|
data.msg[2] = 0x20;
|
||||||
|
data.msg[3] = 0x01;
|
||||||
|
data.msg[4] = uint8_t(freqFromRPM >> 8);
|
||||||
|
data.msg[5] = uint8_t(freqFromRPM & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
VFD::response_parser YL620::initialization_sequence(int index, ModbusCommand& data) {
|
||||||
|
if (index == -1) {
|
||||||
|
// NOTE: data length is excluding the CRC16 checksum.
|
||||||
|
data.tx_length = 6;
|
||||||
|
data.rx_length = 5;
|
||||||
|
|
||||||
|
data.msg[1] = 0x03;
|
||||||
|
data.msg[2] = 0x03;
|
||||||
|
data.msg[3] = 0x08;
|
||||||
|
data.msg[4] = 0x00;
|
||||||
|
data.msg[5] = 0x01;
|
||||||
|
|
||||||
|
// Recv: 01 03 02 03 E8 xx xx
|
||||||
|
// -- -- = 1000
|
||||||
|
return [](const uint8_t* response, Spindles::VFD* vfd) -> bool {
|
||||||
|
auto yl620 = static_cast<YL620*>(vfd);
|
||||||
|
yl620->_minFrequency = (uint16_t(response[3]) << 8) | uint16_t(response[4]);
|
||||||
|
|
||||||
|
#ifdef VFD_DEBUG_MODE
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "YL620 allows minimum frequency of %d Hz", int(yl620->_minFrequency));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
} else if (index == -2) {
|
||||||
|
// NOTE: data length is excluding the CRC16 checksum.
|
||||||
|
data.tx_length = 6;
|
||||||
|
data.rx_length = 5;
|
||||||
|
|
||||||
|
data.msg[1] = 0x03;
|
||||||
|
data.msg[2] = 0x00;
|
||||||
|
data.msg[3] = 0x00;
|
||||||
|
data.msg[4] = 0x00;
|
||||||
|
data.msg[5] = 0x01;
|
||||||
|
|
||||||
|
// Recv: 01 03 02 0F A0 xx xx
|
||||||
|
// -- -- = 4000
|
||||||
|
return [](const uint8_t* response, Spindles::VFD* vfd) -> bool {
|
||||||
|
auto yl620 = static_cast<YL620*>(vfd);
|
||||||
|
yl620->_maxFrequency = (uint16_t(response[3]) << 8) | uint16_t(response[4]);
|
||||||
|
|
||||||
|
vfd->_min_rpm = uint32_t(yl620->_minFrequency) * uint32_t(vfd->_max_rpm) /
|
||||||
|
uint32_t(yl620->_maxFrequency); // 1000 * 24000 / 4000 = 6000 RPM.
|
||||||
|
|
||||||
|
#ifdef VFD_DEBUG_MODE
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "YL620 allows maximum frequency of %d Hz", int(yl620->_maxFrequency));
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL,
|
||||||
|
MsgLevel::Info,
|
||||||
|
"Configured maxRPM of %d RPM results in minRPM of %d RPM",
|
||||||
|
int(vfd->_max_rpm),
|
||||||
|
int(vfd->_min_rpm));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VFD::response_parser YL620::get_current_rpm(ModbusCommand& data) {
|
||||||
|
// NOTE: data length is excluding the CRC16 checksum.
|
||||||
|
data.tx_length = 6;
|
||||||
|
data.rx_length = 5;
|
||||||
|
|
||||||
|
// Send: 01 03 200B 0001
|
||||||
|
data.msg[1] = 0x03;
|
||||||
|
data.msg[2] = 0x20;
|
||||||
|
data.msg[3] = 0x0B;
|
||||||
|
data.msg[4] = 0x00;
|
||||||
|
data.msg[5] = 0x01;
|
||||||
|
|
||||||
|
// Recv: 01 03 02 05 DC xx xx
|
||||||
|
// ---- = 1500
|
||||||
|
return [](const uint8_t* response, Spindles::VFD* vfd) -> bool {
|
||||||
|
uint16_t freq = (uint16_t(response[3]) << 8) | uint16_t(response[4]);
|
||||||
|
|
||||||
|
auto yl620 = static_cast<YL620*>(vfd);
|
||||||
|
|
||||||
|
uint16_t rpm = freq * uint16_t(vfd->_max_rpm) / uint16_t(yl620->_maxFrequency);
|
||||||
|
|
||||||
|
// Set current RPM value? Somewhere?
|
||||||
|
vfd->_sync_rpm = rpm;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
VFD::response_parser YL620::get_current_direction(ModbusCommand& data) {
|
||||||
|
// NOTE: data length is excluding the CRC16 checksum.
|
||||||
|
data.tx_length = 6;
|
||||||
|
data.rx_length = 5;
|
||||||
|
|
||||||
|
// Send: 01 03 20 00 00 01
|
||||||
|
data.msg[1] = 0x03;
|
||||||
|
data.msg[2] = 0x20;
|
||||||
|
data.msg[3] = 0x00;
|
||||||
|
data.msg[4] = 0x00;
|
||||||
|
data.msg[5] = 0x01;
|
||||||
|
|
||||||
|
// Receive: 01 03 02 00 0A xx xx
|
||||||
|
// ----- status is in 00 0A bit 5:4
|
||||||
|
|
||||||
|
// TODO: What are we going to do with this? Update sys.spindle_speed? Update vfd state?
|
||||||
|
return [](const uint8_t* response, Spindles::VFD* vfd) -> bool { return true; };
|
||||||
|
}
|
||||||
|
}
|
44
Grbl_Esp32/src/Spindles/YL620Spindle.h
Normal file
44
Grbl_Esp32/src/Spindles/YL620Spindle.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VFDSpindle.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
YL620Spindle.h
|
||||||
|
|
||||||
|
Part of Grbl_ESP32
|
||||||
|
2021 - Marco Wagner
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
class YL620 : public VFD {
|
||||||
|
protected:
|
||||||
|
uint16_t _minFrequency = 0; // frequency lower limit. Factor 10 of actual frequency
|
||||||
|
uint16_t _maxFrequency = 4000; // max frequency the VFD will allow. Normally 400.0. Factor 10 of actual frequency
|
||||||
|
|
||||||
|
void direction_command(SpindleState mode, ModbusCommand& data) override;
|
||||||
|
void set_speed_command(uint32_t rpm, ModbusCommand& data) override;
|
||||||
|
|
||||||
|
response_parser initialization_sequence(int index, ModbusCommand& data) override;
|
||||||
|
response_parser get_current_rpm(ModbusCommand& data) override;
|
||||||
|
response_parser get_current_direction(ModbusCommand& data) override;
|
||||||
|
response_parser get_status_ok(ModbusCommand& data) override { return nullptr; }
|
||||||
|
|
||||||
|
bool supports_actual_rpm() const override { return true; }
|
||||||
|
bool safety_polling() const override { return false; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
YL620();
|
||||||
|
};
|
||||||
|
}
|
@@ -30,6 +30,7 @@ volatile ExecState sys_rt_exec_state; // Global realtime executor bitflag v
|
|||||||
volatile ExecAlarm sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
volatile ExecAlarm sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||||
volatile ExecAccessory sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
volatile ExecAccessory sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||||
volatile bool cycle_stop; // For state transitions, instead of bitflag
|
volatile bool cycle_stop; // For state transitions, instead of bitflag
|
||||||
|
volatile void* sys_pl_data_inflight; // holds a plan_line_data_t while inverse_kinematics has taken ownership of a line motion
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
volatile bool sys_rt_exec_debug;
|
volatile bool sys_rt_exec_debug;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -138,6 +138,7 @@ extern volatile Percent sys_rt_f_override; // Feed override
|
|||||||
extern volatile Percent sys_rt_r_override; // Rapid feed override value in percent
|
extern volatile Percent sys_rt_r_override; // Rapid feed override value in percent
|
||||||
extern volatile Percent sys_rt_s_override; // Spindle override value in percent
|
extern volatile Percent sys_rt_s_override; // Spindle override value in percent
|
||||||
extern volatile bool cycle_stop;
|
extern volatile bool cycle_stop;
|
||||||
|
extern volatile void* sys_pl_data_inflight; // holds a plan_line_data_t while inverse_kinematics has taken ownership of a line motion
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
extern volatile bool sys_rt_exec_debug;
|
extern volatile bool sys_rt_exec_debug;
|
||||||
#endif
|
#endif
|
||||||
|
94
Grbl_Esp32/src/Uart.cpp
Normal file
94
Grbl_Esp32/src/Uart.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* UART driver that accesses the ESP32 hardware FIFOs directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Grbl.h"
|
||||||
|
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "soc/uart_reg.h"
|
||||||
|
#include "soc/io_mux_reg.h"
|
||||||
|
#include "soc/gpio_sig_map.h"
|
||||||
|
#include "soc/dport_reg.h"
|
||||||
|
#include "soc/rtc.h"
|
||||||
|
|
||||||
|
Uart::Uart(int uart_num) : _uart_num(uart_port_t(uart_num)), _pushback(-1) {}
|
||||||
|
|
||||||
|
void Uart::begin(unsigned long baudrate, Data dataBits, Stop stopBits, Parity parity) {
|
||||||
|
// uart_driver_delete(_uart_num);
|
||||||
|
uart_config_t conf;
|
||||||
|
conf.baud_rate = baudrate;
|
||||||
|
conf.data_bits = uart_word_length_t(dataBits);
|
||||||
|
conf.parity = uart_parity_t(parity);
|
||||||
|
conf.stop_bits = uart_stop_bits_t(stopBits);
|
||||||
|
conf.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
||||||
|
conf.rx_flow_ctrl_thresh = 0;
|
||||||
|
conf.use_ref_tick = false;
|
||||||
|
if (uart_param_config(_uart_num, &conf) != ESP_OK) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
uart_driver_install(_uart_num, 256, 0, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Uart::available() {
|
||||||
|
size_t size = 0;
|
||||||
|
uart_get_buffered_data_len(_uart_num, &size);
|
||||||
|
return size + (_pushback >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Uart::peek() {
|
||||||
|
_pushback = read();
|
||||||
|
return _pushback;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Uart::read(TickType_t timeout) {
|
||||||
|
if (_pushback >= 0) {
|
||||||
|
int ret = _pushback;
|
||||||
|
_pushback = -1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
uint8_t c;
|
||||||
|
int res = uart_read_bytes(_uart_num, &c, 1, timeout);
|
||||||
|
return res != 1 ? -1 : c;
|
||||||
|
}
|
||||||
|
int Uart::read() {
|
||||||
|
return read(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Uart::readBytes(char* buffer, size_t length, TickType_t timeout) {
|
||||||
|
bool pushback = _pushback >= 0;
|
||||||
|
if (pushback && length) {
|
||||||
|
*buffer++ = _pushback;
|
||||||
|
_pushback = -1;
|
||||||
|
--length;
|
||||||
|
}
|
||||||
|
int res = uart_read_bytes(_uart_num, (uint8_t*)buffer, length, timeout);
|
||||||
|
// The Stream class version of readBytes never returns -1,
|
||||||
|
// so if uart_read_bytes returns -1, we change that to 0
|
||||||
|
return pushback + (res >= 0 ? res : 0);
|
||||||
|
}
|
||||||
|
size_t Uart::readBytes(char* buffer, size_t length) {
|
||||||
|
return readBytes(buffer, length, (TickType_t)0);
|
||||||
|
}
|
||||||
|
size_t Uart::write(uint8_t c) {
|
||||||
|
return uart_write_bytes(_uart_num, (char*)&c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Uart::write(const uint8_t* buffer, size_t length) {
|
||||||
|
return uart_write_bytes(_uart_num, (const char*)buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Uart::write(const char* text) {
|
||||||
|
return uart_write_bytes(_uart_num, text, strlen(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uart::setHalfDuplex() {
|
||||||
|
return uart_set_mode(_uart_num, UART_MODE_RS485_HALF_DUPLEX) != ESP_OK;
|
||||||
|
}
|
||||||
|
bool Uart::setPins(int tx_pin, int rx_pin, int rts_pin, int cts_pin) {
|
||||||
|
return uart_set_pin(_uart_num, tx_pin, rx_pin, rts_pin, cts_pin) != ESP_OK;
|
||||||
|
}
|
||||||
|
bool Uart::flushTxTimed(TickType_t ticks) {
|
||||||
|
return uart_wait_tx_done(_uart_num, ticks) != ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uart Uart0(0);
|
49
Grbl_Esp32/src/Uart.h
Normal file
49
Grbl_Esp32/src/Uart.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <driver/uart.h>
|
||||||
|
|
||||||
|
class Uart : public Stream {
|
||||||
|
private:
|
||||||
|
uart_port_t _uart_num;
|
||||||
|
int _pushback;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class Data : int {
|
||||||
|
Bits5 = UART_DATA_5_BITS,
|
||||||
|
Bits6 = UART_DATA_6_BITS,
|
||||||
|
Bits7 = UART_DATA_7_BITS,
|
||||||
|
Bits8 = UART_DATA_8_BITS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Stop : int {
|
||||||
|
Bits1 = UART_STOP_BITS_1,
|
||||||
|
Bits1_5 = UART_STOP_BITS_1_5,
|
||||||
|
Bits2 = UART_STOP_BITS_2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Parity : int {
|
||||||
|
None = UART_PARITY_DISABLE,
|
||||||
|
Even = UART_PARITY_EVEN,
|
||||||
|
Odd = UART_PARITY_ODD,
|
||||||
|
};
|
||||||
|
|
||||||
|
Uart(int uart_num);
|
||||||
|
bool setHalfDuplex();
|
||||||
|
bool setPins(int tx_pin, int rx_pin, int rts_pin = -1, int cts_pin = -1);
|
||||||
|
void begin(unsigned long baud, Data dataBits, Stop stopBits, Parity parity);
|
||||||
|
int available(void) override;
|
||||||
|
int read(void) override;
|
||||||
|
int read(TickType_t timeout);
|
||||||
|
size_t readBytes(char* buffer, size_t length, TickType_t timeout);
|
||||||
|
size_t readBytes(uint8_t* buffer, size_t length, TickType_t timeout) { return readBytes((char*)buffer, length, timeout); }
|
||||||
|
size_t readBytes(char* buffer, size_t length) override;
|
||||||
|
int peek(void) override;
|
||||||
|
size_t write(uint8_t data);
|
||||||
|
size_t write(const uint8_t* buffer, size_t length);
|
||||||
|
inline size_t write(const char* buffer, size_t size) { return write((uint8_t*)buffer, size); }
|
||||||
|
size_t write(const char* text);
|
||||||
|
void flush() { uart_flush(_uart_num); }
|
||||||
|
bool flushTxTimed(TickType_t ticks);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Uart Uart0;
|
@@ -1,12 +1,22 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
src_dir=Grbl_Esp32
|
src_dir = Grbl_Esp32
|
||||||
lib_dir=libraries
|
lib_dir = libraries
|
||||||
data_dir=Grbl_Esp32/data
|
data_dir = Grbl_Esp32/data
|
||||||
default_envs=release
|
default_envs = release
|
||||||
;extra_configs=debug.ini
|
;extra_configs=debug.ini
|
||||||
|
|
||||||
[common_env_data]
|
[common_env_data]
|
||||||
lib_deps_builtin =
|
lib_deps_builtin =
|
||||||
ArduinoOTA
|
ArduinoOTA
|
||||||
BluetoothSerial
|
BluetoothSerial
|
||||||
DNSServer
|
DNSServer
|
||||||
@@ -23,37 +33,40 @@ lib_deps_builtin =
|
|||||||
WiFiClientSecure
|
WiFiClientSecure
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
build_flags =
|
build_flags =
|
||||||
;-DMACHINE_FILENAME=test_drive.h ;Remove ";" from the beginning of this line and specify the machine file
|
;-DMACHINE_FILENAME=test_drive.h ;Remove ";" from the beginning of this line and specify the machine file
|
||||||
-DCORE_DEBUG_LEVEL=0
|
-DCORE_DEBUG_LEVEL=0
|
||||||
-Wno-unused-variable
|
-Wno-unused-variable
|
||||||
-Wno-unused-function
|
-Wno-unused-function
|
||||||
;-DDEBUG_REPORT_HEAP_SIZE
|
|
||||||
;-DDEBUG_REPORT_STACK_FREE
|
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
lib_deps =
|
;lib_deps =
|
||||||
TMCStepper@>=0.7.0,<1.0.0
|
; TMCStepper@>=0.7.0,<1.0.0
|
||||||
platform = espressif32
|
platform = espressif32@3.0.0 ; temporary fix for lost uart rx characters
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
framework = arduino
|
framework = arduino
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
board_build.partitions = min_spiffs.csv
|
board_build.partitions = min_spiffs.csv
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_flags =
|
monitor_flags =
|
||||||
--eol=CRLF
|
--eol=CRLF
|
||||||
--echo
|
--echo
|
||||||
--filter=esp32_exception_decoder
|
--filter=esp32_exception_decoder
|
||||||
board_build.f_cpu = 240000000L
|
board_build.f_cpu = 240000000L
|
||||||
; set frequency to 80MHz
|
|
||||||
board_build.f_flash = 80000000L
|
board_build.f_flash = 80000000L
|
||||||
board_build.flash_mode = qio
|
board_build.flash_mode = qio
|
||||||
build_flags = ${common.build_flags}
|
build_flags = ${common.build_flags}
|
||||||
src_filter =
|
src_filter =
|
||||||
+<*.h> +<*.s> +<*.S> +<*.cpp> +<*.c> +<*.ino> +<src/>
|
+<*.h> +<*.s> +<*.S> +<*.cpp> +<*.c> +<*.ino> +<src/>
|
||||||
-<.git/> -<data/> -<test/> -<tests/>
|
-<.git/> -<data/> -<test/> -<tests/>
|
||||||
|
|
||||||
[env:release]
|
[env:release]
|
||||||
|
lib_deps =
|
||||||
|
TMCStepper@>=0.7.0,<1.0.0
|
||||||
|
ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.2.0
|
||||||
|
|
||||||
[env:debug]
|
[env:debug]
|
||||||
build_type = debug
|
build_type = debug
|
||||||
|
lib_deps =
|
||||||
|
TMCStepper@>=0.7.0,<1.0.0
|
||||||
|
ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.2.0
|
||||||
|
Reference in New Issue
Block a user