GrovePi analog sensors fail with dust sensor [NOT SOLVED]

Hi,

Not sure why John closed the thread, as clearly things were not solved, as I cannot use the temp/hum, light, sound and ranger sensors together without getting odd readings, as described in this thread: http://www.dexterindustries.com/topic/grovepi-sensors-dont-work-or-analog-sensors-dont-work-solved/

At the request of Karan, I attached my scripts so he could try to reproduce. The crontab was only part of the problem description to show how these scripts are run.

I am going to assume that John didn’t quite understand that this was a response to more information from Karan and was therefore closed in error. Please reopen, as my issue continues:

After ~10 minutes of usage with the sound and ranger sensors polled every 0.1 seconds, and the temp/hum and light sensor polling every 2-3 minutes, the light and temperature readings go off. The light sensor reports lower values, and the temp/hum responds returns nan.

Please, would appreciate it if you could reopen the thread, as Karan is trying to reproduce the issue with the scripts supplied, as he so kindly mentioned in the post before the close notification.

Jay

Hey Jay,
Sorry for the misunderstanding. That post was originally intended to solve the problem where people had the wrong fuses burnt on their GrovePi’s hence were unable to read back sensor data at all from the GrovePi, it was a pretty critical issue which made the GrovePi’s pretty unusable for a lot of the sensors.

I am still looking into the problem that you had posted and am trying to find out the problem and will definitely send you a solution to it ASAP. It would be great if you could run the firmware version check and let us know what it shows: https://github.com/DexterInd/GrovePi/blob/master/Software/Python/grove_firmware_version_check.py

I’ll repost your original message here so that if someone else joins the discussion, they do understand the contex.

-Karan

Original Post from @jaythvv in (http://www.dexterindustries.com/topic/grovepi-sensors-dont-work-or-analog-sensors-dont-work-solved/)

Hi Karan,

Sorry for the slight delay. The temp/hum sensor as well as light are working fine, be it without my sound and ranger scripts.

These send results up to a cloud server, but I have commented that stuff out, and should now just print the body of the message. If you get any errors, it’s likely http related and you should be able to remove it. The scripts use the grove_rgb_lcd scripts which I didn’t change so I didn’t include.

I run these scripts from cron: (last two commented out here, of course, but to test you wouldn’t)

*/2 * * * * sudo <path_to>/ho_temp_hum.py
*/2 * * * * sudo <path_to>/ho_light.py

*/5 * * * * sudo <path_to>/watchdog.sh <path_to>/ho_sound.py

*/5 * * * * sudo <path_to>/watchdog.sh <path_to>/ho_ranger.py

The watchdog.sh script simply checks if the process runs, and start it if it doesn’t. For testing, you might just want to run those scripts directly from the shell.

Hi Karan,

Sure thing: here’s the output:

(‘GrovePi has firmware version:’, ‘1.2.3’)

regards,
Jay

Hello,

There are still serious issues with the analog ports and reading them. I was doing some testing where I am using all three (A0, A1, A2) with different sensors on each. A0 has the potentiometer (Rotary Angle Sensor), A1 has the Air Quality v1.3 sensor, and A2 has the HCHO sensor.

If I run each of the sample apps by themselves, they appear to work.

If I run the following program - which queries each one by one - the values are duplicated and overwritten in a way that they are not accurate, and each is reporting back random numbers from the other ports. :frowning:

I finally nailed this down by running the potentiometer example, and it consistently outputs:

(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)
(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)
(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)
(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)
(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)
(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)
(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)
(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)
(&#039;sensor_value =&#039;, 424, &#039; voltage =&#039;, 2.07, &#039; degrees =&#039;, 124.2, &#039; brightness =&#039;, 105)

Without touching it at all … I then run my program, and get the following:

pi@raspberrypi ~/GrovePi/Software/Python $ sudo python wovyn_air_quality.py
Beginning main sensor loop ...
pot_value =  424  pot_voltage = 2.07
Low pollution
  Air Quality =  424
  HCHO =  424 voltage = 2.0703
  PM Concentration =  143.36
  Error Count =  0
pot_value =  56  pot_voltage = 0.27
Air fresh
  Air Quality =  69
  HCHO =  69 voltage = 0.3369
  PM Concentration =  143.36
  Error Count =  0
pot_value =  22927  pot_voltage = 112.06
Air fresh
  Air Quality =  70
  HCHO =  70 voltage = 0.3418
  PM Concentration =  143.36
  Error Count =  0
pot_value =  56  pot_voltage = 0.27

Note that I am NOT touching the potentiometer at all!! It should be a steady 424 at all times. This occurs with ALL analog sensors if I try to read more than one in the same loop … no matter the combination of analog sensors.

In my program I am simply trying to read each sensor in a main loop, within try/exception blocks, and print the outputs. I have found the ADC values often are complete corrupt (jumping into the 20,000-40,000 range) and the values for all of the sensors will come back identical.

Something is VERY wrong … or my program is VERY broken.

My program:

#!/usr/bin/env python
#
# USAGE
#
# Connect the dust sensor to Port 8 on the GrovePi. The dust sensor only works on that port
# Connect the Grove Rotary Angle Sensor to analog port A0
# Connect the Grove Air Quality Sensor v1.3 to analog port A1
# Connect the Grove HCHO Sensor to analog port A2
#

import time
import grovepi

# Set-up the Rotary Angle Sensor to analog port A0
potentiometer = 0
grovepi.pinMode(potentiometer,&quot;INPUT&quot;)

# Set up the Air Quality Sensor - on port A1
air_sensor = 1
grovepi.pinMode(air_sensor,&quot;INPUT&quot;)

# Set up the HCHO Sensor to analog port A2
hcho_sensor = 2
grovepi.pinMode(hcho_sensor,&quot;INPUT&quot;)

# Vcc of the grove interface is normally 5v
grove_vcc = 5
adc_ref = 5

# initialize the error counter
errorCount = 0

# initialize PM Concentration
pmConc = 0

print &quot;Beginning main sensor loop ...&quot;
while True:
    try:
        # Read sensor value from potentiometer
        pot_value = grovepi.analogRead(potentiometer)

        # Calculate voltage
        pot_voltage = round((float)(pot_value) * adc_ref / 1023, 2)

        print &quot;pot_value = &quot;, pot_value, &quot; pot_voltage =&quot;, pot_voltage

    except IOError:
        	# print (&quot;Error&quot;)
        	errorCount += 1

    try:
        # Get AQ sensor value
        air_quality = grovepi.analogRead(air_sensor)

        if air_quality &gt; 700:
            print (&quot;High pollution&quot;)
        elif air_quality &gt; 300:
            print (&quot;Low pollution&quot;)
        else:
            print (&quot;Air fresh&quot;)

        print &quot;  Air Quality = &quot;, air_quality
        	time.sleep(1)

    except IOError:
        	# print (&quot;Error&quot;)
	        errorCount += 1

    try:
        # Get HCHO sensor value
        hcho = grovepi.analogRead(hcho_sensor)

        # Calculate voltage
        voltage = (hcho * grove_vcc * 1.0) / 1024

        print &quot;  HCHO = &quot;, hcho, &quot;voltage = %.4f&quot; % voltage
	        time.sleep(1)

    except IOError:
        	# print (&quot;Error&quot;)
	        errorCount += 1

    try:
        # Get PM sensor value
	        [new_val,conc] = grovepi.dustSensorRead()
        	if new_val and conc &gt; 1:
		                pmConc = conc

        	print &quot;  PM Concentration = &quot;, pmConc
	        time.sleep(1)

    except IOError:
	        # print (&quot;Error&quot;)
	        errorCount += 1

    print &quot;  Error Count = &quot;, errorCount
    time.sleep(1)

Let me know what you are thinking?

Hey humancell,
Thanks a lot for the detailed post about the problem that you have been facing with running multiple sensors. Even jaythvv is facing a similar problem and I have been looking into this for sometime now.I have not found a solution for this yet and am still trying to find the source for the duplicate values. This has most probably to do with how the data is loaded into the I2C buffer on the firmware.

I just want to assure you that this is a high priority on the GrovePi and we are looking into it.

-Karan

Thank you very much … please let me know if there is additional information that I can provide. I wanted to try and get you a scenario that you could reproduce there.

I look forward to the results of your debugging! :slight_smile:

Thanks Karan, and interesting read, Humancell. Looks indeed similar.

Hello,

I just wanted to check in on this issue. I looked around, however did not find any open source, or source code, that I can review to assist in debugging this … is there? I’m curious if there is an estimated time frame on fixing this? We’re about to begin to prototype about 10 units, and I’m wondering if we are going to be able to use the Grove Pi … or when?

I don’t mean to sound badly, I’m just trying to plan for our company and what we do next. I realized that we could maybe add several Grove I2C ADC modules to gain resolution and potentially bypass this issue of the Grove Pi Analog ports … but I’m not clear if they would work either?

Can I get an update and thoughts on how best to support you in resolving this issue?

Thanks!

Hey Humancell,
We are still looking into this issue and it might take some time to solve this issue. You can find the source for the firmware here: https://github.com/DexterInd/GrovePi/tree/master/Firmware/Source/v1.2/grove_pi_v1_2_4 and the software here: https://github.com/DexterInd/GrovePi/tree/master/Software/Python. We suspect that the problem lies in the way the I2C sendData function (https://github.com/DexterInd/GrovePi/blob/master/Firmware/Source/v1.2/grove_pi_v1_2_4/grove_pi_v1_2_4.ino#L643-L673) is working and how we load the data to the buffer to send to the RaspberryPi back, but still haven’t zeroed into the solution.

You should be able to use upto 9 Grove I2C ADC’s with the GrovePi and we even got the excample code working for it https://github.com/DexterInd/GrovePi/tree/master/Software/Python/grove_i2c_adc .

-Karan

Hello,

After a quick look, and reviewing the flow of the code, I have a few questions. I’m far from a expert at the RPi/Python/I2C/Arduino … but something that I wondered about.

Looking at the lines of code in the firmware, and then these lines in the Python library: https://github.com/DexterInd/GrovePi/blob/master/Software/Python/grovepi.py#L207-L213

Is it possible that the main Loop is taking too long to run, and that the time.sleep(.1) is not providing enough time for the values to settle before being returned?

From what I am seeing, the main loop is running all of the time, waiting on the index == 4 (size of incoming request?) or a few other flags, and so a incoming request is received - the Python library waits .1 seconds and then sends the read - which could be catching the loop not yet complete?

Maybe a race condition?

Hey,
The main loop takes something in the order of microseconds to complete an iteration. The slowest thing here is the I2C read write which take ~5ms to complete a transaction, hence we have the delay of .1sec (100ms) to make sure that the command is not ignored. Also, the command is only valid when the command buffer becomes 4 bytes long, so we wait for the command buffer to be filled up to 4 bytes, when it is the main loops runs and loads the data on the data buffer to be sent which we read from the python program after 100ms.

The delays are placed in the python library in a way that race conditions do not happen.

-Karan

Hello,

Ok … it took me sleeping on it … but I think I have it. I’m going to see what I can do to test this today.

In the firmware you’ve changed the top most check in the loop() to be a series of OR’d values … checking for a received command OR background tasks.

if(index==4 ||enc_run_bk ||run_in_bk ||flow_run_bk)

The problem with this is that index == 1 could be true (index == 4 is false), and if there are background tasks - like my dust sensor - then run_in_bk == true and so the if will be true and execute the long list of else if statements. So we have one byte of a new command coming in to the I2C bus, and we’re spinning on the background tasks … and yet we fall down through the entire if/else if set of statements. So we get a corrupt execution of the partially received commands.

Here are my thoughts:

1. The main <code>if</code> at the top of the <code>loop()</code> ought to revert to being <code>if(index==4 &amp;&amp; flag==0)</code> and then ONLY contain the non-background tasks.  This completely isolates the handling of these commands from the background tasks.
  1. The background tasks would then follow the closing of the if above, and be contained in a new, second if: if(enc_run_bk ||run_in_bk ||flow_run_bk) and then contain the background task if statements. This way, the first if, in #1 above, handles non-background commands ensuring the command is fully received, then allows the control to flow to check for background tasks, then completes.

  2. If seems to me that the main if/else if for non-background commands really could be a switch/case statement to make this a little more readable and clear … but not necessary.

I’ll do some testing today to see if I can verify this by editing and modifying the code on my local machine … and then seeing if I can get it installed on my Grove Pi.

Ha … I realize that I can not really test this fix. I don’t know how to generate the .cpp.hex file …

Are there full steps someplace that explain how to do this?

There is a discussion up on the forums about the process for compiling and uploading a new firmware here: http://www.dexterindustries.com/topic/grovepi-with-arduino-ide/ . Try it out and let us know if it works.

-Karan

Wait … did you read my post about the fix? The bug that I found? Thoughts? Comment?

Here is further results from my testing:

  1. The call to duration = pulseIn(8, LOW); is a blocking call, and can easily exceed seconds … potentially.

This means that the statement:

The main loop takes something in the order of microseconds to complete an iteration.

… is actually not correct any longer. In fact, what I found in fixing up the code is that it can take .5 to .8 seconds to return from the AnalogRead with the dust sensor running in the background.

I found this by adding code to zero the array b[] after each response in the sendData() function. I would continue to see 0 being returned for AnalogRead calls until I increased the delay in the GrovePi.py library.

I have done a lot of cleanup of the code, and also changed the delay in the GrovePi.py library to be .8 seconds … and am finally getting solid results.

What I can not understand, is that I would expect the smbus I2C calls to be blocking … should they be? In the GrovePi.py I now am guessing that you put the delay in place as the calls to read are NOT blocking?

Anyhow … I have things working, but still not as solid as I would expect …

Hello,

I’ve been offering up a lot of thoughts and testing results for feedback … and haven’t seen much. I know that you stated “I just want to assure you that this is a high priority on the GrovePi and we are looking into it.” … how is that going?

I’ve asked a few questions and making some progress, but I’d love to know how you are planning to move forward to resolve this, or if you have some thoughts/requests on how to collaborate?

Thanks!

Hey Humancell, just wanted to hop in here and give you an explanation. I still stand by the “high priority” statement, both Karan and I have been working on it and trying to figure out what’s going on. It’s a challenging problem and debugging these sorts of issues can be tough. There’s no guarantee that we can solve it, but we’re trying really hard, and probably more to your implication: we’re not ignoring the problem. Thanks for being patient with it.

Hello John … as a software developer I understand completely. I have actually been attempting to have a conversation to share with you the debugging and thoughts that I have with respect to the problem. I do agree that the issues that you are seeing are non-trivial, and directly related to the addition of the sensor support that requires the background processing.

I’ve been hoping to create some dialog where we can share our discoveries to get this resolved, but I had not seen any replies that acknowledged the issues that I have discovered so far. I’ve been able to resolve many of the issues, but not in the most efficient way … it’s all related to timing.

My thoughts as of the last several days are that you might have to fundamentally change the entire I2C protocol for ALL sensors, to be more like the Dust sensor. I’m thinking that ALL sensor requests ought to be returning the first byte as the “new data ready” flag. No matter what is asked for. This means that any request can be made (e.g. asking for AnalogRead(1)) and then read back and either it contains the “new_value” flag set or not. If it is not set then I know I need to re-request until I get the new value.

In all of my testing so far the issues are all race conditions related to timing, due to the interleaved blocking and non-blocking calls that are being used within the firmware. The fact that the handlers can not be blocking, and that the I2C calls from Python are not blocking forces you to either count on data not being ready (add the “new_value” flag) or to put in excessive timing delays in the code in various places.

I’m now, with all of my changes, reliably reading four sensors - three analog and then Dust sensor - but it’s being done with timing changes to handle the various race conditions. I’m about to completely re-write everything to put in place the “new_value” flags on all calls as the more that I look at it it is really the way to go.

BTW … you can see some of our test data here: Wovyn Air Quality Sensor Demo

I’m really eager to assist you in making this work as I want to see you have a successful product. Let me know if there is a better forum to communicate and collaborate on a solution. :slight_smile: