【花雕学编程】Arduino BLDC 之三模冗余电机控制 + 硬件急停状态机(消防应急机器人核心)

以专业视角来看,基于 Arduino 生态(通常以 ESP32 或 STM32 为核心)的三模冗余电机控制与硬件急停状态机,是专为消防应急机器人等极端恶劣、高风险环境设计的底层安全与动力保障系统。该系统将容错控制与失效安全(Fail-Safe)机制深度结合,确保机器人在火场中具备极高的生存能力和绝对的安全底线。
以下是该系统的主要特点、应用场景及注意事项的详细解析:
一、 主要特点
- 异构多模态冗余控制架构
系统采用“上位机 + 下位机 + 独立安全协处理器”的三层架构。上位机(如 Jetson Nano)负责复杂的火场 SLAM 建图与全局导航;Arduino 作为下位机专注于底层 BLDC 的 FOC 矢量控制与传感器数据采集;同时引入独立的硬件安全协处理器(或硬件看门狗电路),专门监控通信心跳与系统状态。当主系统死机或通信中断时,冗余模块可无缝接管,保障基本移动能力。 - 硬件级“失效安全”急停状态机
系统摒弃了纯软件控制的脆弱性,设计了绕过 MCU 的硬件级安全防线。通过物理急停按钮、独立电路监控母线电压等方式,直接切断 MOS 管驱动或 BLDC 动力电源。同时,软件层面设计了严格的状态机(State Machine),一旦检测到剧烈碰撞、通信超时或任务堆栈溢出,立即触发硬件中断,强制进入“安全悬停”或“缓慢停止”模式。 - 高动态响应与极端环境适应性
底层 BLDC 电机配合 FOC 算法,能提供平稳的低速爬坡力矩和毫秒级的紧急制动能力。在火场浓烟、高温导致视觉传感器失效时,系统可依靠 IMU、编码器及热成像进行非视觉导航,并通过精确的轨迹跟踪算法,在松软或充满瓦砾的地面上保持航向稳定。 - 多重抗干扰与热管理机制
针对火场强电磁干扰(EMI)和高温环境,电路板进行三防漆涂覆防粉尘腐蚀,关键连接器锁紧防震动脱落。对 BLDC 启停大电流和 PWM 开关噪声,采用磁珠滤波、独立电源隔离及同步采样技术,防止主控复位或传感器数据跳变。
二、 应用场景 - 火灾后浓烟环境侦察
在充满高温和有毒烟雾的室内,视觉传感器极易失效。机器人依靠硬件级冗余和热成像/激光雷达,自主规划“贴墙走”或“沿通道中线走”策略,深入核心区寻找被困人员或定位火源,且能在通信微弱时保持基本移动。 - 地震/坍塌废墟搜索
在建筑物倒塌形成的狭小空间内,机器人需自主穿行于断壁残垣之间。三模冗余系统确保其在遇到未知障碍或路径被堵死时,能触发局部重规划(如 DWA 算法)快速生成绕行轨迹,并具备应对瓦砾堆、台阶等复杂地形的全地形通过性。 - 危险品泄漏现场处置
在化工厂爆炸等存在化学污染的区域,机器人自主接近泄漏源,利用机械臂关闭阀门或投放中和剂。冗余系统能规划最短且安全的路径,减少在污染区的暴露时间,并在发生异常时立即切断动力,防止引发二次爆炸。
三、 需要注意的事项 - 硬件急停的绝对优先级
软件层面的模糊调度或状态机可能存在死循环风险。对于“急停”、“碰撞”等最高安全等级的事件,必须设计硬线中断电路(如物理急停按钮直接切断动力电源),严禁仅依赖软件逻辑兜底。 - 通信保活与降级策略
自主系统在未知环境中必然面临失效风险。必须设计心跳包机制,若上位机与下位机通信中断超过阈值,下位机应自动进入“安全悬停”模式。同时需设计降级策略,当主传感器(如 UWB 或视觉)失效时,自动切换备用模式(如纯里程计或沿墙探索)。 - 算力分配与实时性保障
Arduino 平台计算能力有限,严禁在从控节点代码中加入复杂的延时或浮点运算。必须采用双核分工(如 ESP32 Core 0 专责电机 FOC 控制,Core 1 运行视觉算法),并确保控制周期严格稳定(建议 < 10ms),防止调度决策滞后。 - 能源管理与续航优化
自主导航和 BLDC 驱动均为高功耗操作,火场救援任务持续时间长。在软件层面,需采用传感器按需唤醒策略(如静止时降低雷达扫描频率);在硬件层面,使用高倍率锂聚合物电池,并配备电源管理系统实时监控电压,防止过放损坏电池或引发火灾。 - 电磁兼容(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("急停解除:恢复主模块电机使能");
}
代码逻辑说明:
状态联动闭环:以硬件急停状态为核心,三模冗余系统完全配合急停状态运行——正常状态下冗余系统自主驱动,急停状态下同步切断所有动力,复位状态下维持停机直至复位完成,故障状态下进入安全停机,形成状态联动的闭环控制,确保动力与安全深度绑定。
工况自适应控制:引入消防机器人搜救、巡检、撤离三种核心工况,急停解除后可根据场景需求切换目标转速,三模冗余系统同步调整输出,既保障作业场景适配性,又维持动力系统的高可靠性。
多源应急触发:除硬件急停按键外,整合温度传感器、姿态传感器等消防应急传感器,当机器人超温、倾覆时自动触发急停,实现多源应急触发,提升机器人在火场复杂环境中的自救能力,保障救援作业安全。
要点解读
- 三模冗余控制架构:单点故障不停机,筑牢动力可靠性根基
三模冗余是消防应急机器人动力可靠的核心支撑,通过三套独立的BLDC驱动链路并行运行,从物理层面规避单点失效风险,结合智能判定与接管机制,实现故障场景下的持续动力输出,适配火场极端环境对设备持续作业的严苛要求。
物理冗余设计:三套驱动单元(驱动芯片、编码器、电源检测)完全独立,避免因单套驱动芯片烧毁、传感器失效导致整体动力中断,即使其中两套出现故障,剩余一套仍能维持机器人基本动力,保障最低限度的应急撤离能力。
多数表决判定:采用“健康模块≥2才维持运行”的多数表决逻辑,避免单模块误报故障导致系统停机;原主模块故障时,自动切换至健康优先级最高的备模块,切换延迟≤10ms,电机转速波动≤5%,确保机器人在故障切换过程中姿态稳定,适配狭窄通道、复杂地形的作业需求。
故障自恢复机制:故障模块修复后,系统自动纳入健康模块队列,参与主模块判定,无需人工干预即可恢复冗余架构,减少消防现场的设备维护成本,提升机器人的二次作业能力,适配连续救援场景需求。 - 硬件急停独立架构:脱离主控依赖,保障应急触发绝对可靠
硬件急停是消防应急机器人安全的最后一道防线,采用独立于主控的硬件电路设计,脱离软件逻辑与主控运行状态,确保极端情况下急停功能仍能生效,从根源上杜绝因主控故障导致的应急失效,适配火场断电、主控宕机等极端应急场景。
电路独立解耦:急停触发链路由施密特触发器、继电器、NPN晶体管等纯硬件元件组成,不依赖Arduino主控,即使主控芯片烧毁、程序卡死、电源中断,按下急停按键仍能通过硬件电路直接切断电机驱动使能或电源,实现“断电可触发、宕机能急停”,满足消防应急对安全触发的绝对可靠性要求。
状态机闭环管理:定义正常、触发、复位、故障四类状态,通过状态指示灯直观反馈急停状态,复位过程强制保持3秒,避免误操作导致突然恢复动力,复位完成后需系统自检通过才能恢复运行,形成急停全生命周期的闭环管理,防止二次风险。
双信号安全保障:急停采用“机械按键+硬件电路”双信号触发,机械按键确保人工干预的便捷性,硬件电路保障信号传输的抗干扰性;同时急停信号采用低电平有效设计,配合上拉电阻,避免线路断路导致误触发,提升触发链路的稳定性。 - 双系统深度联动:动力与安全协同,实现应急闭环控制
三模冗余与硬件急停的深度联动,构建动力可靠与安全保障的闭环体系,实现正常作业时的高可靠动力输出,应急触发时的快速动力切断,故障解除后的平稳恢复,适配消防机器人从正常作业到应急处置的全流程需求。
状态同步响应:硬件急停触发时,三模冗余系统同步接收急停信号,立即停止所有电机的控制指令,切断驱动使能,实现“急停指令-动力切断”的毫秒级响应;急停解除后,三模冗余系统先完成模块健康自检,再恢复健康模块的驱动使能,避免异常模块启动导致二次故障,确保恢复过程安全可控。
故障协同处置:当三模冗余系统检测到健康模块不足2个时,主动触发硬件急停,同时通过硬件电路切断动力;当急停状态机进入故障状态时,三模冗余系统维持安全停机,直至故障排除,形成“冗余故障→急停触发→停机保护→故障修复→恢复运行”的协同处置流程,适配复杂故障场景。
优先级动态调整:联动系统中,硬件急停优先级最高,任何情况下急停信号优先生效,覆盖三模冗余系统的控制指令;正常状态下,三模冗余系统的控制优先级高于工况切换指令,确保动力输出的稳定,实现多指令场景下的优先级动态平衡,保障系统运行秩序。 - 消防场景适配优化:贴合高危环境,强化极端工况耐受
针对消防火场高温、强电磁干扰、烟雾遮挡、地形复杂等极端工况,方案从硬件选型、软件逻辑、控制策略多维度进行适配优化,确保三模冗余与硬件急停在极端环境下仍能稳定运行,保障机器人核心功能不失效。
硬件抗干扰加固:BLDC驱动模块采用屏蔽线连接,减少电磁干扰对编码器信号、PWM信号的影响;急停电路采用施密特触发器滤波,消除按键抖动与线路噪声,适配火场强电磁环境;电源检测采用高精度ADC与滤波算法,实时监测电池电压波动,应对火场供电不稳定场景。
软件容错优化:三模冗余系统加入去抖动算法与信号校验机制,避免传感器噪声导致的误判定;电机控制采用自适应PID参数,根据负载变化动态调整控制参数,应对火场复杂地形导致的负载突变,保障电机转速稳定,适配机器人攀爬、越障等场景。
工况适配控制:针对搜救、巡检、撤离三种核心消防工况,动态调整电机目标转速与冗余策略——撤离模式采用高速优先,保障快速脱离;搜救模式采用稳定性优先,保障精准操作;巡检模式采用低速高精度,适配狭窄区域作业,实现不同场景下的最优动力输出,提升作业效率与安全性。 - 安全闭环设计:全生命周期管控,规避二次风险
方案从急停触发、状态监测、复位恢复、故障处置全环节构建安全闭环,确保机器人在全生命周期内的风险可控,避免急停后突然恢复动力、故障未排除重启等二次风险,适配消防应急对设备安全操作的严苛要求。
复位安全管控:复位过程强制保持3秒,需人工持续按住复位按键,确保操作人员确认现场安全后再恢复动力,防止误操作导致机器人突然启动,造成人员伤害或设备损坏;复位完成后,系统先进行模块健康自检,健康模块通过后才能恢复运行,避免带故障运行。
状态透明化设计:通过多色LED指示灯实时反馈三模冗余模块的健康状态与急停状态,红色指示急停/故障,绿色指示正常/运行,黄色指示复位过程,操作人员可直观掌握设备运行状态,无需依赖代码调试,适配火场紧急操作的快速决策需求。
故障自诊断与保护:三模冗余系统实时监测电源电压、电流、转速反馈,急停状态机监测硬件电路通断,一旦检测到故障,立即触发停机保护,并锁定故障状态,直至人工排查修复,防止故障扩散,保障机器人核心部件安全,降低维护成本。
请注意:以上案例仅作为思路拓展的参考示例,不保证完全正确、适配所有场景或可直接编译运行。由于硬件平台、实际使用场景、Arduino 版本的差异,均可能影响代码的适配性与使用方法的选择。在实际编程开发时,请务必根据自身硬件配置、使用场景及具体功能需求进行针对性调整,并通过多次实测验证效果;同时需确保硬件接线正确,充分了解所用传感器、执行器等设备的技术规范与核心特性。对于涉及硬件操作的代码,使用前务必核对引脚定义、电平参数等关键信息的准确性与安全性,避免因参数错误导致硬件损坏或运行异常。

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


所有评论(0)