dthain / qmc5883l Goto Github PK
View Code? Open in Web Editor NEWDriver for QMC5883L chip found in many GY-271 boards.
License: MIT License
Driver for QMC5883L chip found in many GY-271 boards.
License: MIT License
With this library I had issues to get a reliable connection to the sensor when I executed readRaw()
command more than 50 times a second. Even though the Sensor could work up to 200Hz.
When reading the chapter "8.2.4 I2C Read" in the datasheet, i discovered, that for reading the sensor data (x,y,z) there should only be sent one Stop-Bit from the master.
I am assuming, that your library instead is sending two Stop-Bits for one data-reading sequence. As far as I understand the Wire.h
library, the Wire.endTransmission();
line is sending a Stop-Bit even though it shouldn't.
After I added a false Wire.endTransmission(false);
in the read function, I could achieve a reliable 100Hz connection.
Hi,
Firstly,thanks for this library :) I wanted to use your library in a project but found it wouldnt compile for the ATtny85. Below is the error message. Is there anyway I can fix this?
Thanks for your time
Dave
Arduino: 1.8.5 (Mac OS X), Board: "ATtiny25/45/85, Disabled, CPU, ATtiny85, 8 MHz (internal), EEPROM retained, B.O.D. Disabled"
/Users/daveandrew/Documents/Arduino/libraries/QMC5883L-master/QMC5883L.cpp: In member function 'void QMC5883L::init()':
/Users/daveandrew/Documents/Arduino/libraries/QMC5883L-master/QMC5883L.cpp:149:6: error: 'TWCR' was not declared in this scope
if(TWCR==0) Wire.begin();
^
exit status 1
Error compiling for board ATtiny25/45/85.
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
Hi, thanks for sharing your code, very inspiring.
However, you may consider allowing to stop auto-calibration at some point. When you now point even a magnetic screwdriver at the sensor, the range becomes useless until you switch everything off (or perhaps only Soft Reset). Potential security hazard ;)
hi I bought GY-271 3.3 volt external compass QMC5883L and it cease to working after couple of minutes and it should reset to start working again , I really appreciated for any hint
I only can detect 90° and no data between, can you help how to solve that? :/ i am stuck there, and this is only lib that works.
hi there,
i used your library but the only thing i got was the message,
"turn the sensor in all directions for calibration"
and when i turned nothing happened
could you please help me with the issue???
What's the License of this library?
A small fix for the compass demo:
void loop()
{
while(1) {
...
The while(1) isn't necessary and blocks other background processing. The loop function will be called repeatedly.
HI,
Just to let you know that you should have #include <Wire.h> in the example now that you took it out in cpp for ATtiny85 compatibility. Else you get a wire not declared verify error.
Thanks again
Dave
sorry to have bothered you but your example in the code is kinda wrong
it is
#include <Serial.h>
QMC5883L compass;
void init()
{
compass.init();
compass.setSamplingRate(50);
Serial.println("QMC5883L Compass Demo");
Serial.println("Turn compass in all directions to calibrate....");
}
void loop()
{
while(1) {
int heading = compass.readHeading();
if(heading==0) {
/* Still calibrating, so measure but don't print */
} else {
Serial.println(heading);
}
}
}
and it should be
#include <QMC5883L.h>
//#include <Serial.h>
QMC5883L compass;
void setup()
{ Serial.begin(9600);
compass.init();
compass.setSamplingRate(50);
Serial.println("QMC5883L Compass Demo");
Serial.println("Turn compass in all directions to calibrate....");
}
void loop()
{
while(1) {
int heading = compass.readHeading();
if(heading==0) {
/* Still calibrating, so measure but don't print */
} else {
Serial.println(heading);
}
}
}
thanks for the code, by the way, keep up the good work
P.S
in the readme, you use an example of calling the function compass.setOverampling(ovl);
and after looking through your code I think it is compass.setOversampling(ovl);
readHeading is returning 1 allways! and you don't have pass by reference so just return heading; mybe? xD
and Wire.begin(sda, scl); call is missing? (for me, for nodemcu) so mybe adding this?
and include arduino.h is needed for atan2 to work (for me again). BTW thanks ALOTE! for code 👍
hi buddy , sorry to pen ticket for my question , but actually I’ve been trying to install Chinese compass QMC5883L (instead of HMC5843 ) to my Arducopter , I ran compos test sketch in the library and notice it didn’t initialize. After tracking the issue I’ve notice init() function do not work correctly because it’s return unsuccessful flag for rest of operation, then I’ve notice there are following parameters which is base on well known HMC5843 compass whereas its not compatible with this Chinese compass
uint16_t expected_x = 715;
uint16_t expected_yz = 715;
float gain_multiple = 1.0;
float calibration[3];
and this is ini() function in the driver lib
bool AP_Compass_QMC5883L::init()
{
int numAttempts = 0, good_count = 0;
bool success = false;
uint16_t expected_x = 715;
uint16_t expected_yz = 715;
float gain_multiple = 1.0;
if (!write_register(ConfigRegB,0x80)) return false; //softReset must reset first
hal.scheduler->delay(10);
write_register(0x0B, 0x01);//SET/RESET Period
_i2c_sem = hal.i2c->get_semaphore();
if (!_i2c_sem->take(HAL_SEMAPHORE_BLOCK_FOREVER)) hal.scheduler->panic(PSTR("Failed to get QMC5883L semaphore"));
// determine if we are using 5843 or 5883L
_base_config = BaseReg;
if ( !write_register(ConfigRegA, Mode_Continuous | ODR_200Hz | Mode_Continuous| RNG_8G | OSR_512 )
// || !read_register(ConfigRegA, &_base_config)
)
{
_healthy[0] = false;
_i2c_sem->give();
return false;
}
product_id = AP_COMPASS_TYPE_QMC5883L;
/*
note that the HMC5883 datasheet gives the x and y expected
values as 766 and the z as 713. Experiments have shown the x
axis is around 766, and the y and z closer to 713.
*/
expected_x = 766;
expected_yz = 713;
gain_multiple = 660.0 / 1090; // adjustment for runtime vs calibration gain
calibration[0] = 0;
calibration[1] = 0;
calibration[2] = 0;
while ( success == 0 && numAttempts < 25 && good_count < 5)
{
// record number of attempts at initialisation
numAttempts++;
// read values from the compass
hal.scheduler->delay(50);
if (!read_raw()) continue; // we didn't read valid values Fill _mag_x _mag_y _mag_z
hal.scheduler->delay(10);
float cal[3];
// hal.console->printf_P(PSTR("%d) mag: %d - %d - %d \n"),numAttempts, _mag_x, _mag_y, _mag_z);
cal[0] = fabsf(expected_x / (float)_mag_x);
cal[1] = fabsf(expected_yz / (float)_mag_y);
cal[2] = fabsf(expected_yz / (float)_mag_z);
// hal.console->printf_P(PSTR(" cal=%.2f %.2f %.2f\n"),numAttempts, cal[0], cal[1], cal[2]);
// we throw away the first two samples as the compass may still be changing its state from the application of the
// strap excitation. After that we accept values in a reasonable range
if (numAttempts > 2 &&
cal[0] > 0.7f && cal[0] < 1.35f &&
cal[1] > 0.7f && cal[1] < 1.35f &&
cal[2] > 0.7f && cal[2] < 1.35f)
{
// hal.console->printf_P(PSTR(" good\n") );
good_count++;
calibration[0] += cal[0];
calibration[1] += cal[1];
calibration[2] += cal[2];
}
#if 0
/* useful for debugging */
hal.console->printf_P(PSTR("MagX: %d MagY: %d MagZ: %d\n"), (int)_mag_x, (int)_mag_y, (int)_mag_z);
hal.console->printf_P(PSTR("CalX: %.2f CalY: %.2f CalZ: %.2f\n"), cal[0], cal[1], cal[2]);
#endif
}
//hal.console->printf_P(PSTR("good_count: %d \n"),good_count);
if (good_count >= 5)
{
/*
The use of gain_multiple below is incorrect, as the gain
difference between 2.5Ga mode and 1Ga mode is already taken
into account by the expected_x and expected_yz values. We
are not going to fix it however as it would mean all
APM1/APM2 users redoing their compass calibration. The
impact is that the values we report on APM1/APM2 are lower
than they should be (by a multiple of about 0.6). This
doesn't have any impact other than the learned compass
offsets
*/
calibration[0] = calibration[0] * gain_multiple / good_count;
calibration[1] = calibration[1] * gain_multiple / good_count;
calibration[2] = calibration[2] * gain_multiple / good_count;
success = true;
}
else
{
/* best guess */
calibration[0] = 1.0;
calibration[1] = 1.0;
calibration[2] = 1.0;
}
// leave test mode
if (!re_initialise())
{
_i2c_sem->give();
return false;
}
_i2c_sem->give();
_initialised = true;
// perform an initial read
_healthy[0] = true;
read();
#if 0
hal.console->printf_P(PSTR("CalX: %.2f CalY: %.2f CalZ: %.2f\n"), calibration[0], calibration[1], calibration[2]);
#endif
return true;//success;
}
so I’ve bypassed it in the way that init() function always return successful flag & calibration[3] array is always equal to 1, then compile and upload the firmware into hardware, but in the end I received compass error that says my compass too bios or fail , I repeated calibration procedure couple of times but the drone didn’t arm so I’m guessing I kinda need to consider calibration into account which is fundamentally need to know correct initial value, unfortunately data sheet didn't be helpful and I don't know how to guess the initial value of expected_x, expected_yz & gain_multiple, so I really appreciated to have your comments about that
full driver lib located here
https://github.com/mkeyno/AP_Compass_QMC5883L/blob/master/AP_Compass_QMC5883L.cpp#L150-L282
I don't know if this is your code error or what, this function never returns an Angle.
int QMC5883L::readHeading()
{
int16_t x, y, z, t;
if(!readRaw(&x,&y,&z,&t)) return 0;
/* Update the observed boundaries of the measurements */
if(x<xlow) xlow = x;
if(x>xhigh) xhigh = x;
if(y<ylow) ylow = y;
if(y>yhigh) yhigh = y;
/* Bail out if not enough data is available. */
if( xlow==xhigh || ylow==yhigh ) return 0;
/* Recenter the measurement by subtracting the average */
x -= (xhigh+xlow)/2;
y -= (yhigh+ylow)/2;
/* Rescale the measurement to the range observed. */
float fx = (float)x/(xhigh-xlow);
float fy = (float)y/(yhigh-ylow);
int heading = 180.0*atan2(fy,fx)/M_PI;
if(heading<=0) heading += 360;
return 1;
}
Hello,
I am unsure why this is happening, but the example seems to crash at random times and hang the Arduino. This is repeatable on both the QMC588L's I have. Any idea why?
-Will
int QMC5883L::readHeading()
{
int16_t x, y, z, t;
if(!readRaw(&x,&y,&z,&t)) return 0;
/* Update the observed boundaries of the measurements */
if(x<xlow) xlow = x;
if(x>xhigh) xhigh = x;
if(y<ylow) ylow = y;
if(y>yhigh) yhigh = y;
/* Bail out if not enough data is available. */
if( xlow==xhigh || ylow==yhigh ) return 0;
/* Recenter the measurement by subtracting the average */
x -= (xhigh+xlow)/2;
y -= (yhigh+ylow)/2;
/* Rescale the measurement to the range observed. */
float fx = (float)x/(xhigh-xlow);
float fy = (float)y/(yhigh-ylow);
int heading = 180.0*atan2(fy,fx)/M_PI;
if(heading<=0) heading += 360;
return heading;
}
The example code in examples/compass/compass.ino won't run as is because Wire.begin() isn't called.
It's easily solved with:
#include <Wire.h>
Setup() {
Wire.begin()
...
However, ideally QMC5883L.cpp would initialize Wire iff it has not been so the Wire usage is fully encapsulated.
This is my first post so please understand improper terms. When I compile my program it fails on M_PI which is buried inside of your library line 200. The little research I did indicates that this has been deprecated in the AVR math library. I am using Arduino 1.6.11 Compiler.
Thanks
Doug
An eager hobbyist
float fx = (float)x/(xhigh-xlow);
float fy = (float)y/(yhigh-ylow);
int heading = 180.0*atan2(fy,fx)/M_PI;
if(heading<=0) heading += 360;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.