请选择 进入手机版 | 继续访问电脑版
搜索
热搜: ROHM 模拟 车载
查看: 467|回复: 2

[分享] 罗姆地磁传感器应用指南

  [复制链接]

该用户从未签到

2

主题

17

帖子

0

精华

初级会员

最后登录
2019-9-12
发表于 2018-7-17 13:23:48 | 显示全部楼层 |阅读模式
13.jpg
上次在Device Plus编辑部寄来的罗姆传感器评估套件中介绍了地磁传感器。我想通过上次的内容您应该已经了解了传感器评估套件的使用便利性,而本次是介绍地磁传感器值的读取方法,及尝试与其他元件组合等使用方法的应用篇。

目录
  • 怎样读取地磁传感器的值和方向?
  • 扰乱地磁传感器的结构~传感器的值的倾角和偏角是什么呢?
  • 查找磁力传感器的最小值和最大值并检测方向
  • 尝试与步进电机组合制作罗盘
  • 总结
怎样读取地磁传感器的值和方向?首先,确认地磁传感器的值如何变化,慢慢移动实际配置于Arduino的地磁传感器,并试着确认其值。上次使用的样本程序通过串行监视器确认时,因小数点变动而不便观察,所以改为了用整数型表示以用于确认。在动画中,预先通过使用了GPS或陀螺罗盘的方向检测精度较高的应用查找正确的北(正北)方,并记载于纸上。我们来看看在地磁传感器与该方向一致时,程序侧取得的XYZ轴的各值。
BM1422GMV的显示程序
  1. #include <Wire.h>

  2. #include <BM1422.h>



  3. BM1422 bm1422(BM1422_DEVICE_ADDRESS_0E);



  4. void setup() {

  5. byte rc;



  6. Serial.begin(9600);

  7. while (!Serial);



  8. Wire.begin();



  9. rc = bm1422.init();

  10. }



  11. void loop() {

  12. byte rc;

  13. float mag[3];

  14. rc = bm1422.get_val(mag);



  15. int x = mag[0];


  16. int y = mag[1];

  17. int z = mag[2];



  18. if (rc == 0) {

  19. Serial.print("X=");

  20. Serial.print(x);

  21. Serial.print("  Y=");

  22. Serial.print(y);

  23. Serial.print("  Z=");

  24. Serial.println(z);

  25. }



  26. delay(500);

  27. }
复制代码




看动画即可明白,在各传感器的最大值的显示位置,一边对Arduino的串行监视器中显示的数字进行确认,一边寻找最大值。
2.png
图1 地磁传感器的状态


3.jpg
图2 地磁気センサのX軸の最大値

动画中X轴的值成为最大值的位置在此角度。奇怪,正如图1所示,由于传感器的值表示地磁强度,因此本来指向正北时的值就应该是最大值…?搞不明白了。 这是怎么回事呢?试着慢慢移动传感器后,发现Y轴也大致与X轴在相同方向上停止了。 正在进行实验的该房屋内或许存在着某种与地球不同的磁场…。
查找Z轴表示最大值的部位时,发现其如照片1所示了。几乎颠倒。果真是从地面释放出了某种神秘的地磁吗…汗。


4.jpg
照片1 Z轴为最大值时的状态


变得有些令人害怕了,关于地磁传感器(看似)设法指示最大值的传感器的数值之谜,我决定通过学习地磁传感器的相关知识来解开这一谜团。
地磁传感器的二轴和三轴传感器的不同首先,地磁传感器大致分为两类,即可使用二轴(XY)和三轴(XYZ)进行检测的两种类型。二轴型为XY轴,可简单地在水平状态下检测方向,但在倾斜状态等时不可正常检测方向。三轴型与XY轴相结合,增加了倾斜的Z轴,因此可根据Z轴的倾斜程度补正XY轴的值,从而检测出方向。
本次传感器评估套件中的传感器为三轴传感器,因此可处理比二轴传感器更详细的数据,嗯哼。


2.扰乱地磁传感器的结构~传感器的值的倾角和偏角是什么呢?接下来我们深入研究一下传感器的最大值之谜。

首先,我们来看看究竟什么是地磁!?

的确,虽说我会使用地磁传感器,但完全不了解"地磁"本身是什么(羞愧…)。
是地球发出的磁力?或是磁场吗?我只有这样的模糊的概念…。

什么是地磁?这里,我们将学习地磁本身及地磁传感器的结构。简单来说,地磁传感器是指可感应磁铁发出的磁力的传感器。如图4所示,地球好比一个巨大的磁铁,其周围环绕着磁力。地磁传感器如同指南针,是可以检测地磁的传感器。
5.png
图4 地球是一个巨大的磁铁

这里我们学习一点科学知识,实际上手持指南针指向北极点或南极点时,若保持方向不变,则无论何时都不可能到达北极点或南极点。这是地球结构暗藏的玄机。在国土地理院和气象厅的网站上刊登了浅显易懂的解说,地磁略偏离了地球中心。因受地球内部活动等的影响而发生了变化,根据2015年的数据,大约向西偏离了7度(后面详细解说)。真是不可思议呀。并且,以数万年~数十万年为单位,地磁可能发生反转。若是这样,即使使用地磁传感器制造出具有未来可永久保持耐久性的元器件,数万年后,也会因地球自身的轴偏离而必须进行补正…
了解地磁 – 国土地理院(日文网页)
http://vldb.gsi.go.jp/sokuchi/geomag/menu_01/
地球电磁的Q&A – 气象厅(日文网页)
http://www.kakioka-jma.go.jp/knowledge/qanda.html

6.png
图5 地球的磁铁与北极点略有偏离

另外,此处还可使用国土地理院的电子国土Web(日文网页)查看偏离程度。
7.jpg
图6 东京的磁北线


东京站刚好偏离了7.0°!

8.jpg
图7 宗谷岬的磁北线


哎呀,日本最北端的稚内并非7.0°,而是9.8°????
那么,南部又如何呢…

9.jpg
图8 那霸市的磁北线


冲绳那霸市并非7.0°,而是4.4°
真搞不明白,这到底是怎么回事呀…


这样,图正中央标记的红色数值表示偏离程度,东京站为7度,而日本最北端宗谷岬为9.8度,冲绳那霸市为4.4度,可以发现各值之间存在较大差异。
然而,这些偏离数值仅仅是告诉了我们偏离因地点的不同而异的现实。谜团更深了…。

倾角和偏角的存在实际上地球地磁的最大值和正北方的偏离角度被称为"倾角"和"偏角"。地磁的偏离量一般记载为7度,但实际上该偏离量因计测位置的不同而异。该偏离量被称为偏角。就日本国内而言,大致为越向北方偏离越大,越向南方偏离越小。另外,将东西南北视为左右(XY轴)时,上下水平(Z轴)也会偏离。其被称为倾角。倾角即为图4、图5所示的与地磁流所形成的角度,就东京而言,以陷入地面的形式倾斜了约49度。因此刚才Z轴近乎颠倒成为最大值正是与此相关的吧?
由此可见,表示正确方向时,由于该倾角和偏角密切相关,因此使用GPS在地球上哪个位置补正偏离是非常难把握的事情…。理清思路后,发现使用地磁传感器等时,若不能明确北是指正北还是磁北,则欲取得的数值就会出现错误。
  • 正北 ・・・ 地球的最北方
  • 磁北 ・・・ 电子磁铁或地磁传感器所示的北的位置(地磁最大的方向)


3.查找磁力传感器的最小值和最大值并检测方向下面,我们实际使用磁力传感器,通过Arduino来实现方向的检测。
包括地磁传感器在内,电子零件传感器在通常状态下电阻值会发生变化,因此通过在Arduino侧计测基于该电阻变化的电压值,读出了传感器的值。我们试着来查找本次使用的地磁传感器的XYZ轴的最小值和最大值。查找的值有水平时和与水平无关时的两种。由于该数值因实验环境而异,因此实验时请将其与传感器实际相连。
[td]               
水平时最小水平时最大最小(Min)最大(Max)
X -90 1 -121 21
Y -84 7 -115 36
Z -98-92 -102 30
本次将计算水平时的方向。下图9表示利用从串行监视器复制地磁传感器旋转一周后的值做成的XY轴的分布图。形成了一个漂亮的圆形。其为水平时,可通过使用反正切函数的公式计算角度。通过将以中点为轴、欲检测角度的点应用到公式中,计算角度。在程序侧,预先确认并设定中点和数值的范围后,需要将其写入Arduino。
10.png
图9 将地磁传感器的值绘制成图表


下面,我们尝试使用该公式通过Arduino进行实际安装!

4.尝试与步进电机组合制作罗盘本次,我们尝试组合地磁传感器与步进电机制作罗盘。将Arduino和地磁传感器放置于圆木板上,通过使用步进电机旋转底座,尝试按照总是指向北方的规格进行实际安装。使步进电机颠倒,将装载Arduino等的底座置于其上。
11.jpg
照片2 成为基座的步进电机


12.jpg
照片3 装在底座上的Arduino、地磁传感器等元件

最初考虑采用一台步进电机的底座,但实际安装时检测出步进电机的磁力干扰地磁传感器的数值,因此拧入螺栓抬高至消除干扰的高度。


照片4 装有所有元件及设备的状态,使用螺栓抬高地磁传感器

使用程序检测角度,达到磁北时停止。若步进电机太快则可能超过磁北,因此在rd变量的if条件句内留有一定的余量。
  1. #include <Arduino.h>

  2. #include <SPI.h>

  3. #include <Wire.h>

  4. #include <BM1422.h>



  5. BM1422 bm1422(BM1422_DEVICE_ADDRESS_0E);



  6. int _px  = -44.5; //中点x

  7. int _py  = -38.5; //中点y



  8. #define PIN_SPI_MOSI 11

  9. #define PIN_SPI_MISO 12

  10. #define PIN_SPI_SCK 13

  11. #define PIN_SPI_SS 10



  12. void setup()

  13. {

  14. delay(1000);

  15. Serial.begin(9600);



  16. //准备步进电机用的针

  17. pinMode(PIN_SPI_MOSI, OUTPUT);

  18. pinMode(PIN_SPI_MISO, INPUT);

  19. pinMode(PIN_SPI_SCK, OUTPUT);

  20. pinMode(PIN_SPI_SS, OUTPUT);

  21. digitalWrite(PIN_SPI_SS, HIGH);



  22. //SPI通信的开始宣言

  23. SPI.begin();

  24. SPI.setDataMode(SPI_MODE3);//通过SCK的起动接收/发送数据,空闲时将pin设定为HIGH

  25. SPI.setBitOrder(MSBFIRST);//由MSB发送



  26. //L6470的使用设定

  27. L6470_setup();



  28. byte rc;



  29. Serial.begin(9600);

  30. while (!Serial);



  31. Wire.begin();



  32. rc = bm1422.init();

  33. }



  34. //**********************************************

  35. //用于SPI通信的函数

  36. //**********************************************

  37. void L6470_send(unsigned char value){

  38. digitalWrite(PIN_SPI_SS, LOW);

  39. SPI.transfer(value);  //通过SPI通信发送控制信号

  40. digitalWrite(PIN_SPI_SS, HIGH);

  41. }



  42. //旋转指定角度

  43. void moveStepper(int val,int r=1){

  44. //360度 - 旋转一次处理

  45. if(r == 1){

  46. L6470_send(0x50);//Run(DIR,SPD),0x51:正转,0x50:逆转

  47. }

  48. else{

  49. L6470_send(0x51);//Run(DIR,SPD),0x51:正转,0x50:逆转

  50. }

  51. L6470_send(0x00);

  52. L6470_send(0x20);//旋转速度的设定

  53. L6470_send(0x00);

  54. double rad = val*9;

  55. delay(rad);//旋转一圈约为1604ms

  56. L6470_send(0xB8);//紧急停止(硬停机)

  57. }



  58. //**********************************************

  59. // L6470的调试

  60. //**********************************************

  61. void L6470_setup(){

  62. //元器件的设定

  63. L6470_send(0x00);

  64. L6470_send(0x00);

  65. L6470_send(0x00);

  66. L6470_send(0x00);

  67. L6470_send(0xc0);




  68. //最大旋转速度的设定

  69. L6470_send(0x07);//寄存器地址

  70. L6470_send(0x20);//值(10bit),默认0x41



  71. //电机停止中的电压设定

  72. L6470_send(0x09);//寄存器地址

  73. L6470_send(0xFF);//值(8bit),默认0x29



  74. //电机恒定速度旋转时的电压设定

  75. L6470_send(0x0a);//寄存器地址

  76. L6470_send(0xFF);//值(8bit),默认0x29



  77. //加速中的电压设定
  78. L6470_send(0x0b);//寄存器地址

  79. L6470_send(0xFF);//值(8bit),默认0x29



  80. //减速中的电压设定

  81. L6470_send(0x0c);//寄存器地址

  82. L6470_send(0xFF);//值(8bit),默认0x29



  83. //全步进、半步进、1/4、1/8、…、1/128步进的设定

  84. L6470_send(0x16);//寄存器地址

  85. L6470_send(0x00);//值(8bit)

  86. }



  87. /** 求角度  **/

  88. double getDirection(double x, double y){

  89. double dir  = 0;

  90. dir = atan((y - _py)/(x - _px));

  91. return dir;

  92. }



  93. void loop(){

  94. byte rc;

  95. float mag[3];

  96. float rd = 0;

  97. rc = bm1422.get_val(mag);



  98. rd = getDirection(mag[0],mag[1]);






  99. int x = mag[0];

  100. int y = mag[1];




  101. Serial.print("rd=");

  102. Serial.print(rd);

  103. Serial.print("  x=");

  104. Serial.print(x);

  105. Serial.print("  y=");

  106. Serial.println(y);



  107. //非磁北时旋转步进电机

  108. //根据步进电机的转速,给rd留有一定的余量

  109. if(rd <= 0.3 && rd >= -0.3 && x > 0){

  110. //磁北的状态

  111. Serial.println("North!");

  112. }

  113. else if(rd > 0){

  114. moveStepper(2,-1);

  115. }

  116. else{

  117. moveStepper(2);

  118. }



  119. delay(2);

  120. }
复制代码



这样,总是指向磁北的罗盘制作完成!为了使其更准确地指向正北方,要遵守先对偏角、倾角等的值进行调整的流程。

5.总结本次为了帮助您理解地磁传感器而介绍了一些理科、数学等相关知识!另外,虽然仅通过Arduino制作罗盘只能说是车轮的再造,但基于这一基本动作,尝试思考相关应用也是件乐事。下次我将进一步使用传感器评估套件分享相关知识。

本文转自:罗姆官网:https://www.rohm.com.cn/sensor-shield-support/device-plus/entry2


回复

使用道具 举报

该用户从未签到

1763

主题

5868

帖子

1

精华

论坛元老

最后登录
2019-11-15
发表于 2018-7-17 16:43:52 | 显示全部楼层
传感器还是挺不错的
回复 支持 反对

使用道具 举报

该用户从未签到

1153

主题

5857

帖子

0

精华

论坛元老

最后登录
2019-10-3
发表于 2018-8-16 23:10:30 | 显示全部楼层
可真够长的
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /4 下一条

小黑屋|手机版|Archiver|罗姆半导体技术社区

GMT+8, 2019-11-17 17:48 , Processed in 0.086656 second(s), 17 queries , MemCache On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表