国外课栈 - 国外电子信息技术视频教程、电子书和博文栈

使用Arduino和HMC5883L磁力计的数字罗盘

 二维码 89
发表时间:2018-12-26 12:59



人脑由复杂的结构层构成,这有助于我们成为地球上的优势物种。例如,大脑中的内嗅皮层可以让您感觉方向,帮助您轻松导航您不熟悉的地方。但与我们不同的是,机器人和无人驾驶的Ariel车辆需要一些东西才能获得这种方向感,这样他们就可以在新的地形和风景中自主操纵。不同机器人 使用不同类型的传感器来实现这一目标,但常用的是磁力计,它可以通知机器人当前面向的地理方向。这不仅有助于机器人感知方向,还可以在预定义的方向和天使中轮流。

由于传感器可以指示地理图形北,南,东和西,我们人类也可以在需要时使用它。因此,在本文中,让我们尝试了解磁力计传感器的工作原理以及如何将其与Arduino等微控制器连接。在这里,我们将构建一个很酷的数字指南针 ,它将帮助我们通过发出指向北方向的LED来找到方向。这款数字罗盘在PCB上整齐地制作而成,这样下次我出去野外时就可以随身携带它,并希望我只是为了找回回家的路而迷路。让我们开始吧。

所需材料

Arduino Pro mini

HMC5883L磁力计传感器

LED灯 -   8Nos

470Ohm电阻器 -   8Nos

Barrel Jack

可靠的PCB制造商,如PCBgogo

用于mini的FTDI编程器

PC /笔记本电脑


什么是磁力计?它是如何工作的?

磁力计实际上是一种能够感应地球磁极 并根据其指向方向的设备。我们都知道地球是一块巨大的球形磁铁,有北极和南极。因此有磁场。磁力计可以感应到这个磁场,并且根据磁场的方向,它可以检测到我们所面对的方向。


HMC5883L传感器模块的如何工作

HMC5883L 作为可以 磁力计传感器 做同样的事情。它上面有HMC5883L IC,来自霍尼韦尔。该IC具有3个磁阻材料,其内部布置在轴x,y和z中。流过这些材料的电流量对地球的磁场敏感。因此,通过测量流过这些材料的电流变化,我们可以检测到地球磁场的变化。一旦磁场被吸收变化,就可以将值发送到任何嵌入式控制器,如微控制器或支持I2C协议的处理器。


由于传感器通过感应磁场工作,如果在附近放置金属,输出值将受到很大影响。也可以利用此行为将这些传感器用作 金属探测器。应注意不要在此传感器附近放置磁铁,因为磁铁的强磁场可能会触发传感器上的错误值。


HMC5883L和QMC5883L之间的区别

对于许多初学者来说,围绕这些传感器存在着共同的混乱。这是因为一些供应商(实际上大多数)销售QMC5883L传感器而不是霍尼韦尔的原装HMC5883L。这主要是因为QMC5883L比HMC5883L模块便宜。可悲的是,这两个传感器的工作略有不同,两者都不能使用相同的代码。这是因为两个传感器的I2C地址不一样。本教程中的代码 仅适用于QMC5883L, 常用的传感器模块。

 磁力仪QMC5883L

要知道您所拥有的传感器型号,您只需要仔细查看IC本身,以便阅读其上面的内容。如果它写的是像 L883 那么它就是HMC58836L,如果写的是像 DA5883 那么它就是QMC5883L IC。两个模块如下图所示,便于轻松下载。

电路图

这款基于Arduino的数字罗盘电路非常简单,我们只需要将HMC5883L传感器与Arduino连接,并将8个LED连接到Arduino Pro mini的GPIO引脚。完整的电路图如下所示

传感器模块具有5针,外面的DRDY(数据准备好)未用在我们的项目,因为我们在连续模式中的使用。 Vcc和接地引脚用于通过Arduino板上的5V为模块供电。该 SCL和SDA是I2C通信总线 ,分别连接到Arduino Pro mini的A4和A5 I2C引脚。由于模块本身在线路上有一个上拉电阻,因此无需在外部添加它们。

为了表明我们使用了8个LED的方向,LED 所有这些都通过470欧姆的限流电阻连接到Arduino的GPIO引脚。完整电路由9V电池供电。该9V直接提供给Arduino的Vin引脚,使用Arduino上的板载稳压器将其调节至5V。然后,该5V用于为传感器和Arduino供电。

为数字罗盘制造PCB

这个电路的想法是将8个LED以圆形方式放置,使每个Led指向所有8个方向,即北,东北,东,东南,南,西南,西和西北分别。因此,将它们整齐地安排在面包板上甚至是穿孔板上并不容易。为此电路开发PCB将使其看起来更整洁,易于使用。所以我打开了我的PCB设计软件,将LED和电阻器放在一个整齐的圆形图案中,并连接了轨道以形成连接。完成后,我的设计看起来如下所示。您也可以从给定的链接下载Gerber文件。

我将它设计成双面板,因为我希望Arduino位于PCB的底部,这样它就不会破坏PCB顶部的外观。如果你担心你必须为双面PCB支付高价,那么坚持下去,我会有新的好消息。

现在,我们的设计准备就绪,是时候让它们制作完成了。要完成PCB操作非常简单,只需按照以下步骤操作即可


第1步:   进入 www.pcbgogo.com,如果这是您第一次注册。然后,在PCB Prototype选项卡中输入PCB的尺寸,层数和所需的PCB数量。我的PCB是80厘米×80厘米所以选项卡如下所示


第2步: 单击“ 立即报价” 按钮继续。如果需要,您将进入一个页面,在那里设置一些额外的参数,如材料使用轨道间距等。但大多数默认值都可以正常工作。我们在这里唯一需要考虑的是价格和时间。正如您所看到的,构建时间仅为2-3天,我们的PSB仅需5美元。然后,您可以根据您的要求选择首选送货方式。


第3步: 最后一步是上传Gerber文件并继续付款。为了确保流程顺利,PCBGOGO会在继续付款之前验证您的Gerber文件是否有效。通过这种方式,您可以确保您的PCB具有制造友好性,并可以按照承诺与您联系。


装配电路电路板

板在订购后,经过一段时间后,它通过一个整齐标记好的包装箱快递到达我,就像PCB的质量一样令人敬畏。我正在分享下面几块电路板的图片供你判断。

我打开我的焊条,开始组装电路板。由于脚印,焊盘,过孔和丝网印刷的形状和尺寸都非常合适,因此组装电路板时没有任何问题。从打开包装盒后的10分钟内,电路板就准备好了。

焊接后电路板的几张图片

如下所示。

对Arduino进行编程

现在我们的硬件已经准备好了,让我们看一下必须上传到我们的Arduino板的程序。该代码的目的是 从QMC5883L磁力计传感器读取数据并将其转换为度数(0到360)。一旦我们知道了角度,我们就必须打开指向特定方向的LED。我在这个项目中使用的方向是北方。因此,无论您身在何处 ,您的电路板上只会有一个LED发光,而LED的方向将指示北方

本的完整代码 “数字罗盘项目” 可在本页末尾找到。您可以在包含库后直接将其上传到您的主板上,然后您就可以开始使用了。

如前所述,我们正在使用 QMC5883L IC与IC通信,我们需要知道其寄存器的I2C地址,这可以在其数据表中找到。但幸运的是,我们所有这一切都已经完成,在Github上,一个名叫keepworking的人已经将它打包成库。所以你要做的就是简单下载QMC5883L库。然后,按照草图 - >包含库 - >添加.ZIP库的方式将库添加到Arduino IDE中

添加库后,我们可以继续我们的程序。我们通过包含所需的库文件开始该程序 如下所示。有wire库用于启用I2C通信,MechaQMC5883是我们刚刚添加到Arduino的那个。该库包含有关如何与EMC5883L传感器通信的所有信息。


#include <Wire.h> //Wire Librarey for I2C communication
#include <MechaQMC5883.h> //QMC5883 Librarey is added since mine is QMC583 and not HMC5883



在下一行中,我们 为我们正在使用的传感器创建一个对象名称。我使用的名称是 qmc, 但它可以是你喜欢的任何东西。


MechaQMC5883 qmc; //Create an object name for the snsor, I have named it as qmc




接下来,我们进入 全局变量声明。 这里由于我们有8个Led作为输出,很难通过引脚名称引用每个引脚,因此 我们使用数组选项来引用所有LED。数组的名称是 ledPins ,变量 led_count 是我们拥有的led数。它从0开始



int ledPins[] = {2,3,4,5,6,7,8,9}; //Array of output pin to which the LED is connected to
char led_count = 7; //Total number of LED pins



void设置 功能中,我们初始化I2C通信,串行通信和传感器。然后我们将所有LED引脚声明为输出引脚。由于我们使用了一个数组,因此很容易使用for 循环引用所有引脚,如下所示。


void setup()
{
  Wire.begin(); //Begin I2C communication  
  Serial.begin(9600); //Begin Serial Communication  

  qmc.init(); //Initialise the QMC5883 Sensor   

   for (int thisPin=0; thisPin <= led_count; thisPin++)

        {                                                                                //Navigate through all the pins in array   

             pinMode(ledPins[thisPin],OUTPUT); //Declare them as output

         }

}



在 主 循环中,我们从传感器获取x,y和z的值并计算传感器当前所面对的角度。使用以下行读取x,y和z的值,




int x,y,z;

qmc.read(&x,&y,&z); //Get the values of X,Y and Z from sensor



计算航向的公式 如下所示。由于我们不打算沿z轴旋转指南针,因此我们不考虑该值。只有当IC平面朝向我们的设置时,才能使用此公式。一旦计算了航向,该值将在-180到180的范围内,我们必须将其转换为0到360,就像我们在所有数字罗盘中发现的那样。



int heading=atan2(x, y)/0.0174532925; //Calculate the degree using X and Y parameters with this formulae //Convert result into 0 to 360   

         if(heading < 0)  

          heading+=360;  

          heading = 360-heading;




最后一步是使指向北方向的LED发光。要做到这一点,我们有一系列if条件声明,我们检查当前程度的范围并根据它打开LED。代码如下所示



//Based on the value of heading print the result for debugging and glow the respective LED.   

if (heading > 338 || heading < 22)  

{   

    Serial.println("NORTH");   

    digitalWrite(ledPins[0],HIGH);  

}  

if (heading > 22 && heading < 68)  

{   

    Serial.println("NORTH-EAST");   

    digitalWrite(ledPins[7],HIGH);  

}  

if (heading > 68 && heading < 113)  

{   

    Serial.println("EAST");   

    digitalWrite(ledPins[6],HIGH);  

}  

if (heading > 113 && heading < 158)

{   

    Serial.println("SOUTH-EAST");   

    digitalWrite(ledPins[5],HIGH);  

}  

if (heading > 158 && heading < 203)  

{   

    Serial.println("SOUTH");   

    digitalWrite(ledPins[4],HIGH);  

}  

if (heading > 203 && heading < 248)  

{   

    Serial.println("SOTUH-WEST");   

    digitalWrite(ledPins[3],HIGH);  

}  

if (heading > 248 && heading < 293)  

{   

     Serial.println("WEST");   

    digitalWrite(ledPins[2],HIGH);  

}  

if (heading > 293 && heading < 338)  

{   

    Serial.println("NORTH-WEST");   

    digitalWrite(ledPins[1],HIGH);  

}





通过查看下表可以理解代码值背后的逻辑。基本上我们计算我们面向的方向并预测北方向和相应的LED发光。


方向
对应方向角度
于该方向的范围
北部
0°/ 360°
> 338°或<22°
东北
45°
22°至68°
东部
90°
68°至113°
东南
135°
113°至158°
180°158°
至203°
西南部
225°203°
248°WEST
170°248°
至293°
西北部
315°293°
到338°


该程序的最后一部分是设置结果的更新速度。我已经创建了一个500毫秒的延迟,然后关闭所有的LED再次从void循环内部的第一个开始。但如果您需要更快的更新,您可以进一步减少延迟。




delay(500); // update position of LED for every alf seconds//Turn off the all the LED     

for (int thisPin=0; thisPin <= led_count; thisPin++)

{     

    digitalWrite(ledPins[thisPin],LOW);  

}




测试数字罗盘

由于我们使用了Arduino pro mini,我们需要像FTDI板这样的外部编程器来上传程序。上传程序后,您应该注意到一块LED在电路板上发光,LED发光 的方向将是北方

然后,您可以通过旋转它,并检查LED是否仍然指向北方向。之后,您可以随时使用9V电池为供电启动并检查您所面对的方向。您可能会注意到,当您的电路板附近有重金属片或者沿着Z轴旋转电路板时,这些值会出错。有办法克服这个问题,这是另一个教程。

希望你喜欢这个教程并从中学到一些有用的东西。如果是的话,


完整代码



#include <Wire.h> //Wire Librarey for I2C communication
#include <MechaQMC5883.h> //QMC5883 Librarey is added since mine is QMC583 and not HMC5883
MechaQMC5883 qmc; //Create an object name for the snsor, I have named it as qmc
int ledPins[] = {2,3,4,5,6,7,8,9}; //Array of output pin to which the LED is connected to
char led_count = 7; //Total number of LED pins
 
void setup() {
  Wire.begin(); //Begin I2C communication
  Serial.begin(9600); //Begin Serial Communication
  qmc.init(); //Initialise the QMC5883 Sensor
  for (int thisPin=0; thisPin <= led_count; thisPin++){ //Navigate through all the pins in array
    pinMode(ledPins[thisPin],OUTPUT); //Declare them as output
  }
}
void loop() { //Infinite Loop
  int x,y,z;
  qmc.read(&x,&y,&z); //Get the values of X,Y and Z from sensor
 
  int heading=atan2(x, y)/0.0174532925; //Calculate the degree using X and Y parameters with this formulae
//Convert result into 0 to 360
  if(heading < 0)
  heading+=360;
  heading = 360-heading;
 
  Serial.println(heading); //Print the value of heading in degree for debugging
//Based on the value of heading print the result for debugging and glow the respective LED.
  if (heading > 338 || heading < 22)
  {
    Serial.println("NORTH");
    digitalWrite(ledPins[0],HIGH);
  }
  if (heading > 22 && heading < 68)
  {
    Serial.println("NORTH-EAST");
    digitalWrite(ledPins[7],HIGH);
  }
  if (heading > 68 && heading < 113)
  {
    Serial.println("EAST");
    digitalWrite(ledPins[6],HIGH);
  }
  if (heading > 113 && heading < 158)
  {
    Serial.println("SOUTH-EAST");
    digitalWrite(ledPins[5],HIGH);
  }
  if (heading > 158 && heading < 203)
  {
    Serial.println("SOUTH");
    digitalWrite(ledPins[4],HIGH);
  }
  if (heading > 203 && heading < 248)
  {
    Serial.println("SOTUH-WEST");
    digitalWrite(ledPins[3],HIGH);
  }
  if (heading > 248 && heading < 293)
  {
    Serial.println("WEST");
    digitalWrite(ledPins[2],HIGH);
  }
  if (heading > 293 && heading < 338)
  {
    Serial.println("NORTH-WEST");
    digitalWrite(ledPins[1],HIGH);
  }
  delay(500); // update position of LED for every alf seconds
//Turn off the all the LED
    for (int thisPin=0; thisPin <= led_count; thisPin++){
     digitalWrite(ledPins[thisPin],LOW);
  }
}








文章分类: Arduino
分享到:
会员登录
登录
我的资料
留言
回到顶部