Arduino 实时数字罗盘:HMC5883L + Processing 可视化教程
项目概述
利用 Arduino 读取 HMC5883L 三轴磁力计(MEMS 磁强计)数据,经串口发送至 Processing IDE,实时渲染旋转指针罗盘界面。硬件极简:仅需磁力计模块(如 GY-80 板载 HMC5883L)、Arduino、杜邦线。
工作原理
Arduino 端:数据采集与航向角计算
- 通过 I2C 读取 HMC5883L 的 X、Y、Z 三轴原始值(16 位有符号整数)。
- 按数据手册灵敏度(0.92 mG/LSB)换算为高斯值。
- 航向角
heading = atan2(Y, X)(弧度),加入磁偏角修正(可在 NOAA 官网 查询当地磁偏)。 - 归一化至 0~2π,转换为度数。
- 一阶低通滤波平滑输出:
headingFiltered = 0.85*headingFiltered + 0.15*headingDegrees。 - 以 115200 波特率经串口逐行发送
headingFiltered。
/* Arduino 罗盘 - HMC5883L
* 作者:Dejan Nedelkovski, www.HowToMechatronics.com
*/
#include <Wire.h>
#define Magnetometer 0x1E // HMC5883L I2C 7-bit 地址
// 寄存器地址
#define Magnetometer_mX0 0x03
#define Magnetometer_mX1 0x04
#define Magnetometer_mY0 0x07
#define Magnetometer_mY1 0x08
#define Magnetometer_mZ0 0x05
#define Magnetometer_mZ1 0x06
int mX0, mX1, mX_out; int mY0, mY1, mY_out; int mZ0, mZ1, mZ_out;
float heading, headingDegrees, headingFiltered, declination;
float Xm, Ym, Zm;
void setup() {
Serial.begin(115200);
Wire.begin(); delay(100);
// 配置连续测量模式
Wire.beginTransmission(Magnetometer);
Wire.write(0x02); // 模式寄存器
Wire.write(0x00); // 连续测量
Wire.endTransmission();
}
void loop() {
// 读取 X 轴
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mX1); Wire.endTransmission();
Wire.requestFrom(Magnetometer, 1); if (Wire.available()) mX0 = Wire.read();
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mX0); Wire.endTransmission();
Wire.requestFrom(Magnetometer, 1); if (Wire.available()) mX1 = Wire.read();
// 读取 Y 轴
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mY1); Wire.endTransmission();
Wire.requestFrom(Magnetometer, 1); if (Wire.available()) mY0 = Wire.read();
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mY0); Wire.endTransmission();
Wire.requestFrom(Magnetometer, 1); if (Wire.available()) mY1 = Wire.read();
// 读取 Z 轴(本项目未用)
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mZ1); Wire.endTransmission();
Wire.requestFrom(Magnetometer, 1); if (Wire.available()) mZ0 = Wire.read();
Wire.beginTransmission(Magnetometer); Wire.write(Magnetometer_mZ0); Wire.endTransmission();
Wire.requestFrom(Magnetometer, 1); if (Wire.available()) mZ1 = Wire.read();
// 合成 16 位有符号值
mX1 = mX1 << 8; mX_out = mX0 + mX1; Xm = mX_out * 0.00092;
mY1 = mY1 << 8; mY_out = mY0 + mY1; Ym = mY_out * 0.00092;
mZ1 = mZ1 << 8; mZ_out = mZ0 + mZ1; Zm = mZ_out * 0.00092;
// 计算航向角
heading = atan2(Ym, Xm);
declination = 0.073; // 示例:4.2° 磁偏角,需替换为当地值
heading += declination;
if (heading < 0) heading += 2*PI;
if (heading > 2*PI) heading -= 2*PI;
headingDegrees = heading * 180/PI;
// 低通滤波
headingFiltered = headingFiltered * 0.85 + headingDegrees * 0.15;
Serial.println(headingFiltered);
delay(50);
}
Processing 端:可视化渲染
- 准备三张透明 PNG 图片:背景(可选)、罗盘盘面、指针,置于 sketch 目录。
setup()中加载图片、打开串口(修改COM4为实际端口)、设置缓冲直到换行符。draw()循环:绘制背景 → 平移坐标系至屏幕中心 →rotateZ(-heading)旋转罗盘盘面 → 恢复坐标系 → 绘制固定指针 → 显示数值。serialEvent()读取串口字符串,转 float 赋值heading。
/* Processing 罗盘可视化
* 作者:Dejan Nedelkovski, www.HowToMechatronics.com
*/
import processing.serial.*;
Serial myPort;
PImage imgCompass, imgCompassArrow, background;
String data = "";
float heading = 0;
void setup() {
size(1920, 1080, P3D); // 可改为你的屏幕分辨率
smooth();
imgCompass = loadImage("Compass.png");
imgCompassArrow = loadImage("CompassArrow.png");
background = loadImage("Background.png");
myPort = new Serial(this, "COM4", 115200); // 修改端口号
myPort.bufferUntil('\n');
}
void draw() {
image(background, 0, 0);
pushMatrix();
translate(width/2, height/2, 0);
rotateZ(radians(-heading));
image(imgCompass, -width/2, -height/2);
popMatrix();
image(imgCompassArrow, 0, 0);
textSize(30);
text("Heading: " + heading, 40, 40);
delay(40);
}
void serialEvent(Serial myPort) {
data = myPort.readStringUntil('\n');
if (data != null) heading = float(trim(data));
}
校准与进阶提示
- 硬铁/软铁校准:裸芯片受环境磁场干扰大,建议采用“8 字形”校准算法或使用库(如
HMC5883L_Simple)自动求偏移与缩放系数。 - 磁偏角:务必替换代码中的
declination为当地实测值,否则指北偏差数度。 - 安装姿态:模块需保持水平;若倾斜需引入加速度计做倾斜补偿(见 AHRS 算法)。
- 供电噪声:模块对电源纹波敏感,建议单独 LDO 供电,I2C 线加上拉电阻。
项目文件(图片、源码)可在文末下载。动手做一个桌面罗盘,感受地磁的指引吧!
制造工艺
- 用 Arduino 打造绚丽显示器 Ambilight 系统
- 用 Arduino 制作超声波悬浮装置:分步指南
- 基于 Arduino、1Sheeld 与红外控制的万能安卓遥控器
- Arduino 与智能手机打造智能电压表——简单易做的 DIY 项目
- 基于Arduino UNO的精准频率与占空比测量
- 自制可拳击的可编程键盘按钮:基于 Arduino 与压电元件的分步指南
- Arduino 声纳实时测距与 Processing 可视化
- 智能停车计数系统:Arduino + Processing + PHP 实时车位追踪上云
- Bolt IoT + Arduino UNO 实现 6 路 LED 无级调光
- DIY 智能 Arduino 机械臂:主从控制与动作记忆教程
- 构建基于 PHP 的 Web 界面控制 Arduino Uno
- 使用 Arduino Nano 和 RDA8057M 制作紧凑型 FM 收音机