在这里插入图片描述
以专业的视角来看,基于Arduino(通常指ESP32平台)与BLDC(无刷直流电机)的机器人双机ESP-NOW通信与动态协同避障系统,是一个集成了低延迟无线通信、多智能体协同控制与高动态底层执行的复杂工程。该系统旨在解决多机器人系统在无中心基站环境下,如何实现高效状态共享、防碰撞以及平滑避让的核心难题。
一、 主要特点
基于ESP-NOW的超低延迟去中心化通信
系统采用ESP-NOW协议作为通信骨干。该协议无需依赖路由器或接入点,支持点对点或广播通信,且数据包大小可达250字节,端到端延迟通常低于5毫秒。这种去中心化架构使得双机地位平等,仅依靠局部交互即可涌现出全局的协同行为,极大提升了系统的可扩展性和鲁棒性。
基于互惠速度障碍(RVO)的动态协同避障
在避障算法层面,系统超越了传统的单向避障,采用互惠速度障碍(RVO)算法。RVO引入了“互惠”思想,即假设对方也会采取一半的避让动作。当双机距离进入预测半径时,系统会计算出一个平滑的避让速度矢量,驱动BLDC电机执行优雅的绕行,有效避免了传统算法中双方陷入“死锁”或“Z字形震荡”的问题。
BLDC底盘的高动态响应与柔顺执行
协同避障的决策最终依赖于底层执行。BLDC电机配合FOC(磁场定向控制)算法,在极低速下依然能提供平滑的扭矩输出,消除了传统直流电机的步进感。其高动态响应能力确保了机器人能够精准、无延迟地执行RVO解算出的复杂速度指令,实现敏捷的差速转向或加减速。
通信容错与系统鲁棒性设计
在无线通信中,丢包是不可避免的。系统在软件架构上进行了防丢包设计:即使在短暂收不到对方坐标数据时,机器人也不会“卡死”,而是依靠上一帧的指令继续运动或执行安全减速,保证了多机协同系统的连续性与鲁棒性。
二、 应用场景
仓储物流与柔性制造
在自动化仓库或柔性制造车间,多台AGV(自动导引车)需要在狭窄通道内交汇。双机协同避障系统能够实时感知对方意图,自动协商通行优先级或平滑绕行,避免交通拥堵和碰撞,保障物流流转的高效与安全。
多机协同编队与领航-跟随
在安防巡逻或物资运输场景中,采用“领航者-跟随者(Leader-Follower)”策略。领航者负责全局路径规划,跟随者通过ESP-NOW接收领航者的实时坐标与航向,结合PID控制保持固定的相对位置,实现刚性或柔性编队行进。
群体机器人与区域覆盖
在灾后搜救或大面积环境监测中,多台机器人以群体形式工作。通过局部交互和状态广播,机器人能够自主实现聚集、分散或区域覆盖(如Boids算法)。即使单台机器人发生故障,也不会导致整个任务中止,具备极强的容错能力。
前沿科研与机器人学教育
该平台是高校和科研机构验证多智能体系统(MAS)、分布式控制算法及RVO/VO避障理论的绝佳低成本硬件平台。学生可通过修改ESP-NOW的数据结构和RVO核心计算逻辑,直观地观察群体智能的涌现过程。
三、 需要注意的事项
通信延迟补偿与预测机制
尽管ESP-NOW延迟极低,但在高速运动中,5-10毫秒的延迟仍可能导致位置误差。系统必须引入运动学预测模型(如基于当前速度和航向推算下一时刻位置),以补偿通信延迟带来的位置偏差,确保RVO计算的准确性。
算力瓶颈与“上下位机”架构
实时运行RVO算法、处理多传感器数据并执行FOC控制对MCU算力要求较高。若使用传统的8位Arduino(如Uno)极易导致控制周期过长。建议采用ESP32作为核心控制器,或采用“上位机+下位机”架构,由高性能MCU负责协同决策,专用驱动板负责BLDC闭环控制。
安全冗余与失效保护机制
自主协同系统必须设置多重安全防线。硬件上需设置最大速度限制(如500mm/s)和物理急停按钮;软件上需设定最小安全距离(如20cm),一旦侵入立即触发紧急制动。同时,若超时未收到对方信号,系统应自动进入安全停止模式,防止因通信彻底中断导致的失控。
通信安全与抗干扰设计
在复杂的电磁环境中,为防止数据被截获或恶意干扰,可利用ESP-NOW的安全密钥功能进行设备身份验证,确保只有授权的机器人节点才能加入协同网络。此外,BLDC电机的高频PWM噪声可能干扰无线模块,需在PCB布局上做好强弱电隔离与电源去耦。

在这里插入图片描述
1、双机位置广播 + 相对距离避障(基础版)
——机器人A(发射端)

#include <esp_now.h>
#include <WiFi.h>

typedef struct {
    float x;
    float y;
    float heading;
} RobotPos;

RobotPos myPos = {0, 0, 0};
RobotPos peerPos;

esp_now_peer_info_t peerInfo;

void onDataSent(const uint8_t *mac, esp_now_send_status_t status) {}

void setup() {
    Serial.begin(115200);
    WiFi.mode(WIFI_STA);
    
    if (esp_now_init() != ESP_OK) {
        Serial.println("ESP-NOW Init Failed");
        return;
    }
    esp_now_register_send_cb(onDataSent);
    
    uint8_t peerMac[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // 替换为机器人B的MAC
    memcpy(peerInfo.peer_addr, peerMac, 6);
    peerInfo.channel = 0;
    peerInfo.encrypt = false;
    esp_now_add_peer(&peerInfo);
}

void loop() {
    myPos.x += 0.1;  // 模拟移动
    myPos.y += 0.05;
    myPos.heading = atan2(myPos.y, myPos.x) * 180 / PI;
    
    esp_now_send(peerInfo.peer_addr, (uint8_t*)&myPos, sizeof(myPos));
    
    float dx = peerPos.x - myPos.x;
    float dy = peerPos.y - myPos.y;
    float dist = sqrt(dx*dx + dy*dy);
    
    if (dist < 50) {
        Serial.print("COLLISION RISK! Dist:");
        Serial.println(dist);
        // 触发BLDC减速
        analogWrite(3, map(dist, 0, 50, 0, 255));
    }
    delay(100);
}

——机器人B(接收端)

#include <esp_now.h>
#include <WiFi.h>

typedef struct {
    float x;
    float y;
    float heading;
} RobotPos;

RobotPos myPos = {10, 0, 0};
RobotPos peerPos;

void onDataRecv(const esp_now_recv_info *info, const uint8_t *data, int len) {
    memcpy(&peerPos, data, sizeof(peerPos));
}

void setup() {
    Serial.begin(115200);
    WiFi.mode(WIFI_STA);
    esp_now_init();
    esp_now_register_recv_cb(onDataRecv);
}

void loop() {
    float dx = peerPos.x - myPos.x;
    float dy = peerPos.y - myPos.y;
    float dist = sqrt(dx*dx + dy*dy);
    
    Serial.print("Peer:");
    Serial.print(dist);
    Serial.print("m Heading:");
    Serial.println(peerPos.heading);
    
    if (dist < 40) {
        // 协同避障:双方同时右转
        analogWrite(5, 180);  // 右电机减速
        analogWrite(6, 255);  // 左电机全速
    }
    delay(50);
}

2、双机速度协商 + 动态让行(进阶版)

#include <esp_now.h>
#include <SimpleFOC.h>

BLDCMotor motorL(11), motorR(11);
BLDCDriver3PWM driver(9, 10, 11, 8);

typedef struct {
    float speed;       // 当前速度 cm/s
    float priority;    // 优先级 0~1
    uint32_t timestamp;
} CmdPacket;

CmdPacket myCmd = {0, 0.5, 0};
CmdPacket peerCmd;

void onDataRecv(const esp_now_recv_info *info, const uint8_t *data, int len) {
    memcpy(&peerCmd, data, sizeof(peerCmd));
}

void setup() {
    Serial.begin(115200);
    motorL.init(); motorR.init();
    driver.init(); driver.voltage_power_supply = 12;
    driver.initFOC();
    
    WiFi.mode(WIFI_STA);
    esp_now_init();
    esp_now_register_recv_cb(onDataRecv);
    
    uint8_t peerMac[] = {0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
    esp_now_peer_info_t p = {0};
    memcpy(p.peer_addr, peerMac, 6);
    p.channel = 0; p.encrypt = false;
    esp_now_add_peer(&p);
}

void loop() {
    myCmd.speed = 30.0;  // 当前速度
    myCmd.priority = (millis() % 2000 < 1000) ? 1.0 : 0.3;  // 交替优先权
    myCmd.timestamp = millis();
    
    esp_now_send(peerInfo.peer_addr, (uint8_t*)&myCmd, sizeof(myCmd));
    
    // 协商逻辑:优先级低的让行
    if (peerCmd.priority > myCmd.priority) {
        motorL.move(0); motorR.move(0);  // 停车让行
    } else if (peerCmd.priority < myCmd.priority) {
        motorL.move(1); motorR.move(1);  // 正常通行
    } else {
        // 同优先级:双方同时右转
        motorL.move(0.8); motorR.move(0.3);
    }
    
    motorL.loopFOC(); motorR.loopFOC();
    delay(20);
}

3、三传感器融合 + 双机编队协同(完整版)

#include <esp_now.h>
#include <NewPing.h>
#include <SimpleFOC.h>

#define TRIG 7  #define ECHO 8  #define IR A0
NewPing sonar(TRIG, ECHO, 400);

BLDCMotor mL(11), mR(11);
BLDCDriver3PWM drv(9,10,11,8);

typedef struct {
    float x, y, heading;
    float sonarD, irD;
    uint32_t ts;
} FusionData;

FusionData myData, peerData;

void onRecv(const esp_now_recv_info *i, const uint8_t *d, int len) {
    memcpy(&peerData, d, sizeof(peerData));
}

void setup() {
    Serial.begin(115200);
    mL.init(); mR.init();
    drv.init(); drv.voltage_power_supply = 12;
    drv.initFOC();
    
    WiFi.mode(WIFI_STA);
    esp_now_init();
    esp_now_register_recv_cb(onRecv);
    
    uint8_t p[] = {0x11,0x22,0x33,0x44,0x55,0x66};
    esp_now_peer_info_t pi = {0};
    memcpy(pi.peer_addr, p, 6); pi.channel = 0; pi.encrypt = false;
    esp_now_add_peer(&pi);
}

void loop() {
    // 1. 多传感器采集
    myData.sonarD = sonar.ping_cm();
    myData.irD = analogRead(IR) * 0.5;
    myData.heading = (myData.sonarD < 30) ? 90 : 0;  // 近距右转
    myData.ts = millis();
    
    // 2. 融合避障决策
    float minDist = min(myData.sonarD, myData.irD * 2);
    float avoidAngle = (minDist < 40) ? map(minDist, 0, 40, 180, 0) : 0;
    
    // 3. 编队协同:保持间距80cm
    float dx = peerData.x - myData.x;
    float dy = peerData.y - myData.y;
    float peerDist = sqrt(dx*dx + dy*dy);
    
    float targetSpeed = 1.0;
    if (peerDist < 60) targetSpeed = 0.2;      // 太近,减速
    else if (peerDist > 100) targetSpeed = 1.5; // 太远,加速追队
    
    // 4. BLDC差速输出
    float base = targetSpeed;
    float turn = (avoidAngle - 90) * 0.01;
    mL.move(base - turn);
    mR.move(base + turn);
    mL.loopFOC(); mR.loopFOC();
    
    // 5. 广播自身状态
    esp_now_send(0, (uint8_t*)&myData, sizeof(myData));
    
    Serial.print("D:"); Serial.print(peerDist);
    Serial.print(" S:"); Serial.print(targetSpeed);
    Serial.print(" A:"); Serial.println(avoidAngle);
    delay(30);
}

要点 解读
① ESP-NOW 是"对讲机",不是"对讲机+GPS" 带宽仅 250 bytes/包,延迟 ~10ms,不能传图像、不能传SLAM地图。双机协同的本质是:只交换位置+速度+意图三个标量,所有避障决策在本地完成。这是工业双机通信的铁律——带宽不够,算力来凑。
② 让行协议必须有"仲裁机制",否则死锁 案例二的优先级轮换是最低成本的死锁破解方案。更稳健的做法是ID大小仲裁(MAC地址小的让行),或时间戳仲裁(先到先走)。两机同时判定"我该走"= 双方都停 = 死锁,这在产线上等于停产。
③ 协同避障的核心不是"看见对方",是"预判对方" 案例三的编队保持(60-100cm区间)比单纯避障更有工业价值。巡检机器人的真实场景是:两台机器走同一条轨道,前后间距不能太近(防追尾),也不能太远(防漏检)。ESP-NOW广播的x,y,heading就是为了这个。
④ 通信丢包是常态,必须有"静默安全"策略 ESP-NOW在2.4GHz干扰下丢包率可达10-30%。如果300ms没收到对方数据,必须默认对方已失联→立即减速停车,而不是继续跑。案例中未显式写这个逻辑,但实际部署时这是红线。
⑤ 双机BLDC必须同步控制周期,否则编队散掉 案例三用delay(30)保证33Hz控制周期,这是底线。如果A机100Hz、B机20Hz,3秒后编队就散了。工业方案的标准做法:主机广播同步脉冲,从机以主机周期为基准校准FOC循环,误差控制在±5ms内。

在这里插入图片描述
4、动态跟随 + 防碰撞(Leader–Follower)
适用场景:AGV 双车物流、仓库搬运。前车(Leader)正常避障,后车(Follower)通过 ESP‑NOW 获取前车位姿,维持安全距离,并在前车急停时同步制动。
Leader 端程序(前车)

/* ===== Leader 机器人:ESP‑NOW + 避障 + 位姿广播 =====
 * 硬件:2×BLDC差速底盘 + 超声波前避障 + MPU6050
 * 通信:ESP‑NOW广播自身位姿
 */
#include <SimpleFOC.h>
#include <WiFi.h>
#include <esp_now.h>
#include <Wire.h>
#include <MPU6050.h>

MPU6050 imu;

BLDCMotor mL(5), mR(6);
BLDCDriver3PWM drvL, drvR;
Encoder encL(2,3,2048), encR(4,5,2048);

// 超声波
#define TRIG_F 7
#define ECHO_F 8

// 自身位姿
float x=0, y=0, yaw=0;

// ESP‑NOW
uint8_t followerMAC[] = {0x24,0x6F,0x28,0xAB,0xCD,0xEF};
typedef struct { float x, y, yaw, v; } Pose_t;
Pose_t myPose;

long readCM(uint8_t t, uint8_t e) {
  digitalWrite(t, LOW); delayMicroseconds(2);
  digitalWrite(t, HIGH); delayMicroseconds(10);
  digitalWrite(t, LOW);
  long d = pulseIn(e, HIGH, 30000);
  return d ? d*0.034/2 : 250;
}

void OnSent(const uint8_t*, esp_err_t) {}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  if(esp_now_init()!=ESP_OK) return;
  esp_now_register_send_cb(OnSent);
  esp_now_peer_info_t peer{}; memcpy(peer.peer_addr,followerMAC,6);
  peer.channel=0; peer.encrypt=false;
  esp_now_add_peer(&peer);

  pinMode(TRIG_F, OUTPUT); pinMode(ECHO_F, INPUT);
  Wire.begin();
  imu.initialize();

  mL.controller = MotionControlType::velocity;
  mR.controller = MotionControlType::velocity;
  mL.init(); mL.initFOC();
  mR.init(); mR.initFOC();
}

void loop() {
  float dF = readCM(TRIG_F, ECHO_F);
  float v = (dF>40) ? 150 : ((dF>20)? 60 : 0);

  // 简单位姿更新
  yaw += imu.getRotationZ() * 0.001;
  x += v * cos(yaw) * 0.05;
  y += v * sin(yaw) * 0.05;

  myPose.x=x; myPose.y=y; myPose.yaw=yaw; myPose.v=v;
  esp_now_send(followerMAC, (uint8_t*)&myPose, sizeof(myPose));

  float vL = v - 0.2*yaw;
  float vR = v + 0.2*yaw;
  mL.move(vL); mR.move(vR);
  mL.loopFOC(); mR.loopFOC();

  delay(30);
}

Follower 端程序(后车)

/* ===== Follower 机器人:接收Leader位姿 + 距离保持 ===== */
#include <SimpleFOC.h>
#include <WiFi.h>
#include <esp_now.h>

BLDCMotor mL(5), mR(6);
BLDCDriver3PWM drvL, drvR;
Encoder encL(2,3,2048), encR(4,5,2048);

typedef struct { float x,y,yaw,v; } Pose_t;
Pose_t leader;
bool newData = false;

const float DESIRED_DIST = 60.0; // cm
const float Kp_dist = 1.2;

void OnRecv(const esp_now_recv_info_t*, const uint8_t* data, int len) {
  if(len==sizeof(Pose_t)) {
    memcpy(&leader, data, sizeof(Pose_t));
    newData = true;
  }
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  esp_now_init();
  esp_now_register_recv_cb(OnRecv);

  mL.controller = MotionControlType::velocity;
  mR.controller = MotionControlType::velocity;
  mL.init(); mL.initFOC();
  mR.init(); mR.initFOC();
}

void loop() {
  if(!newData) return;

  static float x=0,y=0;
  float dx = leader.x - x;
  float dy = leader.y - y;
  float dist = sqrt(dx*dx + dy*dy);

  float v = leader.v + Kp_dist*(DESIRED_DIST - dist);
  v = constrain(v, 0, 200);

  float angleErr = atan2(dy, dx) - leader.yaw;
  float vL = v - 0.5*angleErr;
  float vR = v + 0.5*angleErr;

  mL.move(vL); mR.move(vR);
  mL.loopFOC(); mR.loopFOC();

  newData = false;
  delay(30);
}

关键设计点:
Leader 以 30 ms 周期广播位姿(x,y,yaw,v)
Follower 用距离误差 PD 控制维持固定间距
Leader 急停(v=0)时 Follower 自动减速,避免追尾

5、交叉路口互锁协同(Intersection Coordination)
适用场景:厂区 AGV 十字路口、狭窄通道。双机通过 ESP‑NOW 交换“占用请求”,互斥通行,避免死锁。

/* ===== 双机交叉路口协同避障(简化版) =====
 * 通信:ESP‑NOW 交换 {id, state, pos}
 * 状态机:IDLE → REQUEST → GRANTED → PASS → IDLE
 */
#include <WiFi.h>
#include <esp_now.h>

enum State { IDLE, REQUEST, GRANTED, PASS };
State myState = IDLE;

typedef struct {
  uint8_t id;
  State state;
  float pos;  // 距离路口
} Msg_t;

Msg_t tx, rx;
uint8_t peerMAC[] = {0x24,0x6F,0x28,0xAB,0xCD,0xEF};

void OnRecv(const esp_now_recv_info_t*, const uint8_t* data, int len) {
  if(len==sizeof(Msg_t)) memcpy(&rx, data, sizeof(Msg_t));
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  esp_now_init();
  esp_now_register_recv_callback(OnRecv);
  esp_now_peer_info_t peer{}; memcpy(peer.peer_addr,peerMAC,6);
  peer.channel=0; peer.encrypt=false;
  esp_now_add_peer(&peer);

  tx.id = 1;  // 本机ID
}

void loop() {
  float distToJunction = readDistance(); // 伪函数

  switch(myState) {
    case IDLE:
      if(distToJunction < 100) {
        myState = REQUEST;
        tx.state = REQUEST;
        tx.pos = distToJunction;
        esp_now_send(peerMAC, (uint8_t*)&tx, sizeof(tx));
      }
      break;

    case REQUEST:
      if(rx.state == REQUEST) {
        // 按位置仲裁:谁更近谁先走
        if(tx.pos <= rx.pos) {
          myState = GRANTED;
          tx.state = GRANTED;
        } else {
          myState = IDLE;
        }
        esp_now_send(peerMAC, (uint8_t*)&tx, sizeof(tx));
      }
      break;

    case GRANTED:
      driveThroughJunction();
      if(distToJunction > 150) {
        myState = IDLE;
        tx.state = IDLE;
        esp_now_send(peerMAC, (uint8_t*)&tx, sizeof(tx));
      }
      break;
  }

  delay(20);
}

关键设计点:
用状态机明确“谁可以进路口”
仲裁规则简单可验证(距离优先 / ID 优先)
避免双机同时进入造成死锁

6、主从编队 + 并行避障(Formation with Obstacle)
适用场景:双机编队巡检、协同搬运。主机规划路径,从机相对保持固定偏移;各自独立避障,避障结束后重建编队。

/* ===== 主机:路径规划 + 编队参考点广播 ===== */
#include <SimpleFOC.h>
#include <WiFi.h>
#include <esp_now.h>

typedef struct {
  float x_ref, y_ref;   // 编队参考点
  float obs_left, obs_right;
} Form_t;

Form_t tx;
uint8_t slaveMAC[] = {0x24,0x6F,0x28,0xAB,0xCD,0xEF};

void setup() {
  WiFi.mode(WIFI_STA);
  esp_now_init();
  esp_now_peer_info_t peer{}; memcpy(peer.peer_addr,slaveMAC,6);
  peer.channel=0; peer.encrypt=false;
  esp_now_add_peer(&peer);
}

void loop() {
  // 主机自身避障
  float dL = readLeft(), dR = readRight();
  tx.obs_left = dL; tx.obs_right = dR;

  // 编队参考点(主机右侧30cm)
  tx.x_ref = x + 30*cos(yaw+PI/2);
  tx.y_ref = y + 30*sin(yaw+PI/2);

  esp_now_send(slaveMAC, (uint8_t*)&tx, sizeof(tx));
  delay(30);
}
/* ===== 从机:跟踪编队点 + 独立避障 ===== */
#include <SimpleFOC.h>
#include <WiFi.h>
#include <esp_now.h>

typedef struct {
  float x_ref, y_ref;
  float obs_left, obs_right;
} Form_t;

Form_t rx;
bool newRef = false;

void OnRecv(const esp_now_recv_info_t*, const uint8_t* data, int len) {
  if(len==sizeof(Form_t)) {
    memcpy(&rx, data, sizeof(Form_t));
    newRef = true;
  }
}

void loop() {
  if(!newRef) return;

  float dL = readLeft(), dR = readRight();
  float v = 120;

  // 优先避障
  if(dL < 25 || dR < 25) {
    v = 0;
  }

  // 编队跟踪
  float dx = rx.x_ref - x;
  float dy = rx.y_ref - y;
  float dist = sqrt(dx*dx+dy*dy);
  float angle = atan2(dy, dx);

  float vL = v - 0.5*(angle - yaw);
  float vR = v + 0.5*(angle - yaw);

  motorL.move(vL); motorR.move(vR);
  newRef = false;
}

关键设计点:
主机广播“编队参考点”,从机做位置闭环
各自独立避障优先于编队控制
避障结束后自动回到编队点,恢复队形

要点解读
① ESP‑NOW 适合高频低延迟协同,但不保证可靠性
优点:无需路由器、点对点、延迟 < 10 ms、适合 10–50 Hz 位姿广播
缺点:无重传、无ACK
对策:
关键指令(如急停)使用状态机+超时
非关键数据(位姿)容忍丢包
② 协同避障必须区分“个体避障”和“协同决策”
个体层:超声波/ToF 避障 → 立即反应(<50 ms)
协同层:ESP‑NOW 交换意图 → 中速反应(100–200 ms)
不要试图用协同通信解决所有紧急避障,否则必然撞车
③ 通信协议要极简、定长、可预测
推荐固定结构体:

struct Packet {
  uint8_t id;
  uint8_t state;
  float x,y,yaw,v;
};

不使用 JSON / 字符串
不使用变长数组
便于 Arduino 内存管理和实时性
④ 双机协同必须设计显式仲裁规则
常见规则:
距离优先(谁更接近资源/路口)
ID 固定优先级(主机永远优先)
时间戳(先到先得)
避免隐式竞争(如“谁算得快谁赢”),否则调试极其困难。
⑤ 状态机 + 超时保护是工业级双机协同的底线
每个机器人维护自己的状态机(IDLE / REQUEST / ACTIVE / STOP)
每次收到消息都要校验状态合法性
增加通信超时(如 200 ms 未收到 → 进入安全态)
示例:

if(millis() - lastRx > 200) {
  enterSafeStop();
}

工程提醒:上述代码为教学骨架,实际部署需补充:
SimpleFOC 电流限制与 PWM 参数
ESP‑NOW 多播 / 加密配置
位姿估计(里程计 + IMU)
看门狗与急停逻辑

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

在这里插入图片描述

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐