跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

Arduino BLDC 机器人 IMU 角度读取与 PID 互补滤波控制

基于 Arduino 平台构建的 BLDC 机器人姿态控制系统,整合了 MPU6050 IMU 数据读取、互补滤波算法与 PID 控制策略。文章详细阐述了传感器融合原理、PID 参数整定方法以及电机驱动实现,提供了两轮自平衡、四轴飞行器及云台稳定的代码示例。重点强调了硬件抗干扰设计、实时采样周期保障及校准步骤,为嵌入式姿态控制开发提供实战参考。

BackendPro发布于 2026/3/24更新于 2026/7/2533 浏览
Arduino BLDC 机器人 IMU 角度读取与 PID 互补滤波控制

基于 Arduino 平台实现 BLDC 机器人的 IMU 角度读取、互补滤波及 PID 控制,构成了典型的姿态闭环系统。这套架构是自平衡机器人或稳定云台的核心技术栈,通过融合传感器数据获取精准姿态,再由 PID 计算驱动力矩驱动电机。

核心在于三块:传感器融合、决策大脑和执行机构。互补滤波作为感知中枢,解决了单一传感器无法兼顾动态与静态精度的问题。它利用低通滤波处理加速度计提取重力方向,高通滤波处理陀螺仪捕捉角速度变化,最后加权平均得到稳定角度。PID 控制器则是决策大脑,比例项提供恢复力,微分项抑制振荡,积分项消除静差(平衡系统中通常设为 0)。BLDC 电机负责执行,其快速响应特性适合跟随 PWM 指令产生恢复力矩。

应用场景很广,比如两轮自平衡机器人,通过检测俯仰角维持垂直平衡;云台稳定系统,反向旋转抵消晃动;或是倒立摆实验装置验证控制算法。实际开发中要注意硬件选型与抗干扰。IMU 推荐 MPU6050 或 ICM-20689,需刚性固定在重心附近,远离电机干扰。电源要隔离,防止电机启停拉低电压导致复位。算法实现上,滤波器系数 α 通常在 0.95~0.98 之间,PID 参数建议'由小到大'试凑,采样频率建议≥100Hz,严禁使用 delay() 阻塞主循环。

实战中,我们可以参考以下代码结构,涵盖基础平衡、四轴简化版及云台单轴控制。

1. 两轮自平衡机器人(IMU 角度读取 + PID 控制)

#include <Wire.h>
#include <MPU6050.h>
#include <SimpleFOC.h>

MPU6050 mpu;
BLDCMotor motor(7);
Encoder encoder(2, 3); // 编码器引脚

// PID 参数
float Kp = 40.0, Ki = 10.0, Kd = 0.5;
float targetAngle = 0.0; // 目标角度(垂直平衡点)
float previousError = 0, integral = 0;

// 互补滤波参数
float alpha = 0.98; // 加速度计权重
float dt = 0.01;    // 采样时间 (s)
float filteredAngle = 0;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  mpu.initialize();
  mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);
  mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
  
  motor.init();
  encoder.init();
  motor.linkEncoder(&encoder);
}

void loop() {
  // 1. 读取 IMU 数据
  int16_t ax, ay, az, gx, gy, gz;
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  // 2. 互补滤波计算角度
  float accelAngle = atan2(ay, az) * RAD_TO_DEG;
  float gyroRate = gx / 131.0; // 转换为°/s
  static float gyroAngle = 0;
  gyroAngle += gyroRate * dt;
  filteredAngle = alpha * (filteredAngle + gyroAngle * dt) + (1 - alpha) * accelAngle;

  // 3. PID 控制
  float error = targetAngle - filteredAngle;
  integral += error * dt;
  float derivative = (error - previousError) / dt;
  float output = Kp * error + Ki * integral + Kd * derivative;
  previousError = error;

  // 4. 电机控制(限制输出范围)
  motor.move(constrain(output, -10, 10));

  // 调试输出
  Serial.print("Angle: ");
  Serial.print(filteredAngle);
  Serial.print(" Output: ");
  Serial.println(output);

  delay(dt * 1000); // 保持固定采样周期
}

2. 四轴飞行器姿态控制(简化版)

#include <Wire.h>
#include <MPU6050.h>
#include <Servo.h>

MPU6050 mpu;
Servo motors[4]; // 4 个电机

// PID 参数(俯仰/滚转/偏航)
float Kp_pitch = 1.2, Ki_pitch = 0.05, Kd_pitch = 0.8;
float Kp_roll = 1.2, Ki_roll = 0.05, Kd_roll = 0.8;
float targetPitch = 0, targetRoll = 0;

// 互补滤波
float alpha = 0.95;
float pitchAngle = 0, rollAngle = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  mpu.initialize();
  // 初始化电机
  for (int i = 0; i < 4; i++) {
    motors[i].attach(5 + i); // 引脚 5-8
    motors[i].write(90);     // 初始中立位置
  }
}

void computeAngles() {
  int16_t ax, ay, az, gx, gy, gz;
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  // 加速度计角度
  float accelPitch = atan2(-ax, sqrt(ay * ay + az * az)) * RAD_TO_DEG;
  float accelRoll = atan2(ay, az) * RAD_TO_DEG;

  // 陀螺仪积分
  static float gyroPitch = 0, gyroRoll = 0;
  gyroPitch += gy / 131.0 * 0.01;
  gyroRoll += gx / 131.0 * 0.01;

  // 互补滤波
  pitchAngle = alpha * (pitchAngle + gyroPitch) + (1 - alpha) * accelPitch;
  rollAngle = alpha * (rollAngle + gyroRoll) + (1 - alpha) * accelRoll;
}

void loop() {
  static unsigned long lastTime = 0;
  unsigned long now = millis();
  if (now - lastTime >= 10) { // 100Hz 控制频率
    lastTime = now;
    // 1. 计算姿态角
    computeAngles();

    // 2. PID 控制(简化版:仅俯仰和滚转)
    static float iTerm_pitch = 0, iTerm_roll = 0;
    float errorPitch = targetPitch - pitchAngle;
    float errorRoll = targetRoll - rollAngle;
    iTerm_pitch += errorPitch * 0.01;
    iTerm_roll += errorRoll * 0.01;
    float outputPitch = Kp_pitch * errorPitch + Ki_pitch * iTerm_pitch;
    float outputRoll = Kp_roll * errorRoll + Ki_roll * iTerm_roll;

    // 3. 电机混合(十字型布局)
    int throttle = 1100; // 基础油门(PWM 值)
    int m1 = throttle + outputPitch + outputRoll;
    int m2 = throttle - outputPitch + outputRoll;
    int m3 = throttle - outputPitch - outputRoll;
    int m4 = throttle + outputPitch - outputRoll;

    // 4. 限制输出并写入电机
    for (int i = 0; i < 4; i++) {
      int val = i == 0 ? m1 : i == 1 ? m2 : i == 2 ? m3 : m4;
      motors[i].write(constrain(map(val, 1000, 2000, 0, 180), 0, 180));
    }
  }
}

3. 云台稳定系统(单轴)

#include <Wire.h>
#include <MPU6050.h>
#include <SimpleFOC.h>

MPU6050 mpu;
BLDCMotor motor(7);
Encoder encoder(2, 3);

// PID 参数
float Kp = 2.0, Ki = 0.1, Kd = 0.05;
float targetAngle = 90.0; // 目标角度(度)

// 互补滤波
float alpha = 0.92;
float filteredAngle = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  mpu.initialize();
  motor.init();
  encoder.init();
  motor.linkEncoder(&encoder);
}

void loop() {
  static unsigned long lastTime = 0;
  unsigned long now = millis();
  float dt = (now - lastTime) / 1000.0;
  if (dt > 0.1) dt = 0.1; // 限制最大 dt

  // 1. 读取 IMU
  uint16_t ax, ay, az, gx, gy, gz;
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  // 2. 互补滤波(假设绕 X 轴旋转)
  float accelAngle = atan2(ay, az) * RAD_TO_DEG;
  float gyroRate = gx / 131.0;
  static float gyroAngle = 0;
  gyroAngle += gyroRate * dt;
  filteredAngle = alpha * (filteredAngle + gyroAngle * dt) + (1 - alpha) * accelAngle;

  // 3. PID 控制
  static float integral = 0;
  float error = targetAngle - filteredAngle;
  integral += error * dt;
  float derivative = (error - (lastTime ? (targetAngle - filteredAngle) : 0)) / dt;
  float output = Kp * error + Ki * integral + Kd * derivative;

  // 4. 电机控制
  motor.move(output);

  // 调试输出
  if (now - lastTime >= 50) { // 20Hz 打印
    Serial.print("Target: ");
    Serial.print(targetAngle);
    Serial.print(" Actual: ");
    Serial.print(filteredAngle);
    Serial.print(" Output: ");
    Serial.println(output);
    lastTime = now;
  }
}

要点解读

IMU 数据读取与处理 关键点在于单位转换。加速度计数据需用 atan2 计算角度,陀螺仪数据需根据量程设置转换(如 /131.0 对应±250°/s 量程)。优化建议是添加校准程序消除零偏,或使用 DMP(数字运动处理器)硬件解算。

互补滤波实现 核心公式为 angle = α * (angle + gyro * dt) + (1-α) * accel_angle。参数选择上,α接近 1 时信任陀螺仪(动态响应快但易漂移),α接近 0 时信任加速度计(无漂移但噪声大)。代码技巧是使用静态变量保持状态,并限制积分项增长防止饱和。

PID 控制实现细节 常见问题包括微分项噪声过大,建议使用 (error - previousError)/dt 而非直接微分陀螺仪数据。积分项漂移可通过添加限幅解决。调试技巧是先调 P 参数,再调 D,最后调 I,并通过串口打印观察响应曲线。

实时性保障措施 固定采样周期至关重要。使用 millis() 而非 delay() 实现定时控制,动态调整 dt 但限制最大值。对于低端 MCU(如 Arduino UNO),建议控制频率≤100Hz,避免在循环中使用浮点除法消耗资源。

以上案例旨在拓展思路,实际使用时请根据硬件配置、场景和需求进行调整测试,确保连接安全与参数正确。

目录

  1. 1. 两轮自平衡机器人(IMU 角度读取 + PID 控制)
  2. 2. 四轴飞行器姿态控制(简化版)
  3. 3. 云台稳定系统(单轴)
  4. 要点解读
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Java 剪辑接单报价比价系统架构设计与实现
  • 使用 Trae IDE 与 MCP Server 将 Figma 设计稿转为前端代码
  • Kiro IDE 实战:Spec 驱动 AI 编程,需求明确自动出代码
  • CosyVoice3 支持 ARPAbet 音素标注,提升英文发音准确性
  • Java 模拟算法题目练习
  • Rust 控制流详解:条件、循环与模式匹配
  • C++ 核心就业方向与技术成长指南
  • 大模型 LLMs 热门研究方向盘点:RAG、Agent、Mamba、MoE、LoRA
  • Cookie 与 Session:Web 用户状态管理详解
  • Web3 开发者必懂的 10 个核心 ERC 标准
  • VSCode 中配置 Copilot MCP 快速上手指南
  • OpenAI gpt-oss 开源模型本地部署教程
  • RabbitMQ/Spring-AMQP 高级特性:事务机制与消息限流实战
  • 无人机视觉语言导航入门:概念、挑战与应用
  • 基于 MCP+Skill 的前端 JS 逆向自动化落地实践
  • OpenClaw 多 Agent 与多飞书机器人配置指南
  • llama-cpp-python 完整安装与配置指南
  • 前端安全实战:密码加密与常见攻击防护
  • OpenClaw 微信通道插件接入与配置指南
  • 数据结构与算法核心知识点梳理及学习建议

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online