【花雕学编程】Arduino BLDC 之双 BLDC 轮式消防机器人(左右轮独立冗余 + 互锁急停)

Arduino BLDC 之双 BLDC 轮式消防机器人,本质上是把“差速驱动底盘、左右轮独立冗余、互锁急停与消防执行单元”做成一个高可靠、可降级的嵌入式移动平台;它的价值不只是能喷水,而是用冗余驱动和硬件级急停保证火场、浓烟、狭窄空间里依然可受控、可撤离、可安全停机。
主要特点
. 双 BLDC 独立差速驱动
左右轮各由一路 BLDC 独立驱动,前进、后退、原地转向和弧线避障都通过左右轮速度差实现。相比单电机+机械差速,双 BLDC 能更直接地控制转向力矩,也更容易实现单侧失效后的降级行驶。
. 左右轮独立冗余
左右轮驱动链路由独立电机、独立编码器、独立驱动器和独立功率回路组成。当一侧出现堵转、缺相、过流或编码器失联时,系统可立即切断故障侧,保留另一侧低速撤离或转向。这属于“失效后可降级运行”的设计,而不是简单停机。
. 互锁急停机制
急停必须优先于所有运动指令。硬件上可采用常闭触点串联驱动器使能/主功率继电器,按下后强制切断转矩输出;软件上由急停标志位锁定速度指令为零,并在复位前禁止重新驱动。
互锁体现在:急停触发后,自动/遥控/灭火任务都不能绕过停机;复位后也不能自动恢复运行,需要人工确认。更可靠方案可采用双回路急停,一路故障也能保持安全停机。
. 分层实时控制架构
上层处理火源识别、遥控指令、路径规划和任务调度;下层负责 BLDC FOC、编码器反馈、IMU 姿态、急停判断和故障保护。
在 Arduino 生态中,AVR 系列适合做底层执行或轻量原型;若同时运行 SLAM、视觉火源识别和多路传感器融合,建议采用上位机+下位机架构,下位机专注电机闭环与安全保护。
. 消防执行单元联动
机器人通常配备水泵、电磁阀、水炮舵机、火焰/烟雾/温度/气体传感器。灭火动作必须与底盘安全状态联动:急停触发时应优先保证停机,再决定是否保持水泵关闭、报警或等待人工接管。
应用场景
室内火场侦察:进入烟雾浓、温度高、人员不宜进入的房间,执行火焰定位、温度监测和气体检测。
狭窄空间灭火:仓库、机房、地下车库、配电间等空间受限场景,利用差速转向实现小半径机动。
危险品环境初处置:在可能存在可燃气体、烟雾或电气火灾风险的环境中,由机器人先行靠近侦察。
校园/实验室/创客项目:作为消防机器人教学平台,验证 BLDC 差速控制、冗余驱动、急停设计和多传感器融合。
应急演练与编队演示:多台机器人协同执行侦察、灭火、警戒等任务,验证通信、遥控与安全策略。
需要注意的事项
急停必须硬件优先,不能只靠软件
急停信号应直接作用于驱动器使能、主继电器或安全回路,而不是仅在主循环里把速度设为 0。软件死机、通信丢包或传感器异常时,硬件急停仍能切断动力。
冗余不是简单“多装一个电机”
左右轮独立冗余需要独立功率路径、独立故障检测和独立保护。如果两侧共用同一驱动器、同一保险或同一使能信号,单点故障仍会导致整车失效。
BLDC 必须闭环,不能只用开环 ESC
消防机器人对低速可控性、转向精度和故障检测要求更高。应使用带编码器/霍尔反馈的 BLDC 方案,并实现电流、速度、位置多环控制,否则难以判断堵转、打滑和单侧失效。
电源、散热和 EMC 要单独设计
BLDC 启动、转向和灭火泵同时工作时电流冲击大,控制板、传感器和通信模块容易受干扰。建议动力电源与控制电源隔离,驱动器端加大容量低 ESR 电容,敏感信号线屏蔽并远离动力线。
消防场景要重视防爆、防水和热防护
火场存在高温、水汽、导电粉尘和可燃气体风险。外壳、接插件、传感器和电池舱需做防水防尘处理;在可燃气体环境中应避免产生电火花;电池应配备 BMS,并设置过温、过流、欠压和倾角保护。

1、双节点冗余 BLDC 控制 + 故障切换(专利架构简化实现)
适用场景:左右轮各由独立的 Arduino 节点控制,两节点通过有线通信协调,当一侧节点检测到故障时,可切换至备用控制路径或通知对侧调整。该架构参考了 US20220352833A1 专利中“第一节点与第二节点通过冗余网络协调控制两个 BLDC 电机”的设计。
/**
* 消防机器人 - 双节点冗余BLDC控制 + 故障切换
* 硬件假设:双Arduino节点(左/右轮各一), 2×BLDC(SimpleFOC), 有线通信(串口)
* 参考:US20220352833A1 冗余BLDC控制架构[citation:1]
* 核心:节点间心跳监测 -> 单侧故障检测 -> 降级运行或切换
*/
#include <SimpleFOC.h>
// 本节点控制的电机(以左轮节点为例)
BLDCMotor myMotor(7);
Encoder myEncoder(2, 4, 2048);
BLDCDriver3PWM myDriver(5, 6, 9, 8);
// 节点角色
#define NODE_LEFT 0
#define NODE_RIGHT 1
const int MY_ROLE = NODE_LEFT;
// 节点间通信(简化:串口1用于节点间,串口0用于调试)
// 实际项目中可用RS485/CAN
// 故障检测
enum FaultState {
FAULT_NONE,
FAULT_ENCODER,
FAULT_DRIVER,
FAULT_OVERCURRENT,
FAULT_COMM_LOST
};
FaultState myFault = FAULT_NONE;
// 节点间心跳
unsigned long lastPeerHeartbeat = 0;
const unsigned long HEARTBEAT_TIMEOUT = 500; // 500ms无心跳判定通信故障
// 运行模式
enum RunMode {
MODE_NORMAL, // 正常双轮驱动
MODE_DEGRADED, // 降级:单侧故障,对侧补偿
MODE_ESTOP // 急停
};
RunMode currentMode = MODE_NORMAL;
// 目标速度
float targetSpeed = 3.0;
float mySpeed = 0;
float peerSpeed = 0;
void setup() {
Serial.begin(115200); // 调试
Serial1.begin(115200); // 节点间通信
myDriver.voltage_power_supply = 24;
myDriver.init();
myMotor.linkDriver(&myDriver);
myMotor.linkSensor(&myEncoder);
myMotor.init();
myMotor.initFOC();
myMotor.controller = MotionControlType::velocity;
lastPeerHeartbeat = millis();
}
// 发送心跳和数据给对侧节点
void sendHeartbeat() {
// 格式: "H,role,speed,fault\n"
Serial1.print("H,");
Serial1.print(MY_ROLE);
Serial1.print(",");
Serial1.print(mySpeed, 2);
Serial1.print(",");
Serial1.println(myFault);
}
// 接收对侧节点数据
void receivePeerData() {
if (Serial1.available()) {
String data = Serial1.readStringUntil('\n');
// 解析 "H,role,speed,fault"
if (data.startsWith("H,")) {
int firstComma = data.indexOf(',');
int secondComma = data.indexOf(',', firstComma + 1);
int thirdComma = data.indexOf(',', secondComma + 1);
if (secondComma > 0 && thirdComma > 0) {
peerSpeed = data.substring(secondComma + 1, thirdComma).toFloat();
lastPeerHeartbeat = millis();
}
}
}
}
// 本地故障检测
void checkLocalFault() {
// 简化:检测电机电流异常(实际需根据驱动器反馈)
// 此处模拟:如果电机堵转,电流异常
static unsigned long lastCheck = 0;
if (millis() - lastCheck > 100) {
lastCheck = millis();
// SimpleFOC 电流检测(需配置电流传感器)
// float current = myMotor.current_sp;
// if (abs(current) > 20.0) myFault = FAULT_OVERCURRENT;
// 编码器合理性检查
float vel = myMotor.shaftVelocity();
if (abs(vel) > 50.0 && abs(targetSpeed) < 1.0) {
myFault = FAULT_ENCODER;
}
}
}
void loop() {
myMotor.loopFOC();
sendHeartbeat();
receivePeerData();
checkLocalFault();
// 通信故障检测
if (millis() - lastPeerHeartbeat > HEARTBEAT_TIMEOUT) {
myFault = FAULT_COMM_LOST;
currentMode = MODE_DEGRADED;
}
// 模式决策
switch (currentMode) {
case MODE_NORMAL:
if (myFault != FAULT_NONE) {
// 本侧故障,进入降级模式
currentMode = MODE_DEGRADED;
}
mySpeed = targetSpeed;
break;
case MODE_DEGRADED:
// 降级运行:如果本侧健康,补偿对侧
if (myFault == FAULT_NONE && peerSpeed < 0.5) {
// 对侧可能故障,本侧降低速度防止失控
mySpeed = targetSpeed * 0.5;
} else if (myFault != FAULT_NONE) {
// 本侧故障,尝试停止
mySpeed = 0;
currentMode = MODE_ESTOP;
}
break;
case MODE_ESTOP:
mySpeed = 0;
break;
}
myMotor.move(mySpeed);
Serial.print("Role:"); Serial.print(MY_ROLE);
Serial.print(" Speed:"); Serial.print(mySpeed);
Serial.print(" PeerSpeed:"); Serial.print(peerSpeed);
Serial.print(" Fault:"); Serial.print(myFault);
Serial.print(" Mode:"); Serial.println(currentMode);
delay(20);
}
要点:该代码体现了节点级冗余与协调控制的架构。参考专利 US20220352833A1,两个节点通过有线通信交换心跳和故障状态,当一侧检测到故障时,另一侧可感知并调整行为。关键设计在于:心跳超时作为通信故障的判据,而非等待显式故障信号(通信本身可能已中断)。降级模式下,健康侧降低速度而非全速运行,防止因对侧失控导致机器人整体失稳。
2、硬件互锁急停状态机 + 双通道使能控制(参考轮椅制动专利)
搜索结果显示,US10945900 专利揭示了一种电动轮椅的互锁急停架构:左右电机的制动继电器通过串联的常闭开关链连接,任何一个急停开关断开都会同时切断两个电机的制动回路,实现“任一急停触发 → 双侧同时制动”的互锁效果。以下案例简化实现了这一逻辑。
/**
* 消防机器人 - 互锁急停 + 双通道使能控制
* 硬件假设:Arduino Mega, 2×BLDC驱动(带使能引脚EN), 急停按钮(常闭), 抱闸继电器
* 参考:US10945900 电动轮椅互锁制动架构[citation:5]
* 核心:急停按钮串联 -> 任一触发双侧断电;使能引脚独立控制
*/
#include <SimpleFOC.h>
BLDCMotor motorL(7);
BLDCMotor motorR(7);
Encoder encL(2, 4, 2048);
Encoder encR(3, 5, 2048);
// 驱动器使能引脚(低电平使能,高电平禁用)
#define EN_LEFT 22
#define EN_RIGHT 23
// 抱闸继电器(高电平释放,低电平抱闸)
#define BRAKE_L 24
#define BRAKE_R 25
// 硬件急停按钮(常闭,按下时断开)
#define ESTOP_PIN 2
// 互锁使能信号(来自硬件串联链,低电平有效)
#define INTERLOCK_OK 26
// 急停状态
volatile bool estopTriggered = false;
void estopISR() {
estopTriggered = true;
}
void setup() {
Serial.begin(115200);
// 急停按钮:常闭,按下时接地,触发中断
pinMode(ESTOP_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ESTOP_PIN), estopISR, FALLING);
// 互锁链状态
pinMode(INTERLOCK_OK, INPUT_PULLUP);
// 使能引脚
pinMode(EN_LEFT, OUTPUT);
pinMode(EN_RIGHT, OUTPUT);
digitalWrite(EN_LEFT, LOW); // 使能
digitalWrite(EN_RIGHT, LOW);
// 抱闸控制
pinMode(BRAKE_L, OUTPUT);
pinMode(BRAKE_R, OUTPUT);
digitalWrite(BRAKE_L, HIGH); // 释放抱闸
digitalWrite(BRAKE_R, HIGH);
motorL.linkSensor(&encL);
motorR.linkSensor(&encR);
motorL.init(); motorL.initFOC();
motorR.init(); motorR.initFOC();
motorL.controller = MotionControlType::velocity;
motorR.controller = MotionControlType::velocity;
Serial.println("互锁急停系统就绪");
}
// 执行急停:双侧同时禁用 + 抱闸
void executeEmergencyStop() {
// 1. 禁用双侧驱动器(硬件级切断动力)
digitalWrite(EN_LEFT, HIGH);
digitalWrite(EN_RIGHT, HIGH);
// 2. 激活双侧抱闸
digitalWrite(BRAKE_L, LOW);
digitalWrite(BRAKE_R, LOW);
// 3. 电机零力矩
motorL.move(0);
motorR.move(0);
Serial.println("!!! 急停激活:双侧动力切断 + 抱闸 !!!");
}
void loop() {
motorL.loopFOC();
motorR.loopFOC();
// ========== 最高优先级:急停检查 ==========
// 条件1:软件急停标志(中断触发)
// 条件2:硬件互锁链断开(常闭开关链某处断开)
bool hardwareInterlock = digitalRead(INTERLOCK_OK) == HIGH; // 高电平表示链断
if (estopTriggered || hardwareInterlock) {
executeEmergencyStop();
// 急停状态锁定,等待硬件复位
while (1) {
Serial.println("急停锁定 - 等待硬件复位");
delay(500);
}
}
// ========== 正常控制 ==========
// 简化:双轮同步直行
float speed = 3.0;
// 安全检查:如果一侧使能异常,双侧停止
if (digitalRead(EN_LEFT) == HIGH || digitalRead(EN_RIGHT) == HIGH) {
executeEmergencyStop();
return;
}
motorL.move(speed);
motorR.move(speed);
Serial.print("L:"); Serial.print(speed);
Serial.print(" R:"); Serial.print(speed);
Serial.print(" Interlock:"); Serial.println(hardwareInterlock ? "OPEN" : "OK");
delay(20);
}
要点:该案例的核心是互锁急停的硬件-软件协同设计。参考专利 US10945900 的架构,急停按钮采用串联常闭开关链——任何一个开关断开,整个使能回路失电,双侧驱动器同时被禁用。代码中的 executeEmergencyStop() 同时执行三个动作:禁用使能引脚、激活抱闸、电机零力矩。关键安全原则:急停状态是不可逆汇点,必须通过硬件复位(如主开关重新上电)才能恢复,而非软件复位。
3、分级制动 + 冗余速度反馈仲裁(消防规范符合性)
搜索结果显示,XF892.1-2010 消防机器人标准要求“紧急停止按钮按下后,消防机器人应立即停止所有动作”,且“制动距离应不大于0.3m”。消防场景的急停不能是简单的断电滑行,而需要受控制动。以下案例实现了基于冗余速度反馈的分级制动状态机。
/**
* 消防机器人 - 分级制动 + 冗余速度反馈仲裁
* 硬件假设:Arduino Mega, 2×BLDC, 双编码器/霍尔, 抱闸继电器
* 参考:XF892.1-2010 消防机器人标准[citation:12], 硬件急停状态机[citation:2][citation:6]
* 核心:双源速度反馈 -> 仲裁 -> 分级制动(减速->软停->抱闸)
*/
#include <SimpleFOC.h>
BLDCMotor motorL(7);
BLDCMotor motorR(7);
Encoder encL(2, 4, 2048); // 主编码器
Encoder encR(3, 5, 2048);
// 冗余霍尔传感器(简化:数字引脚)
#define HALL_L_A 14
#define HALL_L_B 15
#define HALL_R_A 16
#define HALL_R_B 17
#define BRAKE_L 24
#define BRAKE_R 25
#define ESTOP_PIN 2
// 制动分级阈值 (cm/s)
#define DECEL_THRESHOLD 30
#define SOFT_STOP_THRESHOLD 8
#define HOLD_THRESHOLD 1.0
// 制动状态
enum BrakeState {
BRAKE_RUNNING,
BRAKE_DECEL,
BRAKE_SOFT_STOP,
BRAKE_HOLD,
BRAKE_EMERGENCY
};
BrakeState brakeState = BRAKE_RUNNING;
volatile bool estopFlag = false;
float targetSpeed = 5.0;
float currentSpeed = 0;
// 冗余速度读取:编码器 + 霍尔交叉验证
float readRedundantSpeed() {
// 主源:编码器
float encSpeed = motorL.shaftVelocity() * 10.0; // rad/s -> cm/s 近似
// 冗余源:霍尔脉冲计数(简化)
static unsigned long lastHallTime = 0;
static int hallCount = 0;
static float hallSpeed = 0;
// 霍尔中断计数(需额外中断处理,此处简化示意)
// 实际项目中应在ISR中计数,主循环计算速度
// 仲裁:如果编码器和霍尔偏差过大,标记故障
// 简化:优先使用编码器,霍尔作为合理性检查
float speedDiff = abs(encSpeed - hallSpeed);
if (speedDiff > 20.0 && abs(encSpeed) > 10.0) {
// 传感器偏差过大,降级使用霍尔
return hallSpeed;
}
return encSpeed;
}
void estopISR() {
estopFlag = true;
}
void setup() {
Serial.begin(115200);
pinMode(ESTOP_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ESTOP_PIN), estopISR, FALLING);
pinMode(BRAKE_L, OUTPUT);
pinMode(BRAKE_R, OUTPUT);
digitalWrite(BRAKE_L, HIGH); // 释放
digitalWrite(BRAKE_R, HIGH);
pinMode(HALL_L_A, INPUT_PULLUP);
pinMode(HALL_L_B, INPUT_PULLUP);
pinMode(HALL_R_A, INPUT_PULLUP);
pinMode(HALL_R_B, INPUT_PULLUP);
motorL.linkSensor(&encL);
motorR.linkSensor(&encR);
motorL.init(); motorL.initFOC();
motorR.init(); motorR.initFOC();
motorL.controller = MotionControlType::velocity;
motorR.controller = MotionControlType::velocity;
}
void loop() {
motorL.loopFOC();
motorR.loopFOC();
currentSpeed = readRedundantSpeed();
// ========== 急停触发 ==========
if (estopFlag) {
brakeState = BRAKE_EMERGENCY;
estopFlag = false;
}
// ========== 分级制动状态机 ==========
switch (brakeState) {
case BRAKE_RUNNING:
motorL.move(targetSpeed);
motorR.move(targetSpeed);
// 可添加触发条件
break;
case BRAKE_DECEL:
// 一级:快速减速(电机制动)
targetSpeed -= 8.0 * 0.05;
if (targetSpeed < 0) targetSpeed = 0;
motorL.move(targetSpeed);
motorR.move(targetSpeed);
if (currentSpeed < SOFT_STOP_THRESHOLD) {
brakeState = BRAKE_SOFT_STOP;
}
break;
case BRAKE_SOFT_STOP:
// 二级:精细逼近零速
targetSpeed -= 3.0 * 0.05;
if (targetSpeed < 0) targetSpeed = 0;
motorL.move(targetSpeed);
motorR.move(targetSpeed);
if (currentSpeed < HOLD_THRESHOLD) {
brakeState = BRAKE_HOLD;
digitalWrite(BRAKE_L, LOW); // 抱闸
digitalWrite(BRAKE_R, LOW);
}
break;
case BRAKE_HOLD:
motorL.move(0);
motorR.move(0);
break;
case BRAKE_EMERGENCY:
// 急停:立即禁用 + 抱闸(最快制动)
motorL.move(0);
motorR.move(0);
digitalWrite(BRAKE_L, LOW);
digitalWrite(BRAKE_R, LOW);
Serial.println("紧急制动 - 立即抱闸");
// 保持
break;
}
Serial.print("State:"); Serial.print(brakeState);
Serial.print(" Speed:"); Serial.print(currentSpeed);
Serial.print(" Target:"); Serial.println(targetSpeed);
delay(20);
}
要点:该案例实现了符合消防机器人标准的分级制动架构。与普通急停的“一刀切断电”不同,消防机器人的急停需要在最短制动距离内完成制动(标准要求 ≤0.3m),同时避免机械冲击。分级制动状态机从快速电机制动(DECEL)→ 精细软停(SOFT_STOP)→ 机械抱闸(HOLD)逐步过渡。冗余速度反馈(编码器 + 霍尔)通过交叉验证避免单一传感器故障导致的制动误判。
要点解读
-
左右轮独立冗余的核心价值不是“性能提升”,而是“故障后仍能撤离”。 消防机器人的工作环境(火场、浓烟、高温)对电子设备极不友好,单侧驱动失效的概率远高于普通场景。独立冗余架构使机器人在一侧完全失效时,仍能通过另一侧的动力实现原地旋转或弧线撤离。关键设计原则:两个节点的通信必须是有线冗余(如 RS485 双绞线),而非无线——火场中的无线通信可能因浓烟和金属结构严重衰减。
-
互锁急停的本质是“串联使能链”,而非“软件判断”。 参考 US10945900 专利,左右电机的制动回路通过串联常闭开关连接,任何一个急停开关或故障检测触点断开,整个使能链失电,双侧同时制动。这种硬件互锁无法被软件绕过,符合工业安全规范中“安全功能必须独立于控制系统”的要求。软件层面的急停检测(如中断)是补充,而非替代。
-
消防机器人的急停不能是“自由滑行”,必须是“受控制动”。 XF892.1-2010 要求制动距离 ≤0.3m。如果急停仅切断电机动力,机器人会因惯性滑行远超 0.3m。正确的做法是:电机制动(反向力矩)优先,机械抱闸作为最终保障。分级制动状态机(案例三)体现了这一原则:先以受控减速度降速,再抱闸锁定。BLDC 配合 FOC 的反向力矩控制能力是实现短距制动的关键。
-
冗余速度反馈需要“仲裁机制”,而非简单平均。 案例三中编码器和霍尔的速度差异如果超过阈值,不能取平均——因为可能是编码器故障导致读数异常。正确的做法是:优先使用编码器(精度高),霍尔作为合理性检查。如果两者偏差过大且编码器读数明显异常(如速度为负但电机正转),则降级使用霍尔。这种“主-备-仲裁”策略比简单平均更可靠。
-
Arduino 在消防机器人中的合理定位是“执行层+安全监测层”,核心安全功能应由硬件电路实现。 消防机器人的完整架构通常包括:硬件急停电路(独立于 MCU)、安全继电器链(硬件互锁)、MCU(Arduino/STM32 执行控制逻辑)、上位机(路径规划)。Arduino 不应参与“是否触发急停”的决策——这个决策必须由硬件电路完成。Arduino 的职责是:执行制动指令、监测状态、向操作员报告。搜索结果中的硬件急停状态机(案例二)体现了这一分层原则。

4、双驱动基础行驶+冗余检测+互锁急停程序(核心:基础控制+安全联锁)
适用场景:消防巡检、初期火灾探查,要求机器人可直行、转向,具备基础冗余和紧急停机功能。
核心逻辑
左右BLDC独立PWM控制,实现直行、转向、变速行走
双通道编码器反馈,实时检测轮速,识别电机故障
独立急停按键+联锁逻辑,异常时同步切断双电机电源,实现安全停机
// 双BLDC消防机器人基础控制+冗余急停程序
// 硬件:左/右BLDC电机、编码器、双通道急停按键、PWM驱动
// 功能:独立驱动、轮速反馈、冗余检测、联锁急停
#include <Arduino.h>
// ========== 硬件定义 ==========
const byte PWM_LEFT = 9, DIR_LEFT = 8;
const byte PWM_RIGHT = 10, DIR_RIGHT = 11;
const byte ENC_LEFT_A=2, ENC_LEFT_B=3; // 左编码器
const byte ENC_RIGHT_A=4, ENC_RIGHT_B=5; // 右编码器
const byte ESTOP_LEFT = 12; // 左急停
const byte ESTOP_RIGHT=13; // 右急停
// ========== 变量定义 ==========
int targetLeftSpeed = 120, targetRightSpeed = 120;
long encLeft = 0, encRight = 0, lastEncLeft=0, lastEncRight=0;
unsigned long lastTime = 0;
bool estopActive = false, motorError = false;
// ========== 函数声明 ==========
void readEncoders(unsigned long dt);
bool checkRedundancy();
void driveMotors(int leftPWM, int rightPWM);
void emergencyStop();
void setup() {
Serial.begin(115200);
Serial.println("双BLDC消防机器人基础系统启动");
pinMode(PWM_LEFT, OUTPUT); pinMode(DIR_LEFT, OUTPUT);
pinMode(PWM_RIGHT, OUTPUT); pinMode(DIR_RIGHT, OUTPUT);
pinMode(ESTOP_LEFT, INPUT_PULLUP); pinMode(ESTOP_RIGHT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENC_LEFT_A), [](){ if(digitalRead(ENC_LEFT_A)) encLeft++; }, RISING);
attachInterrupt(digitalPinToInterrupt(ENC_RIGHT_A), [](){ if(digitalRead(ENC_LEFT_A)) encRight++; }, RISING);
}
void loop() {
unsigned long dt = millis() - lastTime;
if (dt <20) return;
lastTime = millis();
// 急停检测if (digitalRead(ESTOP_LEFT)==LOW || digitalRead(ESTOP_RIGHT)==LOW) {
emergencyStop();
while (digitalRead(ESTOP_LEFT)==LOW || digitalRead(ESTOP_RIGHT)==LOW) {delay(100);}
}
// 冗余检测
motorError = checkRedundancy();
if (motorError) { emergencyStop(); delay(500); return; } 读取轮速
readEncoders(dt);
// 差速PID(简化闭环)
int leftPWM = targetLeftSpeed + (encLeft - lastEncLeft)/dt;
int rightPWM = targetRightSpeed + (encRight - lastEncRight)/dt; // 驱动电机
driveMotors(leftPWM, rightPWM);
lastEncLeft=encLeft; lastEncRight=encRight;
Serial.print("左速:");Serial.print((encLeft-lastEncLeft)/dt);
Serial.print(" 右速:");Serial.print((encRight-lastEncRight)/dt);
delay(20);
}
// 读取编码器,计算轮速
void readEncoders(unsigned long dt) {
// 简化计算,实际需按编码器精度换算
}
// 冗余检测:轮速一致性与电机响应
bool checkRedundancy() {
// 模拟轮速,实际由编码器读取
int leftSpeed = 100, rightSpeed=110;
return abs(leftSpeed-rightSpeed)>30; // 误差过大判定故障
}
// 差速驱动电机
void driveMotors(int leftPWM, int rightPWM) {
leftPWM = constrain(leftPWM, 0, 200);
rightPWM = constrain(rightPWM, 0, 200);
digitalWrite(DIR_LEFT, HIGH); digitalWrite(DIR_RIGHT, HIGH);
analogWrite(PWM_LEFT, leftPWM); analogWrite(PWM_RIGHT, rightPWM);
}
// 互锁急停,同步切断双电机
void emergencyStop() {
digitalWrite(DIR_LEFT, LOW); digitalWrite(DIR_RIGHT, LOW);
analogWrite(PWM_LEFT, 0); analogWrite(PWM_RIGHT, 0);
Serial.println("紧急停机触发!");
}
适用场景优化
加入坡度检测,上下坡自动调整驱动力,防止溜坡
优化编码器滤波,减少抖动干扰,提升轮速检测精度
增加温度检测,电机过热时自动降速或急停,保护设备
5、冗余容错+双急停互锁+故障自动恢复程序(核心:冗余容错+安全联锁)
适用场景:火灾现场浓烟、高温环境,需应对单侧电机故障、信号干扰,保障机器人能安全撤离或作业。
核心逻辑
左右轮独立闭环控制,实现动力冗余,单侧故障可单驱动运行
双路急停联锁,任意急停触发即断电,且重启需双急停复位
故障诊断+自动恢复,非致命故障可自动复位重启,避免作业中断
// 双BLDC冗余容错消防机器人程序
// 硬件:双BLDC、双重编码器、双急停、故障检测、PWM驱动
// 功能:独立闭环、冗余容错、联锁急停、故障恢复
#include <Arduino.h>
// ========== 硬件定义 ==========
const byte PWM[2] = {9,10}, DIR[2]={8,11};
const byte ENC_A[2]={2,4}, ENC_B[2]={3,5};
const byte ESTOP[2]={12,13};
const byte FAULT_PIN=A0; // 故障检测
// ========== 状态变量 ==========
bool estopState[2]={true,true};
bool motorFault[2]={false,false};
bool recoveryRequest=false;
int targetSpeed[2]={120,120};
long encCount[2]={0,0}, lastEnc[2]={0,0};
unsigned long lastTime=0;
// ========== 函数声明 ==========
void readEncoders();
bool estopInterlock();
bool checkMotorFault();
void handleRecovery();
void driveMotor(uint8_t idx, int pwm);
void setup() {
Serial.begin(115200);
Serial.println("冗余容错系统启动");
for(uint8_t i=0;i<2;i++) {
pinMode(PWM[i],OUTPUT); pinMode(DIR[i],OUTPUT);
pinMode(ESTOP[i], INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENC_A[i]), [i](){ if(digitalRead(ENC_A[i])) encCount[i]++; }, RISING);
}
pinMode(FAULT_PIN, INPUT);
}
void loop() {
// 互锁急停检测
if (!estopInterlock()) {
driveMotor(0,0); driveMotor(1,0);
Serial.println("互锁急停生效");
}
// 故障检测
motorFault[0] = checkMotorFault();
motorFault[1] = checkMotorFault();
if (motorFault[0] || motorFault[1]) handleRecovery();
// 编码器读取
unsigned long dt=millis()-lastTime; lastTime=millis();
readEncoders();
// 独立闭环,容错控制
int pwm[2];
for (uint8_t i=0;i<2;i++) {
if (!motorFault[i]) { pwm[i] = targetSpeed[i] + (encCount[i]-lastEnc[i])/dt;
} else {
pwm[i] = 0; // 故障侧停转,对侧运行
}
driveMotor(i, pwm[i]);
}
lastEnc[0]=encCount[0]; lastEnc[1]=encCount[1];
delay(30);
}
// 急停联锁,双通道触发即停机
bool estopInterlock() {
estopState[0] = digitalRead(ESTOP[0]);
estopState[1] = digitalRead(ESTOP[1]);
return estopState[0] && estopState[1]; // 仅双复位才恢复
}
// 电机故障检测,电流/转速异常判定
bool checkMotorFault() {
uint16_t faultVal = analogRead(FAULT_PIN);
return faultVal > 800; // 模拟故障阈值
}
// 故障恢复处理
void handleRecovery() {
Serial.println("检测到故障,尝试恢复");
driveMotor(0,0); driveMotor(1,0);
recoveryRequest=true;
delay(1000);
if (estopInterlock()) { // 复位后恢复运行
motorFault[0]=motorFault[1]=false;
Serial.println("故障恢复,重新启动");
} else {
Serial.println("复位失败,保持停机");
}
}
// 读取编码器
void readEncoders() {}
// 单电机驱动
void driveMotor(uint8_t idx, int pwm) {
pwm = constrain(pwm,0,200);
digitalWrite(DIR[idx], HIGH);
analogWrite(PWM[idx], pwm);
}
适用场景优化
加入烟雾浓度检测,浓烟时自动降速,保障视野与通信
优化故障诊断逻辑,细分过流、堵转、过热等故障类型,分级处理
增加远程急停控制,支持后台远程触发互锁停机
6、双轮协同转向+消防作业协同控制程序(核心:协同转向+作业联动)
适用场景:大型火场作业,机器人需边行驶边喷水/送风,双轮精准协同转向,保障作业精度。
核心逻辑
双BLDC差速实现原地转向、曲线行驶,转向精度可控
行驶速度与作业设备联动,移动时自动控制消防水炮/风机启停
互锁急停联动作业设备,停机时同步关闭作业,保障安全
// 双BLDC协同转向+消防作业程序
// 硬件:双BLDC、编码器、水炮/风机、急停、PWM驱动
// 功能:精准转向、协同行驶、作业联动、安全急停
#include <Arduino.h>
// ========== 硬件定义 ==========
const byte MOTOR_PWM[2]={9,10}, MOTOR_DIR[2]={8,11};
const byte ENC_PIN[2]={2,4};
const byte ESTOP = 12;
const byte WATER_VALVE=13, FAN=14;
// ========== 控制参数 ==========
int targetLeft=130, targetRight=130;
int turnAngle = 0; // 转向角度(正右,负左)
long enc[2]={0,0}, lastEnc[2]={0,0};
bool workActive=false;
// ========== 函数声明 ==========
void decodeTurn(int angle);
bool estopCheck();
void controlWork();
void driveMotors(int l, int r);
void setup() {
Serial.begin(115200);
Serial.println("消防作业协同系统启动");
for(uint8_t i=0;i<2;i++) {
pinMode(MOTOR_PWM[i], OUTPUT); pinMode(MOTOR_DIR[i], OUTPUT);
} pinMode(ESTOP, INPUT_PULLUP);
pinMode(WATER_VALVE, OUTPUT); pinMode(FAN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(ENC_PIN[0]), [](){ enc[0]++; }, RISING); attachInterrupt(digitalPinToInterrupt(ENC_PIN[1]), [](){ enc[1]++; }, RISING);
}
void loop() {
// 急停检测
if (!estopCheck()) {
driveMotors(0,0); digitalWrite(WATER_VALVE,LOW); digitalWrite(FAN,LOW);
Serial.println("急停触发,作业停止");
while(!estopCheck()) delay(100);
}
// 解码转向指令
decodeTurn(turnAngle);
// 轮速闭环
unsigned long dt = millis();
int leftPWM = targetLeft + (enc[0]-lastEnc[0]);
int rightPWM = targetRight + (enc[1]-lastEnc[1]);
driveMotors(leftPWM, rightPWM);
// 作业联动
controlWork();
lastEnc[0]=enc[0]; lastEnc[1]=enc[1];
Serial.print("左速:");Serial.print(targetLeft);
Serial.print(" 右速:");Serial.print(targetRight);
delay(20);
}
// 转向指令解码,差速实现转向
void decodeTurn(int angle) {
if (angle >50) { targetLeft=100; targetRight=160; }
else if (angle <50) { targetLeft=160; targetRight=100; }
else { targetLeft=130; targetRight=130; }
}
// 急停检测
bool estopCheck() { return digitalRead(ESTOP)==HIGH; }
// 作业联动
void controlWork() {
if (abs(targetLeft-targetRight) <20) { // 直行/微调开启作业
digitalWrite(WATER_VALVE,HIGH); digitalWrite(FAN,HIGH); workActive=true;
} else { // 转向时减少作业,避免偏移
digitalWrite(WATER_VALVE,LOW); digitalWrite(FAN,LOW); workActive=false;
}
}// 双电机驱动
void driveMotors(int leftPWM, int rightPWM) {
leftPWM = constrain(leftPWM,0,200);
rightPWM = constrain(rightPWM,0,200);
digitalWrite(MOTOR_DIR[0], HIGH); digitalWrite(MOTOR_DIR[1], HIGH);
analogWrite(MOTOR_PWM[0], leftPWM); analogWrite(MOTOR_PWM[1], rightPWM);
}
适用场景优化
加入作业距离检测,精准控制水炮喷射角度,提升灭火效率
实现转向记忆功能,复杂场景下重复精准转向,适配火场布局
联动环境传感器,高温区域自动加大作业强度,提升灭火效果
要点解读
要点1:双路冗余设计,提升设备可靠性
消防作业环境恶劣,单侧电机/线路故障可能导致机器人瘫痪,双路冗余是核心保障。
硬件冗余:左右轮独立电机、驱动电路、编码器、急停按键,关键部件双份配置,避免单点故障
动力冗余:单侧故障时,对侧电机可独立运行,支撑机器人撤离或继续作业,降低作业中断风险
信号冗余:关键控制信号双路传输,减少信号丢失或干扰,保障控制指令稳定下达
要点2:互锁急停必须双路联动,杜绝误动作
急停是消防机器人的安全底线,互锁设计能避免单开关失效导致的安全事故。
双通道联锁:左右急停按键串联,任意一个触发即切断总电源,防止单急停损坏后失效
强制复位逻辑:急停触发后,必须双路同时复位才能重启,避免误复位或单复位启动
联动作业停机:急停触发时,行驶电机与作业设备同步断电,彻底终止动作,保障现场安全
要点3:独立闭环控制,保障行走与转向精度
双轮独立控制是轮式机器人灵活转向的基础,闭环反馈可抵消负载、地形干扰。
独立PID控制:左右轮各成闭环,分别采集编码器反馈,精准控制转速,避免差速偏差
差速转向精准:通过左右轮转速差实现转向、原地转弯,转向角度可控,适配窄小火场空间
动态补偿:负载变化、地面坡度干扰时,实时调整电机输出,保持速度与转向稳定
要点4:故障诊断+容错运行,兼顾安全与作业效率
火场情况复杂,需精准识别故障并分级处理,避免因小故障完全停机影响救援。
分级故障判定:区分致命故障(堵转、短路)和非致命故障(信号波动),致命故障立即急停,非致命故障可降速运行
自动恢复机制:非致命故障延时复位,自动重启运行,减少作业中断,提升救援连续性
预警提示:故障发生时及时上报后台,提示运维人员,便于快速排查隐患
要点5:行驶与作业联动,适配消防场景实际需求
消防机器人核心是救援作业,行驶控制需与灭火、送风等作业功能协同。
速度-作业联动:直行稳定时全功率作业,转向时降低作业强度,避免移动偏移影响作业精度
环境自适应调整:浓烟、高温环境自动调整行驶速度与作业功率,保障机器人稳定与灭火效果
协同调度:支持多机协同,双轮控制与作业系统统一调度,适配大型火场联合救援
请注意:以上案例仅作为思路拓展的参考示例,不保证完全正确、适配所有场景或可直接编译运行。由于硬件平台、实际使用场景、Arduino 版本的差异,均可能影响代码的适配性与使用方法的选择。在实际编程开发时,请务必根据自身硬件配置、使用场景及具体功能需求进行针对性调整,并通过多次实测验证效果;同时需确保硬件接线正确,充分了解所用传感器、执行器等设备的技术规范与核心特性。对于涉及硬件操作的代码,使用前务必核对引脚定义、电平参数等关键信息的准确性与安全性,避免因参数错误导致硬件损坏或运行异常。

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


所有评论(0)