mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-08-15 11:04:16 +02:00
@@ -39,10 +39,12 @@
|
||||
#include "BESCSpindle.h"
|
||||
#include "10vSpindle.h"
|
||||
#include "YL620Spindle.h"
|
||||
#include "TecoL510.h"
|
||||
|
||||
namespace Spindles {
|
||||
// An instance of each type of spindle is created here.
|
||||
// This allows the spindle to be dynamicly switched
|
||||
|
||||
Null null;
|
||||
PWM pwm;
|
||||
Relay relay;
|
||||
@@ -52,7 +54,8 @@ namespace Spindles {
|
||||
H2A h2a;
|
||||
BESC besc;
|
||||
_10v _10v;
|
||||
YL620 yl620;
|
||||
YL620 yl620;
|
||||
L510 l510;
|
||||
|
||||
void Spindle::select() {
|
||||
switch (static_cast<SpindleType>(spindle_type->get())) {
|
||||
@@ -83,6 +86,9 @@ namespace Spindles {
|
||||
case SpindleType::YL620:
|
||||
spindle = &yl620;
|
||||
break;
|
||||
case SpindleType::L510:
|
||||
spindle = &l510;
|
||||
break;
|
||||
case SpindleType::NONE:
|
||||
default:
|
||||
spindle = &null;
|
||||
@@ -109,4 +115,4 @@ namespace Spindles {
|
||||
void Spindle::deinit() { stop(); }
|
||||
}
|
||||
|
||||
Spindles::Spindle* spindle;
|
||||
Spindles::Spindle* spindle;
|
||||
|
@@ -39,6 +39,7 @@ enum class SpindleType : int8_t {
|
||||
_10V,
|
||||
H2A,
|
||||
YL620,
|
||||
L510
|
||||
};
|
||||
|
||||
#include "../Grbl.h"
|
||||
|
210
Grbl_Esp32/src/Spindles/TecoL510.cpp
Normal file
210
Grbl_Esp32/src/Spindles/TecoL510.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
#include "TecoL510.h"
|
||||
|
||||
/*
|
||||
TecoL510.cpp
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2021 - Jesse Schoch
|
||||
|
||||
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.
|
||||
|
||||
See TecoL510.md for details
|
||||
*/
|
||||
|
||||
namespace Spindles {
|
||||
L510::L510() : VFD() {
|
||||
_baudrate = 9600;
|
||||
_parity = Uart::Parity::None;
|
||||
// TODO: should defaults be set here? What happens if the motor settings in the VFD are wrong or default?
|
||||
// I think they are overloaded with DEFAULT_SPINDLE_RPM_MAX and DEFAULT_SPINDLE_RPM_MIN
|
||||
_max_rpm = 24000;
|
||||
_min_rpm = 6000;
|
||||
_max_freq = 40000;
|
||||
}
|
||||
|
||||
void L510::direction_command(SpindleState mode, ModbusCommand& data) {
|
||||
// Note: The direction command is always called on M3,M4, and M5
|
||||
// This is where the spindle start/stop should be sent
|
||||
|
||||
|
||||
// NOTE: data length is excluding the CRC16 checksum.
|
||||
data.tx_length = 6;
|
||||
data.rx_length = 6;
|
||||
|
||||
data.msg[1] = 0x06; // WRITE
|
||||
data.msg[2] = 0x25; // Command ID 0x2501
|
||||
data.msg[3] = 0x01;
|
||||
data.msg[4] = 0x00;
|
||||
switch (mode) {
|
||||
case SpindleState::Disable:
|
||||
//data.msg[4] = 0x00;
|
||||
data.msg[5] = 0x00;
|
||||
break;
|
||||
case SpindleState::Cw:
|
||||
data.msg[5] = 0x01;
|
||||
break;
|
||||
case SpindleState::Ccw:
|
||||
data.msg[5] = 0x03;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void L510::set_speed_command(uint32_t rpm, ModbusCommand& data) {
|
||||
// NOTE: data length is excluding the CRC16 checksum.
|
||||
data.tx_length = 6;
|
||||
data.rx_length = 6;
|
||||
|
||||
uint16_t freq = rpm_to_frequency(rpm);
|
||||
|
||||
data.msg[1] = 0x06; // WRITE
|
||||
data.msg[2] = 0x25; // Command ID 0x2502
|
||||
data.msg[3] = 0x02;
|
||||
data.msg[4] = uint8_t(freq >> 8); // RPM
|
||||
data.msg[5] = uint8_t(freq & 0xFF);
|
||||
|
||||
#ifdef VFD_DEBUG_MODE2
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "setting speed to: %d", speed);
|
||||
#endif
|
||||
}
|
||||
uint16_t L510::rpm_to_frequency(uint32_t rpm) {
|
||||
auto max_rpm = this->_max_rpm;
|
||||
auto max_freq = this->_max_freq;
|
||||
uint16_t freq = (uint32_t(rpm) * max_freq) / uint32_t(max_rpm);
|
||||
if (freq < 0) {
|
||||
freq = 0;
|
||||
}
|
||||
if (freq > max_freq) {
|
||||
freq = max_freq;
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
uint32_t L510::freq_to_rpm(uint16_t freq) {
|
||||
auto max_rpm = this->_max_rpm;
|
||||
auto max_freq = this->_max_freq;
|
||||
uint32_t rpm = (freq * max_rpm) / max_freq;
|
||||
if (rpm < 0) {
|
||||
// sometimes it returns -1 which causes an alarm
|
||||
rpm = 0;
|
||||
}
|
||||
return rpm;
|
||||
}
|
||||
|
||||
VFD::response_parser L510::initialization_sequence(int index, ModbusCommand& data) {
|
||||
if (index == -1) {
|
||||
// NOTE: data length is excluding the CRC16 checksum.
|
||||
data.tx_length = 6;
|
||||
data.rx_length = 11;
|
||||
|
||||
// read parameters 02-03..02-06
|
||||
|
||||
// Send:
|
||||
data.msg[1] = 0x03; // READ
|
||||
data.msg[2] = 0x02; // 0x0203 = Get max rpm
|
||||
data.msg[3] = 0x03;
|
||||
data.msg[4] = 0x00; // Read 4 values
|
||||
data.msg[5] = 0x04;
|
||||
|
||||
// Recv: ??
|
||||
|
||||
return [](const uint8_t* response, Spindles::VFD* vfd) -> bool {
|
||||
uint32_t rpm = (response[3] << 8) | response[4];
|
||||
|
||||
// NOTE: the frequency is stored xxx.x but the input command is frequency * 100;
|
||||
uint16_t freq = ((uint16_t)response[9] << 8) | (uint16_t)response[10];
|
||||
freq = freq * 10;
|
||||
auto l510 = static_cast<L510*>(vfd);
|
||||
|
||||
l510->_max_rpm = rpm;
|
||||
l510->_max_freq = freq;
|
||||
|
||||
grbl_msg_sendf(
|
||||
CLIENT_SERIAL, MsgLevel::Info, "L510 initialized: spindle max_rpm %d max_freq %d", vfd->_max_rpm, l510->_max_freq);
|
||||
|
||||
return true;
|
||||
};
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
VFD::response_parser L510::get_status_ok(ModbusCommand& data) {
|
||||
// NOTE: data length is excluding the CRC16 checksum.
|
||||
data.tx_length = 6;
|
||||
data.rx_length = 5;
|
||||
|
||||
// Send:
|
||||
data.msg[1] = 0x03; // READ
|
||||
data.msg[2] = 0x25; // 0x2520 = Get state
|
||||
data.msg[3] = 0x20;
|
||||
data.msg[4] = 0x00; // Read 1 value
|
||||
data.msg[5] = 0x01;
|
||||
|
||||
return [](const uint8_t* response, Spindles::VFD* vfd) -> bool {
|
||||
uint16_t vfd_state = ((uint16_t)response[3] << 8) | (uint16_t)response[4];
|
||||
|
||||
if (bitRead(vfd_state, 3)) {
|
||||
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "L510 Fault detected");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
VFD::response_parser L510::get_current_rpm(ModbusCommand& data) {
|
||||
// NOTE: data length is excluding the CRC16 checksum.
|
||||
data.tx_length = 6;
|
||||
data.rx_length = 5;
|
||||
|
||||
// Send: 01 03 700C 0002
|
||||
data.msg[1] = 0x03; // READ
|
||||
data.msg[2] = 0x25; // 0x2524 = Get output frequency
|
||||
data.msg[3] = 0x24;
|
||||
data.msg[4] = 0x00; // Read 1 value
|
||||
data.msg[5] = 0x01;
|
||||
|
||||
return [](const uint8_t* response, Spindles::VFD* vfd) -> bool {
|
||||
uint16_t freq = ((uint16_t)response[3] << 8) | (uint16_t)response[4];
|
||||
|
||||
auto l510 = static_cast<L510*>(vfd);
|
||||
|
||||
vfd->_sync_rpm = l510->freq_to_rpm(freq);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
VFD::response_parser L510::get_current_direction(ModbusCommand& data) {
|
||||
// does this run ever??
|
||||
// NOTE: data length is excluding the CRC16 checksum.
|
||||
data.tx_length = 6;
|
||||
data.rx_length = 5;
|
||||
|
||||
// Send: 01 03 30 00 00 01
|
||||
data.msg[1] = 0x03; // READ
|
||||
data.msg[2] = 0x25; // 0x2520
|
||||
data.msg[3] = 0x20;
|
||||
data.msg[4] = 0x00; // Message ID
|
||||
data.msg[5] = 0x01;
|
||||
|
||||
// Receive: 01 03 00 02 00 02
|
||||
// ----- status
|
||||
|
||||
return [](const uint8_t* response, Spindles::VFD* vfd) -> bool {
|
||||
uint16_t got = (uint16_t(response[3]) << 8) | uint16_t(response[4]);
|
||||
bool dir = bitRead(got, 1);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
48
Grbl_Esp32/src/Spindles/TecoL510.h
Normal file
48
Grbl_Esp32/src/Spindles/TecoL510.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "VFDSpindle.h"
|
||||
|
||||
/*
|
||||
TecoL510.h
|
||||
|
||||
Part of Grbl_ESP32
|
||||
2021 - Jesse Schoch
|
||||
|
||||
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 L510 : public VFD {
|
||||
protected:
|
||||
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;
|
||||
|
||||
// what is this, what should it do?
|
||||
bool supports_actual_rpm() const override { return true; }
|
||||
bool safety_polling() const override { return true; }
|
||||
response_parser get_status_ok(ModbusCommand& data) override;
|
||||
uint16_t rpm_to_frequency(uint32_t rpm);
|
||||
uint32_t freq_to_rpm(uint16_t);
|
||||
//uint32_t set_rpm(uint32_t rpm) override;
|
||||
void start_spindle();
|
||||
|
||||
public:
|
||||
L510();
|
||||
uint16_t _max_freq;
|
||||
};
|
||||
}
|
31
Grbl_Esp32/src/Spindles/TecoL510_README.md
Normal file
31
Grbl_Esp32/src/Spindles/TecoL510_README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# VFD setup
|
||||
|
||||
Change these values:
|
||||
1) 00-02, Main Run Command Source Selection, Default = 0 Change to 2
|
||||
2) 00-05, Main Freq Command Source Selection, Default = 0 Change to 5
|
||||
|
||||
Check that these are set to the default factory values:
|
||||
3) 00-07, Main and Alternative Freq Cmnd Source Selection, Default = 0
|
||||
4) 09-00, Assigned Communication Number, Default = 1 this is defined as VFD_RS485_ADDR
|
||||
5) 09-01, RTU/ASCII Code Selection, Default = 0 Should be 0 (We are using hex "RTU" commands, not ASCII commands)
|
||||
6) 09-02, Baud Rate Setting, Default = 1 Should be 1 (9600 baud) but can be changed in the TecoL510.cpp
|
||||
7) 09-03, Stop Bit Selection, Default = 0 Should be 0 (1 stop bit)
|
||||
8) 09-04, Parity Selection, Default = 0 Should be 0 (Without parity)
|
||||
9) 09-05, Data Format Selection, Default = 0 Should be 0 (8 data bits)
|
||||
|
||||
# Implementation details
|
||||
|
||||
this was tested with pin 16 RX and 26 TX mapped in the machine config file. Pin 4 was used for RTS but it is not used on the rs485 module I tested with.
|
||||
|
||||
```
|
||||
#define VFD_RS485_TXD_PIN GPIO_NUM_26
|
||||
#define VFD_RS485_RTS_PIN GPIO_NUM_4
|
||||
#define VFD_RS485_RXD_PIN GPIO_NUM_16
|
||||
// Not sure why this isn't a setting
|
||||
|
||||
#define DEFAULT_SPINDLE_RPM_MAX 24000.0 // rpm
|
||||
#define DEFAULT_SPINDLE_RPM_MIN 6000.0 // rpm
|
||||
```
|
||||
|
||||
not sure how to detect and parse error messages
|
||||
max frequency is currenly hardcode
|
Reference in New Issue
Block a user