睿诚科技协会

arduino四旋翼无人机

第一部分:核心概念与工作原理

在开始之前,你需要理解无人机是如何飞行的。

arduino四旋翼无人机-图1
(图片来源网络,侵删)
  1. 基本结构:

    • 机架: 无人机的骨架,连接所有部件。
    • 电机与螺旋桨: 4 个电机,每个电机带动一个螺旋桨,提供升力。
    • 电调: 电子调速器,接收来自控制板的 PWM 信号,控制电机的转速。
    • 飞行控制板: 核心大脑,负责处理传感器数据、计算控制指令,并向电调发送信号。
    • 电池: 提供动力,通常是 LiPo 电池。
    • 遥控器与接收机: 用于手动控制无人机起飞、转向、飞行模式切换等。
  2. 飞行姿态与控制: 无人机通过改变四个电机的转速来实现不同姿态的飞行。

    • 俯仰: 无人机前后倾斜,通过增加后侧两个电机的转速,同时减小前侧两个电机的转速实现前进。
    • 横滚: 无人机左右倾斜,通过增加右侧两个电机的转速,同时减小左侧两个电机的转速实现向右飞行。
    • 偏航: 无人机水平旋转,通过对角线上两个电机的转速增加,另外两个对角线上的电机转速减小(左前+右后,右前+左后)实现,这是由于螺旋桨的反扭矩效应。
    • 升降: 所有四个电机的同时增加或减小转速,实现上升或下降。
  3. 传感器与姿态解算: 控制板需要知道无人机当前的姿态(角度)才能进行稳定控制,这通常通过以下传感器组合实现:

    • 陀螺仪: 测量角速度(旋转速度),但它有温漂问题,数据会随时间产生偏差。
    • 加速度计: 测量加速度(包括重力加速度),可以用来测量静态姿态(俯仰角和横滚角),但在运动中(比如飞行时)数据会非常“抖动”且不准确。
    • 磁力计: 测量地磁场,用于确定机头朝向(航向角)。

    传感器融合: 单独使用任何一个传感器都不行,我们需要将陀螺仪、加速度计和磁力计的数据融合起来,得到一个准确、平滑的姿态估计,最常用的算法是 MadgwickMahony 算法,幸运的是,很多现成的库已经帮我们实现了这些算法。

    arduino四旋翼无人机-图2
    (图片来源网络,侵删)

第二部分:所需硬件清单

对于初学者,我强烈建议使用集成了传感器和必要电路的开发板,而不是从零开始焊接所有元件。

初学者首选(强烈推荐)

  • 飞行控制板: Arduino Mega 2560 + GY-68 (MPU-6050) 传感器板,这是最经典、资料最多的组合,MPU-6050 集成了 3 轴陀螺仪和 3 轴加速度计,你需要自己添加一个磁力计(如 HMC5883L)。
  • 升级版: Arduino Due + GY-85 (或类似的 10DOF 传感器板),Due 性能更强,可以处理更复杂的传感器融合,GY-85 通常集成了 MPU-6050、HMC5883L 和气压计(用于高度测量)。

集成度更高(推荐有一定基础后使用)

  • 飞行控制板: MultiWii, Cleanflight, Betaflight 等开源固件的开发板(如 Naze32, Flip32, SPRacingF3),这些板子性能强大,但配置和调试相对复杂,通常需要使用专门的配置软件(如 Cleanflight Configurator),它们的核心也是基于 Arduino 或类似架构的,但底层优化得更好。

通用硬件清单

  1. 主控板: Arduino Mega 2560 或 Arduino Due。
  2. IMU 传感器模块: GY-68 (MPU-6050) + HMC5883L (磁力计)。
  3. 电机: 4 个无刷直流电机(KV 值根据你的机架大小选择,如 1006 KV1500)。
  4. 电调: 4 个 2-4S 的无刷电调,确保支持你选择的电机和电池。
  5. 螺旋桨: 2 对(4 个)正反桨(2 个 CW 顺时针,2 个 CCW 逆时针)。
  6. 机架: 150mm 或 200mm 的四轴机架。
  7. 电池: 1S 或 2S 的 LiPo 电池(1S 更安全,动力稍弱;2S 动力强,但风险也高)。
  8. 遥控器与接收机: 至少 4 通道的遥控器(用于油门、副翼、升降、方向)和配套的接收机。
  9. 其他: 杜邦线、香蕉线(连接电池和电调)、热缩管、扎带、螺丝等。

第三部分:软件架构与代码

这是项目的核心,我们将分步实现。

环境准备

  • 安装 Arduino IDE
  • 安装必要的库:
    • Wire.h: 用于 I2C 通信,与 MPU-6050 通信必需。
    • I2Cdev.h: MPU-6050 的底层驱动库。
    • MPU6050.h: MPU-6050 的上层库。
    • HMC5883L.h: 磁力计库。
    • Madgwick.hMahony.h: 传感器融合库(推荐 Madgwick)。
    • PID_v1.h: PID 控制算法库。

硬件连接

  • IMU -> Arduino:
    • VCC -> 5V
    • GND -> GND
    • SCL -> SCL (Arduino Mega: 21, Arduino Due: 22)
    • SDA -> SDA (Arduino Mega: 20, Arduino Due: 21)
  • 电调 -> Arduino:
    • 每个电调的信号线连接到 Arduino 的一个 PWM 引脚(3, 5, 6, 9)。注意: 这些引脚必须支持 analogWrite()
  • 接收机 -> Arduino:
    • 接收机的通道信号线连接到另外的 PWM 引脚(2, 4, 7, 8)。

代码实现步骤

我们将代码分为几个模块:

步骤 1:传感器初始化与读取

arduino四旋翼无人机-图3
(图片来源网络,侵删)
#include <Wire.h>
#include <I2Cdev.h>
#include <MPU6050.h>
#include <HMC5883L.h>
#include <Madgwick.h>
// 创建传感器对象
MPU6050 mpu;
HMC5883L mag;
// 创建 Madgwick 滤波器对象
Madgwick filter;
// 陀螺仪和加速度计原始数据
int16_t ax, ay, az, gx, gy, gz;
// 磁力计原始数据
int16_t mx, my, mz;
void setup() {
  Serial.begin(57600);
  Wire.begin();
  // 初始化 MPU6050
  mpu.initialize();
  if (!mpu.testConnection()) {
    Serial.println("MPU6050 connection failed!");
    while(1);
  }
  // 初始化 HMC5883L
  mag.initialize();
  if (!mag.testConnection()) {
    Serial.println("HMC5883L connection failed!");
    while(1);
  }
  // 设置 Madgwick 滤波器采样频率
  filter.begin(100); // 假设 loop 函数每秒运行100次
}
void loop() {
  // 读取所有传感器数据
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  mag.getHeading(&mx, &my, &mz);
  // 将原始数据转换为物理单位
  float accX = ax / 16384.0; // 假设加速度计灵敏度为 ±2g
  float accY = ay / 16384.0;
  float accZ = az / 16384.0;
  float gyroX = gx / 131.0; // 假设陀螺仪灵敏度为 ±250 deg/s
  float gyroY = gy / 131.0;
  float gyroZ = gz / 131.0;
  // 更新 Madgwick 滤波器
  filter.updateIMU(gyroX, gyroY, gyroZ, accX, accY, accZ);
  // 获取计算出的姿态角 (弧度)
  float roll = filter.getRoll();
  float pitch = filter.getPitch();
  float yaw = filter.getYaw();
  // 打印到串口用于调试
  Serial.print("Roll: "); Serial.print(roll * 180/M_PI);
  Serial.print("\tPitch: "); Serial.print(pitch * 180/M_PI);
  Serial.print("\tYaw: "); Serial.print(yaw * 180/M_PI);
  Serial.println();
  delay(10); // 控制循环频率
}

测试: 上传这段代码,打开串口监视器,当你慢慢倾斜无人机时,应该能看到 Roll 和 Pitch 值随之变化,转动无人机,Yaw 值也会变化,这是成功的第一步!

步骤 2:读取遥控器信号

你需要一个函数来读取 PWM 信号,通常使用 pulseIn() 函数。

#define CHAN1_PIN 2 // 副翼
#define CHAN2_PIN 4 // 升降
#define CHAN3_PIN 7 // 油门
#define CHAN4_PIN 8 // 方向
int chan1_val, chan2_val, chan3_val, chan4_val;
void readReceiver() {
  chan1_val = pulseIn(CHAN1_PIN, HIGH, 25000); // 约 1-2ms 的脉宽
  chan2_val = pulseIn(CHAN2_PIN, HIGH, 25000);
  chan3_val = pulseIn(CHAN3_PIN, HIGH, 25000);
  chan4_val = pulseIn(CHAN4_PIN, HIGH, 25000);
}

测试: 在 loop() 中调用 readReceiver() 并打印 chan3_val(油门),当你拨动摇杆时,应该能看到数值在 1000-2000 之间变化。

步骤 3:实现 PID 控制器

PID 控制器是无人机的“平衡大师”,它比较“目标值”(我们希望的角度,通常是0)和“当前值”(传感器读到的角度),然后计算出修正量。

#include <PID_v1.h>
// 定义 PID 对象
// PID(&输入值, &输出值, &设定值, Kp, Ki, Kd, 方向)
double rollInput, rollOutput, rollSetpoint = 0;
double pitchInput, pitchOutput, pitchSetpoint = 0;
double yawInput, yawOutput, yawSetpoint = 0;
// PID 参数,需要实际调试
double Kp_roll = 1.0, Ki_roll = 0.1, Kd_roll = 0.01;
double Kp_pitch = 1.0, Ki_pitch = 0.1, Kd_pitch = 0.01;
double Kp_yaw = 1.0, Ki_yaw = 0.01, Kd_yaw = 0.0;
// 创建 PID 实例
PID rollPID(&rollInput, &rollOutput, &rollSetpoint, Kp_roll, Ki_roll, Kd_roll, DIRECT);
PID pitchPID(&pitchInput, &pitchOutput, &pitchSetpoint, Kp_pitch, Ki_pitch, Kd_pitch, DIRECT);
PID yawPID(&yawInput, &yawOutput, &yawSetpoint, Kp_yaw, Ki_yaw, Kd_yaw, DIRECT);
void setupPIDs() {
  rollPID.SetMode(AUTOMATIC);
  pitchPID.SetMode(AUTOMATIC);
  yawPID.SetMode(AUTOMATIC);
}

loop() 中,将传感器读到的角度赋值给 rollInputpitchInput,然后调用 rollPID.Compute()pitchPID.Compute() 得到 rollOutputpitchOutput

步骤 4:混合电机输出

这是最后一步,将 PID 输出、遥控器输入和基础油门混合,计算出最终给每个电机的 PWM 值。

// 电机引脚定义
#define M1_PIN 3 // 前左
#define M2_PIN 5 // 前右
#define M3_PIN 6 // 后左
#define M4_PIN 9 // 后右
// 电机基础油门
float base_throttle;
void mixOutput() {
  // 1. 从遥控器获取基础油门
  base_throttle = map(chan3_val, 1000, 2000, 1000, 1500); // 将遥控器油门映射到安全范围
  // 2. 应用 PID 修正
  // 电机布局:
  //   M1(FL)   M2(FR)
  //   M3(BL)   M4(BR)
  // 横滚控制: 左右电机速度差
  int roll_mix = rollOutput; // rollOutput 可能为正或负
  // 俯仰控制: 前后电机速度差
  int pitch_mix = pitchOutput; // pitchOutput 可能为正或负
  // 偏航控制: 对角电机速度差
  int yaw_mix = yawOutput;
  // 计算每个电机的最终值
  int motor1_val = base_throttle - pitch_mix + roll_mix + yaw_mix;
  int motor2_val = base_throttle - pitch_mix - roll_mix - yaw_mix;
  int motor3_val = base_throttle + pitch_mix + roll_mix - yaw_mix;
  int motor4_val = base_throttle + pitch_mix - roll_mix + yaw_mix;
  // 限制 PWM 值在安全范围内 (通常是 1000-2000)
  motor1_val = constrain(motor1_val, 1000, 2000);
  motor2_val = constrain(motor2_val, 1000, 2000);
  motor3_val = constrain(motor3_val, 1000, 2000);
  motor4_val = constrain(motor4_val, 1000, 2000);
  // 输出到电机
  analogWrite(M1_PIN, motor1_val / 8 - 125); // 电调通常使用 1000-2000 的脉宽,analogWrite 是 0-255
  analogWrite(M2_PIN, motor2_val / 8 - 125);
  analogWrite(M3_PIN, motor3_val / 8 - 125);
  analogWrite(M4_PIN, motor4_val / 8 - 125);
}

注意: analogWrite() 的输出范围是 0-255,而电调通常需要 1000-2000us 的 PWM 信号,上面的 motor_val / 8 - 125 是一个简单的转换(1000/8-125=0, 2000/8-125=125),但更可靠的方法是使用 servo.writeMicroseconds(),更好的做法是使用 Servo 库来控制电调。


第四部分:调试与安全(极其重要!)

绝对不要在室内或人群密集处进行首次试飞!

  1. 地面测试:

    • 电机测试: 在不安装螺旋桨的情况下,通过遥控器给油门,观察四个电机是否按照你的预期旋转(M1逆时针,M2顺时针,M3顺时针,M4逆时针),如果方向反了,交换任意两根电机线即可。
    • PID 调试: 这是最耗时也是最关键的一步。
      • P (比例): 从一个很小的值开始(如 0.1),增加 P,无人机会开始“抖动”,抖动越厉害,P 越大,找到一个刚好能让无人机抵抗轻微晃动的值。
      • D (微分): 增加 D 可以抑制抖动,让飞行更平滑,但如果 D 太大,会导致无人机响应迟钝甚至产生新的振荡。
      • I (积分): 主要用于抵抗持续的、方向不变的力(如风),I 太大会导致无人机在平衡点附近来回“漂移”,初学者可以先设为 0。
    • 推荐顺序: 先调俯仰和横滚的 PID,最后调偏航,偏航的 PID 通常比较简单。
  2. 首次试飞:

    • 找一个巨大、开阔、无风的草地。
    • 将无人机放在起飞点,机头对着你。
    • 油门推到最低,然后快速推到中高位置(约 50%)。
    • 无人机可能会剧烈晃动,不要惊慌,立即将油门拉回最低。
    • 根据晃动的方向,微调相应的 PID 参数,然后再次尝试。
    • 重复这个过程,直到无人机能短暂地悬停。

总结与进阶

  • 这个项目涉及硬件、软件、物理和调试,挑战巨大,但完成后你会收获满满,从简单的 Arduino Mega + MPU-6050 开始,一步步调试,是成功的关键。
  • 进阶:
    • 使用气压计: 添加气压计(如 BMP280)可以实现定高飞行。
    • 使用激光雷达: 激光雷达可以实现厘米级的精准定高和室内飞行。
    • 姿态模式与自稳模式: 实现不同的飞行模式。
    • 自动返航: 在遥控器信号丢失时,自动飞回起飞点。
    • 开源固件: 当你对这个项目有了深入理解后,可以尝试研究和配置 Cleanflight/Betaflight 等更强大的固件。

祝你项目成功!这是一个充满乐趣和挑战的旅程。

分享:
扫描分享到社交APP
上一篇
下一篇