- 嵌入式
- 硬件开发
- 物联网
- 工业制造
【免费下载链接】Grbl_Esp32
A port of Grbl CNC Firmware for ESP32
本文围绕 Grbl_Esp32 中 TECO L510 变频器(VFD)主轴驱动的接入指南 TecoL510_README.md 展开:先给出变频器端必须修改与必须核对的完整参数清单,再说明 ESP32 侧机器配置文件中的引脚与编译宏定义,最后结合 TecoL510.cpp 与 VFDSpindle.cpp 的源码,讲清 M3/M4/M5 指令如何经 Modbus RTU 报文下发、RPM 与输出频率如何换算、转速同步(sync)机制如何保证安全。读完本文,你可以独立完成 L510 VFD 与 ESP32 的接线配置、固件编译接入,并理解每条寄存器报文在协议栈中的位置。
一、VFD 端参数配置(必须修改与必须核对的参数)
L510 通过 Modbus RTU 总线受控,前提是变频器的"命令来源"切换为通讯口。README 原文给出的配置步骤分两类:
1. 必须修改的两个参数
| 参数编号 | 名称 | 默认值 | 目标值 |
|---|---|---|---|
| 00-02 | Main Run Command Source Selection(主运行命令源选择) | 0 | 2(通讯口运行) |
| 00-05 | Main Freq Command Source Selection(主频率命令源选择) | 0 | 5(通讯口频率指令) |
这两项把 VFD 的启停命令和频率指令源都从面板/端子改到 RS485 通讯口,是 Grbl 能控制 VFD 的前提。
2. 必须核对为出厂默认值的通讯参数
| 参数编号 | 名称 | 默认值 | 说明 |
|---|---|---|---|
| 00-07 | Main and Alternative Freq Cmnd Source Selection | 0 | 保持默认 |
| 09-00 | Assigned Communication Number(通讯地址) | 1 | 对应固件中的VFD_RS485_ADDR |
| 09-01 | RTU/ASCII Code Selection | 0 | 使用十六进制 RTU 帧,而非 ASCII 帧 |
| 09-02 | Baud Rate Setting | 1 | 即 9600 baud,可在 TecoL510.cpp 中修改 |
| 09-03 | Stop Bit Selection | 0 | 1 位停止位 |
| 09-04 | Parity Selection | 0 | 无校验位 |
| 09-05 | Data Format Selection | 0 | 8 位数据位 |
也就是说总线格式为Modbus RTU,地址 0x01,9600-8-N-1。这些值与源码完全对应:TecoL510.cpp 构造函数中_baudrate = 9600; _parity = Uart::Parity::None;;VFDSpindle.cpp 中#ifndef VFD_RS485_ADDR / #define VFD_RS485_ADDR 0x01,数据位与停止位固定为Bits8 / Bits1。如果机器配置文件里额外定义了VFD_RS485_BAUD_RATE或VFD_RS485_PARITY(见 VFDSpindle.cpp 构造函数中的#ifdef分支),ESP32 侧会以这些宏为准,此时 VFD 端的 09-02 / 09-04 需要一并改成相同设置。
二、ESP32 侧机器配置:引脚定义与编译宏
README 的 Implementation details 一节给出了实测通过的引脚映射(RX 用 GPIO16、TX 用 GPIO26,RS485 模块虽然引出 RTS 但实测未使用):
#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这些宏的作用路径可以逐条在源码中验证:
- 引脚宏:
VFD_RS485_TXD_PIN / VFD_RS485_RXD_PIN / VFD_RS485_RTS_PIN在 VFDSpindle.cpp 的构造函数中被读入_txd_pin / _rxd_pin / _rts_pin,未定义时取-1;随后VFD::get_pins_and_settings()会对每个为-1的引脚逐条打印Undefined VFD_RS485_TXD_PIN等提示并拒绝初始化——三个引脚宏在 VFD 类下都是必填项。仓库中已有现成参照,例如 Root_Controller_Root_4_Lite_RS485.h 里同时定义了VFD_RS485_TXD_PIN GPIO_NUM_17、VFD_RS485_RXD_PIN GPIO_NUM_16、VFD_RS485_RTS_PIN GPIO_NUM_4。 - RPM 范围宏:
DEFAULT_SPINDLE_RPM_MAX / DEFAULT_SPINDLE_RPM_MIN是 G-code 设置$30(GCode/MaxS)与$31(GCode/MinS)的编译期默认值,定义见 SettingsDefinitions.cpp(rpm_min = new FloatSetting(..., "31", "GCode/MinS", ...)),兜底默认在 Defaults.h(Min 默认 0.0,Max 默认 1000.0)。运行时VFD::get_pins_and_settings()会用rpm_min->get()/rpm_max->get()覆盖固件内置的_min_rpm / _max_rpm,所以烧录后可直接改$30/$31,无需重新编译。 - 选择 L510 类型:还需要
#define SPINDLE_TYPE SpindleType::L510。SpindleType枚举包含NONE/PWM/RELAY/LASER/DAC/HUANYANG/BESC/_10V/H2A/YL620/L510,见 Spindle.h;Spindle::select()依据Spindle/Type扩展设置(运行时可用$Spindle/Type=L510切换)分发到对应实例,见 Spindle.cpp 中case SpindleType::L510: spindle = &l510;。 - 附加能力宏:
DEFAULT_SPINDLE_DELAY_SPINUP / DEFAULT_SPINDLE_DELAY_SPINDOWN控制启停延时,VFD_DEBUG_MODE / VFD_DEBUG_MODE2打开后可在串口看到每条 RS485 报文的十六进制内容,排查总线问题时非常有用(VFDSpindle.cpp 中大量#ifdef VFD_DEBUG_MODE分支)。
三、通信链路:VFD 基类的 RS485 任务模型
L510 类继承自VFD基类(class L510 : public VFD,见 TecoL510.h),所有与总线打交道的工作都由基类统一完成。VFDSpindle.cpp 中的关键常量:
const int VFD_RS485_UART_PORT = 2; // 固定使用 UART2 const int VFD_RS485_QUEUE_SIZE = 10; // 命令队列深度 const int RESPONSE_WAIT_MILLIS = 1000; // 单帧等待响应超时 1s const int VFD_RS485_POLL_RATE = 250; // 命令间隔 250ms初始化时(VFD::init())流程为:校验引脚 →setPins→ 按 9600-8-N-1begin()→setHalfDuplex()切换为 RS485 半双工模式(对应 Uart.h 的UART_MODE_RS485_HALF_DUPLEX)→ 创建队列xQueueCreate(VFD_RS485_QUEUE_SIZE, ...)并xTaskCreatePinnedToCore启动独立的vfd_cmd_task(优先级 1,栈 2048,绑定辅助核)。基类同时把is_reversable = true、use_delays = true置位,即 VFD 主轴视为可反转且使用启停延时。
vfd_cmd_task主循环的行为值得细读:
- 帧拼装:
next_cmd.msg[0] = VFD_RS485_ADDR(恒为 0x01);具体寄存器内容由 L510 的虚函数填入;发送前调用ModRTU_CRC()计算标准 Modbus CRC16(多项式 0xA001,初始值 0xFFFF)并追加 2 字节校验。 - 轮询节拍:无命令入队时按
get_current_rpm → get_current_direction → get_status_ok三档轮询,每档间隔 250ms。源码注释解释了原因:Modbus RTU 要求帧间静默 3.5 字符时间,9600 baud 下 250ms 余量充足。 - 重试与判活:单帧最多重试 5 次(
MAX_RETRIES = 5),成功后会校验"长度一致、地址回显一致、CRC 一致"三项条件。若最终超时:非关键命令仅报告Spindle RS485 Unresponsive并把轮询索引重置为初始化序列(pollidx = -1)重新自检;若命令标记为critical(运行作业中发启停、停机命令属关键命令),则触发mc_reset()并置ExecAlarm::SpindleControl报警,保证"主轴没停成功"不会带病继续走刀。 - 初始化自检:任务启动时(或上次初始化失败导致
_max_rpm == 0)先执行initialization_sequence(),L510 用它从 VFD 读取真实参数,见下一节。
另外注意get_pins_and_settings()中有一条互斥检查:若当前是激光模式($32开启),VFD 直接拒绝初始化并提示VFD spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart。
四、L510 寄存器命令逐条解析
VFD基类把每条通讯抽象为ModbusCommand { tx_length; rx_length; msg[16]; }加一个"响应解析器"回调(response_parser)。L510 覆写了全部抽象方法,逐条对应如下。
1. 启停与转向:direction_command(寄存器 0x2501)
M3/M4/M5 都会调用它(源码注释:The direction command is always called on M3,M4, and M5)。它写功能码 0x06 到寄存器 0x2501:
data.tx_length = 6; data.rx_length = 6; // 不含 CRC 的长度 data.msg[1] = 0x06; // WRITE data.msg[2] = 0x25; // Command ID 0x2501 data.msg[3] = 0x01; switch (mode) { case SpindleState::Disable: data.msg[5] = 0x00; break; // 停止 case SpindleState::Cw: data.msg[5] = 0x01; break; // 正转 case SpindleState::Ccw: data.msg[5] = 0x03; break; // 反转 }即一个整数值控制启停方向:0=停止,1=CW,3=CCW。反转对应 G-code 的 M4(前提是主轴被识别为可反转,基类对 VFD 恒定置is_reversable = true)。
2. 转速设定:set_speed_command(寄存器 0x2502)
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); data.msg[5] = uint8_t(freq & 0xFF);RPM 先经线性换算转为频率再写入 0x2502(输出频率指令寄存器):
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); // 再钳位到 [0, max_freq] }反向换算freq_to_rpm()用于把 VFD 上报的频率还原为 RPM。两个换算都以_max_rpm与_max_freq为斜率,而这两个量的来源正是初始化序列(见下)。
3. 初始化序列:读 0x0203 起 4 个寄存器
initialization_sequence(-1, data)构造一条读命令(功能码 0x03,起始 0x0203,读 4 个值,rx_length = 11),解析器从响应中取:
response[3..4]→ 寄存器 02-03(电机额定转速),写入_max_rpm;response[9..10]→ 寄存器 02-06(最大输出频率),按freq * 10换算(源码注释:VFD 内部以 xxx.x 存储,而指令寄存器按 frequency×100 计数),写入_max_freq。
随后串口打印L510 initialized: spindle max_rpm %d max_freq %d。这一步把 README 末尾"max frequency is currently hardcode"的说法部分地修正了:从当前源码看,_max_rpm和_max_freq在启动时是从 VFD 实读的(构造函数里的24000 / 6000 / 40000只是兜底初始值),但若初始化失败则会一直沿用兜底值并反复重试读参数。
4. 状态与故障:get_status_ok(寄存器 0x2520)
data.msg[2] = 0x25; data.msg[3] = 0x20; // 0x2520 = Get state解析器读回 1 个 16 位状态字,bit3 置位即判定为故障,打印L510 Fault detected并返回 false(基类随即把总线标记为 unresponsive 并回到初始化流程)。README 中"not sure how to detect and parse error messages"的遗留问题,在源码中的现状就是:只做了这一位级的故障总检测,具体故障代码并未进一步解析。
5. 实际转速回读:get_current_rpm(寄存器 0x2524)
读输出频率寄存器,再经freq_to_rpm()得到_sync_rpm。这是"实际转速同步"的数据来源(下一节)。get_current_direction()同样读 0x2520 取 bit1 判断转向,但源码里作者自己标注了// does this run ever??的存疑注释,说明该路径在轮询逻辑中实际很少被执行到。
五、RPM 同步机制:supports_actual_rpm 如何改变等待策略
L510 覆写了supports_actual_rpm() { return true; }。在基类VFD::set_state()中,这决定了主轴状态切换后的等待方式:
- 不支持实际转速的 VFD:只能"盲等"
$Spindle/Delay/SpinUp(Spindle/Delay/SpinUp,0–30 秒,见 SettingsDefinitions.cpp)或 SpinDown 延时; - L510 这类支持实际转速的:进入同步循环——把
_syncing置位(轮询任务随即每 250ms 只读 0x2524),每 500ms 比较一次_sync_rpm是否进入目标转速 ±2.5% 容差带(drpm = (_max_rpm - _min_rpm) / 40,不足 100 时取 100)。连续 20 次(约 10 秒)转速无变化则判定"达不到转速",触发Critical Spindle RS485 did not reach speed错误并复位报警;若等待期间发生安全门等事件(mc_dwell返回 false)则提前退出。
这意味着 L510 接入后,Grbl 不再依赖延时猜测主轴是否就绪,而是真正轮询变频器确认——这是选择 L510 驱动相对普通 PWM 主轴在安全性上的实质优势。同时safety_polling()返回 true 使空闲期也持续轮询状态字,VFD 掉线或故障时能尽快被发现。
六、运行行为小结与已知限制
结合 README 与源码,L510 驱动的完整运行链路是:
- G-code 的 M3/M4/M5 →
Spindle::sync()(先protocol_buffer_synchronize()排空规划器缓冲,确保主轴指令在加工程序点前生效,见 Spindle.cpp)→VFD::set_state(); set_state先set_mode()把启停/转向命令入队,再set_rpm()(内部应用$S倍率 override 并钳位到$30/$31范围)把频率命令入队;- RS485 任务按序发出 0x2501 与 0x2502 写帧,随后进入 0x2524 转速同步循环直至达到 ±2.5% 容差或超时报警。
需要注意的仓库现状(来自 README 原文与源码印证):
- 故障细节未解析:只有 0x2520 的 bit3 故障总检测,无具体故障码读取;
- 波特率等参数以编译宏为准:README 提示 09-02 波特率"can be changed in the TecoL510.cpp",实际 ESP32 侧优先读取机器文件中的
VFD_RS485_BAUD_RATE宏,两处需保持一致; - VFD 属于高压大功率设备:VFDSpindle.cpp 文件头明确警告 "VFDs are very dangerous. They have high voltages and are very powerful. Remove power before changing bits.",接线改线务必先断电;
- 与激光模式互斥:开启
$32(GCode/LaserMode)后 VFD 拒绝初始化。
排查建议:在机器头文件中定义VFD_DEBUG_MODE(或VFD_DEBUG_MODE2)重新编译,串口即可看到RS485 Tx:/RS485 Rx:十六进制帧与 "RS485 CRC check failed"、"Spindle RS485 Unresponsive" 等分级诊断信息,可快速定位是接线、地址、波特率还是解析环节的问题。
- 嵌入式
- 硬件开发
- 物联网
- 工业制造
【免费下载链接】Grbl_Esp32
A port of Grbl CNC Firmware for ESP32
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考