在这里插入图片描述
以专业视角来看,基于 Arduino 生态(通常以 ESP32 或 STM32 为核心)的三模冗余电机控制与硬件急停状态机,是专为消防应急机器人等极端恶劣、高风险环境设计的底层安全与动力保障系统。该系统将容错控制与失效安全(Fail-Safe)机制深度结合,确保机器人在火场中具备极高的生存能力和绝对的安全底线。
以下是该系统的主要特点、应用场景及注意事项的详细解析:
一、 主要特点

  1. 异构多模态冗余控制架构
    系统采用“上位机 + 下位机 + 独立安全协处理器”的三层架构。上位机(如 Jetson Nano)负责复杂的火场 SLAM 建图与全局导航;Arduino 作为下位机专注于底层 BLDC 的 FOC 矢量控制与传感器数据采集;同时引入独立的硬件安全协处理器(或硬件看门狗电路),专门监控通信心跳与系统状态。当主系统死机或通信中断时,冗余模块可无缝接管,保障基本移动能力。
  2. 硬件级“失效安全”急停状态机
    系统摒弃了纯软件控制的脆弱性,设计了绕过 MCU 的硬件级安全防线。通过物理急停按钮、独立电路监控母线电压等方式,直接切断 MOS 管驱动或 BLDC 动力电源。同时,软件层面设计了严格的状态机(State Machine),一旦检测到剧烈碰撞、通信超时或任务堆栈溢出,立即触发硬件中断,强制进入“安全悬停”或“缓慢停止”模式。
  3. 高动态响应与极端环境适应性
    底层 BLDC 电机配合 FOC 算法,能提供平稳的低速爬坡力矩和毫秒级的紧急制动能力。在火场浓烟、高温导致视觉传感器失效时,系统可依靠 IMU、编码器及热成像进行非视觉导航,并通过精确的轨迹跟踪算法,在松软或充满瓦砾的地面上保持航向稳定。
  4. 多重抗干扰与热管理机制
    针对火场强电磁干扰(EMI)和高温环境,电路板进行三防漆涂覆防粉尘腐蚀,关键连接器锁紧防震动脱落。对 BLDC 启停大电流和 PWM 开关噪声,采用磁珠滤波、独立电源隔离及同步采样技术,防止主控复位或传感器数据跳变。
    二、 应用场景
  5. 火灾后浓烟环境侦察
    在充满高温和有毒烟雾的室内,视觉传感器极易失效。机器人依靠硬件级冗余和热成像/激光雷达,自主规划“贴墙走”或“沿通道中线走”策略,深入核心区寻找被困人员或定位火源,且能在通信微弱时保持基本移动。
  6. 地震/坍塌废墟搜索
    在建筑物倒塌形成的狭小空间内,机器人需自主穿行于断壁残垣之间。三模冗余系统确保其在遇到未知障碍或路径被堵死时,能触发局部重规划(如 DWA 算法)快速生成绕行轨迹,并具备应对瓦砾堆、台阶等复杂地形的全地形通过性。
  7. 危险品泄漏现场处置
    在化工厂爆炸等存在化学污染的区域,机器人自主接近泄漏源,利用机械臂关闭阀门或投放中和剂。冗余系统能规划最短且安全的路径,减少在污染区的暴露时间,并在发生异常时立即切断动力,防止引发二次爆炸。
    三、 需要注意的事项
  8. 硬件急停的绝对优先级
    软件层面的模糊调度或状态机可能存在死循环风险。对于“急停”、“碰撞”等最高安全等级的事件,必须设计硬线中断电路(如物理急停按钮直接切断动力电源),严禁仅依赖软件逻辑兜底。
  9. 通信保活与降级策略
    自主系统在未知环境中必然面临失效风险。必须设计心跳包机制,若上位机与下位机通信中断超过阈值,下位机应自动进入“安全悬停”模式。同时需设计降级策略,当主传感器(如 UWB 或视觉)失效时,自动切换备用模式(如纯里程计或沿墙探索)。
  10. 算力分配与实时性保障
    Arduino 平台计算能力有限,严禁在从控节点代码中加入复杂的延时或浮点运算。必须采用双核分工(如 ESP32 Core 0 专责电机 FOC 控制,Core 1 运行视觉算法),并确保控制周期严格稳定(建议 < 10ms),防止调度决策滞后。
  11. 能源管理与续航优化
    自主导航和 BLDC 驱动均为高功耗操作,火场救援任务持续时间长。在软件层面,需采用传感器按需唤醒策略(如静止时降低雷达扫描频率);在硬件层面,使用高倍率锂聚合物电池,并配备电源管理系统实时监控电压,防止过放损坏电池或引发火灾。
  12. 电磁兼容(EMC)与电源隔离
    BLDC 电机运行时会产生强烈的电磁干扰,极易导致 Arduino 复位。电机与控制器必须使用独立电源并严格共地,加装 1000μF 电解电容与 0.1μF 陶瓷电容做滤波,敏感信号线必须进行屏蔽处理。

在这里插入图片描述
1、三模冗余执行器表决与故障降级(同轴并联驱动)
适用场景:消防机器人驱动轮,三组BLDC通过齿轮箱耦合到同一输出轴,单组故障时仍能输出2/3扭矩,确保火场机动能力不中断。
核心逻辑:三组BLDC独立控制,每组自带编码器和电流传感器。系统实时健康检测(电流超限、编码器偏离中值),通过中值表决确定最终扭矩指令。单组故障自动隔离,双组故障降额运行,三组全故障触发应急模式。

#include <SimpleFOC.h>

// ==================== 三组BLDC电机 ====================
BLDCMotor motorA(7), motorB(7), motorC(7);
BLDCDriver3PWM drvA(2,3,4,5), drvB(6,7,8,9), drvC(10,11,12,13);
Encoder encA(14,15,2048), encB(16,17,2048), encC(18,19,2048);

// ==================== 电机组状态结构体 ====================
struct MotorGroup {
    BLDCMotor* motor;
    BLDCDriver3PWM* driver;
    Encoder* encoder;
    float actualTorque;
    float targetTorque;
    float currentDraw;
    bool healthy;
    unsigned long lastHeartbeat;
};

MotorGroup groups[3];

// ==================== 故障状态 ====================
struct FaultStatus {
    bool groupA_fault : 1;
    bool groupB_fault : 1;
    bool groupC_fault : 1;
} faultStatus = {false, false, false};

// ==================== 总扭矩需求 ====================
float totalTorqueDemand = 2.0;  // Nm

void setup() {
    Serial.begin(115200);

    // 初始化三组电机 (差异化PID增强鲁棒性)
    groups[0] = {&motorA, &drvA, &encA, 0, 0, 0, true, 0};
    groups[1] = {&motorB, &drvB, &encB, 0, 0, 0, true, 0};
    groups[2] = {&motorC, &drvC, &encC, 0, 0, 0, true, 0};

    for(int i = 0; i < 3; i++) {
        groups[i].motor->linkSensor(groups[i].encoder);
        groups[i].motor->linkDriver(groups[i].driver);
        groups[i].motor->controller = MotionControlType::torque;
        groups[i].motor->init();
        groups[i].motor->initFOC();
        groups[i].lastHeartbeat = millis();

        // 差异化PID参数 - 避免共因失效
        if(i == 0) groups[i].motor->PID_velocity.P = 0.3;
        else if(i == 1) groups[i].motor->PID_velocity.P = 0.28;
        else groups[i].motor->PID_velocity.P = 0.32;
    }
}

// ==================== 健康检测 ====================
void healthCheck() {
    for(int i = 0; i < 3; i++) {
        // 检测1:电流是否超限
        groups[i].currentDraw = analogRead(A0 + i) * 5.0 / 1023.0;
        if(groups[i].currentDraw > 3.0) {
            groups[i].healthy = false;
            Serial.print("Group "); Serial.print(i); Serial.println(" overcurrent!");
        }

        // 检测2:编码器是否与其他组一致
        float speeds[3];
        for(int j = 0; j < 3; j++) {
            speeds[j] = groups[j].motor->shaft_velocity;
        }
        float median = medianFilter(speeds, 3);
        if(abs(groups[i].motor->shaft_velocity - median) > 0.5) {
            groups[i].healthy = false;
            Serial.print("Group "); Serial.print(i); Serial.println(" encoder mismatch!");
        }
    }
}

// ==================== 中值滤波 ====================
float medianFilter(float arr[], int n) {
    for(int i = 0; i < n-1; i++) {
        for(int j = 0; j < n-i-1; j++) {
            if(arr[j] > arr[j+1]) {
                float temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    return arr[n/2];
}

void loop() {
    // 1. 健康监测
    healthCheck();

    // 2. 计算健康组数
    int healthyCount = 0;
    int healthyIndices[3];
    for(int i = 0; i < 3; i++) {
        if(groups[i].healthy) {
            healthyIndices[healthyCount++] = i;
        }
    }

    // 3. 故障分级处理
    float torquePerGroup = 0;
    if(healthyCount == 3) {
        // 三模模式:扭矩均分
        torquePerGroup = totalTorqueDemand / 3.0;
    } else if(healthyCount == 2) {
        // 双模降级:剩余两组各承担一半
        torquePerGroup = totalTorqueDemand / 2.0;
        Serial.println("WARNING: Degraded to dual-mode");
    } else if(healthyCount == 1) {
        // 单模模式:基本功能,准备安全停机
        torquePerGroup = totalTorqueDemand * 0.6;  // 降额60%
        Serial.println("CRITICAL: Single-mode operation");
    } else {
        // 应急模式:全部故障,安全停机
        Serial.println("EMERGENCY: All motors failed!");
        for(int i = 0; i < 3; i++) {
            groups[i].motor->move(0);
        }
        return;
    }

    // 4. 执行扭矩指令
    for(int i = 0; i < healthyCount; i++) {
        int idx = healthyIndices[i];
        groups[idx].motor->move(torquePerGroup);
        groups[idx].motor->loopFOC();
    }

    // 5. 故障组强制停机
    for(int i = 0; i < 3; i++) {
        if(!groups[i].healthy) {
            groups[i].motor->move(0);
        }
    }

    delay(20);
}

2、硬件急停状态机(独立中断响应 + 分级制动)
适用场景:消防应急机器人核心安全机制,急停按钮、限位开关等硬件信号触发纳秒级响应,独立于软件调度层,确保极端情况下绝对安全。
核心逻辑:硬件急停信号通过外部中断(FALLING触发)强行打断主循环,执行紧急刹车并进入安全状态。软件看门狗作为第二道防线,异常时硬件复位系统。状态机管理空闲→运行→急停→恢复的完整生命周期。

#include <SimpleFOC.h>
#include <avr/wdt.h>  // 看门狗定时器

// ==================== BLDC电机 ====================
BLDCMotor motor(7);
BLDCDriver3PWM driver(2,3,4,5);
Encoder encoder(18,19,2048);

// ==================== 急停引脚 ====================
#define EMERGENCY_BUTTON 2     // 常闭型,低电平触发
#define LIMIT_SWITCH 3         // 限位开关
#define ENABLE_PIN 8           // 驱动使能引脚

// ==================== 状态机枚举 ====================
enum RobotState {
    STATE_IDLE,      // 空闲
    STATE_RUNNING,   // 正常运行
    STATE_EMERGENCY, // 急停状态
    STATE_RECOVER    // 恢复中
};

RobotState currentState = STATE_IDLE;
RobotState previousState = STATE_IDLE;
volatile bool emergencyTriggered = false;

// ==================== 制动参数 ====================
const float BRAKE_FORCE = 0.3;   // 制动扭矩
const float RECOVER_DELAY = 2000; // 恢复延迟(ms)

void setup() {
    Serial.begin(115200);

    // 急停引脚配置(外部上拉)
    pinMode(EMERGENCY_BUTTON, INPUT_PULLUP);
    pinMode(LIMIT_SWITCH, INPUT_PULLUP);
    pinMode(ENABLE_PIN, OUTPUT);
    digitalWrite(ENABLE_PIN, HIGH);  // 默认使能

    // 外部中断:急停信号最高优先级
    attachInterrupt(digitalPinToInterrupt(EMERGENCY_BUTTON), 
                    emergencyISR, FALLING);

    // 初始化BLDC
    motor.linkSensor(&encoder);
    motor.linkDriver(&driver);
    motor.init();
    motor.initFOC();
    motor.controller = MotionControlType::velocity;

    // 启动看门狗(8秒超时)
    wdt_enable(WDTO_8S);
}

// ==================== 急停中断服务程序 ====================
void emergencyISR() {
    emergencyTriggered = true;
    // 硬急停:独立硬件通道切断驱动使能
    digitalWrite(ENABLE_PIN, LOW);
    // 软件层标记状态
    currentState = STATE_EMERGENCY;
}

// ==================== 限位检测(非中断)====================
bool checkLimitSwitch() {
    return digitalRead(LIMIT_SWITCH) == LOW;
}

void loop() {
    // 喂狗
    wdt_reset();

    // 1. 状态机主循环
    switch(currentState) {
        case STATE_IDLE:
            motor.move(0);
            break;

        case STATE_RUNNING:
            // 正常控制逻辑
            if(checkLimitSwitch()) {
                // 限位触发:分级制动
                softBrake();
                currentState = STATE_EMERGENCY;
            } else {
                motor.move(1.0);  // 正常运行速度
            }
            break;

        case STATE_EMERGENCY:
            // 急停状态:保持停机,禁止任何运动指令
            motor.move(0);
            digitalWrite(ENABLE_PIN, LOW);
            // 等待手动恢复
            break;

        case STATE_RECOVER:
            // 恢复过程:逐步释放制动
            if(millis() - recoverStartTime > RECOVER_DELAY) {
                digitalWrite(ENABLE_PIN, HIGH);
                currentState = STATE_RUNNING;
            }
            break;
    }

    motor.loopFOC();

    // 2. 急停恢复逻辑(通过串口指令)
    if(Serial.available()) {
        char cmd = Serial.read();
        if(cmd == 'R' && currentState == STATE_EMERGENCY) {
            // 手动确认恢复
            currentState = STATE_RECOVER;
            recoverStartTime = millis();
            emergencyTriggered = false;
        }
    }

    delay(10);
}

// ==================== 柔性制动 ====================
void softBrake() {
    // 分级制动:逐渐减小速度到0
    float currentSpeed = motor.shaft_velocity;
    while(abs(currentSpeed) > 0.01) {
        motor.move(-currentSpeed * BRAKE_FORCE);
        motor.loopFOC();
        currentSpeed *= 0.95;  // 指数衰减
        delay(5);
    }
    motor.move(0);
}

3、三模冗余通信 + 拜占庭协议表决(分布式指令融合)
适用场景:消防应急机器人的远程控制链路,三条独立通信通道(如5G、Mesh自组网、卫星),地面站通过“三取二”表决确认指令,防止单链路故障或恶意指令导致误动作。
核心逻辑:三套独立通信通道并行接收指令,每条消息附带CRC校验和时间戳。采用拜占庭容错协议——当三条通道中至少两条接收一致且有效时,才执行指令;否则进入安全模式。

#include <SoftwareSerial.h>
#include <CRC16.h>

// ==================== 三路独立通信 ====================
SoftwareSerial commA(4,5);   // 5G模块
SoftwareSerial commB(6,7);   // Mesh自组网
SoftwareSerial commC(8,9);   // UWB/卫星模块

// ==================== 通信通道定义 ====================
struct CommChannel {
    SoftwareSerial* port;
    bool valid;
    unsigned long lastHeartbeat;
    uint16_t crc;
};

CommChannel channels[3] = {
    {&commA, false, 0, 0},
    {&commB, false, 0, 0},
    {&commC, false, 0, 0}
};

// ==================== 指令包结构 ====================
struct CommandPacket {
    uint8_t command;     // 0x01=前进 0x02=停止 0x03=急停
    int16_t speed;       // 速度值
    uint16_t crc;        // CRC16校验
    uint32_t timestamp;  // 时间戳
};

CommandPacket receivedCmds[3];
CommandPacket finalCmd;

// ==================== 表决参数 ====================
const int TIMEOUT_MS = 2000;
const int REQUIRED_AGREEMENT = 2;  // 三取二

void setup() {
    Serial.begin(115200);
    commA.begin(4800);
    commB.begin(4800);
    commC.begin(4800);
}

// ==================== 单通道接收 ====================
bool receiveFromChannel(CommChannel* ch, CommandPacket* packet) {
    if(ch->port->available() >= sizeof(CommandPacket)) {
        ch->port->readBytes((uint8_t*)packet, sizeof(CommandPacket));
        ch->lastHeartbeat = millis();

        // CRC校验
        uint16_t calcCrc = CRC16::calculate((uint8_t*)packet, sizeof(CommandPacket) - 2);
        if(calcCrc == packet->crc) {
            ch->valid = true;
            return true;
        }
    }
    ch->valid = false;
    return false;
}

// ==================== 三通道并行接收 ====================
void receiveAllChannels() {
    receiveFromChannel(&channels[0], &receivedCmds[0]);
    receiveFromChannel(&channels[1], &receivedCmds[1]);
    receiveFromChannel(&channels[2], &receivedCmds[2]);
}

// ==================== 三取二表决 ====================
bool voteCommand(CommandPacket* output) {
    int voteCounts[3] = {0};  // 统计三种指令的得票数
    int voteIdx[3] = {-1};
    int uniqueCmds = 0;

    for(int i = 0; i < 3; i++) {
        if(!channels[i].valid) continue;

        // 检查是否已有该指令的计数
        int found = -1;
        for(int j = 0; j < uniqueCmds; j++) {
            if(voteIdx[j] == receivedCmds[i].command) {
                found = j;
                break;
            }
        }
        if(found == -1) {
            voteIdx[uniqueCmds] = receivedCmds[i].command;
            voteCounts[uniqueCmds] = 1;
            uniqueCmds++;
        } else {
            voteCounts[found]++;
        }
    }

    // 查找得票最高的指令
    int maxVotes = 0;
    int winnerIdx = -1;
    for(int i = 0; i < uniqueCmds; i++) {
        if(voteCounts[i] > maxVotes) {
            maxVotes = voteCounts[i];
            winnerIdx = i;
        }
    }

    // 三取二:至少2票一致
    if(maxVotes >= REQUIRED_AGREEMENT && winnerIdx != -1) {
        // 取第一个有效通道的对应指令
        for(int i = 0; i < 3; i++) {
            if(channels[i].valid && receivedCmds[i].command == voteIdx[winnerIdx]) {
                memcpy(output, &receivedCmds[i], sizeof(CommandPacket));
                return true;
            }
        }
    }

    return false;  // 无共识
}

// ==================== 通信健康监控 ====================
void checkCommHealth() {
    unsigned long now = millis();
    for(int i = 0; i < 3; i++) {
        if(now - channels[i].lastHeartbeat > TIMEOUT_MS) {
            channels[i].valid = false;
            Serial.print("Channel "); Serial.print(i); Serial.println(" timeout!");
        }
    }
}

void loop() {
    // 1. 并行接收三通道数据
    receiveAllChannels();

    // 2. 通信健康监控
    checkCommHealth();

    // 3. 拜占庭协议表决
    if(voteCommand(&finalCmd)) {
        // 执行表决后的指令
        if(finalCmd.command == 0x03) {  // 急停指令
            // 触发硬件急停
            digitalWrite(ENABLE_PIN, LOW);
            motor.move(0);
            Serial.println("EMERGENCY STOP via vote!");
        } else {
            // 执行常规指令
            motor.move(finalCmd.speed / 100.0);
        }
    } else {
        // 无共识:进入安全模式
        motor.move(0);
        Serial.println("No consensus! Entering safe mode.");
    }

    motor.loopFOC();
    delay(50);
}

要点解读
三模冗余(TMR)的核心是“多数表决 + 故障隔离”:通过三套独立硬件/软件系统并行运行,采用中值滤波或多数表决消除单点故障,故障系统自动隔离。关键设计包括差异化PID参数(避免共因失效)、CRC校验(检测数据传输错误)和拜占庭协议(防止恶意/错误指令)。分级策略为:三模全性能→双模降级→单模安全停机。

硬件急停必须独立于软件逻辑:软件级急停依赖MCU正常运行,存在死机风险。硬件急停采用独立中断通道(外部中断FALLING触发),串联在驱动使能端,实现纳秒级响应。看门狗作为第二道防线,程序异常时硬件复位系统。分级制动策略(预警→减速→急停)平衡安全与机械冲击。

状态机(FSM)是应急管理的骨架:无论控制逻辑多复杂,最终需落实到清晰的状态机,管理空闲→运行→急停→恢复的生命周期。状态机需配合previousState变量实现任务挂起与恢复,确保急停解除后能无缝回到原工作流程。

三模冗余通信防止“命令风暴”与“指令冲突”:消防现场存在强电磁干扰、信号衰减甚至恶意干扰,需三通道独立通信(如5G+Mesh+卫星)。关键指令(急停、喷射)通过三通道同时发送,地面站采用“三取二”表决确认指令后再执行,极大提高了通信可靠性。同时采用时间戳+超时机制防止指令粘滞。

BLDC FOC是安全急停精准执行的物理保障:急停时需在毫秒级完成减速→制动→锁轴,传统有刷电机响应滞后、制动距离长。SimpleFOC的扭矩闭环控制可精准控制制动扭矩,实现柔性制动(指数衰减)避免机械冲击。三模冗余执行器可实现扭矩均分→故障隔离→降额运行的完整容错链条。

在这里插入图片描述
4、三模冗余BLDC电机闭环驱动(主备判定+无缝接管)
适用场景:消防应急机器人的核心动力驱动,需保障电机控制链路的持续可靠性,避免单套驱动模块失效导致机器人停驶,适配火场高温、强电磁干扰等复杂环境下的持续作业需求,核心目标是实现三套驱动链路实时监测、主模块优先控制、故障时备模块无扰接管,确保动力输出不中断。
核心逻辑:三套独立的BLDC驱动单元(驱动芯片+编码器)并行连接至主控,主控通过SPI/ADC实时采集三套模块的运行状态(电流、转速反馈、电源电压),采用“多数表决+健康阈值”机制判定主模块;主模块正常运行时,统一下发控制指令至三套驱动单元;当主模块出现电流过载、转速失稳、通信超时等故障时,立即触发备模块接管,同步切换控制指令,切换延迟控制在10ms以内,确保电机转速波动≤5%,满足消防机器人持续稳定移动需求。

// 三模冗余BLDC电机闭环驱动:主程序(基于Arduino + SimpleFOC库)
#include <Arduino.h>
#include <SimpleFOC.h>

// 三模冗余核心配置(可按实际硬件调整)
#define NUM_REDUNDANT_MODULES 3   // 三模冗余模块数量
#define MOTOR_BASE_FREQ 50000      // 电机控制基准频率(Hz)
#define MOTOR_TARGET_SPEED 3000    // 目标转速(RPM)
#define HEALTH_CHECK_TIMEOUT 500   // 健康检查超时阈值(ms)

// 三套冗余模块的硬件引脚定义(电源检测ADC引脚、驱动使能引脚、状态指示LED)
const int redundantConfig[NUM_REDUNDANT_MODULES][7] = {
  // 模块0:电源检测ADC、驱动使能、状态LED、BLDC正/负/霍尔A/B
  {A0, 2, 3, 4, 5, 6, 7},
  // 模块1:电源检测ADC、驱动使能、状态LED、BLDC正/负/霍尔A/B
  {A1, 8, 9, 10, 11, 12, 13},
  // 模块2:电源检测ADC、驱动使能、状态LED、BLDC正/负/霍尔A/B
  {A2, 14, 15, 16, 17, 18, 19}
};

// 三模冗余状态结构体
struct RedundantModuleState {
  BLDCMotor motor;          // BLDC电机对象
  bool isHealthy;            // 模块健康状态
  unsigned long lastHealthCheckTime; // 最后健康检查时间
  bool isActive;             // 是否为主控模块
  int moduleId;              // 模块编号
  float supplyVoltage;        // 供电电压(V)
  float currentFeedback;      // 电流反馈(A)
};

// 全局状态变量
RedundantModuleState redundantModules[NUM_REDUNDANT_MODULES];
int activeModuleId = 0;        // 当前主控模块ID
unsigned long lastActiveSwitchTime = 0;

// 初始化三模冗余模块
void initRedundantModules() {
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    redundantModules[i].moduleId = i;
    redundantModules[i].isHealthy = false;
    redundantModules[i].isActive = (i == activeModuleId);
    redundantModules[i].lastHealthCheckTime = 0;
    redundantModules[i].supplyVoltage = 0.0f;
    redundantModules[i].currentFeedback = 0.0f;

    // 初始化电机对象
    redundantModules[i].motor.linkDriver(new BLDCDriver3PWM(
      redundantConfig[i][3], // PWM A
      redundantConfig[i][4], // PWM B
      redundantConfig[i][5]  // PWM C
    ));
    redundantModules[i].motor.linkSensor(new EncoderAnalog(
      redundantConfig[i][6], // 霍尔A
      redundantConfig[i][7]  // 霍尔B
    ));
    
    // 配置电机参数
    redundantModules[i].motor.PID_velocity.P = 0.1f;
    redundantModules[i].motor.PID_velocity.I = 2.0f;
    redundantModules[i].motor.PID_velocity.D = 0.0f;
    redundantModules[i].motor.PID_velocity.limit = 10.0f;
    redundantModules[i].motor.phase_in_polar = _120; // 120°相位
    
    // 初始化电机
    redundantModules[i].motor.init();
    redundantModules[i].motor.initFOC();
    
    // 点亮模块初始状态LED(初始化中)
    pinMode(redundantConfig[i][2], OUTPUT);
    digitalWrite(redundantConfig[i][2], HIGH);
    delay(200);
    digitalWrite(redundantConfig[i][2], LOW);
  }
  Serial.println("三模冗余BLDC模块初始化完成");
}

// 单模块健康检查(检测电源、电流、通信)
bool checkModuleHealth(int moduleId) {
  int adcPin = redundantConfig[moduleId][0];
  // 电源检测:计算ADC电压(按实际分压电阻调整系数,示例按3.3V参考,分压比10:1)
  float rawVoltage = analogRead(adcPin) * (3.3f / 1023.0f) * 10.0f;
  redundantModules[moduleId].supplyVoltage = rawVoltage;
  
  // 电源电压阈值检测:消防机器人电池正常工作范围24V±10%(示例按24V系统)
  if (rawVoltage < 21.6f || rawVoltage > 26.4f) {
    return false;
  }
  
  // 电机运行反馈检测:若模块激活,检查转速反馈是否正常
  if (redundantModules[moduleId].isActive) {
    float currentSpeed = redundantModules[moduleId].motor.shaft_velocity;
    if (abs(currentSpeed) < 100) { // 转速突降判定故障
      return false;
    }
  }
  
  // 通信有效性检测:模块能正常响应FOC初始化
  if (!redundantModules[moduleId].motor.driver->initialized) {
    return false;
  }
  
  redundantModules[moduleId].lastHealthCheckTime = millis();
  return true;
}

// 主备模块判定(多数表决+健康排序)
void determineActiveModule() {
  int healthyCount = 0;
  int healthyModules[NUM_REDUNDANT_MODULES];
  int modulePriority[NUM_REDUNDANT_MODULES];
  
  // 统计健康模块数量,记录健康模块ID
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    bool health = checkModuleHealth(i);
    redundantModules[i].isHealthy = health;
    if (health) {
      healthyModules[healthyCount] = i;
      modulePriority[healthyCount] = i; // 优先级按模块ID顺序(可按实际调整)
      healthyCount++;
    } else {
      // 故障模块关闭驱动,点亮故障LED
      digitalWrite(redundantConfig[i][1], LOW); // 关闭驱动使能
      digitalWrite(redundantConfig[i][2], HIGH); // 点亮故障灯
    }
  }
  
  // 多数表决逻辑:至少2个模块健康才维持系统运行
  if (healthyCount < 2) {
    // 健康模块不足,触发全系统急停(交由硬件急停状态机处理)
    triggerEmergencyStop();
    return;
  }
  
  // 多数表决优先:若原主模块健康,维持其主控;否则选优先级最高的健康模块
  bool originalActiveHealthy = false;
  for (int i = 0; i < healthyCount; i++) {
    if (healthyModules[i] == activeModuleId) {
      originalActiveHealthy = true;
      break;
    }
  }
  
  if (!originalActiveHealthy) {
    // 原主模块故障,选择优先级最高的健康模块为主控
    activeModuleId = healthyModules[0];
    lastActiveSwitchTime = millis();
    Serial.print("主控模块切换:模块" + String(activeModuleId) + " 接管");
  }
  
  // 更新模块激活状态,开启主控模块驱动,关闭其他模块驱动
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    if (i == activeModuleId) {
      redundantModules[i].isActive = true;
      digitalWrite(redundantConfig[i][1], HIGH); // 开启驱动使能
      digitalWrite(redundantConfig[i][2], LOW);  // 熄灭故障灯,点亮工作灯
    } else {
      redundantModules[i].isActive = false;
      digitalWrite(redundantConfig[i][1], LOW); // 关闭非主控模块驱动
      digitalWrite(redundantConfig[i][2], HIGH); // 非主控模块维持待机灯
    }
  }
}

// 控制主模块执行目标转速
void controlActiveModule(float targetSpeed) {
  if (redundantModules[activeModuleId].isHealthy && redundantModules[activeModuleId].isActive) {
    redundantModules[activeModuleId].motor.target = targetSpeed;
    redundantModules[activeModuleId].motor.loopFOC();
    redundantModules[activeModuleId].motor.move(targetSpeed);
  }
}

// 触发应急停止(预留接口,与硬件急停联动)
void triggerEmergencyStop() {
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    // 关闭所有模块的驱动使能
    digitalWrite(redundantConfig[i][1], LOW);
    redundantModules[i].motor.target = 0.0f;
    redundantModules[i].motor.loopFOC();
    redundantModules[i].motor.move(0.0f);
  }
  Serial.println("三模冗余系统触发应急停止");
}

// 硬件急停状态机联动(示例接口,详细实现见案例2)
void linkHardwareEmergencyStop() {
  // 此处预留与硬件急停状态机的联动接口,实际接入急停信号中断
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  initRedundantModules();
  // 初始化硬件急停接口(案例2详细实现)
  initHardwareEmergencyStateMachine();
  linkHardwareEmergencyStop();
}

void loop() {
  // 1. 主备模块判定
  determineActiveModule();
  // 2. 控制主模块执行目标转速
  controlActiveModule(MOTOR_TARGET_SPEED);
  // 3. 硬件急停状态监测(联动急停信号)
  monitorHardwareEmergencyState();
  delay(10);
}

代码逻辑说明:
三模块独立驱动:三套BLDC驱动链路完全独立,主控通过统一接口分别管理,避免单模块故障影响其他模块,保障动力系统的物理冗余。
健康监测闭环:通过电源电压检测、转速反馈校验、通信状态验证,实时掌握每个模块的健康状态,为模块切换提供数据依据,适配火场电压波动、电磁干扰等复杂环境。
多数表决切换:采用“健康模块≥2才维持运行”的多数表决逻辑,原主模块故障时,自动切换至优先级最高的健康模块,切换过程控制指令同步下发,确保电机转速无明显波动,实现无扰接管,保障消防机器人持续作业。

5、硬件急停状态机(独立于主控,断电可触发)
适用场景:消防应急机器人的突发应急处置,当机器人遭遇障碍物碰撞、电机失控、火场环境突变等紧急情况时,需通过独立硬件链路实现瞬时切断电机动力,即使主控系统宕机、供电中断,急停功能仍能生效,核心目标是构建不依赖主控、断电可触发、复位可控的硬件急停闭环,保障人员与设备安全。
核心逻辑:采用独立于Arduino主控的硬件状态机电路,核心由施密特触发器、继电器、NPN晶体管等元件组成,急停按键、复位按键、状态指示灯直接接入硬件电路,不经过主控芯片;急停触发时,通过硬件电路切断BLDC驱动芯片的电源或使能信号,瞬时停止电机;主控仅负责状态监测与辅助复位,不参与急停触发链路,确保急停的绝对可靠。

// 硬件急停状态机:主控联动程序(核心为硬件状态监测与复位逻辑)
#include <Arduino.h>

// 硬件急停状态机引脚配置(硬件电路与主控连接的监测引脚)
#define EMERGENCY_STOP_INPUT 2  // 急停触发信号输入(低电平有效,来自硬件电路)
#define EMERGENCY_RESET_INPUT 3 // 复位按键输入(高电平触发,机械按键)
#define EMERGENCY_STATUS_LED 4   // 急停状态指示灯(高电平点亮:红灯=急停,绿灯=正常)
#define RESET_STATUS_LED 5       // 复位状态指示灯(高电平点亮,复位过程闪烁)

// 急停状态机状态枚举(对应硬件状态)
typedef enum {
  EMERGENCY_STATE_NORMAL = 0,   // 正常待机状态
  EMERGENCY_STATE_TRIGGERED = 1, // 急停触发状态
  EMERGENCY_STATE_RESETTING = 2,  // 复位处理状态
  EMERGENCY_STATE_FAULT = 3      // 硬件故障状态
} EmergencyState;

// 全局急停状态变量
volatile EmergencyState currentEmergencyState = EMERGENCY_STATE_NORMAL;
volatile bool resetInProgress = false;
volatile unsigned long resetStartTime = 0;

// 初始化硬件急停状态机(配置引脚模式、中断)
void initHardwareEmergencyStateMachine() {
  // 急停输入引脚:配置为上拉输入(硬件触发时为低电平)
  pinMode(EMERGENCY_STOP_INPUT, INPUT_PULLUP);
  // 复位按键引脚:配置为下拉输入(机械按键按下时为高电平)
  pinMode(EMERGENCY_RESET_INPUT, INPUT_PULLDOWN);
  // 状态指示灯引脚:配置为输出
  pinMode(EMERGENCY_STATUS_LED, OUTPUT);
  pinMode(RESET_STATUS_LED, OUTPUT);
  
  // 初始化指示灯状态:正常状态绿灯常亮
  digitalWrite(EMERGENCY_STATUS_LED, LOW); // 初始熄灭,后续按状态点亮
  digitalWrite(RESET_STATUS_LED, LOW);
  
  // 配置急停信号中断(下降沿触发,确保急停触发时立即响应)
  attachInterrupt(digitalPinToInterrupt(EMERGENCY_STOP_INPUT), emergencyStopTriggered, FALLING);
  
  Serial.println("硬件急停状态机初始化完成");
}

// 急停触发中断服务函数(独立于主循环,响应速度最快)
void emergencyStopTriggered() {
  currentEmergencyState = EMERGENCY_STATE_TRIGGERED;
  resetInProgress = false;
  Serial.println("硬件急停触发!状态切换为:TRIGGERED");
}

// 监测急停状态机状态(主循环调用,同步硬件状态)
void monitorHardwareEmergencyState() {
  // 1. 检测复位按键状态
  bool resetPressed = digitalRead(EMERGENCY_RESET_INPUT) == HIGH;
  
  switch (currentEmergencyState) {
    case EMERGENCY_STATE_NORMAL:
      // 正常状态:绿灯常亮,急停输入为高电平
      digitalWrite(EMERGENCY_STATUS_LED, LOW); // 熄灭红灯,点亮绿灯(假设双色LED,需按电路调整)
      digitalWrite(RESET_STATUS_LED, LOW);
      
      // 持续监测急停信号,避免抖动误触发(硬件电路已做滤波,软件二次确认)
      if (digitalRead(EMERGENCY_STOP_INPUT) == LOW) {
        // 去抖动:延时10ms再次检测
        delay(10);
        if (digitalRead(EMERGENCY_STOP_INPUT) == LOW) {
          emergencyStopTriggered();
        }
      }
      break;
      
    case EMERGENCY_STATE_TRIGGERED:
      // 急停状态:红灯常亮,输出急停信号至三模冗余系统
      digitalWrite(EMERGENCY_STATUS_LED, HIGH); // 点亮红灯
      digitalWrite(RESET_STATUS_LED, LOW);
      // 调用急停处理函数,切断电机动力
      triggerEmergencyStopFromStateMachine();
      
      // 检测复位按键是否按下
      if (resetPressed && !resetInProgress) {
        resetInProgress = true;
        resetStartTime = millis();
        currentEmergencyState = EMERGENCY_STATE_RESETTING;
        Serial.println("检测到复位按键按下,进入复位处理状态");
      }
      break;
      
    case EMERGENCY_STATE_RESETTING:
      // 复位处理状态:红灯闪烁,复位指示灯闪烁
      digitalWrite(EMERGENCY_STATUS_LED, !digitalRead(EMERGENCY_STATUS_LED));
      digitalWrite(RESET_STATUS_LED, !digitalRead(RESET_STATUS_LED));
      
      // 复位保持时间:消防应急场景要求复位保持≥3秒,防止误复位
      if (millis() - resetStartTime >= 3000) {
        // 复位完成,解除急停,切换至正常状态
        digitalWrite(EMERGENCY_STATUS_LED, LOW);
        digitalWrite(RESET_STATUS_LED, LOW);
        currentEmergencyState = EMERGENCY_STATE_NORMAL;
        resetInProgress = false;
        Serial.println("急停复位完成,切换至正常状态");
        // 通知三模冗余系统解除急停,恢复电机使能
        releaseEmergencyStop();
      }
      // 复位期间保持复位按键按下,若松开则维持复位状态直至时间达标
      if (!resetPressed && (millis() - resetStartTime < 3000)) {
        resetInProgress = false;
        currentEmergencyState = EMERGENCY_STATE_TRIGGERED;
      }
      break;
      
    case EMERGENCY_STATE_FAULT:
      // 硬件故障状态:红灯快闪,故障指示灯点亮(需人工排查)
      digitalWrite(EMERGENCY_STATUS_LED, digitalRead(EMERGENCY_STATUS_LED) ^ 1);
      digitalWrite(RESET_STATUS_LED, HIGH);
      // 持续检测硬件故障是否恢复(如急停信号回路短路、断路)
      if (digitalRead(EMERGENCY_STOP_INPUT) == HIGH && !resetPressed) {
        currentEmergencyState = EMERGENCY_STATE_NORMAL;
        digitalWrite(EMERGENCY_STATUS_LED, LOW);
        digitalWrite(RESET_STATUS_LED, LOW);
      }
      break;
  }
}

// 从状态机触发急停(联动三模冗余系统,切断电机动力)
void triggerEmergencyStopFromStateMachine() {
  // 1. 切断三模冗余系统的电机使能信号(直接控制硬件驱动使能引脚)
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    digitalWrite(redundantConfig[i][1], LOW); // 关闭所有模块驱动使能
  }
  // 2. 通过硬件电路切断电机电源(需额外硬件继电器,此处为逻辑控制)
  // digitalWrite(POWER_RELAY_PIN, LOW);
  // 3. 通知其他系统模块进入急停模式
  Serial.println("硬件急停状态机触发:切断所有电机动力");
}

// 解除急停,恢复电机使能
void releaseEmergencyStop() {
  // 检测三模冗余模块健康状态,选择健康模块恢复使能
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    if (redundantModules[i].isHealthy) {
      digitalWrite(redundantConfig[i][1], HIGH); // 恢复健康模块驱动使能
      activeModuleId = i;
      break;
    }
  }
  Serial.println("急停解除:恢复主模块电机使能");
}

// 复位按键中断服务函数(可选,增强复位响应速度)
void resetButtonPressed() {
  if (currentEmergencyState == EMERGENCY_STATE_TRIGGERED && !resetInProgress) {
    resetInProgress = true;
    resetStartTime = millis();
    currentEmergencyState = EMERGENCY_STATE_RESETTING;
    Serial.println("复位按键中断触发,进入复位处理状态");
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  initHardwareEmergencyStateMachine();
  // 配置复位按键中断(可选,高电平触发)
  attachInterrupt(digitalPinToInterrupt(EMERGENCY_RESET_INPUT), resetButtonPressed, RISING);
}

void loop() {
  monitorHardwareEmergencyState();
  delay(10);
}

代码逻辑说明:
硬件独立触发:急停信号直接接入硬件电路,通过中断服务函数触发,不依赖主控主循环,即使主控卡死,硬件电路仍能切断电机动力,确保急停的绝对可靠,适配火场主控宕机极端场景。
多状态闭环管理:定义正常、触发、复位、故障四类状态,覆盖急停全生命周期,通过指示灯直观反馈状态,复位过程强制保持3秒,避免误操作导致突然恢复动力,保障复位安全。
主控联动设计:主控仅负责状态监测与复位流程控制,不参与急停触发链路,急停触发时通过硬件电路直接切断电机驱动,确保触发响应速度在毫秒级,满足消防应急快速响应需求。

6、三模冗余+硬件急停联动控制(消防机器人完整动力核心)
适用场景:消防应急机器人的完整动力控制,融合三模冗余电机驱动与硬件急停状态机,适配火场搜救、危化品区域巡检等高危场景,核心目标是实现三冗余驱动的可靠运行+硬件急停的快速响应+故障时的自动协同处置,构建动力与安全一体化的核心控制逻辑。
核心逻辑:以三模冗余驱动为基础,硬件急停为安全保障,实现二者的深度联动——急停未触发时,三模冗余系统自主运行,保障动力输出;急停触发时,硬件急停状态机切断所有电机动力,同时三模冗余系统接收急停信号,停止控制指令输出;故障解除后,通过硬件复位与软件复位协同,恢复三模冗余系统的正常运行,同时更新主模块状态,确保动力系统持续稳定。

// 三模冗余+硬件急停联动控制:消防应急机器人完整核心程序
#include <Arduino.h>
#include <SimpleFOC.h>

// 全局配置(与案例1、案例2保持一致,确保联动兼容)
#define NUM_REDUNDANT_MODULES 3
#define MOTOR_TARGET_SPEED 3000
#define EMERGENCY_STOP_INPUT 2
#define EMERGENCY_RESET_INPUT 3
#define EMERGENCY_STATUS_LED 4
#define RESET_STATUS_LED 5

// 导入案例1、案例2的模块函数(此处为简化,直接复用核心变量与逻辑)
// 复用案例1的三模冗余状态结构体与硬件配置
struct RedundantModuleState {
  BLDCMotor motor;
  bool isHealthy;
  unsigned long lastHealthCheckTime;
  bool isActive;
  int moduleId;
  float supplyVoltage;
  float currentFeedback;
};

// 复用案例2的急停状态枚举
typedef enum {
  EMERGENCY_STATE_NORMAL = 0,
  EMERGENCY_STATE_TRIGGERED = 1,
  EMERGENCY_STATE_RESETTING = 2,
  EMERGENCY_STATE_FAULT = 3
} EmergencyState;

// 全局变量(整合案例1与案例2的状态)
RedundantModuleState redundantModules[NUM_REDUNDANT_MODULES];
int activeModuleId = 0;
volatile EmergencyState currentEmergencyState = EMERGENCY_STATE_NORMAL;
volatile bool resetInProgress = false;
volatile unsigned long resetStartTime = 0;

// 硬件引脚配置(与案例1保持一致)
const int redundantConfig[NUM_REDUNDANT_MODULES][7] = {
  {A0, 2, 3, 4, 5, 6, 7},
  {A1, 8, 9, 10, 11, 12, 13},
  {A2, 14, 15, 16, 17, 18, 19}
};

// 联动核心函数声明(整合案例1、案例2的核心逻辑)
void initRedundantModules();
bool checkModuleHealth(int moduleId);
void determineActiveModule();
void controlActiveModule(float targetSpeed);
void initHardwareEmergencyStateMachine();
void emergencyStopTriggered();
void monitorHardwareEmergencyState();
void triggerEmergencyStopFromStateMachine();
void releaseEmergencyStop();

// 联动控制核心:急停与冗余系统的协同处理
void handleRedundancyAndEmergencyLinkage() {
  switch (currentEmergencyState) {
    case EMERGENCY_STATE_NORMAL:
      // 正常状态:三模冗余系统自主运行
      determineActiveModule();
      controlActiveModule(MOTOR_TARGET_SPEED);
      break;
      
    case EMERGENCY_STATE_TRIGGERED:
      // 急停状态:三模冗余系统配合急停,停止所有动力
      for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
        // 停止所有模块的电机控制
        redundantModules[i].motor.target = 0.0f;
        redundantModules[i].motor.loopFOC();
        redundantModules[i].motor.move(0.0f);
        // 关闭驱动使能
        digitalWrite(redundantConfig[i][1], LOW);
      }
      Serial.println("急停联动:三模冗余系统停止所有动力输出");
      break;
      
    case EMERGENCY_STATE_RESETTING:
      // 复位处理状态:保持电机停止,等待复位完成
      for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
        redundantModules[i].motor.target = 0.0f;
        redundantModules[i].motor.loopFOC();
        redundantModules[i].motor.move(0.0f);
      }
      // 复位完成后,恢复三模冗余系统运行
      if (millis() - resetStartTime >= 3000) {
        // 重新判定主模块,恢复使能
        determineActiveModule();
        for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
          if (i == activeModuleId && redundantModules[i].isHealthy) {
            digitalWrite(redundantConfig[i][1], HIGH);
          }
        }
        Serial.println("复位联动:三模冗余系统恢复运行");
      }
      break;
      
    case EMERGENCY_STATE_FAULT:
      // 硬件故障状态:三模冗余系统进入安全停机模式
      for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
        redundantModules[i].motor.target = 0.0f;
        redundantModules[i].motor.loopFOC();
        redundantModules[i].motor.move(0.0f);
        digitalWrite(redundantConfig[i][1], LOW);
      }
      Serial.println("故障联动:三模冗余系统进入安全停机");
      break;
  }
}

// 消防机器人工况切换逻辑(适配不同火场作业场景)
void switchRobotWorkingMode(int mode) {
  if (currentEmergencyState != EMERGENCY_STATE_NORMAL) {
    Serial.println("急停未解除,无法切换工况!");
    return;
  }
  
  float targetSpeed = 0.0f;
  switch (mode) {
    case 1: // 搜救模式:中低速,高稳定性
      targetSpeed = 2000.0f;
      Serial.println("切换至搜救模式,目标转速2000RPM");
      break;
    case 2: // 巡检模式:低速,高精度转向
      targetSpeed = 1200.0f;
      Serial.println("切换至巡检模式,目标转速1200RPM");
      break;
    case 3: // 撤离模式:高速,快速脱离
      targetSpeed = 3500.0f;
      Serial.println("切换至撤离模式,目标转速3500RPM");
      break;
    default:
      Serial.println("无效工况模式!");
      return;
  }
  
  // 更新目标转速,由三模冗余系统执行
  MOTOR_TARGET_SPEED = targetSpeed;
}

// 消防机器人应急传感器监测(联动急停与冗余系统)
void monitorFireEmergencySensors() {
  // 示例:监测机器人温度传感器(超过阈值触发急停)
  // 实际需接入温度传感器ADC引脚,此处为逻辑示意
  int tempSensorPin = A3;
  float robotTemp = analogRead(tempSensorPin) * 0.1f; // 模拟温度值(℃)
  
  // 消防机器人高温阈值(示例:80℃)
  if (robotTemp > 80.0f && currentEmergencyState == EMERGENCY_STATE_NORMAL) {
    // 温度超阈值,触发急停(硬件急停电路直接触发,此处为软件辅助)
    Serial.println("机器人温度超阈值,触发应急急停");
    emergencyStopTriggered();
  }
  
  // 监测机器人姿态传感器(倾覆判定,触发急停)
  // 示例:姿态角度超过60°判定倾覆,触发急停
  float tiltAngle = 0.0f; // 实际需从姿态传感器读取
  if (tiltAngle > 60.0f && currentEmergencyState == EMERGENCY_STATE_NORMAL) {
    Serial.println("机器人倾覆,触发应急急停");
    emergencyStopTriggered();
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  
  // 初始化三模冗余模块
  initRedundantModules();
  // 初始化硬件急停状态机
  initHardwareEmergencyStateMachine();
  
  Serial.println("消防应急机器人:三模冗余+硬件急停联动系统初始化完成");
}

void loop() {
  // 1. 监测消防应急传感器
  monitorFireEmergencySensors();
  // 2. 监测硬件急停状态机状态
  monitorHardwareEmergencyState();
  // 3. 执行三模冗余与急停的联动控制
  handleRedundancyAndEmergencyLinkage();
  
  delay(10);
}

// 以下是案例1、案例2核心函数的实现(为保持代码完整,此处重新实现核心逻辑,实际可复用)
void initRedundantModules() {
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    redundantModules[i].moduleId = i;
    redundantModules[i].isHealthy = false;
    redundantModules[i].isActive = (i == activeModuleId);
    redundantModules[i].lastHealthCheckTime = 0;
    redundantModules[i].supplyVoltage = 0.0f;
    redundantModules[i].currentFeedback = 0.0f;

    redundantModules[i].motor.linkDriver(new BLDCDriver3PWM(
      redundantConfig[i][3], redundantConfig[i][4], redundantConfig[i][5]
    ));
    redundantModules[i].motor.linkSensor(new EncoderAnalog(
      redundantConfig[i][6], redundantConfig[i][7]
    ));

    redundantModules[i].motor.PID_velocity.P = 0.1f;
    redundantModules[i].motor.PID_velocity.I = 2.0f;
    redundantModules[i].motor.PID_velocity.D = 0.0f;
    redundantModules[i].motor.PID_velocity.limit = 10.0f;
    redundantModules[i].motor.phase_in_polar = _120;

    redundantModules[i].motor.init();
    redundantModules[i].motor.initFOC();

    pinMode(redundantConfig[i][2], OUTPUT);
    digitalWrite(redundantConfig[i][2], HIGH);
    delay(200);
    digitalWrite(redundantConfig[i][2], LOW);
  }
  Serial.println("三模冗余BLDC模块初始化完成");
}

bool checkModuleHealth(int moduleId) {
  int adcPin = redundantConfig[moduleId][0];
  float rawVoltage = analogRead(adcPin) * (3.3f / 1023.0f) * 10.0f;
  redundantModules[moduleId].supplyVoltage = rawVoltage;

  if (rawVoltage < 21.6f || rawVoltage > 26.4f) {
    return false;
  }

  if (redundantModules[moduleId].isActive) {
    float currentSpeed = redundantModules[moduleId].motor.shaft_velocity;
    if (abs(currentSpeed) < 100) {
      return false;
    }
  }

  if (!redundantModules[moduleId].motor.driver->initialized) {
    return false;
  }

  redundantModules[moduleId].lastHealthCheckTime = millis();
  return true;
}

void determineActiveModule() {
  int healthyCount = 0;
  int healthyModules[NUM_REDUNDANT_MODULES];
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    bool health = checkModuleHealth(i);
    redundantModules[i].isHealthy = health;
    if (health) {
      healthyModules[healthyCount] = i;
      healthyCount++;
    } else {
      digitalWrite(redundantConfig[i][1], LOW);
      digitalWrite(redundantConfig[i][2], HIGH);
    }
  }

  if (healthyCount < 2) {
    emergencyStopTriggered();
    return;
  }

  bool originalActiveHealthy = false;
  for (int i = 0; i < healthyCount; i++) {
    if (healthyModules[i] == activeModuleId) {
      originalActiveHealthy = true;
      break;
    }
  }

  if (!originalActiveHealthy) {
    activeModuleId = healthyModules[0];
    lastActiveSwitchTime = millis();
    Serial.print("主控模块切换:模块" + String(activeModuleId) + " 接管");
  }

  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    if (i == activeModuleId) {
      redundantModules[i].isActive = true;
      digitalWrite(redundantConfig[i][1], HIGH);
      digitalWrite(redundantConfig[i][2], LOW);
    } else {
      redundantModules[i].isActive = false;
      digitalWrite(redundantConfig[i][1], LOW);
      digitalWrite(redundantConfig[i][2], HIGH);
    }
  }
}

void controlActiveModule(float targetSpeed) {
  if (redundantModules[activeModuleId].isHealthy && redundantModules[activeModuleId].isActive) {
    redundantModules[activeModuleId].motor.target = targetSpeed;
    redundantModules[activeModuleId].motor.loopFOC();
    redundantModules[activeModuleId].motor.move(targetSpeed);
  }
}

void initHardwareEmergencyStateMachine() {
  pinMode(EMERGENCY_STOP_INPUT, INPUT_PULLUP);
  pinMode(EMERGENCY_RESET_INPUT, INPUT_PULLDOWN);
  pinMode(EMERGENCY_STATUS_LED, OUTPUT);
  pinMode(RESET_STATUS_LED, OUTPUT);

  digitalWrite(EMERGENCY_STATUS_LED, LOW);
  digitalWrite(RESET_STATUS_LED, LOW);

  attachInterrupt(digitalPinToInterrupt(EMERGENCY_STOP_INPUT), emergencyStopTriggered, FALLING);

  Serial.println("硬件急停状态机初始化完成");
}

void emergencyStopTriggered() {
  currentEmergencyState = EMERGENCY_STATE_TRIGGERED;
  resetInProgress = false;
  Serial.println("硬件急停触发!状态切换为:TRIGGERED");
}

void monitorHardwareEmergencyState() {
  bool resetPressed = digitalRead(EMERGENCY_RESET_INPUT) == HIGH;

  switch (currentEmergencyState) {
    case EMERGENCY_STATE_NORMAL:
      digitalWrite(EMERGENCY_STATUS_LED, LOW);
      digitalWrite(RESET_STATUS_LED, LOW);
      if (digitalRead(EMERGENCY_STOP_INPUT) == LOW) {
        delay(10);
        if (digitalRead(EMERGENCY_STOP_INPUT) == LOW) {
          emergencyStopTriggered();
        }
      }
      break;

    case EMERGENCY_STATE_TRIGGERED:
      digitalWrite(EMERGENCY_STATUS_LED, HIGH);
      digitalWrite(RESET_STATUS_LED, LOW);
      if (resetPressed && !resetInProgress) {
        resetInProgress = true;
        resetStartTime = millis();
        currentEmergencyState = EMERGENCY_STATE_RESETTING;
        Serial.println("检测到复位按键按下,进入复位处理状态");
      }
      break;

    case EMERGENCY_STATE_RESETTING:
      digitalWrite(EMERGENCY_STATUS_LED, !digitalRead(EMERGENCY_STATUS_LED));
      digitalWrite(RESET_STATUS_LED, !digitalRead(RESET_STATUS_LED));
      if (millis() - resetStartTime >= 3000) {
        digitalWrite(EMERGENCY_STATUS_LED, LOW);
        digitalWrite(RESET_STATUS_LED, LOW);
        currentEmergencyState = EMERGENCY_STATE_NORMAL;
        resetInProgress = false;
        Serial.println("急停复位完成,切换至正常状态");
        releaseEmergencyStop();
      }
      if (!resetPressed && (millis() - resetStartTime < 3000)) {
        resetInProgress = false;
        currentEmergencyState = EMERGENCY_STATE_TRIGGERED;
      }
      break;

    case EMERGENCY_STATE_FAULT:
      digitalWrite(EMERGENCY_STATUS_LED, digitalRead(EMERGENCY_STATUS_LED) ^ 1);
      digitalWrite(RESET_STATUS_LED, HIGH);
      if (digitalRead(EMERGENCY_STOP_INPUT) == HIGH && !resetPressed) {
        currentEmergencyState = EMERGENCY_STATE_NORMAL;
        digitalWrite(EMERGENCY_STATUS_LED, LOW);
        digitalWrite(RESET_STATUS_LED, LOW);
      }
      break;
  }
}

void triggerEmergencyStopFromStateMachine() {
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    digitalWrite(redundantConfig[i][1], LOW);
  }
  Serial.println("硬件急停状态机触发:切断所有电机动力");
}

void releaseEmergencyStop() {
  for (int i = 0; i < NUM_REDUNDANT_MODULES; i++) {
    if (redundantModules[i].isHealthy) {
      digitalWrite(redundantConfig[i][1], HIGH);
      activeModuleId = i;
      break;
    }
  }
  Serial.println("急停解除:恢复主模块电机使能");
}

代码逻辑说明:
状态联动闭环:以硬件急停状态为核心,三模冗余系统完全配合急停状态运行——正常状态下冗余系统自主驱动,急停状态下同步切断所有动力,复位状态下维持停机直至复位完成,故障状态下进入安全停机,形成状态联动的闭环控制,确保动力与安全深度绑定。
工况自适应控制:引入消防机器人搜救、巡检、撤离三种核心工况,急停解除后可根据场景需求切换目标转速,三模冗余系统同步调整输出,既保障作业场景适配性,又维持动力系统的高可靠性。
多源应急触发:除硬件急停按键外,整合温度传感器、姿态传感器等消防应急传感器,当机器人超温、倾覆时自动触发急停,实现多源应急触发,提升机器人在火场复杂环境中的自救能力,保障救援作业安全。

要点解读

  1. 三模冗余控制架构:单点故障不停机,筑牢动力可靠性根基
    三模冗余是消防应急机器人动力可靠的核心支撑,通过三套独立的BLDC驱动链路并行运行,从物理层面规避单点失效风险,结合智能判定与接管机制,实现故障场景下的持续动力输出,适配火场极端环境对设备持续作业的严苛要求。
    物理冗余设计:三套驱动单元(驱动芯片、编码器、电源检测)完全独立,避免因单套驱动芯片烧毁、传感器失效导致整体动力中断,即使其中两套出现故障,剩余一套仍能维持机器人基本动力,保障最低限度的应急撤离能力。
    多数表决判定:采用“健康模块≥2才维持运行”的多数表决逻辑,避免单模块误报故障导致系统停机;原主模块故障时,自动切换至健康优先级最高的备模块,切换延迟≤10ms,电机转速波动≤5%,确保机器人在故障切换过程中姿态稳定,适配狭窄通道、复杂地形的作业需求。
    故障自恢复机制:故障模块修复后,系统自动纳入健康模块队列,参与主模块判定,无需人工干预即可恢复冗余架构,减少消防现场的设备维护成本,提升机器人的二次作业能力,适配连续救援场景需求。
  2. 硬件急停独立架构:脱离主控依赖,保障应急触发绝对可靠
    硬件急停是消防应急机器人安全的最后一道防线,采用独立于主控的硬件电路设计,脱离软件逻辑与主控运行状态,确保极端情况下急停功能仍能生效,从根源上杜绝因主控故障导致的应急失效,适配火场断电、主控宕机等极端应急场景。
    电路独立解耦:急停触发链路由施密特触发器、继电器、NPN晶体管等纯硬件元件组成,不依赖Arduino主控,即使主控芯片烧毁、程序卡死、电源中断,按下急停按键仍能通过硬件电路直接切断电机驱动使能或电源,实现“断电可触发、宕机能急停”,满足消防应急对安全触发的绝对可靠性要求。
    状态机闭环管理:定义正常、触发、复位、故障四类状态,通过状态指示灯直观反馈急停状态,复位过程强制保持3秒,避免误操作导致突然恢复动力,复位完成后需系统自检通过才能恢复运行,形成急停全生命周期的闭环管理,防止二次风险。
    双信号安全保障:急停采用“机械按键+硬件电路”双信号触发,机械按键确保人工干预的便捷性,硬件电路保障信号传输的抗干扰性;同时急停信号采用低电平有效设计,配合上拉电阻,避免线路断路导致误触发,提升触发链路的稳定性。
  3. 双系统深度联动:动力与安全协同,实现应急闭环控制
    三模冗余与硬件急停的深度联动,构建动力可靠与安全保障的闭环体系,实现正常作业时的高可靠动力输出,应急触发时的快速动力切断,故障解除后的平稳恢复,适配消防机器人从正常作业到应急处置的全流程需求。
    状态同步响应:硬件急停触发时,三模冗余系统同步接收急停信号,立即停止所有电机的控制指令,切断驱动使能,实现“急停指令-动力切断”的毫秒级响应;急停解除后,三模冗余系统先完成模块健康自检,再恢复健康模块的驱动使能,避免异常模块启动导致二次故障,确保恢复过程安全可控。
    故障协同处置:当三模冗余系统检测到健康模块不足2个时,主动触发硬件急停,同时通过硬件电路切断动力;当急停状态机进入故障状态时,三模冗余系统维持安全停机,直至故障排除,形成“冗余故障→急停触发→停机保护→故障修复→恢复运行”的协同处置流程,适配复杂故障场景。
    优先级动态调整:联动系统中,硬件急停优先级最高,任何情况下急停信号优先生效,覆盖三模冗余系统的控制指令;正常状态下,三模冗余系统的控制优先级高于工况切换指令,确保动力输出的稳定,实现多指令场景下的优先级动态平衡,保障系统运行秩序。
  4. 消防场景适配优化:贴合高危环境,强化极端工况耐受
    针对消防火场高温、强电磁干扰、烟雾遮挡、地形复杂等极端工况,方案从硬件选型、软件逻辑、控制策略多维度进行适配优化,确保三模冗余与硬件急停在极端环境下仍能稳定运行,保障机器人核心功能不失效。
    硬件抗干扰加固:BLDC驱动模块采用屏蔽线连接,减少电磁干扰对编码器信号、PWM信号的影响;急停电路采用施密特触发器滤波,消除按键抖动与线路噪声,适配火场强电磁环境;电源检测采用高精度ADC与滤波算法,实时监测电池电压波动,应对火场供电不稳定场景。
    软件容错优化:三模冗余系统加入去抖动算法与信号校验机制,避免传感器噪声导致的误判定;电机控制采用自适应PID参数,根据负载变化动态调整控制参数,应对火场复杂地形导致的负载突变,保障电机转速稳定,适配机器人攀爬、越障等场景。
    工况适配控制:针对搜救、巡检、撤离三种核心消防工况,动态调整电机目标转速与冗余策略——撤离模式采用高速优先,保障快速脱离;搜救模式采用稳定性优先,保障精准操作;巡检模式采用低速高精度,适配狭窄区域作业,实现不同场景下的最优动力输出,提升作业效率与安全性。
  5. 安全闭环设计:全生命周期管控,规避二次风险
    方案从急停触发、状态监测、复位恢复、故障处置全环节构建安全闭环,确保机器人在全生命周期内的风险可控,避免急停后突然恢复动力、故障未排除重启等二次风险,适配消防应急对设备安全操作的严苛要求。
    复位安全管控:复位过程强制保持3秒,需人工持续按住复位按键,确保操作人员确认现场安全后再恢复动力,防止误操作导致机器人突然启动,造成人员伤害或设备损坏;复位完成后,系统先进行模块健康自检,健康模块通过后才能恢复运行,避免带故障运行。
    状态透明化设计:通过多色LED指示灯实时反馈三模冗余模块的健康状态与急停状态,红色指示急停/故障,绿色指示正常/运行,黄色指示复位过程,操作人员可直观掌握设备运行状态,无需依赖代码调试,适配火场紧急操作的快速决策需求。
    故障自诊断与保护:三模冗余系统实时监测电源电压、电流、转速反馈,急停状态机监测硬件电路通断,一旦检测到故障,立即触发停机保护,并锁定故障状态,直至人工排查修复,防止故障扩散,保障机器人核心部件安全,降低维护成本。

请注意:以上案例仅作为思路拓展的参考示例,不保证完全正确、适配所有场景或可直接编译运行。由于硬件平台、实际使用场景、Arduino 版本的差异,均可能影响代码的适配性与使用方法的选择。在实际编程开发时,请务必根据自身硬件配置、使用场景及具体功能需求进行针对性调整,并通过多次实测验证效果;同时需确保硬件接线正确,充分了解所用传感器、执行器等设备的技术规范与核心特性。对于涉及硬件操作的代码,使用前务必核对引脚定义、电平参数等关键信息的准确性与安全性,避免因参数错误导致硬件损坏或运行异常。

在这里插入图片描述

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐