MrYsLab / pymata-aio

This is the second generation PyMata client.
https://github.com/MrYsLab/pymata-aio/wiki
GNU Affero General Public License v3.0
155 stars 51 forks source link

pymata_core.get_analog_map() times out prematurely on some Arduino boards #60

Closed VincentYZ closed 6 years ago

VincentYZ commented 6 years ago

I ran into a knock-off Arduino Mega 2560 board for which 2 seconds appears to be insufficient to transmit the entire analog pin map. Increasing timeout threshold appears to fix the issue.

async def get_analog_map(self):
       ...
            # wait for the report results to return for 2 seconds
            # if the timer expires, shutdown
            while self.query_reply_data.get(
                    PrivateConstants.ANALOG_MAPPING_RESPONSE) is None:
                elapsed_time = time.time()
                # This times out prematurely on some hardware, doubling it to 4 seems to fix the issue
                if elapsed_time - current_time > 4:
                    return None
                await asyncio.sleep(self.sleep_tune)
        return self.query_reply_data.get(
            PrivateConstants.ANALOG_MAPPING_RESPONSE)
MrYsLab commented 6 years ago

Does lengthening the arduino_wait_time parameter help solve this issue for you?

MrYsLab commented 6 years ago

I am closing this issue. If you have any additional information or comments, you can add them here.

VincentYZ commented 6 years ago

Sorry for the late reply. I was trying to get different Arduino boards for more testing. For now, at least on this particular board I have, the problem seems to be with the get_analog_map function.

Even if I increase arduino_wait_time to 10, I'm still getting the same error. Increasing get_analog_map timeout threshold appears to be the only way to workaround it.

More hardware/software environment details:

Board Info: BN: Arduino/Genuino Mega or Mega 2560 VID: 2341 PID: 0042 SN: 5543131323835151E012 Arduino Firmware ID: 2.4 StandardFirmata.ino

It's a knockoff Arduino, but appears to be identical to the genuine board in all aspects that matter.

PC: Windows 10 running Python 3.6 and latest pymata-aio

I'm running a slightly modified version of your example code here: https://gist.github.com/MrYsLab/0b9f125f04f171065af0

MrYsLab commented 6 years ago

I just tested the code at the link above on a SainSmart 2560 clone by flashing the latest version of FirmataPlus (2.5.3) using the latest version of the Arduino software 1.8.5 and it starts without issue. Please note that FiramataPlus is the sketch that is part of this repo and not StandardFirmataPlus.

If this is the only 2560 board you own, I would suggest that you just clone this repo and make the changes locally. There are no planned changes to this library so it is low risk.

I am very reluctant to make changes to the code, not because the change itself is difficult to do, but because of the time it will take to do regression testing and to redo the API documentation. I would need to make the change for the timeout configurable, with the default the current value, so as not to change anything for those with working applications.

Is this an acceptable solution?

VincentYZ commented 6 years ago

Thanks for looking into this. I too suspect this issue is specific to particular clone boards. Agree that this doesn't warrant the overheads to change the library since this problem seems rare. Let's consider the issue resolved.

MrYsLab commented 6 years ago

Thanks.

chelsell commented 6 years ago

@MrYsLab I'm experiencing what appears to be the very same problem, but it affects genuine Arduinos. In Windows 10, neither my Arduino Mega 2560 or Mega ADK can reliably connect due to the analog map retrieval timing out. I've never seen this problem in MacOS, and on Windows 10 my Arduino Uno works fine. I tried @VincentYZ's change and it works. I can clone the repo to keep this change, but I thought you might like to know that the same issue appears to affect genuine Arduinos.

EDIT: It's also worth mentioning that this problem is at least somewhat random--I can occasionally get the connection to work without changing the timeout threshold, but it's extremely unreliable and I haven't been able to link the successful attempts to something I'm doing differently.

MrYsLab commented 6 years ago

@chelsell On the boards that fail, if you first remove the USB, then plug it back in and wait for the tx/rx LEDS to stop flashing, and then start your program does it still fail?

Also, if you increase the timeout beyond 2 seconds, what value works reliably?

chelsell commented 6 years ago

@MrYsLab It sometimes works when I unplug it and plug it back in again (waiting until the lights stop blinking per your suggestion), but never consistently. With the timeout set to 4 seconds, I have yet to see the connection fail and I've tried around 10 times.

MrYsLab commented 6 years ago

@chelsell I am considering changing the code to accommodate the larger timeout, but since I am unable to reproduce the problem here, could you please provide some additional information:

  1. On your Windows 10 machine, are you running it natively or as a virtual machine (such as virtualbox)?
  2. What CPU does your computer have (for example, Intel Core i3, etc.)?

Thanks.

chelsell commented 6 years ago
  1. I am running natively.
  2. It's an Intel Core i7, 7700K 4.20GHz
MrYsLab commented 6 years ago

Ok, I will make the change in the next few days.

MrYsLab commented 6 years ago

@VincentYZ @chelsell I have increased the timeout to 4 seconds and published the change as version 2.21. It is available on pypi.

chelsell commented 6 years ago

Thanks for your prompt attention! Hopefully this will help someone in the future too.