feat(motor): 引入运行禁止机制重构电机控制安全系统

- 添加 run_inhibit.h/cpp 模块作为全局运行闸门,统一管理所有停机/唤醒逻辑
- 移除 FOC 控制器中的 5 个相互引用的开关机函数(shut_down/resume 等)
- 将 nFAULT 硬件故障检测从仅上报改为运行门控制,连续采样故障时申请禁止位
- 改进电压检测逻辑,欠压判定现在通过 run_inhibit 统一执行停机动作
- 修正 PB2(nFAULT) 引脚配置为内部上拉输入,避免浮空误读导致系统锁死
- 在 CAN 状态帧中新增 RunInhibit 位图(字节 36-39),实时反映禁止运行的故障源
- 电流采样失效、过热故障现在通过禁止位管理而非直接操作驱动状态
- 校准函数增加运行许可检查,防止在停机状态下意外唤醒驱动
This commit is contained in:
cbb
2026-10-13 00:47:52 +08:00
parent 72cc10b40d
commit 86ca7666fa
11 changed files with 255 additions and 144 deletions
+16 -11
View File
@@ -18,6 +18,7 @@
#include "gd32c10x_gpio.h"
#include "initial.h"
#include "motor.h"
#include "run_inhibit.h"
#include "systick.h"
#include <cstdio>
#include <cstdlib>
@@ -766,7 +767,8 @@ void CAN_transmiter::update(void) {
mcu_temp = sampler.get_mcu_temp() * 100;
motor_temp = sampler.get_drv_temp() * 100;
Power_Voltage = sampler.get_vbus_voltage() * 1000;
MotorStatus = gpio_input_bit_get(GPIOB, GPIO_PIN_2) == RESET;
// MotorStatus 不在此读取:改由 health.cpp 的 1ms nFAULT 轮询写入,
// 那份判据同时决定是否停机,避免"上报的位"和"停机的依据"分家。
EEPROMStatus = flashEEP.EEPROMStatus;
Target_Control_Mode = FOC.control_mode;
controller_Mode = FOC.control_mode;
@@ -788,7 +790,9 @@ void CAN_transmiter::update(void) {
u8 CAN_transmiter::send_status_frame() {
// 打包 status 数据 - 只清零实际使用的 48 字节
// v0.74:字节 32~35 新增 InitStatus(初始化错误码位图,0=全部正常,
// 定义见 config.h INIT_ERR_*,含电流检测配平超限/无采样帧),36~47 预留
// 定义见 config.h INIT_ERR_*,含电流检测配平超限/无采样帧)
// 本版:字节 36~39 新增 RunInhibit(当前"禁止运行"来源位图,0=允许运行,
// 定义见 sys/run_inhibit.h InhibitSource)。DBC 尚未加信号,抓原始帧即可读。
memset(transmit_data, 0, 48);
pack_u16_to_bytes(transmit_data, 0, mcu_temp);
pack_u16_to_bytes(transmit_data, 2, motor_temp);
@@ -808,6 +812,7 @@ u8 CAN_transmiter::send_status_frame() {
transmit_data[30] = (test_u16 >> 8) & 0xFF;
transmit_data[31] = cpu_usage;
pack_u32_to_bytes(transmit_data, 32, (u32)init_error_flags);
pack_u32_to_bytes(transmit_data, 36, run_inhibit.sources());
// 使用节点 ID 构建发送 ID (高 16 位为节点 ID)
return CANFD_AsyncSend(build_can_id(CANFD_STATUS_ID), 48, transmit_data);
}
@@ -1111,15 +1116,11 @@ void CAN_transmiter::handle_node_message(can_receive_message_struct &current_mes
void CAN_transmiter::handle_control_command(can_receive_message_struct &current_message) {
// 控制帧布局:模式、电压限制、目标电流/速度/角度、三组 P 参数。
/* 收到非零控制模式即视为驱动意图:v2 板 EN 经 R17 10k 下拉、DRV8313
* 上电默认睡眠(上电配平后也保持睡眠态),控制路径里没有其他唤醒点,
* 不在此唤醒则所有闭环控制都落在 Hi-Z 桥臂上永远无效。
* 模式 0(drv_hold 主动锁止,A 相恒 HOLD_PWM_DUTY)不唤醒:上位机
* 上电先发模式 0 当"静止待机"时不至于意外通电锁止发热;驱动已在
* 唤醒态时模式 0 仍是锁止。幂等;关机态(过流/过压/过热)不唤醒,
* 恢复仍由 power_manage / resume_from_thermal 统一管理。 */
if (current_message.rx_data[0] != 0U && !FOC.is_shut_down) {
motor_resume();
// 这里不再直接碰驱动使能:唤醒功率级是 run_inhibit 闸门在 50us 控制任务里做的。
// 非零模式 = 上位机使能意图,撤销"未使能"这一禁止位;模式 0(静止待机/锁止)
// 不解除,保持上电默认睡眠。被禁止期间本函数照常收下参数,但控制函数不会被派发。
if (current_message.rx_data[0] != 0U) {
run_inhibit.release(INHIBIT_NOT_ENABLED);
}
FOC.control_mode = current_message.rx_data[0];
FOC.limit_voltage = float(unpack_bytes_to_u16(current_message.rx_data, 1)) / 1000;
@@ -1160,6 +1161,10 @@ void CAN_transmiter::handle_reset_command(can_receive_message_struct &current_me
u8 eigth_byte = current_message.rx_data[7];
if (first_byte & 0x01) {
// motReset = 撤销 nFAULT 这一禁止申请。之后能否真的重新运行由闸门看位图;
// 若故障源还在,1ms 的 nFAULT 轮询会立刻重新 request(),而驱动唤醒建立期
// (DRV_WAKE_SETTLE_50US)内输出保持 0,不会带故障出 torque。
run_inhibit.release(INHIBIT_DRV_NFAULT);
motor_reset();
testfloat_union.f = KTH7823.getcurrent_sensorangle();
}