pimoroni / bme680-python

Python library for the BME680 gas, temperature, humidity and pressure sensor.
https://shop.pimoroni.com/products/bme680
MIT License
260 stars 93 forks source link

Pressure reading too high (micropython) #3

Closed gkluoe closed 6 years ago

gkluoe commented 6 years ago

Hi,

I'm using this code on a LoPy and it seems to work well, other than that the pressure reading is too high. I'm consistently seeing readings around 21mb higher than they should be (eg currently 1038 when the real pressure is ~1017). The pressure reading also consistently rises as the temperature drops. It doesn't seem to make a difference whether I have the gas heater on or off.

I've had good success with the BMP180 measuring temp/pressure in the same environment (just a house, nothing special!)

Can you think of anything I should try?

Gadgetoid commented 6 years ago

Do you have a Raspberry Pi to run this library on and test it against your LoPy setup? This library wasn't targeted at any MicroPython boards, so it's possible there might be issues with the opaque calculations supplied by the manufacturer to transform the sensor readings into meaningful units.

I also don't know how the sensor may correlate or deviate from pressure readings from other sources. What do you mean by real pressure? Do you have another sensor you're comparing this against?

gkluoe commented 6 years ago

Thanks for the reply - I do have a Pi B so my next step was going to be exactly that. I'll try to get it hooked up and report back.

The 'real' pressure is as reported by a BMP180 in the same room and a weather station a couple of miles away, which agree to within 1 hPa or so. The 680 is wrong enough that it's definitely not intended output, but all the other readings seem OK.

Gadgetoid commented 6 years ago

Yeah, that's quite significantly wrong.

I have a suspicion it could be a Python vs MicroPython issue, I'll grab a board and run some tests on it.

Gadgetoid commented 6 years ago

A quick test of just the conversion routines disproves my theory- the _calc_temperature and _calc_pressure routines produce the same output (number of decimal places notwithstanding) on both platforms.

The temperature is used to compensate the pressure readings, and should in theory cancel out any correlative effect you might see between the two.

I'm assuming you're using this library?

gkluoe commented 6 years ago

Yup, using this library and the breakout board from pimoroni. I wrote a little I2C wrapper class to convert the smbus byte_data() and block_data() calls into micropython's readfrom_mem() and writeto_mem(). This is my first foray into I2C and I'll happily believe it's my code that's at fault, but it does seem to work fine in all other respects.

I dug out a Pi B last night so will test on that tomorrow and get back to you. If I get the same weird readings, I guess that rules out a platform/code issue and we're left with a possible dodgy sensor?

gkluoe commented 6 years ago

Hello again. So, running this on a Pi B rev 2 gives very similar results. As you can see below I get 1040.41 as the pressure reading (yes, my house really is about 14 degrees C!). For reference a BMP180 currently gives me 1021.53 and the weather station down the road is showing 1020

Dodgy sensor?

>>> b = bme680.BME680() >>> b.get_sensor_data() True >>> b.data.pressure 1040.41 >>> b.data.temperature 14.35 >>> b.data.humidity 68.477 >>> b.chip_id 97

jorisvervuurt commented 6 years ago

I don’t think it’s a dodgy sensor. I just noticed that mine reads ~1050 hPa at the moment, while it should read ~1030 hPa. Thats the same ~20 hPa difference you also appear to have. I think it’s miscalculating in software.

gkluoe commented 6 years ago

Ah, interesting! I was thinking of compiling the Bosch reference driver to see if it gives a different reading, but that's a bit out of my comfort zone. Will try it if I get the time this evening though.

Gadgetoid commented 6 years ago

This is surprising, since I rigged up the Bosch C code and my Python code to perform the same calculations so I could verify them. Perhaps an error has crept in somewhere with an incorrect sign or premature rounding.

Comparing the results you get with the Bosch driver would be a good start- we had some code somewhere to read/print the values. I'll see if I can dig it up.

Gadgetoid commented 6 years ago

Good news, everyone! (for me anyway) It's not my fault! And the sensor is not faulty.

See: https://github.com/BoschSensortec/BME680_driver/commit/94fd057adfb36077d57dde21df986f6d48939b29

My Python code is a direct port of Bosch's BME680_driver code. If you read the commit linked above you'll see:

v3.5.3
 - Changed the compensation equation formulas to use shifting operation
 - Updated the "bme680_get_profile_dur" API
 - Fixed Checkpatch and made linux compatible
 - Fixed bug of temperature compensation in pressure
 - Updated self test APIs

Not only does this fix a bugbear of mine - using division in place of logical shifts - but it also "Fixed bug of temperature compensation in pressure."

D'oh!

I will port these fixes to Python ASAP.

Gadgetoid commented 6 years ago

Okay, first run at it done. I've verified the Python code isn't riddled with syntax errors, but I've been unable to actually test it.

See: https://github.com/pimoroni/bme680/commit/d9970151cd9d20b7f49a4ee6ece7005c108d56a3

You can try this out by installing it from Git:

git clone https://github.com/pimoroni/bme680
cd bme680/library
sudo python setup.py develop

(substitute python3 if appropriate)

This will symlink this GitHub repository, so you can update to the latest development library by doing a "git pull".

Once everything is working, you can clean that up and revert to the stable library by running:

sudo python setup.py develop --uninstall
jorisvervuurt commented 6 years ago

I've just updated the library on my Pi and at the moment, the pressure value is spot on. Since the bug was temperature-related, I'll check tomorrow morning to see if the value is still right.

Looking good so far!

gkluoe commented 6 years ago

Sounds positive! I won't be able to test this until tomorrow, but will do so and report back.

jorisvervuurt commented 6 years ago

I’m afraid it didn’t fix the problem. :-( I just checked and it now reads ~1043 hPa at ~13 degrees C, where it should read ~1023 hPa. It does seem to give correct readings at ~21 degrees C though...

gkluoe commented 6 years ago

Same results here. I'm seeing this sort of thing if I warm the sensor up gently then let it cool (reference pressure is ~1018hPa):

13.44 C,1040.25 hPa,63.93 %RH,2132 Ohms 14.90 C,1036.87 hPa,62.52 %RH,35057 Ohms 16.78 C,1032.67 hPa,61.85 %RH,57254 Ohms 17.89 C,1030.35 hPa,60.47 %RH,58319 Ohms ... 26.48 C,1014.99 hPa,35.37 %RH,112361 Ohms 25.02 C,1017.22 hPa,35.73 %RH,123106 Ohms ... 14.61 C,1037.44 hPa,58.15 %RH,57109 Ohms

Definitely still an issue with the temperature compensation (gas readings look odd but they tend to take a while to settle down).

If you have a file I could compile against the Bosch API I'd love to test that: unfortunately my C isn't good enough to construct one myself.

gkluoe commented 6 years ago

Ok, so I managed to hack together something that uses the Bosch C code and can confirm that it seems to work as expected. Currently:

T: 13.40 degC, P: 1021.07 hPa, H 57.11 %rH

whereas the latest python code is giving me:

13.04 C,1045.02 hPa,59.151 %RH

Pressure reading seems stable with temperature changes using the C library, too.

jorisvervuurt commented 6 years ago

Very interesting! How's the gas measurement compared to the Python code? I also noticed that the library no longer works under Python 3.

Looks like it's back to the drawing board for @Gadgetoid or @sandyjmacdonald...

gkluoe commented 6 years ago

Gas sensor looks reasonable & stable, too (now that I've got my head slightly more around what the C code is doing and managed to make it loop)

result: 0, T: 14.96 degC, P: 1019.60 hPa, H 54.17 %rH , G: 134784 ohms
result: 0, T: 14.94 degC, P: 1019.60 hPa, H 54.19 %rH , G: 136199 ohms
result: 0, T: 14.93 degC, P: 1019.58 hPa, H 54.20 %rH , G: 137419 ohms
result: 0, T: 14.92 degC, P: 1019.56 hPa, H 54.22 %rH , G: 138547 ohms

If you promise not to laugh (I've never written any C before!), the code is here: https://gist.github.com/gkluoe/a297f6bcf76e4466f1bfa6fd40038983

ghost commented 6 years ago

If anyone wants to check their workings-out, CircuitPython code for Adafruit's BME680 breakout is here: https://github.com/adafruit/Adafruit_CircuitPython_BME680 and will, presumably (it's slightly beyond me), be easily comparable to Micropython/Python code.

Gadgetoid commented 6 years ago

Try the Python code as of #4 being merged, it could well be that floating point results were propagating through the calculations and causing the difference.

In the interim I'll have a look over the Bosch code versus our port, and see if anything has been overlooked in the new fixes.

gkluoe commented 6 years ago

No change for me using the latest python code - but then I'm using 2.7 where, as I understand, it '/' and '//' are functionally the same...

Gadgetoid commented 6 years ago

I'm a little bit stumped with this- perhaps I'm barking up the wrong tree. I'm genuinely surprised that back-porting the upstream fix for what sounds like exactly the same issue hasn't fix this though. Perhaps it's fixed one discrepancy and revealed another. Looks like I've got some more testing and debugging to do.

gkluoe commented 6 years ago

Couldn't leave this alone - I think I found the issue: #5

robmarkcole commented 6 years ago

@gkluoe are you using this board with micro/circuit-python?

gkluoe commented 6 years ago

@robmarkcole yup. Or at least, I was. I haven't put it back on the LoPy yet since moving it over to the pi for debugging. I wrote a little I2CAdapter class, as the methods provided by machine.i2c are a little different from the SMBus methods this code expects. I can commit the code somewhere public this evening if you like.

robmarkcole commented 6 years ago

Hi @gkluoe would be grateful, thanks 🙏

gkluoe commented 6 years ago

Ho @robmarkcole

So as not to hijack this issue, I've opened a new one for micropython support at #7

giampiero7 commented 6 years ago

Hi, not sure if it is intended or an error, but, comparing the BME680_driver C code to this python port, I've noticed a difference in the _calc_pressure function:

https://github.com/pimoroni/bme680/blob/50902ac08ee9ba850186cf6132f9a0fac37b07ad/library/bme680/__init__.py#L327

VS

https://github.com/BoschSensortec/BME680_driver/blob/e6b9bbade923d792d9ccd822ab5fada99bf40501/bme680.c#L915

if (pressure_comp >= BME680_MAX_OVERFLOW_VAL)

https://github.com/BoschSensortec/BME680_driver/blob/e6b9bbade923d792d9ccd822ab5fada99bf40501/bme680_defs.h#L323

/** BME680 pressure calculation macros */
/*! This max value is used to provide precedence to multiplication or division
 * in pressure compensation equation to achieve least loss of precision and
 * avoiding overflows.
 * i.e Comparing value, BME680_MAX_OVERFLOW_VAL = INT32_C(1 << 30)
 */
#define BME680_MAX_OVERFLOW_VAL      INT32_C(0x40000000)

Hope it helps...