玩转物联网人工智能小车(ESP32):利用HMC5883L电子罗盘模块实现方向感知
摘要:本文介绍使用HMC5883L电子罗盘模块来辨别方向
在前边制作避障小车的时候,大家可能已经发现,虽然两个轮子的驱动信号是一样的,但是小车可能不走直线,走过一端距离之后,小车就会偏向一边。这是由于电机的个体差异导致的,虽然是同一标准、同一批次生产的电动机,但在电气特性上还是存在着些许的差距,经过比较长距离的累积之后,表现出来的就是两个轮子累计转过的圈数不同,小车就会朝一边偏。
小车跑偏的一个解决办法就是通过长距离的测试,找出两个轮子转速的差距,然后调整控制信号PWM的占空比率,让转速慢的轮子占空比率大一些,而转速快的轮子占空比率小一些,就可以在很大程度上改善这个问题了。这种解决办法要经过很多次的测试,才能找到一个比较满意的参数出来。
那么有没有更好的办法呢?能不能让小车自己知道自己在朝哪个方向行驶,自己进行调整呢?答案当然是肯定的。可以给小车安装一个电子罗盘模块,让小车自己知道自己在朝着哪个方向行驶。
我们知道,地球附近的空间遍布着地磁场,地磁场的方向是从地球的地磁北极(地理南极附近)指向地磁南极(地理北极附近),传统的指南针就是利用了地磁场来辨别方向的。基于HMC5883L芯片的电子罗盘模块同样也是利用了这一原理,它通过测量相互垂直的X轴、Y轴和Z轴的磁场的磁通量大小,因为这三个方向的磁通量的矢量和始终指向地磁南极(地理北极附近),所以,就可以计算出HMC5883L电子罗盘模块的水平方向角了,从而可以确定自己的朝向。
和前面的红外测距模块一样,HMC5833L电子罗盘模块也是通过内部寄存器来和外界交互的,通过这些寄存器可以对其设置,也可以得到模块的测量数据。具体的寄存器如下表:
地址 |
名称 |
访问 |
用途 |
00 |
配置寄存器A |
读/写 |
采样平均数、数据输出速率和测量配置寄存器 |
01 |
配置寄存器B |
读/写 |
增益配置寄存器 |
02 |
模式寄存器 |
读/写 |
测量模式配置寄存器,连续模式/单一模式(默认)。 |
03 |
数据输出X MSB寄存器 |
读 |
通道X测量结果的高位数据。 |
04 |
数据输出X LSB寄存器 |
读 |
通道X测量结果的低位数据。 |
05 |
数据输出Z MSB寄存器 |
读 |
通道Z测量结果的高位数据。 |
06 |
数据输出Z LSB寄存器 |
读 |
通道Z测量结果的低位数据。 |
07 |
数据输出Y MSB寄存器 |
读 |
通道Y测量结果的高位数据。 |
08 |
数据输出Y LSB寄存器 |
读 |
通道Y测量结果的低位数据。 |
09 |
状态寄存器 |
读 |
测量数据状态寄存器。 |
10 |
识别寄存器A |
读 |
用来识别装置 |
11 |
识别寄存器B |
读 |
用来识别装置 |
12 |
识别寄存器C |
读 |
用来识别装置 |
在这里,需要提醒一下,电子罗盘芯片有HMC5883和QMC5883两个系列,其中前者为进口芯片,后者为国产芯片,两者功能相同。但是,这两个芯片的寄存器定义不同,请在使用时确认相关文档。
对于配置寄存器的详细描述,请参考datasheet中的详细说明。
下面来看一下HMC5883L电子罗盘接口的详细说明:
序号 |
引脚 |
含义 |
1 |
VCC |
电源正极(3-5V) |
2 |
GND |
电源负极 |
3 |
SCL |
IIC串行时钟线 |
4 |
SDA |
IIC串行数据线 |
5 |
DRDY |
中断引脚,表明数据准备好了 |
寄存器看起来很复杂,实际上大多数情况下都不需要你直接去操作寄存器,因为有人已经给你进行了底层的封装,并提供了相应的库函数。打开“Arduino IDE”,安装HMC5883L电子罗盘模块的库函数,选择“Adafruit HMC5883L Unified”,如下图所示:
同样,使用该库函数还是那基本的几个步骤:
- 实例化对象
- 初始化模块
- 读取测量结果
- 数据处理显示
在这里,比之前复杂的就是数据处理部分,因为HMC5883L电子罗盘模块所返回的测量值,只是X、Z和Y三个方向的磁通量,因此想要计算方向,还要根据测量出来的X和Y以及你所在地的磁偏角来进行计算。具体的计算方法,请参见程序代码。
使用HMC5883L电子罗盘模块的时候,有个特别需要注意的地方是,固定HMC5883L芯片的时候,要保证它的Z轴是向上的,并且芯片处于水平状态,否则测量出来的结果是不正确的。
测试的代码如下:
#include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_HMC5883_U.h>
/* 为对象的实例分配一个唯一ID */ Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);
void setup(void) { Serial.begin(115200);
/* 初始化传感器 */ if(!mag.begin()) { /* 未找到传感器,请检查配置…… */ Serial.println("未找到传感器,请检查配置……"); while(1); } }
void loop(void) { /* 创建一个传感器数据对象 */ sensors_event_t event; mag.getEvent(&event);
/* 显示磁向量的值 (单位:uT) */ Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print(" "); Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print(" "); Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print(" ");Serial.println("uT");
// 让模块的Z轴向上,并保持模块水平,这样才能得到正确的角度结果 float heading = atan2(event.magnetic.y, event.magnetic.x);
// 在这里,你必须要设置你所在位置的磁偏角,否则计算出来的结果是错误的 // 可以使用这个网站查询你的磁偏角: http://www.magnetic-declination.com/ // 查询到的数值是度,需要转换为弧度 // 如果查不到你的磁偏角,请把这两行注释掉,那样测量结果会有稍微的偏移 float declinationAngle = 0.13; heading += declinationAngle;
// 符号修正 if(heading < 0) heading += 2*PI;
// 修正后,超过360度了 if(heading > 2*PI) heading -= 2*PI;
// 把弧度转换成角度 float headingDegrees = heading * 180/M_PI;
Serial.print("偏离正北方角度: "); Serial.println(headingDegrees);
delay(500); } |
程序中已经增加了详细的注释,如果你是从开始学到现在,相信你是能看懂的,在这里就不再解释了。运行结果如下图所示:
好了,关于HMC5883L电子罗盘模块的基本使用就介绍到这里了。