1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-08-31 18:11:48 +02:00

Spindle Updates

- protocol.cpp when spindle speed is overridden, spindlee object gets notified
- protocol.cpp Reformat
- HuanyanySpindle.cpp - Prevent it from running if the $Spindle/Type is changed to Haunyang, but the pins were not defined.
- Increase command queue size from 5 to 10. Queue is cleared if M5 is received.
- Added spindle override to Huanyang.
This commit is contained in:
bdring
2020-07-27 16:18:27 -05:00
committed by Mitch Bradley
parent 05ff080935
commit b5a478cfc9
4 changed files with 152 additions and 83 deletions

View File

@@ -2,6 +2,8 @@
HuanyangSpindle.cpp HuanyangSpindle.cpp
This is for a Huanyang VFD based spindle via RS485 Modbus. This is for a Huanyang VFD based spindle via RS485 Modbus.
Sorry for the lengthy comments, but finding the details on this
VFD was a PITA. I am just trying to help the next person.
Part of Grbl_ESP32 Part of Grbl_ESP32
2020 - Bart Dring 2020 - Bart Dring
@@ -21,6 +23,21 @@
VFDs are very dangerous. They have high voltages and are very powerful VFDs are very dangerous. They have high voltages and are very powerful
Remove power before changing bits. Remove power before changing bits.
==============================================================================
If a user changes state or RPM level, the command to do that is sent. If
the command is not responded to a message is sent to serial that there was
a timeout. If the Grbl is in a critical state, an alarm will be generated and
the machine stopped.
If there are no commands to execute, various status items will be polled. If there
is no response, it will behave as described above. It will stop any running jobs with
an alarm.
===============================================================================
Protocol Details
VFD frequencies are in Hz. Multiply by 60 for RPM VFD frequencies are in Hz. Multiply by 60 for RPM
before using spindle, VFD must be setup for RS485 and match your spindle before using spindle, VFD must be setup for RS485 and match your spindle
@@ -47,26 +64,49 @@
Spindle Talker 2 https://github.com/GilchristT/SpindleTalker2/releases Spindle Talker 2 https://github.com/GilchristT/SpindleTalker2/releases
Python https://github.com/RobertOlechowski/Huanyang_VFD Python https://github.com/RobertOlechowski/Huanyang_VFD
=========================================================================
Commands Commands
ADDR CMD LEN DATA CRC ADDR CMD LEN DATA CRC
0x01 0x03 0x01 0x01 0x31 0x88 Start spindle clockwise 0x01 0x03 0x01 0x01 0x31 0x88 Start spindle clockwise
0x01 0x03 0x01 0x08 0xF1 0x8E Stop spindle 0x01 0x03 0x01 0x08 0xF1 0x8E Stop spindle
0x01 0x03 0x01 0x11 0x30 0x44 Start spindle counter-clockwise 0x01 0x03 0x01 0x11 0x30 0x44 Start spindle counter-clockwise
Return values are
0 = run
1 = jog
2 = r/f
3 = running
4 = jogging
5 = r/f
6 = Braking
7 = Track start
==========================================================================
Setting RPM Setting RPM
ADDR CMD LEN DATA CRC ADDR CMD LEN DATA CRC
0x01 0x05 0x02 0x09 0xC4 0xBF 0x0F Write Frequency (0x9C4 = 2500 = 25.00HZ) 0x01 0x05 0x02 0x09 0xC4 0xBF 0x0F Write Frequency (0x9C4 = 2500 = 25.00HZ)
Response is same as data sent
==========================================================================
Status registers Status registers
Addr Read Len Reg Data Data CRC CRC Addr Read Len Reg DataH DataL CRC CRC
0x01 0x04 0x03 0x00 0x00 0x00 // Set Frequency 0x01 0x04 0x03 0x00 0x00 0x00 CRC CRC // Set Frequency * 100 (25Hz = 2500)
0x01 0x04 0x03 0x01 // Ouput Frequency 0x01 0x04 0x03 0x01 0x00 0x00 CRC CRC // Ouput Frequency * 100
0x01 0x04 0x03 0x02 // Ouput Amps 0x01 0x04 0x03 0x02 0x00 0x00 CRC CRC // Ouput Amps * 10
0x01 0x04 0x03 0x03 0x00 0x00 0xF0 0x4E // Read RPM 0x01 0x04 0x03 0x03 0x00 0x00 0xF0 0x4E // Read RPM (example CRC shown)
0x01 0x04 0x03 0x04 // DC voltage 0x01 0x04 0x03 0x0 0x00 0x00 CRC CRC // DC voltage
0x01 0x04 0x03 0x05 // AC voltage 0x01 0x04 0x03 0x05 0x00 0x00 CRC CRC // AC voltage
0x01 0x04 0x03 0x06 // Cont 0x01 0x04 0x03 0x06 0x00 0x00 CRC CRC // Cont
0x01 0x04 0x03 0x07 // VFD Temp 0x01 0x04 0x03 0x07 0x00 0x00 CRC CRC // VFD Temp
Message is returned with requested value = (DataH * 16) + DataL (see decimal offset above)
TODO:
Move CRC Calc to task to free up main task
*/ */
#include "SpindleClass.h" #include "SpindleClass.h"
@@ -76,6 +116,7 @@
#define HUANYANG_UART_PORT UART_NUM_2 // hard coded for this port right now #define HUANYANG_UART_PORT UART_NUM_2 // hard coded for this port right now
#define ECHO_TEST_CTS UART_PIN_NO_CHANGE // CTS pin is not used #define ECHO_TEST_CTS UART_PIN_NO_CHANGE // CTS pin is not used
#define HUANYANG_BUF_SIZE 127 #define HUANYANG_BUF_SIZE 127
#define HUANYANG_QUEUE_SIZE 10 // numv\ber of commands that can be queued up.
#define RESPONSE_WAIT_TICKS 50 // how long to wait for a response #define RESPONSE_WAIT_TICKS 50 // how long to wait for a response
#define HUANYANG_MAX_MSG_SIZE 16 // more than enough for a modbus message #define HUANYANG_MAX_MSG_SIZE 16 // more than enough for a modbus message
#define HUANYANG_POLL_RATE 200 // in milliseconds betwwen commands #define HUANYANG_POLL_RATE 200 // in milliseconds betwwen commands
@@ -113,6 +154,8 @@ QueueHandle_t hy_cmd_queue;
static TaskHandle_t vfd_cmdTaskHandle = 0; static TaskHandle_t vfd_cmdTaskHandle = 0;
bool hy_spindle_ok = true;
// The communications task // The communications task
void vfd_cmd_task(void* pvParameters) { void 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
@@ -163,9 +206,16 @@ void vfd_cmd_task(void* pvParameters) {
// ================== Class methods ================================== // ================== Class methods ==================================
void HuanyangSpindle :: init() { void HuanyangSpindle :: init() {
hy_spindle_ok = true; // initialize
// fail if required items are not defined
if (!get_pins_and_settings()) {
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle errors");
return;
}
if (! _task_running) { // init can happen many times, we only want to start one task if (! _task_running) { // init can happen many times, we only want to start one task
hy_cmd_queue = xQueueCreate(5, sizeof(hy_command_t)); hy_cmd_queue = xQueueCreate(HUANYANG_QUEUE_SIZE, sizeof(hy_command_t));
xTaskCreatePinnedToCore(vfd_cmd_task, // task xTaskCreatePinnedToCore(vfd_cmd_task, // task
"vfd_cmdTaskHandle", // name for task "vfd_cmdTaskHandle", // name for task
2048, // size of task stack 2048, // size of task stack
@@ -177,12 +227,6 @@ void HuanyangSpindle :: init() {
_task_running = true; _task_running = true;
} }
// fail if required items are not defined
if (!get_pins_and_settings()) {
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle errors");
return;
}
// 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(HUANYANG_UART_PORT); uart_driver_delete(HUANYANG_UART_PORT);
@@ -227,30 +271,38 @@ void HuanyangSpindle :: init() {
// It returns a message for each missing pin // It returns a message for each missing pin
// Returns true if all pins are defined. // Returns true if all pins are defined.
bool HuanyangSpindle :: get_pins_and_settings() { bool HuanyangSpindle :: get_pins_and_settings() {
bool pins_ok = true;
#ifdef HUANYANG_TXD_PIN #ifdef HUANYANG_TXD_PIN
_txd_pin = HUANYANG_TXD_PIN; _txd_pin = HUANYANG_TXD_PIN;
#else #else
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Missing HUANYANG_TXD_PIN"); grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_TXD_PIN");
pins_ok = false; hy_spindle_ok = false;
#endif #endif
#ifdef HUANYANG_RXD_PIN #ifdef HUANYANG_RXD_PIN
_rxd_pin = HUANYANG_RXD_PIN; _rxd_pin = HUANYANG_RXD_PIN;
#else #else
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No HUANYANG_RXD_PIN"); grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RXD_PIN");
pins_ok = false; hy_spindle_ok = false;
#endif #endif
#ifdef HUANYANG_RTS_PIN #ifdef HUANYANG_RTS_PIN
_rts_pin = HUANYANG_RTS_PIN; _rts_pin = HUANYANG_RTS_PIN;
#else #else
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No HUANYANG_RTS_PIN"); grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RTS_PIN");
pins_ok = false; hy_spindle_ok = false;
#endif #endif
return pins_ok; if (laser_mode->get()) {
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart");
hy_spindle_ok = false;
}
_min_rpm = rpm_min->get();
_max_rpm = rpm_max->get();
return hy_spindle_ok;
} }
void HuanyangSpindle :: config_message() { void HuanyangSpindle :: config_message() {
@@ -260,7 +312,6 @@ void HuanyangSpindle :: config_message() {
pinName(_txd_pin).c_str(), pinName(_txd_pin).c_str(),
pinName(_rxd_pin).c_str(), pinName(_rxd_pin).c_str(),
pinName(_rts_pin).c_str()); pinName(_rts_pin).c_str());
} }
@@ -294,6 +345,9 @@ void HuanyangSpindle :: set_state(uint8_t state, uint32_t rpm) {
} }
bool HuanyangSpindle :: set_mode(uint8_t mode, bool critical) { bool HuanyangSpindle :: set_mode(uint8_t mode, bool critical) {
if (!hy_spindle_ok) return false;
hy_command_t mode_cmd; hy_command_t mode_cmd;
mode_cmd.tx_length = 6; mode_cmd.tx_length = 6;
@@ -307,9 +361,14 @@ bool HuanyangSpindle :: set_mode(uint8_t mode, bool critical) {
mode_cmd.msg[3] = 0x01; mode_cmd.msg[3] = 0x01;
else if (mode == SPINDLE_ENABLE_CCW) else if (mode == SPINDLE_ENABLE_CCW)
mode_cmd.msg[3] = 0x11; mode_cmd.msg[3] = 0x11;
else //SPINDLE_DISABLE else { //SPINDLE_DISABLE
mode_cmd.msg[3] = 0x08; mode_cmd.msg[3] = 0x08;
if (! xQueueReset(hy_cmd_queue)) {
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD spindle off, queue could not be reset");
}
}
add_ModRTU_CRC(mode_cmd.msg, mode_cmd.rx_length); add_ModRTU_CRC(mode_cmd.msg, mode_cmd.rx_length);
mode_cmd.critical = critical; mode_cmd.critical = critical;
@@ -322,8 +381,21 @@ bool HuanyangSpindle :: set_mode(uint8_t mode, bool critical) {
uint32_t HuanyangSpindle :: set_rpm(uint32_t rpm) { uint32_t HuanyangSpindle :: set_rpm(uint32_t rpm) {
if (!hy_spindle_ok) return 0;
hy_command_t rpm_cmd; hy_command_t rpm_cmd;
// apply override
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent)
// apply limits
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
rpm = _max_rpm;
else if (rpm != 0 && rpm <= _min_rpm)
rpm = _min_rpm;
sys.spindle_speed = rpm;
if (rpm == _current_rpm) // prevent setting same RPM twice if (rpm == _current_rpm) // prevent setting same RPM twice
return rpm; return rpm;

View File

@@ -176,6 +176,10 @@ class HuanyangSpindle : public Spindle {
static void read_value(uint8_t reg); static void read_value(uint8_t reg);
static void add_ModRTU_CRC(char* buf, int full_msg_len); static void add_ModRTU_CRC(char* buf, int full_msg_len);
protected:
uint32_t _min_rpm;
uint32_t _max_rpm;
}; };

View File

@@ -22,7 +22,7 @@
// Grbl versioning system // Grbl versioning system
#define GRBL_VERSION "1.3a" #define GRBL_VERSION "1.3a"
#define GRBL_VERSION_BUILD "20200726" #define GRBL_VERSION_BUILD "20200727"
//#include <sdkconfig.h> //#include <sdkconfig.h>

View File

@@ -39,21 +39,17 @@ typedef struct {
} client_line_t; } client_line_t;
client_line_t client_lines[CLIENT_COUNT]; client_line_t client_lines[CLIENT_COUNT];
static void empty_line(uint8_t client) static void empty_line(uint8_t client) {
{
client_line_t* cl = &client_lines[client]; client_line_t* cl = &client_lines[client];
cl->len = 0; cl->len = 0;
cl->buffer[0] = '\0'; cl->buffer[0] = '\0';
} }
static void empty_lines() { static void empty_lines() {
for (uint8_t client = 0; client < CLIENT_COUNT; client++) { for (uint8_t client = 0; client < CLIENT_COUNT; client++)
empty_line(client); empty_line(client);
} }
}
err_t add_char_to_line(char c, uint8_t client) {
err_t add_char_to_line(char c, uint8_t client)
{
client_line_t* cl = &client_lines[client]; client_line_t* cl = &client_lines[client];
// Simple editing for interactive input // Simple editing for interactive input
if (c == '\b') { if (c == '\b') {
@@ -64,9 +60,8 @@ err_t add_char_to_line(char c, uint8_t client)
} }
return STATUS_OK; return STATUS_OK;
} }
if (cl->len == (LINE_BUFFER_SIZE - 1)) { if (cl->len == (LINE_BUFFER_SIZE - 1))
return STATUS_OVERFLOW; return STATUS_OVERFLOW;
}
if (c == '\r' || c == '\n') { if (c == '\r' || c == '\n') {
cl->len = 0; cl->len = 0;
cl->line_number++; cl->line_number++;
@@ -77,21 +72,17 @@ err_t add_char_to_line(char c, uint8_t client)
return STATUS_OK; return STATUS_OK;
} }
err_t execute_line(char* line, uint8_t client, auth_t auth_level) err_t execute_line(char* line, uint8_t client, auth_t auth_level) {
{
err_t result = STATUS_OK; err_t result = STATUS_OK;
// Empty or comment line. For syncing purposes. // Empty or comment line. For syncing purposes.
if (line[0] == 0) { if (line[0] == 0)
return STATUS_OK; return STATUS_OK;
}
// Grbl '$' or WebUI '[ESPxxx]' system command // Grbl '$' or WebUI '[ESPxxx]' system command
if (line[0] == '$' || line[0] == '[') { if (line[0] == '$' || line[0] == '[')
return system_execute_line(line, client, auth_level); return system_execute_line(line, client, auth_level);
}
// Everything else is gcode. Block if in alarm or jog mode. // Everything else is gcode. Block if in alarm or jog mode.
if (sys.state & (STATE_ALARM | STATE_JOG)) { if (sys.state & (STATE_ALARM | STATE_JOG))
return STATUS_SYSTEM_GC_LOCK; return STATUS_SYSTEM_GC_LOCK;
}
return gc_execute_line(line, client); return gc_execute_line(line, client);
} }
@@ -188,11 +179,10 @@ void protocol_main_loop() {
} }
// check to see if we should disable the stepper drivers ... esp32 work around for disable in main loop. // check to see if we should disable the stepper drivers ... esp32 work around for disable in main loop.
if (stepper_idle) { if (stepper_idle) {
if (esp_timer_get_time() > stepper_idle_counter) { if (esp_timer_get_time() > stepper_idle_counter)
motors_set_disable(true); motors_set_disable(true);
} }
} }
}
return; /* Never reached */ return; /* Never reached */
} }
@@ -456,6 +446,9 @@ void protocol_exec_rt_system() {
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_RPM); bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_RPM);
sys.spindle_speed_ovr = last_s_override; sys.spindle_speed_ovr = last_s_override;
sys.report_ovr_counter = 0; // Set to report change immediately sys.report_ovr_counter = 0; // Set to report change immediately
// If spinlde is on, tell it the rpm has been overridden
if (gc_state.modal.spindle != SPINDLE_DISABLE)
spindle->set_rpm(gc_state.spindle_speed);
} }
if (rt_exec & EXEC_SPINDLE_OVR_STOP) { if (rt_exec & EXEC_SPINDLE_OVR_STOP) {
// Spindle stop override allowed only while in HOLD state. // Spindle stop override allowed only while in HOLD state.