查看: 3415|回复: 0

[资料] 入手维特智能的9轴模块,试验成功,完美替换原来的MPU6050

[复制链接]

该用户从未签到

发表于 2019-8-14 14:27:28 | 显示全部楼层 |阅读模式
分享到:
各位朋友,大家好,小弟新人,请多多关照。我是打算做平衡小车的,一直想找一款合适的传感器,用来测小车的姿态角度。
        之前试过6050的DMP,感觉效果不行。最近网上大家用的比较多的一款串口的6050模块,尝试了一下。有一个很大的问题就是Z轴的漂移问题,当然测量倾角的效果还是很好的,就是方向角有问题,放在那里不动还好,运动起来,就会有累积误差,只能用短时间内的两个角度只差算小车转了多少角度,店主说6050模块没有磁场,不可避免会出现累计误差,虽然理论上说小车的平衡不依赖于方向角,但是方向角一直测不准,对于我这种追求完美的偏执狂来说,总觉得是个遗憾。
        好在现在维特智能的9轴的JY-901模块出来了,据说能解决Z轴漂移的问题。赶紧定了一片。今天刚到手,第一感觉是做工很真的精致,元件布局密度很大,几乎没有空的空间了,据店主说新款的为了保持和原来的串口6050的兼容性,封装和体积都是一样大小的,但是要布下比原来的串口6050模块多一倍的元件,只能采用4层板工艺了。看上去确实比原来的好很多,更精致了。


微信图片_20190814140732.png



  不过店主并没有公开硬件的方案,个人觉得应该还是MPU6050+磁力计的方案,不知道各位前辈有何高见。






微信图片_20190814141404.jpg

  软件不再是原来单一的曲线显示了,现在还加入了仪表盘和三维显示,接上线测试了一下,测到的数据能够很好地跟踪模块姿态的变换,不过刚开始的时候,方向角总是感觉不太准有些误差,后来跟店主请教后,发现是没有校准的问题,昨晚磁场校准以后,果然没有再出现方向不准的问题了。精度确实很好。比DMP好太多了。大家可以看我的测试数据。
        可能是磁场传感器都会有零偏误差的原因,而且这个初始误差还不小,足矣影响方向角的测量。陀螺仪的校准比较简单,点了校准按钮以后,等等数据不再变化即可。但是磁场的校准就比较麻烦一些了,在此也跟大家分享一下:点击磁场校准按钮以后,先绕X轴转动360度,再绕Y轴转360度,再绕Z轴转360度,然后再随意转动几下,知道显示的偏移值不再改变为止。原理是这样的:磁场传感器需要检测传感器在当前磁场环境中的最大值和最小值,然后去平均就是该轴的零点误差。因为地磁场是恒定的,比如X轴测到的最大值是700,最小值是-500,但实际上测到的都是地磁场,所以,X轴的零偏就是(700-500)/2=100,也就是说,修正以后,X的最大值是600,最小值是-600,这样两边就一致了。所以磁场校准需要寻找三个轴分别的最大值和最小值,因此需要分别绕三轴转360度。
        连电脑测试以后,又马上测试了一下连接arduino,我用的是Arduino Uno R3极客版,个人感觉比原版的Uno R3好用,我的Win8系统现在可以直接用了,原版的UnoR3驱动怎么都装不上,每次都得去找个XP电脑才行。最主要的是极客的价格是原版的1/3,很划算,嘻嘻。。。
        JY901对Arduino的支持很好,店主提供了Arduino的库函数,根据说明的方法安装以后,就可以再Arduino的菜单下面看到Demo了。




店主提供了IIC的和串口的Demo,小弟都分别作了测试。先说串口连接,JY901的VCC接5V,GND接GND,JY901的TX接UnoR3的TX->1,JY901的RX线不用接。




注意给UnoR3下载程序的时候,一定要先把TX线断开,然后再下载程序,下载完成后,再接上TX线。因为UnoR3下载程序用的也是这个串口,如果接上JY901以后,JY901会持续给模块发送数据,这样就会干扰UnoR3的程序下载。串口的代码如下:
[pre lang="arduino" line="1" file="JY901Serial.ino"]#include <Wire.h>
#include <JY901.h>

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  //print received data. Data was received in serialEvent;
  Serial.print("Time:20");Serial.print(JY901.stcTime.ucYear);Serial.print("-");Serial.print(JY901.stcTime.ucMonth);Serial.print("-");Serial.print(JY901.stcTime.ucDay);
  Serial.print(" ");Serial.print(JY901.stcTime.ucHour);Serial.print(":");Serial.print(JY901.stcTime.ucMinute);Serial.print(":");Serial.println((float)JY901.stcTime.ucSecond+(float)JY901.stcTime.usMiliSecond/1000);
               
  Serial.print("Acc:");Serial.print((float)JY901.stcAcc.a[0]/32768*16);Serial.print(" ");Serial.print((float)JY901.stcAcc.a[1]/32768*16);Serial.print(" ");Serial.println((float)JY901.stcAcc.a[2]/32768*16);
  
  Serial.print("Gyro:");Serial.print((float)JY901.stcGyro.w[0]/32768*2000);Serial.print(" ");Serial.print((float)JY901.stcGyro.w[1]/32768*2000);Serial.print(" ");Serial.println((float)JY901.stcGyro.w[2]/32768*2000);
  
  Serial.print("Angle:");Serial.print((float)JY901.stcAngle.Angle[0]/32768*180);Serial.print(" ");Serial.print((float)JY901.stcAngle.Angle[1]/32768*180);Serial.print(" ");Serial.println((float)JY901.stcAngle.Angle[2]/32768*180);
  
  Serial.print("Mag:");Serial.print(JY901.stcMag.h[0]);Serial.print(" ");Serial.print(JY901.stcMag.h[1]);Serial.print(" ");Serial.println(JY901.stcMag.h[2]);
  
  Serial.print("Pressure:");Serial.print(JY901.stcPress.lPressure);Serial.print(" ");Serial.println((float)JY901.stcPress.lAltitude/100);
  
  Serial.print("DStatus:");Serial.print(JY901.stcDStatus.sDStatus[0]);Serial.print(" ");Serial.print(JY901.stcDStatus.sDStatus[1]);Serial.print(" ");Serial.print(JY901.stcDStatus.sDStatus[2]);Serial.print(" ");Serial.println(JY901.stcDStatus.sDStatus[3]);
  
  Serial.print("Longitude:");Serial.print(JY901.stcLonLat.lLon/10000000);Serial.print("Deg");Serial.print((double)(JY901.stcLonLat.lLon % 10000000)/1e5);Serial.print("m Lattitude:");
  Serial.print(JY901.stcLonLat.lLat/10000000);Serial.print("Deg");Serial.print((double)(JY901.stcLonLat.lLat % 10000000)/1e5);Serial.println("m");
  
  Serial.print("GPSHeight:");Serial.print((float)JY901.stcGPSV.sGPSHeight/10);Serial.print("m GPSYaw:");Serial.print((float)JY901.stcGPSV.sGPSYaw/10);Serial.print("Deg GPSV:");Serial.print((float)JY901.stcGPSV.lGPSVelocity/1000);Serial.println("km/h");
  
  Serial.println("");
  delay(500);
}

/*
  SerialEvent occurs whenever a new data comes in the
hardware serial RX.  This routine is run between each
time loop() runs, so using delay inside loop can delay
response.  Multiple bytes of data may be available.
*/
void serialEvent()
{
  while (Serial.available())
  {
    JY901.CopeSerialData(Serial.read()); //Call JY901 data cope function
  }
}[/code]
        步骤很简单,首先初始化串口,然后在串口中断里面调用JY901的数据处理函数即可。其实大部分都是在打印输出,数据解析都是在库里面完成的。非常简洁明了。测试结果如下:
        IIC的接线方法也很简单,接上VCC和GND以后,将JY901的SCL和SDA分别接上UnoR3的SCL和SDA上面即可。




IIC的程序如下:
        [pre lang="arduino" line="1" file="JY901IIC.ino"]#include <Wire.h>
#include <JY901.h>

void setup()
{
  Serial.begin(9600);
  JY901.StartIIC();
}

void loop()
{
  //print received data. Data was received in serialEvent;
  JY901.GetTime();
  Serial.print("Time:20");Serial.print(JY901.stcTime.ucYear);Serial.print("-");Serial.print(JY901.stcTime.ucMonth);Serial.print("-");Serial.print(JY901.stcTime.ucDay);
  Serial.print(" ");Serial.print(JY901.stcTime.ucHour);Serial.print(":");Serial.print(JY901.stcTime.ucMinute);Serial.print(":");Serial.println((float)JY901.stcTime.ucSecond+(float)JY901.stcTime.usMiliSecond/1000);
            
  JY901.GetAcc();
  Serial.print("Acc:");Serial.print((float)JY901.stcAcc.a[0]/32768*16);Serial.print(" ");Serial.print((float)JY901.stcAcc.a[1]/32768*16);Serial.print(" ");Serial.println((float)JY901.stcAcc.a[2]/32768*16);
  
  JY901.GetGyro();  
  Serial.print("Gyro:");Serial.print((float)JY901.stcGyro.w[0]/32768*2000);Serial.print(" ");Serial.print((float)JY901.stcGyro.w[1]/32768*2000);Serial.print(" ");Serial.println((float)JY901.stcGyro.w[2]/32768*2000);
  
  JY901.GetAngle();
  Serial.print("Angle:");Serial.print((float)JY901.stcAngle.Angle[0]/32768*180);Serial.print(" ");Serial.print((float)JY901.stcAngle.Angle[1]/32768*180);Serial.print(" ");Serial.println((float)JY901.stcAngle.Angle[2]/32768*180);
  
  JY901.GetMag();
  Serial.print("Mag:");Serial.print(JY901.stcMag.h[0]);Serial.print(" ");Serial.print(JY901.stcMag.h[1]);Serial.print(" ");Serial.println(JY901.stcMag.h[2]);
  
JY901.GetPress();
  Serial.print("Pressure:");Serial.print(JY901.stcPress.lPressure);Serial.print(" ");Serial.println((float)JY901.stcPress.lAltitude/100);
  
JY901.GetDStatus();
  Serial.print("DStatus:");Serial.print(JY901.stcDStatus.sDStatus[0]);Serial.print(" ");Serial.print(JY901.stcDStatus.sDStatus[1]);Serial.print(" ");Serial.print(JY901.stcDStatus.sDStatus[2]);Serial.print(" ");Serial.println(JY901.stcDStatus.sDStatus[3]);
  
JY901.GetLonLat();
  Serial.print("Longitude:");Serial.print(JY901.stcLonLat.lLon/10000000);Serial.print("Deg");Serial.print((double)(JY901.stcLonLat.lLon % 10000000)/1e5);Serial.print("m Lattitude:");
  Serial.print(JY901.stcLonLat.lLat/10000000);Serial.print("Deg");Serial.print((double)(JY901.stcLonLat.lLat % 10000000)/1e5);Serial.println("m");
  
JY901.GetGPSV();
  Serial.print("GPSHeight:");Serial.print((float)JY901.stcGPSV.sGPSHeight/10);Serial.print("m GPSYaw:");Serial.print((float)JY901.stcGPSV.sGPSYaw/10);Serial.print("Deg GPSV:");Serial.print((float)JY901.stcGPSV.lGPSVelocity/1000);Serial.println("km/h");
  
  Serial.println("");
  delay(500);
}[/code]
        也很简单,初始化串口,然后开始IIC通信,读取需要的数据,再打印输出即可。同样很简洁。
        总结一下:个人觉得IIC更好用一些,首先下载程序不用再拔线了,另外数据可以根据需要读取,不像串口是被动接受的,总是会经常进入中断里面去收取数据。浪费CPU的时间。另外空出来的宝贵的串口就可以拿来连接别的设备啦。
        附实验所使用的材料清单及TB传送门:
  
        通过实验觉得这个模块还是很好用的,精度很高,资料也非常齐全,现在希望我的平衡小车能够快点站起来,后续再来和大家分享。




回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

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

手机版|小黑屋|与非网

GMT+8, 2024-12-20 00:03 , Processed in 0.112102 second(s), 16 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.