FastBond4挑战部分-基于M5StickC PLUS2的飞机姿态监测与Web三维可视化系统
该项目使用了M5StickC PLUS2开发板(内置MPU6886六轴姿态传感器),实现了板(内置MPU6886六轴姿态传感器)的设计,它的主要功能为:姿态数据采集:通过MPU6886六轴IMU传感器采集加速度和角速度数据;实时姿态解算:采用互补滤波算法,实时计算横滚角、俯仰角和偏航角;M5StickC端姿态显示:1.14英寸TFT竖屏绘制人工地平仪,实时显示姿态坐标图像。
标签
物联网
MQTT
FastBond4
姿态监测
ESP32-PICO
Three.js
WebSocket
风行者
更新2026-07-08
4

一、所选主题和项目介绍

1.1 项目背景

在航空模拟训练、无人机姿态监测和体感交互控制等应用场景中,实时获取和可视化展示物体姿态信息是一个重要需求。传统的姿态监测系统往往需要昂贵的专用设备,且数据显示方式单一,缺乏直观的三维可视化交互体验。

本项目使用M5StickC PLUS2开发板(内置MPU6886六轴姿态传感器),实现一款高性价比的飞机姿态监测节点。通过互补滤波算法实时解算横滚角(Roll)、俯仰角(Pitch)和偏航角(Yaw),在M5StickC PLUS2的1.14英寸135×240 TFT竖屏上绘制人工地平仪,同时通过MQTT协议将姿态数据上报到树莓派Web服务器,在浏览器中通过Three.js 3D引擎实现飞机模型的实时姿态同步,为用户提供沉浸式的姿态监测体验。

1.2 项目目标

本项目使用M5StickC PLUS2 (SKU: K016-H2) 开发板,配合内置MPU6886六轴惯性传感器,实现一款智能飞机姿态监测与三维可视化系统,主要功能如下:

  1. 姿态数据采集:通过MPU6886六轴IMU传感器采集加速度和角速度数据
  2. 实时姿态解算:采用互补滤波算法,实时计算横滚角、俯仰角和偏航角
  3. M5StickC端姿态显示:1.14英寸TFT竖屏绘制人工地平仪,实时显示姿态坐标图像
  4. MQTT数据上报:通过MQTT协议将姿态数据实时上报至树莓派服务器
  5. Web三维可视化:浏览器中通过Three.js 3D引擎显示飞机模型,姿态实时同步
  6. Web端姿态显示:网页中显示姿态坐标数值和人工地平仪
  7. 一键归零:M5StickC PLUS2按键一键复位偏航角

1.3 创新点

  1. 互补滤波姿态解算:加速度计与陀螺仪数据融合,实现高精度姿态解算,有效抑制陀螺仪漂移
  2. M5StickC端人工地平仪:在135×240像素的竖屏上绘制旋转人工地平仪,视觉效果直观
  3. Web端3D姿态同步:Three.js 3D引擎构建飞机模型,姿态数据通过WebSocket实时推送到浏览器
  4. 双端姿态显示:M5StickC屏幕和Web页面同时显示姿态坐标图像,双重可视化
  5. 实时MQTT+WebSocket架构:端到端延迟低于200ms,流畅的实时姿态跟踪体验
  6. 一键复位:M5StickC PLUS2板载按键可一键复位偏航角,方便校准

二、硬件介绍

2.1 主控设备

M5StickC PLUS2 (SKU: K016-H2) — 基于ESP32-PICO-V3-02的高度集成物联网可编程控制器,内置MPU6886六轴姿态传感器,配备1.14英寸TFT竖屏。

参数

规格

主控芯片

ESP32-PICO-V3-02,双核240MHz

Flash

16MB

PSRAM

8MB

显示屏

1.14英寸 ST7789V,135×240 竖屏

六轴传感器

MPU6886 (加速度+陀螺仪)

按键

板载按键BtnA (GPIO 0)

电池

内置锂电池,支持USB充电

尺寸

48.2 × 25.0 × 13.8mm

2.2 传感器模块

MPU6886六轴惯性传感器 — 集成3轴加速度计和3轴陀螺仪的高精度IMU,通过内部I2C与主控通信。

参数

规格

加速度计量程

±2g / ±4g / ±8g / ±16g (可配置)

加速度计精度

0.05%

陀螺仪量程

±250°/s / ±500°/s / ±1000°/s / ±2000°/s (可配置)

陀螺仪精度

0.05°/s

通信接口

内部I2C (地址0x68)

数据输出频率

最高4000Hz (加速度计) / 最高4000Hz (陀螺仪)

2.3 树莓派设备

树莓派3B+ (Raspberry Pi 3 Model B+)

参数

规格

CPU

BCM2837B0, Cortex-A53 1.4GHz (四核)

RAM

1GB LPDDR2

网络

2.4/5GHz WiFi, 千兆以太网

存储

MicroSD卡 (推荐16GB以上)

核心服务组件

组件

用途

运行方式

Mosquitto

MQTT消息代理

systemd服务

rpi_airplane_web_server.py

Web服务器+MQTT订阅+WebSocket推送

Python服务

Flask

HTTP网页服务器

Python模块

Flask-SocketIO

WebSocket实时通信

Python模块

Three.js

3D引擎 (浏览器端)

JavaScript库

2.4 硬件连接

M5StickC PLUS2为一体化设计,所有传感器已集成在板载,无需外接传感器模块。仅需USB Type-C供电即可运行。

M5StickC接口

连接设备

功能

USB Type-C

5V电源/固件下载

供电与编程

板载MPU6886

内部I2C

六轴姿态数据采集

板载ST7789V

SPI

135x240 TFT显示

板载按键BtnA

GPIO 0

用户输入(偏航角归零)

板载LED

GPIO 10

状态指示

6轴姿态传感器

内置I2C

加速度+陀螺仪

三、方案框图和项目设计思路

3.1 系统架构

系统架构

3.2 设备启动流程

设备启动流程

3.3 姿态解算算法

采用互补滤波算法融合加速度计和陀螺仪数据:

  1. 加速度计计算姿态
    • Roll_acc = atan2(accel_y, accel_z) × 180/π
    • Pitch_acc = atan2(-accel_x, √(accel_y² + accel_z²)) × 180/π
  2. 互补滤波融合
    • Roll = α × (Roll + gyro_x × dt) + (1-α) × Roll_acc
    • Pitch = α × (Pitch + gyro_y × dt) + (1-α) × Pitch_acc
    • 滤波系数 α = 0.96,短时信任陀螺仪,长时由加速度计校正
  3. 偏航角积分
    • Yaw += gyro_z × dt (陀螺仪积分,可通过按键归零)

四、原理图和PCB展示及介绍

4.1 设计过程

通过KiCad完成了电路的原理图绘制和PCB版图设计。在实际动手环节,作为电路设计的新手,这次从零开始画原理图、布PCB的经历让我学到了很多。设计过程中得到了老师的指导和反馈,谢谢老师。

4.2 硬件连接原理图

本项目设计了专用的I2C适配板(PCB),用于连接M5StickC PLUS2主控与外围接口增加飞机操作。

4.3 PCB布局展示

五、软件流程和关键代码介绍

5.1 主程序结构

"""
File: airplane_attitude.py
硬件: M5StickC PLUS2 (K016-H2) + MPU6886 IMU

功能特性:
1. MPU6886六轴IMU姿态数据采集
2. 互补滤波实时姿态解算 (Roll/Pitch/Yaw)
3. 1.14" TFT 135x240竖屏人工地平仪显示
4. MQTT数据上报到树莓派
5. 按键一键偏航角归零

开发平台: UiFlow2 (MicroPython)
Web IDE: https://uiflow2.m5stack.com/
"""

5.2 姿态解算模块 (UiFlow2 MicroPython)

def update_attitude():
global _roll, _pitch, _yaw, _last_time
import time
from M5 import Imu

now = time.ticks_ms()
dt = time.ticks_diff(now, _last_time) / 1000.0
if dt <= 0.0 or dt > 0.1:
dt = 0.01
_last_time = now

accel = Imu.getAccel()
gyro = Imu.getGyro()

ax, ay, az = accel[0], accel[1], accel[2]
gx, gy, gz = gyro[0], gyro[1], gyro[2]

accel_roll = math.atan2(ay, az) * _RAD_TO_DEG
accel_pitch = math.atan2(-ax,
math.sqrt(ay * ay + az * az)) * _RAD_TO_DEG

gx_dps = gx * _RAD_TO_DEG
gy_dps = gy * _RAD_TO_DEG
gz_dps = gz * _RAD_TO_DEG

_roll = 0.96 * (_roll + gx_dps * dt) + 0.04 * accel_roll
_pitch = 0.96 * (_pitch + gy_dps * dt) + 0.04 * accel_pitch
_yaw += gz_dps * dt

5.3 人工地平仪显示模块 (UiFlow2 MicroPython)

# M5StickC PLUS2 竖屏显示 (135x240)
# 全屏地平仪每80ms刷新一次,文字数值每10ms更新
# 大幅减少屏幕闪烁

_DISPLAY_INTERVAL = 8 # 每8次循环全屏刷新一次
_display_counter = 0


def _draw_scanline_horizon(roll, pitch):
roll_rad = math.radians(roll)
cos_r = math.cos(roll_rad)
sin_r = math.sin(roll_rad)
if abs(sin_r) < 0.001:
sin_r = 0.001
Lcd.fillScreen(_SKY_COLOR)
for y in range(240): # 竖屏240
y_local = y - 85 + int(pitch)
x_horizon = 67 - (y_local * cos_r) / sin_r
if cos_r >= 0:
x_start = int(max(0, min(135, x_horizon)))
if x_start < 135:
Lcd.fillRect(x_start, y, 135 - x_start, 1, _GROUND_COLOR)
else:
x_end = int(max(0, min(135, x_horizon)))
if x_end > 0:
Lcd.fillRect(0, y, x_end, 1, _GROUND_COLOR)


def update_display(roll, pitch, yaw):
global _display_counter
_display_counter += 1
if _display_counter >= _DISPLAY_INTERVAL:
_draw_scanline_horizon(roll, pitch)
_draw_horizon_line(roll)
_draw_pitch_ladder(roll, pitch)
_draw_aircraft_symbol()
_display_counter = 0
_draw_attitude_text(roll, pitch, yaw)
_draw_status_line()

5.4 MQTT数据上报 (UiFlow2 MicroPython)

from umqtt import MQTTClient

_MQTT_TOPIC = b"fastbond4/m5stick_airplane_attitude/attitude"


def send_attitude_mqtt(roll, pitch, yaw):
if not _mqtt_connected or _mqtt_client is None:
return
payload = '{{"roll":{:.2f},"pitch":{:.2f},"yaw":{:.2f}}}'.format(
roll, pitch, yaw)
try:
_mqtt_client.publish(_MQTT_TOPIC, payload)
except Exception as e:
print("[MQTT] Publish failed:", e)
_mqtt_connected = False


# 新增:MQTT代理可达性检测,避免连接阻塞
def _test_broker(host, port, timeout_ms=3000):
import usocket
addr = usocket.getaddrinfo(host, port)[0][4]
s = usocket.socket()
s.settimeout(timeout_ms / 1000)
s.connect(addr)
s.close()
return True

5.5 树莓派Web服务器

# MQTT消息回调 - 接收姿态数据并推送到WebSocket客户端
def on_mqtt_message(client, userdata, msg):
global _current_attitude
payload = msg.payload.decode('utf-8')
data = json.loads(payload)

if "roll" in data and "pitch" in data and "yaw" in data:
with _attitude_lock:
_current_attitude = data

# 通过WebSocket推送到所有连接的浏览器
socketio.emit('attitude_update', data)


@app.route('/')
def index():
return render_template('index.html')

5.6 Three.js 3D飞机模型

function createAirplane() {
airplane = new THREE.Group();

// 机身: 圆柱体
const fuselage = new THREE.Mesh(
new THREE.CylinderGeometry(0.25, 0.15, 1.6, 12),
bodyMat
);
fuselage.rotation.x = Math.PI / 2;

// 机翼: 长方体
const mainWing = new THREE.Mesh(
new THREE.BoxGeometry(1.6, 0.04, 0.4),
wingMat
);

// 尾翼、垂直尾翼、发动机...

// 姿态更新
airplane.rotation.order = 'YXZ';
airplane.rotation.x = pitchRad;
airplane.rotation.y = yawRad;
airplane.rotation.z = rollRad;
}

六、硬件功能展示图及说明

6.1 M5StickC PLUS2显示界面

实物展示

实物展示

6.2 网页显示界面

页面截图1

页面截图2

6.3 树莓派

树莓派截图

6.4 树莓派端日志

运行截图

七、设计中遇到的难题和解决方法

7.1 IMU数据噪声滤波

问题描述:MPU6886加速度计原始数据存在高频噪声,导致横滚角和俯仰角波动明显,影响显示效果。

解决方案

  1. 采用互补滤波算法融合加速度计和陀螺仪数据
  2. 滤波系数α=0.96,短时信任陀螺仪动态响应,长时由加速度计校正漂移
  3. 时间步长dt限幅保护,防止异常值导致滤波发散
# 互补滤波核心公式
_roll = 0.96 * (_roll + gx_dps * dt) + 0.04 * accel_roll
_pitch = 0.96 * (_pitch + gy_dps * dt) + 0.04 * accel_pitch

7.2 陀螺仪零偏漂移

问题描述:陀螺仪存在零偏误差,长时间运行后偏航角会逐渐漂移。

解决方案

  1. 静态时采集陀螺仪零偏值进行校准
  2. 按键一键归零偏航角
  3. 互补滤波只对Roll和Pitch进行加速度计校正,Yaw通过按键手动复位
if BtnA.wasPressed():
reset_yaw() # 偏航角归零
print("[Button] Yaw reset")

7.3 135x240竖屏人工地平仪绘制与闪烁优化

问题描述:M5StickC PLUS2的1.14英寸135×240竖屏相比AtomS3R的128×128小方屏,扫描行数从128行增加到240行,每次全屏重绘耗时更长(约80ms),导致画面严重闪烁。

解决方案

  1. 分频刷新策略:全屏地平仪每80ms刷新一次(8个循环),文字数值每10ms更新一次
  2. 文字更新只改变LCD光标位置的文本内容,不触发全屏重绘
  3. 地平线、俯仰梯和飞机符号随全屏刷新一起绘制,减少绘制次数
# 分频刷新核心逻辑
_DISPLAY_INTERVAL = 8 # 全屏刷新间隔
_display_counter = 0

def update_display(roll, pitch, yaw):
global _display_counter
_display_counter += 1
if _display_counter >= _DISPLAY_INTERVAL:
# 每80ms全屏重绘地平仪(避免闪烁)
_draw_scanline_horizon(roll, pitch)
_draw_horizon_line(roll)
_draw_pitch_ladder(roll, pitch)
_draw_aircraft_symbol()
_display_counter = 0
# 每10ms更新姿态数值文字(文字更新快,不闪烁)
_draw_attitude_text(roll, pitch, yaw)
_draw_status_line()

7.4 MQTT连接阻塞问题

问题描述:当MQTT代理不可达时,MQTTClient.connect()会长时间阻塞,导致主循环无法启动。

解决方案

  1. 新增_test_broker()函数,使用3秒超时Socket探测代理可达性
  2. 只有探测成功后才创建MQTT连接
  3. 代理不可达时优雅跳过,主循环正常启动
def _test_broker(host, port, timeout_ms=3000):
import usocket
addr = usocket.getaddrinfo(host, port)[0][4]
s = usocket.socket()
s.settimeout(timeout_ms / 1000)
s.connect(addr)
s.close()
return True

def connect_mqtt(...):
if not _test_broker(_MQTT_BROKER, _MQTT_PORT):
print("[MQTT] Broker unreachable, skipping")
return False
# 才执行MQTTClient.connect()

7.5 MQTT与WebSocket实时桥接

问题描述:需要将MQTT接收到的姿态数据实时推送到多个浏览器客户端,确保低延迟同步。

解决方案

  1. 树莓派端使用Flask-SocketIO实现WebSocket服务
  2. MQTT消息回调中直接通过SocketIO向所有客户端广播姿态数据
  3. 线程安全锁保护共享数据,避免竞态条件
def on_mqtt_message(client, userdata, msg):
data = json.loads(msg.payload)
with _attitude_lock:
_current_attitude = data
socketio.emit('attitude_update', data) # WebSocket广播

7.6 Three.js 3D飞机模型构建

问题描述:需要在浏览器中构建一个可被姿态数据驱动的3D飞机模型,要求模型结构完整且旋转顺序正确。

解决方案

  1. 使用Three.js基本几何体组合构建飞机(机身、机翼、尾翼、发动机等)
  2. 设置rotation.order为YXZ,与航空标准姿态角旋转顺序一致
  3. 添加人工地平仪背景纹理、网格辅助线和多方向光源增强视觉效果
airplane.rotation.order = 'YXZ';
airplane.rotation.x = pitchRad; // 俯仰
airplane.rotation.y = yawRad; // 偏航
airplane.rotation.z = rollRad; // 横滚

八、心得体会

8.1 项目收获

  1. IMU姿态解算:深入理解了加速度计和陀螺仪的工作原理,掌握了互补滤波姿态解算算法
  2. 嵌入式显示技术:在135×240竖屏上绘制旋转人工地平仪的技术,理解了坐标旋转和像素级渲染
  3. Web 3D可视化:掌握了Three.js 3D引擎构建三维模型和实时姿态同步的技术
  4. 实时数据管道:实践了MQTT + WebSocket的端到端实时数据推送架构
  5. 双端同步显示:实现了设备端和Web端同步显示姿态坐标图像的完整方案
  6. 嵌入式系统设计:熟悉了UiFlow2开发环境、MicroPython编程和M5Burner固件烧录工具的使用

8.2 技术亮点

  1. 互补滤波高精度解算:加速度计和陀螺仪融合,姿态解算精度高、响应快
  2. 竖屏人工地平仪:135×240像素竖屏上实现带旋转的人工地平仪,视觉效果出色
  3. 分频刷新防闪烁:全屏地平仪80ms刷新、文字10ms更新的分频策略,彻底解决竖屏闪烁问题
  4. MQTT非阻塞连接:Socket探测+超时机制,代理不可达时优雅跳过
  5. Web端3D实时同步:Three.js 3D飞机模型毫秒级跟随M5StickC姿态变化
  6. 双端姿态显示:设备端LCD和Web页面同时显示姿态坐标图像
  7. 端到端低延迟:MQTT + WebSocket架构,端到端延迟低于200ms
  8. 一键偏航角归零:M5StickC按键便捷复位偏航角,提升使用体验

8.3 改进建议

  1. 地磁传感器融合:增加地磁传感器修正偏航角漂移,实现完整9轴姿态解算
  2. 扩展ESP-NOW无线通信:增加ESP-NOW低延迟局域网通信,减少对WiFi路由器的依赖
  3. 多节点组网:支持多个M5StickC姿态节点同时接入,实现多机姿态同步显示
  4. 数据记录回放:在树莓派SQLite数据库中存储姿态数据,支持历史姿态回放
  5. 体感交互游戏:利用M5StickC姿态控制网页游戏中的物体,实现体感交互
  6. 移动端适配:优化Web页面在手机和平板上的显示效果
  7. 姿态数据滤波:引入卡尔曼滤波进一步提升姿态解算精度
  8. OTA固件升级:支持远程无线固件更新
  9. 自定义PID参数:Web界面允许用户调节互补滤波系数

创意方向关联

本项目的技术创新为以下创意方向提供了新的思路:

1. 人工智能在嵌入式系统中的应用

本项目的姿态解算技术为AI应用提供了基础:

  • 姿态行为识别:机器学习模型通过学习姿态变化模式,识别用户的动作意图
  • 异常姿态检测:AI模型检测异常姿态,用于跌倒检测、设备故障预警
  • 运动模式分析:通过持续的姿态数据分析用户运动模式

2. 体感交互游戏

实时姿态追踪是体感交互的核心技术:

  • 飞行模拟器:M5StickC作为飞行摇杆的体感控制器
  • VR/AR交互:低延迟姿态数据用于VR头显和AR设备的交互控制
  • 运动健身:监测用户运动姿态,提供实时反馈和矫正

3. 无人机 / 机器人控制

姿态解算是无人机和机器人控制的基础:

  • 无人机飞控:IMU姿态数据用于无人机飞行控制系统的姿态反馈
  • 机器人平衡:两轮自平衡机器人基于Roll/Pitch数据的PID控制
  • 机械臂姿态:多节点姿态传感器用于机械臂关节角度测量

技术迁移价值

本项目开发的技术方案可迁移到:

  • AI应用:姿态行为识别、异常检测、运动模式分析
  • 体感交互:飞行模拟器、VR/AR控制、运动监测
  • 无人机/机器人:飞控系统、平衡控制、机械臂姿态

致谢

感谢 DigiKey电子森林 提供的FastBond4活动支持,本次活动链接:https://www.eetree.cn/page/digikey-fastbond

感谢 Three.js 开源社区提供的优秀3D引擎和开发资源。

附件下载
adapter.zip
PCB
rpi_airplane_web_server.py
airplane_attitude.py
adapter.epro
rpi_mqtt_client.py
团队介绍
评论
0 / 100
查看更多
猜你喜欢
FastBond4挑战部分-基于M5StickC PLUS2的手腕运动状态检测控制器该项目使用了M5Stack M5StickC PLUS2智能手表开发套件(K016-H2),实现了手腕运动状态检测控制器的设计,它的主要功能为:姿态检测:通过六轴IMU传感器(MPU6886)实时检测手腕倾斜角度;状态识别:识别前进、后退、左转、右转、停止五种手势状态;实时显示:在1.14寸TFT屏幕上实时显示当前状态、方向箭头和传感器数据。
林守护
5
FastBond4挑战部分-基于M5StickC PLUS2与M5Paper的智能视力测试系统该项目使用了M5StickC PLUS2 (K016-H2)、M5Paper (E-Ink显示屏) 和 树莓派,实现了基于GB 11533-2011标准的智能视力测试系统的设计,它的主要功能为:手腕动作控制:通过MPU6886 IMU检测手腕姿态(上下左右),控制E视标开口方向选择;E-Ink大屏显示:M5Paper 540×960 E-Ink显示屏清晰呈现E视标,墨水屏无闪烁不伤眼;自适应阶梯法:从4.3级开始,每级4个视标,≥3正确升级,<3正确降级。
时光老六
5
FastBond4挑战部分-基于CoreS3的多传感器环境监测与Web可视化系统该项目使用了M5Stack CoreS3 主控、DLight (BH1750) 光照传感器、CO2 SCD40 温湿度/CO2传感器、PAHUB I2C多路复用器和树莓派3B+,实现了基于WiFi MQTT的室内环境监测系统的设计,它的主要功能为:光照采集:使用DLight (BH1750) 传感器采集环境光照值;CO2/温湿度采集:使用SCD40传感器采集CO2浓度、温度、湿度;PAHUB I2C多路复用:通过PAHUB切换I2C通道管理多个传感器。
幻影客
5
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号