Skip to content
This repository has been archived by the owner on Mar 28, 2020. It is now read-only.

Analog Report Lagging #32

Closed
jimmykh opened this issue Nov 25, 2015 · 13 comments
Closed

Analog Report Lagging #32

jimmykh opened this issue Nov 25, 2015 · 13 comments

Comments

@jimmykh
Copy link

jimmykh commented Nov 25, 2015

The analog report has been lagging, and I've got the updated values from analog pin only after 8-10 seconds. Tried the pymata with Python 2.7 and results are okay.

from pymata_aio.pymata3 import PyMata3
from pymata_aio.constants import Constants

board = PyMata3(arduino_wait=5)
board.set_pin_mode(1, Constants.ANALOG)

while True:
    value = board.analog_read(1)
    print (value)
    board.sleep(2)

I've tried both on UNO and Nano, and both are not working with results greatly lagging behind. Please help pinpoint what has been gone wrong.

Thanks.

@MrYsLab
Copy link
Owner

MrYsLab commented Nov 25, 2015

Could you please provide some detail. If I connect a potentiometer to an analog pin and run your example, I see the value being updated accurately as I change the pot position no matter how long the code is running. The updates occur every 2 seconds as specified by the board.sleep(2).

@jimmykh
Copy link
Author

jimmykh commented Nov 25, 2015

Sorry forgot to mention. The code was perfectly okay when I tested it with Mac, but when I run the same program in Win 8 and Win 10, and when I connect the photocell light sensor to analog pin, the readings were updated very slowly - like almost 10 seconds behind.

The following was the result with about when I covered and uncovered the sensor and when the figure got updated.

Using COM Port:com5

Initializing Arduino - Please wait... Auto-discovery complete. Found 20 Digital
Pins and 6 Analog Pins


0
28
27 <--  this is when I covered the light sensor with my finger
28
23
1
1
1  <-- this is when I uncovered the sensor
1
2
2
27
27 
27  <-- this is when I covered again
28
28
27
28
28
28  
28
28
1
1
1

@fisherds
Copy link
Contributor

Try dropping the sleep_tune parameter to 0 and see if that makes a difference on your Windows machine. The problem is that your computer can't keep up with your Arduino. Isn't that funny? ;) Reducing the sleep_tune might help. That can closing other programs.

@MrYsLab
Copy link
Owner

MrYsLab commented Nov 25, 2015

I am seeing the same problem on Windows and yes, if the 2 second delay is changed to a very small time (or zero) response is good. I will need to characterize the asyncio.sleep for windows some more, but if I run the following code, it all seems to work as expected. The behavior is definitely different between Linux and Windows (the internal python loop mechanisms are different). This is definitely weird and I suspect a bug in the Python loop code for windows. @jimmykh Can you try the code below and see if it provides a workaround for you. Please let me know the results, good or bad.

@fisherds Dave, I guess I am confused. The fact that I run a short timer in a loop seems to work, does that mean the computer can't keep up with Arduino, or the asyncio sleep in Windows is somehow broken? Any thoughts? I am even more confused in that 200 * .001 = .2, yet the delay seems to be 2 seconds. Just too weird.

By the way, I am running Windows 10 64 Bit in virtual box. I am not sure if running on a native Windows machine would show any different behavior.

Thanks.

from pymata_aio.pymata3 import PyMata3
from pymata_aio.constants import Constants


board = PyMata3(arduino_wait=5)
board.set_pin_mode(2, Constants.ANALOG)

while True:
    value = board.analog_read(2)
    print(value)
    for i in range(0, 200):
        board.sleep(.001)

@MrYsLab
Copy link
Owner

MrYsLab commented Nov 25, 2015

@jimmykh Please try the following code which uses callbacks. This seems to work for me:

from pymata_aio.pymata3 import PyMata3
from pymata_aio.constants import Constants

value = 0


def my_callback(data):
    global value
    # data[0] is the pin number and data[1] is the changed value
    value = (data[1])


board = PyMata3(arduino_wait=5)
board.set_pin_mode(1, Constants.ANALOG, my_callback)

while True:
    print(value)
    board.sleep(2)

@MrYsLab
Copy link
Owner

MrYsLab commented Nov 25, 2015

I have updated the wiki page with a link to the following example https://gist.github.com/MrYsLab/0b9f125f04f171065af0. The wiki update recommends using callbacks over the polling method to retrieve input data.

@jimmykh
Copy link
Author

jimmykh commented Nov 26, 2015

I've tried both options - shortening the sleep time as well as the callback, and both worked okay. Thanks. BTW, shortening the sleep time might not be a good option as it consumed quite a bit of CPU time.

On the other hand, I've tried the following code as well using PymataCore instead of Pymata3.

import asyncio
from pymata_aio.pymata_core import PymataCore
from pymata_aio.constants import Constants

PIN = 1
value = 0

#@asyncio.coroutine
def my_callback(data):
    global value
    value = (data[1])

@asyncio.coroutine
    def analog_read():
        board = PymataCore(arduino_wait=5)
        yield from board.start_aio()
        yield from board.set_pin_mode(PIN, Constants.ANALOG, my_callback, Constants.CB_TYPE_DIRECT)

       while True:
           print (value)
           yield from board.sleep(0.5)

loop = asyncio.get_event_loop()
loop.run_until_complete(analog_read())

If I invoked the callback using DIRECT, everything worked okay, but if I invoked using ASYNCIO, the same issue persists.

Anyway, I confirm that the issue can be resolved using callback. Should I close the issue?

Thanks for all the help!

@jimmykh
Copy link
Author

jimmykh commented Nov 26, 2015

An update. If I tried to get inputs from 2 analog pins at the same time, the lagging issue comes back even with the callback.

from pymata_aio.pymata3 import PyMata3
from pymata_aio.constants import Constants

value = {}

def my_callback(data):
    global value
    pin = data[0] 
    value[pin] = (data[1])

board = PyMata3(5)
board.set_pin_mode(1, Constants.ANALOG, my_callback)
board.set_pin_mode(2, Constants.ANALOG, my_callback)

while True:
    print (value)
    board.sleep(0.5)

@MrYsLab
Copy link
Owner

MrYsLab commented Nov 26, 2015

@jimmykh I can confirm your findings. There is something really strange going on with Windows. If I run an instance of pymata_iot and bring up this web page and enable the 2 analog inputs, all works well (this is on Windows). It almost seems like the print statement is blocking.

I will try to profile this later this weekend and let you know if I find anything that can explain this behavior.

@fisherds
Copy link
Contributor

It would be fun to see if there is a better way to do print statements in an asyncio way. It takes time to print. I don't know if there is a better way to print and not cause lags. Maybe asyncio could help or maybe there is an optional flag you could send went printing???

https://docs.python.org/3/library/functions.html?highlight=print#print

Would this behave any better or worse???
print('Hello World!', flush=True)

Links from: http://stackoverflow.com/questions/107705/disable-output-buffering

@MrYsLab
Copy link
Owner

MrYsLab commented Nov 28, 2015

@jimmykh I may have led you astray with the last posting (it has been deleted). I had tested using Pycharm which masks the problem and I thought I solved it but actually did not.

It turns out the for whatever reason, Windows cannot handle the amount of data that the Arduino is sending. The fix is to alter the sampling rate of the Arduino. The following code does that and seems to work when I have all 5 analog inputs configured to send data change reports, which is a worse case. You may need to increase the sampling interval parameter depending upon the speed of your computer.

Avoid using the polling method to read data and always use the callback method.

Please try the code below and let me know if it works for you or not.

from pymata_aio.pymata3 import PyMata3
from pymata_aio.constants import Constants

value = {}


def my_callback(data):
    global value
    pin = data[0]
    value[pin] = (data[1])


board = PyMata3(5)

board.set_sampling_interval(100)

board.set_pin_mode(0, Constants.ANALOG, my_callback)
board.set_pin_mode(1, Constants.ANALOG, my_callback)

# potentiometer
board.set_pin_mode(2, Constants.ANALOG, my_callback)

board.set_pin_mode(3, Constants.ANALOG, my_callback)

board.set_pin_mode(4, Constants.ANALOG, my_callback)

# light sensor
board.set_pin_mode(5, Constants.ANALOG, my_callback)

# push button switch
board.set_pin_mode(12, Constants.INPUT, my_callback)

# slide switch
board.set_pin_mode(13, Constants.INPUT, my_callback)

while True:
    print(value)
    board.sleep(0.5)

@MrYsLab
Copy link
Owner

MrYsLab commented Nov 29, 2015

@jimmykh I am closing this issue, since I have provided 2 workarounds and have added some documentation to the wiki pages giving examples of the 2 workarounds. The link is https://github.com/MrYsLab/pymata-aio/wiki/Windows-Anomalies

If you are still having issues, please feel free to reopen this issue.

@MrYsLab MrYsLab closed this as completed Nov 29, 2015
@MrYsLab
Copy link
Owner

MrYsLab commented Dec 3, 2015

I continued pursuing this issue and I believe I have found a fix that does not require any workarounds. I am in the final stages of testing version 2.8 that addresses the issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants