Bosch Sensortec Community

    BME680 BSEC dual sampling rate

    Highlighted
    Member

    BME680 BSEC dual sampling rate

    Dear community,

    I'm currently setting up a project using the BME680 with BSEC Arduino Library 1.4.7.4. I want to use the ability of sampling the different sensor parts with different rates as given in the ULP_LP_Example. LP sampling rate for T/P/H and ULP sampling rate for IAQ/bVOC/eCO2. 

    My first question is which bsec_config_iaq file to use? The 3s or the 300s version? In the example I see that the following was done:

    #include "bsec_serialized_configurations_iaq.h"

    But this can be either one of the eight config files provided, right? 

    My second question is more of an observation where I can't explain the reason but hope that you can help me out. I set up my two sensor lists as given in the example and provided the respective sampling rates as follows:

    //just an excerpt of the full program  
    
    bsec_virtual_sensor_t sensorList_LP[3] = {
        BSEC_OUTPUT_RAW_PRESSURE,
        BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
        BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
      };
    
      bsec_virtual_sensor_t sensorList_ULP[5] = {
        BSEC_OUTPUT_STABILIZATION_STATUS,
        BSEC_OUTPUT_RUN_IN_STATUS,
        BSEC_OUTPUT_CO2_EQUIVALENT,
        BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
        BSEC_OUTPUT_IAQ,
      };
      
      iaqSensor.updateSubscription(sensorList_ULP, 5, BSEC_SAMPLE_RATE_ULP);
      checkIaqSensorStatus();
      iaqSensor.updateSubscription(sensorList_LP, 3, BSEC_SAMPLE_RATE_LP);
      checkIaqSensorStatus();
    
    void loop() {
      if(iaqSensor.run()){
        updateState();
        Serial.print(String((uint16_t)(millis()/1000)) + "s");
        Serial.print(" BSECstate: " + String(iaqSensor.status));
        //    Serial.print(" IAQacc: " + String(iaqSensor.iaqAccuracy));
        Serial.print(" riStat: " + String(iaqSensor.runInStatus));
        Serial.print(" stabStat: " + String(iaqSensor.stabStatus));
        Serial.print(" IAQ: " + String(iaqSensor.iaq) + "(" + String(iaqSensor.iaqAccuracy) + ")");
        Serial.print(" CO2: " + String(iaqSensor.co2Equivalent) + "(" + String(iaqSensor.co2Accuracy) + ")");
        Serial.print(" bVOC: " + String(iaqSensor.breathVocEquivalent) + "(" + String(iaqSensor.breathVocAccuracy) + ")");
        Serial.print(" p: " + String(iaqSensor.pressure));
        Serial.print(" t: " + String(iaqSensor.temperature));
        Serial.println(" h: " + String(iaqSensor.humidity));
        }
        else {
          checkIaqSensorStatus();
        }
    }
    1. The values for the gas sensor (IAQ, bVOC, eCO2) are updated on a 3s basis and their values are changing. Is this normal, when their sampling rate is set to ULP?
    2. What struck me most is that the temperature value is "running away" in ULP_LP mode. It rises quickly to like 2°C above the value that it measures, when all of the above sensors are polled in either LP or ULP mode. What can the reason for that behavior be? It seems to me as if the heater is either not turned off or activated for a longer duration as in when all sensors are polled with the same rate.

     

    Thanks,
    Benedikt

    4 REPLIES 4
    Highlighted
    Community Moderator

    Re: BME680 BSEC dual sampling rate

    The IAQ is in ULP mode,  so you should use the configure file as 300s interval version. 

    If the IAQ is set to ULP mode,  it should be only update at 300s interval, it should not update in 3s interval. 

    Also the temperature sensor should not have 2 degrees higher than environment.

    The reason might be the following function execute wrongly then the sensor is not working under expected sample rate.

    updateSubscription

     

    Highlighted
    Member

    Re: BME680 BSEC dual sampling rate

    So Vincent,

    first of all thank you for clarifying which config file to use for this setup!

    I got curious the last days and tried the basic_config_state_ULP_LP.ino example provided on Github. This is the example I initially used to set up two subscription rates for my own project. To my surprise the Github example shows the same behaviour as my own, meaning that the error must be somewhere either in the BSEC framework or in the sensor API (this is what i presume but can't confirm).

    I did an other example to confirm my observations for which I attach the code and logfile to this post.
    I initialize and start the BME680 with T/P/H/Gas measurements in UPL mode. At second 3500 I change the subscription rates for T/P/H to LP. After the last ULP interval (seconds 3300 -> 3600) has ended output values are returned, as expected, in 3s intervals for T/P/H BUT also for the Gas sensor.

    Also from this point on the overall sensor temperature rises drastically until about 2.5°C above the before measured values (see figure attached or logfile). To me it seems as if the sensor suddenly experiences a much higher heat dissipation, like the gas heater was enabled at much higher frequency than usual. Unfortunately I don't have enough experience to trace back this behavior to either the BSEC framework or the sensor API.

    Any thoughts on that? 

    Thanks and BR,
    Ben

    #include <EEPROM.h>
    #include "bsec.h"
    
    
    const uint8_t bsec_config_iaq[] = {
    #include "config/generic_33v_300s_4d/bsec_iaq.txt"
    };
    
    #define STATE_SAVE_PERIOD  UINT32_C(360 * 60 * 1000) // 360 minutes - 4 times a day
    void checkIaqSensorStatus(void);
    void loadState(void);
    void updateState(void);
    
    Bsec iaqSensor;
    uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
    uint16_t stateUpdateCounter = 0;
    uint8_t setLP = 0;
    
      bsec_virtual_sensor_t sensorList_LP[3] = {
        BSEC_OUTPUT_RAW_PRESSURE,
        BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
        BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
      };
    
    
    void setup() {
      EEPROM.begin(BSEC_MAX_STATE_BLOB_SIZE + 1); // 1st address for the length
      Wire.begin();
      Serial.begin(115200);
      iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire);
      
      Serial.println("BSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix));
      checkIaqSensorStatus();
      iaqSensor.setConfig(bsec_config_iaq);
      checkIaqSensorStatus();
    
      loadState();
    
      bsec_virtual_sensor_t sensorList_ULP[8] = {
        BSEC_OUTPUT_STABILIZATION_STATUS,
        BSEC_OUTPUT_RUN_IN_STATUS,
        BSEC_OUTPUT_CO2_EQUIVALENT,
        BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
        BSEC_OUTPUT_IAQ,
        BSEC_OUTPUT_RAW_PRESSURE,
        BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
        BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY
      };
      
      iaqSensor.updateSubscription(sensorList_ULP, 8, BSEC_SAMPLE_RATE_ULP);
      checkIaqSensorStatus();
      
      Serial.println("Running main program");
    }
    
    
    void loop() {
      if(iaqSensor.run()){
        updateState();
        Serial.print(String((uint16_t)(millis()/1000)) + "s");
        Serial.print(" BSECstate: " + String(iaqSensor.status));
        //    Serial.print(" IAQacc: " + String(iaqSensor.iaqAccuracy));
        Serial.print(" riStat: " + String(iaqSensor.runInStatus));
        Serial.print(" stabStat: " + String(iaqSensor.stabStatus));
        Serial.print(" IAQ: " + String(iaqSensor.iaq) + "(" + String(iaqSensor.iaqAccuracy) + ")");
        Serial.print(" CO2: " + String(iaqSensor.co2Equivalent) + "(" + String(iaqSensor.co2Accuracy) + ")");
        Serial.print(" bVOC: " + String(iaqSensor.breathVocEquivalent) + "(" + String(iaqSensor.breathVocAccuracy) + ")");
        Serial.print(" p: " + String(iaqSensor.pressure));
        Serial.print(" t: " + String(iaqSensor.temperature));
        Serial.println(" h: " + String(iaqSensor.humidity));
        }
        else {
          checkIaqSensorStatus();
        }
    
      if((millis()/1000) == 3500 && setLP == 0){
        iaqSensor.updateSubscription(sensorList_LP, 3, BSEC_SAMPLE_RATE_LP);
        setLP = 1;
        Serial.println("LP sensors configured");
      }
    
    }
    
    void checkIaqSensorStatus(void)
    {
      if (iaqSensor.status != BSEC_OK) {
        if (iaqSensor.status < BSEC_OK) {
          //output = "BSEC error code : " + String(iaqSensor.status);
          Serial.println("BSEC error code : " + String(iaqSensor.status));
          while(1);
        } else {
          //output = "BSEC warning code : " + String(iaqSensor.status);
          Serial.println("BSEC warning code : " + String(iaqSensor.status));
        }
      }
    
      if (iaqSensor.bme680Status != BME680_OK) {
        if (iaqSensor.bme680Status < BME680_OK) {
          //output = "BME680 error code : " + String(iaqSensor.bme680Status);
          Serial.println("BME680 error code : " + String(iaqSensor.bme680Status));
          while(1);
        } else {
          //output = "BME680 warning code : " + String(iaqSensor.bme680Status);
          Serial.println("BME680 warning code : " + String(iaqSensor.bme680Status));
        }
      }
      iaqSensor.status = BSEC_OK;
    }
    
    void loadState(void)
    {
      if (EEPROM.read(0) == BSEC_MAX_STATE_BLOB_SIZE) {
        // Existing state in EEPROM
        Serial.println("Reading state from EEPROM");
    
        for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) {
          bsecState[i] = EEPROM.read(i + 1);
          Serial.println(bsecState[i], HEX);
        }
    
        iaqSensor.setState(bsecState);
        checkIaqSensorStatus();
      } else {
        // Erase the EEPROM with zeroes
        Serial.println("Erasing EEPROM");
    
        for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE + 1; i++)
          EEPROM.write(i, 0);
    
        EEPROM.commit();
      }
    }
    
    void updateState(void)
    {
      bool update = false;
      /* Set a trigger to save the state. Here, the state is saved every STATE_SAVE_PERIOD with the first state being saved once the algorithm achieves full calibration, i.e. iaqAccuracy = 3 */
      if (stateUpdateCounter == 0) {
        if (iaqSensor.iaqAccuracy >= 3) {
          update = true;
          stateUpdateCounter++;
        }
      } else {
        /* Update every STATE_SAVE_PERIOD milliseconds */
        if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) {
          update = true;
          stateUpdateCounter++;
        }
      }
    
      if (update) {
        iaqSensor.getState(bsecState);
        checkIaqSensorStatus();
    
        Serial.println("Writing state to EEPROM");
    
        for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE ; i++) {
          EEPROM.write(i + 1, bsecState[i]);
          Serial.println(bsecState[i], HEX);
        }
    
        EEPROM.write(0, BSEC_MAX_STATE_BLOB_SIZE);
        EEPROM.commit();
      }
    }
    Highlighted
    Established Member

    Re: BME680 BSEC dual sampling rate

    Hi, 

     

    Please don't use Arduino github example code, there is buggy now. 

    Instead, please use our official library and example "bsec_iot_example.ino" as url - https://www.bosch-sensortec.com/software-tools/software/bsec/

    Then, you need to migrate some steps as below. ( Currently, I'm working on Arduino DUE)

    1) Unzip src.zip file and copy to BSEC library src folder. Could be C:\Users\USERNAME\Documents\Arduino\libraries\BSEC-Arduino-library-master\src

    2) Unzip bsec_iot_example.zip and run it. 

    If you want to migrate in your way, please refer to BST-BME680-Integration-Guide-AN008-48.pdf in our latest BSEC official library. 

    Please let me know if you have any questions. 

    Thanks, 

     

    Minhwan

    Highlighted
    Established Member

    Re: BME680 BSEC dual sampling rate

    By the way, found one workaround. 

    Please comment out bsec_init function in run function in bsec.cpp. 

    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist