Go Down

Topic: [solved] strange measurement effect (Read 1 time) previous topic - next topic

wothke

Jun 13, 2017, 01:49 pm Last Edit: Jun 13, 2017, 10:41 pm by wothke
I built a garden sensor device using a DHT22 temperature-humidity sensor and a simple soil moisture sensor.

Most of the time the obtained sensor readings are plausible but sporadically (I have now idea what triggers it) I am getting fluctuating/distorted readings:



Due to the fact that the distortions seem to affect both sensors (that I am using within the same device - see graph above) I would guess that it is not a problem of the sensors but some problem of my circuit. Unfortunately I am missing the electronics background and could use some help here...


My device runs on a 9V battery and is meant to employ a power saving mode of operation, i.e. the used ProMini328 (3v3) sleeps for most of the time and the power supply to the sensors and the transmitter are shut down during those periods.. (see MOSFETs and the D7 pin in schema below) every 20 minutes the device wakes up, powers up the sensors and the transmitter, takes its measurements, sends home the result and then goes back to sleep (in addition the circuit also tries to measure the battery voltage to detect when it might need to be replaced/recharged).


Here the schema of my circuit (open image in separate tab - otherwise it is too small to read anything):



PS: I had already experimented with various delays after "power-up" and also by taking multiple successive measurements, but with no avail.. something seems to disturb the voltage picked up on the respective input pins (analog) SOME OF THE TIME (I've seem multiple-days timespans where the effect did NOT occur even once..).

Is there anything obviously wrong with my circuit that explains this effect?

PPS: for completeness here the links to the components that I am using:
transmitter: https://de.aliexpress.com/item/Free-shipping-433Mhz-RF-transmitter-and-receiver-kit-Project-Drop-Shipping/32267645321.html

soil-sensor: https://de.aliexpress.com/item/Smart-Electronics-Soil-Moisture-Hygrometer-Detection-Humidity-Sensor-Module-For-arduino-Development-Board-DIY-Robot-Smart/32328189936.html

level-shifter: https://de.aliexpress.com/item/Free-shipping-10pcs-lot-4-channel-IIC-I2C-Logic-Level-Converter-Bi-Directional-Module-5V-to/32360153538.html

DHT22: https://de.aliexpress.com/item/1pcs-DHT22-digital-temperature-and-humidity-sensor-Temperature-and-humidity-module-AM2302-replace-SHT11-SHT15-Free/1734450621.html

MarkT

Well the MOSFET switching the resistive divider isn't going to work well, its neither a high-side
nor a low-side switch, there's no guarantee the 2N7000 is switched on properly.

Are you clearing the ADC state after power up (take a reading and discard the result)?

You are assuming the problem is hardware and isn't in the code, so you haven't shown us the code,
but the problem could be there.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

wothke

Well the MOSFET switching the resistive divider isn't going to work well, its neither a high-side
nor a low-side switch, there's no guarantee the 2N7000 is switched on properly.

Are you clearing the ADC state after power up (take a reading and discard the result)?

You are assuming the problem is hardware and isn't in the code, so you haven't shown us the code,
but the problem could be there.
Would your 2N7000 related concerns be a likely root cause for fluctuating sensor measurements? I am not using them for the sensor related parts (only for the transmitter & the voltage test.. and those seem to work  well enough..) and I would expect that they should make no difference to the sensor readings...

Currently I am reading & discarding the result and then reading a second time (with added delays in between).. and indeed I'd be surprised if it was a code problem. Still here the respective main program:

Code: [Select]

#define DEVICE_ID  2

#include <RH_ASK.h>
#include <SPI.h> // Not actually used but needed to compile
#include <SensorMsg.h>
#include <Time.h>

#include "SoilSensor.h"
#include "AirSensor.h"
#include "BatterySensor.h"
#include "Transmitter.h"
#include "LowPower.h"

SoilSensor *soilSensor;
AirSensor *airSensor;
BatterySensor *batterySensor;
Transmitter *transmitter;

unsigned int runIntervalInSecs= 20*60;    // measurement interval: 20 minutes
unsigned int activationCountdown= 0;


// -- main sketch stuff ---------------------------------------------------

void setup() {
  Serial.begin(9600);

  soilSensor= new SoilSensor();
  airSensor= new AirSensor();
  batterySensor= new BatterySensor();
  transmitter= new Transmitter();

  // battery measurements are way off if started immediately.. (wait
  // a bit to let voltage stabilize..)
  delay(2000);
}

void doWhenAwake() {
  batterySensor->turnOn();
  uint8_t batteryVoltage = batterySensor->getVoltageLevel();
  batterySensor->turnOff();

  transmitter->turnOn();
  soilSensor->turnOn();
  airSensor->turnOn();

  // wait until the components are ready..
  delay( max( max(soilSensor->getStartupDelay(), airSensor->getStartupDelay()),
  transmitter->getStartupDelay()));

  // FIXME XXX measurements for some reason seems to wildly oscillate between consecutive
  // measurements.. the below hacks try to stabilize the results..

  delay(500);




  // get sensor readings..
  uint8_t soilMoisture = soilSensor->getMoistureLevel();
  delay(500);
  uint8_t airTemperature = airSensor->getTemperatureLevel();
  delay(500);
  uint8_t airHumidity = airSensor->getHumidityLevel();
  delay(500);
  soilMoisture = soilSensor->getMoistureLevel();
  delay(500);
  airTemperature = airSensor->getTemperatureLevel();
  delay(500);
  airHumidity = airSensor->getHumidityLevel();


  // Power-down the sensors
  soilSensor->turnOff();
  airSensor->turnOff();


  transmitter->sendSensorResult(DEVICE_ID, soilMoisture, airTemperature, airHumidity, batteryVoltage, 3);  // send 3x to increase chances of someone receiving it..

  // Power-down the transmitter
  transmitter->turnOff();
}

void loop() {
  LowPower.flash();

  if (!(activationCountdown--)) {
    doWhenAwake();

    activationCountdown= (unsigned int)runIntervalInSecs/8;  // sleep interval is 8secs (see below)
  }
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}


 

MarkT

[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

wothke

#4
Jun 13, 2017, 04:43 pm Last Edit: Jun 13, 2017, 06:06 pm by wothke
And all the .h files?
I don't see what you'd need all the source code for (much less all the *.h files which do little more than define the I/O pin IDs used my the respective building blocks).. as an example below the respective *.cpp code for the soil sensor:

Code: [Select]

#include "SoilSensor.h"
#include "Arduino.h"



SoilSensor::SoilSensor(void) {
    pinMode(powerPinMoistureSens, OUTPUT);
}

int SoilSensor::doGetPowerPin(void) {
    return powerPinMoistureSens;
}

int SoilSensor::getStartupDelay(void) {
  return 1000;  // 1sec needed by humidity sensor
}

uint8_t SoilSensor::rescaleSoilReading(int soilVal) {
  // the analog-pin data is 10-bit has a range from 0 to 1023!
  // soil sensor:
  //    original range seems to be 0-1000... but rescaled one byte rep should be sufficient

uint8_t ret= (soilVal>>2) & 0xff;
   Serial.print("Soil: ");
  Serial.println(soilVal);
  Serial.print(" \tt: ");
  Serial.println(ret);
  return ret; 
}

uint8_t SoilSensor::getMoistureLevel(void) {
  return rescaleSoilReading(analogRead(moistureAnalogPin));
}


MarkT

Bugs are often lurking where you least expect (or you'd have found them already).  Fresh eyes are
usually much better at spotting problems.

Have you monitored the battery voltage during these events BTW?

From the graph it looks very much like every other wake up is affected, as if there are two possible
states that alternate, which is an interesting feature, suggestive of the sleep/wakeup cycle having issues.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Smajdalf

You say every 20 minutes wake up but from the graph it looks like 12(11?) points during 2 hours (2:00-4:00) - it means wake up every 10 minutes! Maybe the unwanted wake-ups are doing something wrong? On the other hand between 12:00 and 14:00 I see only 4 (or 5?) points and one of them is wrong (13:20). Measurement from 13:40 is probably missing at all. Your timing looks wrong. It may be SW bug after all.
How to insert images: https://forum.arduino.cc/index.php?topic=519037.0

wothke

#7
Jun 13, 2017, 08:18 pm Last Edit: Jun 13, 2017, 08:36 pm by wothke
You say every 20 minutes wake up but from the graph it looks like 12(11?) points during 2 hours (2:00-4:00) - it means wake up every 10 minutes! Maybe the unwanted wake-ups are doing something wrong? On the other hand between 12:00 and 14:00 I see only 4 (or 5?) points and one of them is wrong (13:20). Measurement from 13:40 is probably missing at all. Your timing looks wrong. It may be SW bug after all.
you have a keen eye :-) i just checked the timestamps in the DB and  indeed the device seems to wake up twice as often as it should.. something seems to go wrong with the timing of the "LowPower" lib that I am using:

Code: [Select]

/*******************************************************************************
* LowPower Library
* Version: 1.30
* Date: 22-05-2013
* Company: Rocket Scream Electronics
* Website: www.rocketscream.com
*
* This is a lightweight low power library for Arduino. Please check our wiki
* (www.rocketscream.com/wiki) for more information on using this piece of
* library.
*
* This library is licensed under Creative Commons Attribution-ShareAlike 3.0
* Unported License.
*
*********************************************************************************
* NOTICE: SOME ADD-ON UTILITIES WERE ADDED AT THE VERY END OF THIS FILE.
*********************************************************************************
*
* Revision  Description
* ========  ===========
* 1.30 Added support for ATMega168, ATMega2560, ATMega1280 & ATMega32U4.
* Tested to work with Arduino IDE 1.0.1 - 1.0.4.
* 1.20 Remove typo error in idle method for checking whether Timer 0 was
* turned off.
* Remove dependecy on WProgram.h which is not required.
* Tested to work with Arduino IDE 1.0.
* 1.10 Added #ifndef for sleep_bod_disable() for compatibility with future
* Arduino IDE release.
* 1.00      Initial public release.
*******************************************************************************/
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include "LowPower.h"

// Only Pico Power devices can change BOD settings through software
#if defined __AVR_ATmega328P__
#ifndef sleep_bod_disable
#define sleep_bod_disable() \
do { \
  unsigned char tempreg; \
  __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \
                       "ori %[tempreg], %[bods_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" "\n\t" \
                       "andi %[tempreg], %[not_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" \
                       : [tempreg] "=&d" (tempreg) \
                       : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \
                         [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \
                         [not_bodse] "i" (~_BV(BODSE))); \
} while (0)
#endif
#endif

#define lowPowerBodOn(mode) \
do { \
      set_sleep_mode(mode); \
      cli(); \
      sleep_enable(); \
      sei(); \
      sleep_cpu(); \
      sleep_disable(); \
      sei(); \
} while (0);

// Only Pico Power devices can change BOD settings through software
#if defined __AVR_ATmega328P__
#define lowPowerBodOff(mode)\
do { \
      set_sleep_mode(mode); \
      cli(); \
      sleep_enable(); \
 sleep_bod_disable(); \
      sei(); \
      sleep_cpu(); \
      sleep_disable(); \
      sei(); \
} while (0);
#endif

// Some macros is still missing from AVR GCC distribution for ATmega32U4
#if defined __AVR_ATmega32U4__
 // Timer 4 PRR bit is currently not defined in iom32u4.h
 #ifndef PRTIM4
 #define PRTIM4 4
 #endif

 // Timer 4 power reduction macro is not defined currently in power.h
 #ifndef power_timer4_disable
 #define power_timer4_disable() (PRR1 |= (uint8_t)(1 << PRTIM4))
 #endif

 #ifndef power_timer4_enable
 #define power_timer4_enable() (PRR1 &= (uint8_t)~(1 << PRTIM4))
 #endif
#endif
 
....

/*******************************************************************************
* Name: powerDown
* Description: Putting microcontroller into power down state. This is
*         the lowest current consumption state. Use this together with
*         external pin interrupt to wake up through external event
*         triggering (example: RTC clockout pin, SD card detect pin).
*
* Argument   Description
* =========   ===========
* 1. period   Duration of low power mode. Use SLEEP_FOREVER to use other wake
* up resource:
* (a) SLEEP_15MS - 15 ms sleep
* (b) SLEEP_30MS - 30 ms sleep
* (c) SLEEP_60MS - 60 ms sleep
* (d) SLEEP_120MS - 120 ms sleep
* (e) SLEEP_250MS - 250 ms sleep
* (f) SLEEP_500MS - 500 ms sleep
* (g) SLEEP_1S - 1 s sleep
* (h) SLEEP_2S - 2 s sleep
* (i) SLEEP_4S - 4 s sleep
* (j) SLEEP_8S - 8 s sleep
* (k) SLEEP_FOREVER - Sleep without waking up through WDT
*
* 2. adc ADC module disable control. Turning off the ADC module is
* basically removing the purpose of this low power mode.
* (a) ADC_OFF - Turn off ADC module
* (b) ADC_ON - Leave ADC module in its default state
*
* 3. bod Brown Out Detector (BOD) module disable control:
* (a) BOD_OFF - Turn off BOD module
* (b) BOD_ON - Leave BOD module in its default state
*
*******************************************************************************/
void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod)
{
 if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN);
 
 if (period != SLEEP_FOREVER)
 {
 wdt_enable(period);
 WDTCSR |= (1 << WDIE);
 }
 if (bod == BOD_OFF)
 {
 #if defined __AVR_ATmega328P__
 lowPowerBodOff(SLEEP_MODE_PWR_DOWN);
 #else
 lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
 #endif
 }
 else
 {
 lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
 }
 
 if (adc == ADC_OFF) ADCSRA |= (1 << ADEN);
}
....


/*******************************************************************************
* Name: ISR (WDT_vect)
* Description: Watchdog Timer interrupt service routine. This routine is
*           required to allow automatic WDIF and WDIE bit clearance in
*         hardware.
*
*******************************************************************************/
ISR (WDT_vect)
{
 // WDIE & WDIF is cleared in hardware upon entering this ISR
 wdt_disable();
}

LowPowerClass LowPower;



I just double checked that I am not using a 5V/16mHz ProMini328 by accident (which might have explained why sleep runs twice as fast..).. but I just measured 3V3 from the built-in regulator so I think it actually is the 8mHz version. even if it triggers too often, that should not be a problem for the mesurement quality, unless the lib's respective "wakeup" cycle has additional problems - i.e. if every odd cycle does not power up correctly (as suggested by MarkT above).

Regarding "missing measurements" - these are totally OK: My sensors are not equipped with a receiver and they don't care wheather or not anybody is actually listening, i.e. if for some reason my receiver device is busy then it may well miss a sensor message once in a while.

Smajdalf

I don't see the time stamps but it looks like only those "extra" readings are corrupted: when data are "normal" there is only 5-6 readings per 3 hours (you use WDT for timing and it is running a bit slower than nominal, so you get more than 20 min between measurements). Maybe the event that causes Arduino wake up prematurely also causes the reading corruption? The "corruption" looks so evenly spaced I doubt power glitch/some (external) noise is causing it. BTW what "LowPower.flash();" does? You are calling it every time the loop runs.
How to insert images: https://forum.arduino.cc/index.php?topic=519037.0

wothke

solved: I just analyzed the raw DB data instead of the resulting diagram.. I should have done so earlier - mea culpa :-(

The problem is NOT caused by the measurements AT ALL: The respective changes in temperature from one measurement to the next are OK. (most of the time the interval between measurements is 20min - but sporadically it is 25min.. which still is strange..)

But the problem is caused by a reset of the used timestamps: on a "problem day" it suddenly jumps from 13:02:55 (of the previous measurement) to 00:55:39 (for the next).. i.e. the "afternoon" measurements are then interleaved with the existing "early morning" measurements of the same day.

So it is a bug in the software - but not the SW on the sensor device. Probably something to do with the RTC synchronization that I am performing on my receiver device whenever it connects to the PC.
(1PM seems a likely time for me to have started the PC application - that then must have triggered the bug..)

In any case it IS NOT a hardware problem and the SW bug should not be too hard to find. Sorry to have bothered you here and thanks to everyone that has tried to help!

Southpark

#10
Jun 13, 2017, 11:18 pm Last Edit: Jun 13, 2017, 11:20 pm by Southpark
In any case it IS NOT a hardware problem and the SW bug should not be too hard to find. Sorry to have bothered you here and thanks to everyone that has tried to help!
That's ok. Just write 'issue with my temperature measurement system' rather than "strange measurement effect". Things should be labelled strange if unexplainable by a significant number of people, including experts in the area.

The join-the-dots saw-tooth shape can be confusing - unless it's mentioned that the plotting software is basically joining the dots.

MarkT

Hmm, interesting and unexpected bug, shows the importance of assuming nothing and checking everything
even the things you know can't be wrong!
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

Go Up