本帖最后由 老张383 于 2020-6-28 16:49 编辑
先前的想法很简单:用指南针模块GY271,主芯片HMC5883L做一个指南针,采用指南针的读数调整小车的转向,是小车沿着正南方向行驶。 file:///C:/Users/kx/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpgfile:///C:/Users/kx/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg file:///C:/Users/kx/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg 但是困难重重,碰的头破血流,死的心都快有了。
让大家看看什么是超级小白,什么哀鸣菜鸟。 使用 arduino UNO R3 单片机,指南针模块 GY271,主芯片 HMC5883L
安装Gy271库文件,包含 HMC5883L.h, HMC5883L.cpp , HMC5883L_Example.pde,HHMC5883L_Example_Ansifa.pde,keywords.txt。 这里有两示例文件,HMC5883L_Example.pde 和HHMC5883L_Example_Ansifa.pde, 1、先上传HMC5883L_Example.pde,看看运行它会出现什么状况。
#include <Wire.h> #include <HMC5883L.h> HMC5883L compass; int error = 0; void setup() { Serial.begin(9600); Serial.println("Starting the I2C interface."); Wire.begin(); // Start the I2C interface. Serial.println("Constructing new HMC5883L"); compass = HMC5883L(); // Construct a new HMC5883 compass. Serial.println("Setting scale to +/- 1.3 Ga"); error = compass.SetScale(1.3); // Set the scale of the compass. if(error != 0) // If there is an error, print it out. Serial.println(compass.GetErrorText(error)); Serial.println("Setting measurement mode to continous."); error = compass.SetMeasurementMode(Measurement_Continuous); // Set themeasurement mode to Continuous if(error != 0) // If there is an error, print it out. Serial.println(compass.GetErrorText(error)); } void loop() { MagnetometerRaw raw = compass.ReadRawAxis(); MagnetometerScaled scaled = compass.ReadScaledAxis(); int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis) float heading = atan2(scaled.YAxis, scaled.XAxis); float declinationAngle = 0.0457; heading += declinationAngle; if(heading < 0) heading += 2*PI; if(heading > 2*PI) heading -= 2*PI; float headingDegrees = heading * 180/M_PI; Output(raw, scaled, heading, headingDegrees); } void Output(MagnetometerRaw raw,MagnetometerScaled scaled, float heading, float headingDegrees) { Serial.print("Raw:\t"); Serial.print(raw.XAxis); Serial.print(" "); Serial.print(raw.YAxis); Serial.print(" "); Serial.print(raw.ZAxis); Serial.print(" \tScaled:\t"); Serial.print(scaled.XAxis); Serial.print(" "); Serial.print(scaled.YAxis); Serial.print(" "); Serial.print(scaled.ZAxis); Serial.print(" \tHeading:\t");
Serial.print(heading); Serial.print(" Radians \t"); 2、再看HHMC5883L_Example_Ansifa.pde,不知道这里为什么用了Ansifa。运行结果依然很八卦。
#include <Wire.h> #include <HMC5883L.h> HMC5883L compass; void setup(){ Serial.begin(9600); Wire.begin(); compass = HMC5883L(); compass.SetScale(1.3); compass.SetMeasurementMode(Measurement_Continuous); } void loop() { MagnetometerRaw raw = compass.ReadRawAxis(); MagnetometerScaled scaled = compass.ReadScaledAxis(); float xHeading = atan2(scaled.YAxis, scaled.XAxis); float yHeading = atan2(scaled.ZAxis, scaled.XAxis); float zHeading = atan2(scaled.ZAxis, scaled.YAxis); if(xHeading < 0) xHeading +=2*PI; if(xHeading > 2*PI) xHeading-= 2*PI; if(yHeading < 0) yHeading +=2*PI; if(yHeading > 2*PI) yHeading-= 2*PI; if(zHeading < 0) zHeading +=2*PI; if(zHeading > 2*PI) zHeading-= 2*PI; float xDegrees = xHeading * 180/M_PI; float yDegrees = yHeading * 180/M_PI; float zDegrees = zHeading * 180/M_PI; Serial.print(xDegrees); Serial.print(","); Serial.print(yDegrees); Serial.print(","); Serial.print(zDegrees); Serial.println(";"); delay(100); } 看到数据一片惊喜,数据变化啦,细细一看这个变化是有规律的,周期性变化,并不随器件的转动变化,是我行我素的自我运动,串口监视器让人眼花缭乱。
file:///C:/Users/kx/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg 更有甚者,串口绘图仪可以清楚了,这种变化有极高的稳定性、抗冲击性和抗破坏性,因为拔掉时钟线和数据线,它依然不停的按自己的路子变化着。这个特点的深入研究没准还能别有他用呢。绘图仪给出的图片如下。file:///C:/Users/kx/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg
3、也不是完全的山穷水尽,再看从某宝买模块时送的实验程序HMC5883_example_code.ino, 当两个示例文件百般求索也没找到出路时,想起了商家也许有道,请注意这里并没有用到HMC5883L.h的库文件,商家给的这段代码也是令人沮困惑的。这是2011年的代码,年代久远IDE都换了多个版本了,Arduino没准都不认识呢。代码如下 #include <Wire.h> //I2C ArduinoLibrary #define address 0x1E //0011110b,I2C 7bit address of HMC5883 void setup(){ //Initialize Serial and I2C communications Serial.begin(9600); Wire.begin();
//Put the HMC5883 IC into the correct operating mode Wire.beginTransmission(address); //open communication with HMC5883 Wire.send(0x02); //select mode register Wire.send(0x00); //continuous measurement mode Wire.endTransmission(); }
void loop(){
int x,y,z; //triple axis data
//Tell the HMC5883 where to begin reading data Wire.beginTransmission(address); Wire.send(0x03); //select register 3, X MSB register Wire.endTransmission();
//Read data from each axis, 2 registers peraxis Wire.requestFrom(address, 6); if(6<=Wire.available()){ x = Wire.receive()<<8; //X msb x |= Wire.receive(); //X lsb z = Wire.receive()<<8; //Z msb z |= Wire.receive(); //Z lsb y = Wire.receive()<<8; //Y msb y |= Wire.receive(); //Y lsb }
//Print out values of each axis Serial.print("x: "); Serial.print(x); Serial.print(" y: "); Serial.print(y); Serial.print(" z: "); Serial.println(z);
delay(250); }
不但arduino不认识,重要的是Wire.h中就没有send这样的成员函数,度娘说,变啦,变啦,send变成write而receive变成read。加电修改一试成啦,本以为两块模块同时坏了,准备买新的再试,没想到一个简单的素代码竟让人快乐起来。如下图可以看出模块随运动和静止时给出的磁场强度曲线。
file:///C:/Users/kx/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg
请注意,程序中没有用到HMC5883L.h的库函数,直接按HMC5883L手册对其寄存器进行赋值,利用I2C进行操作输出芯片获得的原始数据。手册给出模式寄存器的后两位确定了模块的状态 file:///C:/Users/kx/AppData/Local/Temp/msohtmlclip1/01/clip_image016.jpg Wire.beginTransmission(address);//open communication with HMC5883 Wire.write(0x02); //select mode register Wire.write(0x00); //continuous measurement mode 从而确定了模块是连续进行测量。 4、以上说明不是探索的全部,探索的过程满身已刺满荆棘! arduino是优秀的硬件平台吗?学习arduino可以节约学习成本吗?使用arduino能够缩短开发周期吗?我只想做一个小车,参考指南针给出的方向,向南行驶5米,再向东行驶2米,并且方向的宽容度很大,一个自娱自乐的小车,看书害死人啊,每本介绍arduino的书都说arduino如何简单有趣,如何好学宜人,一个猛子扎进去方知道arduino的境界谁冷谁知道。 还拿做小车这件事说事,只想做一个依方向运动的小车耍耍,没有太高要求,但是选定了指南针模块后灾难就开始了。 如果你想用GY271模块,就要了解HMC5883L芯片,就要搜索HMC5883L的库文件,因为我们关心的是里面的例程文件,看看大师们是怎么用的,依葫芦画瓢是最基本最直接的心理,但是所找的的例程文件都玩不转,各种各样的不转,中间出现的“致命性错误”一堆一堆的,当你打开.h文件时你是什么都看不懂的,你只看到了它的成员数据和成员函数,如何操作你并不清楚,成员函数是解决问题的方法,这个方法如何使用是在源程序.cpp中,那你就需要认真研读.cpp,谈何容易,没办法你需要重新学习C++,可是C++在讲类库编写时用的对象是圆类,为了简明扼要,讲的轻松听得明白,讲解的是求圆面积和圆周长两个成员函数,类似于我们的书中超声波的的两个成员函数,让人看着清新爽快,但是解决不了应用过程中的实际问题。大学老师都是这样上课的,简单的反复讲,重复讲,遇见难题一带而过,绕着走,呵呵。 如果使用类库,还要熟悉类库,还要熟悉器件,还要完成的学完C/C++,怎么总让人产生有点上了贼船的感觉。 看着arduino的程序简洁,只是包含了若干头文件,可以建立若干对象,解决我们的一些问题,其实这只是表象,大量的源程序.cpp在后台运作,如果打开.cpp看看,大量的寄存器操作,指针操作,地址数据操作,美其名曰这是进行了二次封装。造成了如此多的困难,饶了这么多弯弯,还不如直接用51或是树莓派来的直接--努力去学习各类编程语言。 看着这么一堆arduino东东,一事无成也无颜见爹娘,还是去做那些无聊的流水灯呼吸灯去吧............
|