pimoroni/bme680-python

Pressure reading too high (micropython)

Closed this issue · 28 comments

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?

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?

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.

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.

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?

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?

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

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.

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.

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.

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.

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: d997015

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

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!

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

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...

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.

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.

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...

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

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.

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.

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...

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.

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

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

@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.

Hi @gkluoe would be grateful, thanks 🙏

Ho @robmarkcole

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

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...