A little aside from the analytical topics of this blog, I also was occupied with a little ubiquitous computing project. It was about machine learning with a magnetic field sensor, the QMC5883.
In the Arduino module GY-271, usually the chip HMC5883 is equipped. Unfortunately, in cheap modules from china, another chip is used: the QMC5883. And, as a matter of course, the software library used for the HMC5883 does not work with the QMC version, because the I2C adress and the usage is a little bit different.
Another problem to me was, that I didn't find any proper working source codes for that little magnetic field device, and so I had to debug a source code I found for Arduino at Github (thanks to dthain). Unfortunately it didn't work properly at this time, and to change it for the Raspberry Pi into Python. Below you can find the "driver" module for the GY-271 with the QMC5883 chip. Sorry for the bad documentation, but at least it will work on a Raspberry Pi 3.
But, why ever, Python does not recognize the proper number format. The result was, that Python always received positive values - twice in 360 degrees and they looked somehow scrambled. The values should have been between -32768 and 32767 (regarding the datasheet).
After a little modification (which took hours to be found), the received values were better. The module Struct had to be used:
After this, the values looked much better and within 360 degrees, there are a positive half-circle and a negative one now. Though I'm not sure, if the represent the fulll double-word spectrum of information, because the values lay between -4000 and 4000.
Special thanks to Eileen (Trier University) for her help on debugging the Python 3 number casting issue.
In the Arduino module GY-271, usually the chip HMC5883 is equipped. Unfortunately, in cheap modules from china, another chip is used: the QMC5883. And, as a matter of course, the software library used for the HMC5883 does not work with the QMC version, because the I2C adress and the usage is a little bit different.
Another problem to me was, that I didn't find any proper working source codes for that little magnetic field device, and so I had to debug a source code I found for Arduino at Github (thanks to dthain). Unfortunately it didn't work properly at this time, and to change it for the Raspberry Pi into Python. Below you can find the "driver" module for the GY-271 with the QMC5883 chip. Sorry for the bad documentation, but at least it will work on a Raspberry Pi 3.
Challenge: Python's Casting
The way how Python 3 casts numbers was a problem. It occupied me for hours. Usually, you would write something like this to return the yaw angle of the X-axis:
x = self.bus.read_i2c_word_data(QMC5883.ADDR, QMC5883.X_LSB)
But, why ever, Python does not recognize the proper number format. The result was, that Python always received positive values - twice in 360 degrees and they looked somehow scrambled. The values should have been between -32768 and 32767 (regarding the datasheet).
After a little modification (which took hours to be found), the received values were better. The module Struct had to be used:
register = self.bus.read_i2c_block_data(QMC5883.ADDR, QMC5883.X_LSB, 9)
x = struct.unpack('<h', bytes([register[0], register[1]]))[0]
x = struct.unpack('<h', bytes([register[0], register[1]]))[0]
After this, the values looked much better and within 360 degrees, there are a positive half-circle and a negative one now. Though I'm not sure, if the represent the fulll double-word spectrum of information, because the values lay between -4000 and 4000.
Special thanks to Eileen (Trier University) for her help on debugging the Python 3 number casting issue.
Python module code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | import smbus import time import struct class QMC5883: #Default I2C address ADDR = 0x0D #QMC5883 = Register = numbers X_LSB = 0 X_MSB = 1 Y_LSB = 2 Y_MSB = 3 Z_LSB = 4 Z_MSB = 5 STATUS = 6 T_LSB = 7 T_MSB = 8 CONFIG = 9 CONFIG2 = 10 RESET = 11 CHIP_ID = 13 #Bit values for the STATUS register STATUS_DRDY = 1 STATUS_OVL = 2 STATUS_DOR = 4 #Oversampling values for the CONFIG register MC5883L_CONFIG_OS512 = 0b00000000 CONFIG_OS256 = 0b01000000 CONFIG_OS128 = 0b10000000 CONFIG_OS64 = 0b11000000 #Range values for the CONFIG register CONFIG_2GAUSS = 0b00000000 CONFIG_8GAUSS = 0b00010000 #Rate values for the CONFIG register CONFIG_10HZ = 0b00000000 CONFIG_50HZ = 0b00000100 CONFIG_100HZ = 0b00001000 CONFIG_200HZ = 0b00001100 #Mode values for the CONFIG register CONFIG_STANDBY = 0b00000000 CONFIG_CONT = 0b00000001 #bus = smbus.SMBus(1) def reconfig(self): print("{0:b}".format(self.oversampling | self.range | self.rate | self.mode)) self.bus.write_byte_data(QMC5883.ADDR, QMC5883.CONFIG, self.oversampling | self.range | self.rate | self.mode); def reset(self): self.bus.write_byte_data(QMC5883.ADDR, QMC5883.RESET, 0x01) time.sleep(0.1) self.reconfig() time.sleep(0.01) def __init__(self): self.bus = smbus.SMBus(1) self.oversampling = QMC5883.CONFIG_OS64 self.range = QMC5883.CONFIG_2GAUSS self.rate = QMC5883.CONFIG_100HZ self.mode = QMC5883.CONFIG_CONT self.reset() def setOversampling(self, x): self.oversampling = x self.reconfig() def setRange(x): self.range = x self.reconfig() def setSamplingRate(self, x): self.rate = x self.reconfig() def ready(self): status = self.bus.read_byte_data(QMC5883.ADDR, QMC5883.STATUS) # prevent hanging up here. # Happens when reading less bytes then then all 3 axis and will end up in a loop. # So, return any data but avoid the loop. if (status == QMC5883.STATUS_DOR): print("fail") return QMC5883.STATUS_DRDY return status & QMC5883.STATUS_DRDY def readRaw(self): while (not self.ready()): pass # Python performs a wrong casting at read_i2c_block_data. # The filled buffer has to be onverted afterwards by mpdule Struct register = self.bus.read_i2c_block_data(QMC5883.ADDR, QMC5883.X_LSB, 9); # Convert the axis values to signed Short before returning x = struct.unpack('<h', bytes([register[0], register[1]]))[0] y = struct.unpack('<h', bytes([register[2], register[3]]))[0] z = struct.unpack('<h', bytes([register[4], register[5]]))[0] t = struct.unpack('<h', bytes([register[7], register[8]]))[0] return (x, y, z, t) |
Hi, before finding this page I was struggling on reading data from the QMC5883L using the Raspberry Pi, because no code found on the net was working for me. So I wrote my driver. If you are interested you can find it here: https://github.com/RigacciOrg/py-qmc5883l
AntwortenLöschen