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

Analog data callback functions persist past shutdown and interfere with new board initialization #54

Closed chelsell closed 7 years ago

chelsell commented 7 years ago

Hi,

I've noticed that since I implemented sensor callback functions for my arduino project, I'm having trouble initializing a new board even after the old one is terminated. The only real hint I have at the cause is that the TX indicator light on my arduino stays on for a few minutes after my arduino shuts down and my program ends completely.

I assume this has something to do with asyncio. I'm implementing my callback directly, like this:

def _record(self, data) -> None:
   if data[1] != self.previous_value:
   self.log_file.write('%s,%s,\n' % (data[1],datetime.datetime.now()))
      self.previous_value = data[1]

self._board.set_pin_mode(pin_number=5, pin_state=Constants.ANALOG, callback=_record, cb_type=Constants.CB_TYPE_DIRECT)

The arduino does eventually shut down completely, so it's not the highest impact bug for me. All the same, I'd like to hear your thoughts on how to avoid this problem altogether?

MrYsLab commented 7 years ago

@chelsell The issue is not asyncio, but the Arduino reset circuitry. The way StandardFirmata and FirmataPlus work, is that once you place a pin in analog input mode, it streams data back to the python code. When you restart the python code without restarting (powering down and then powering up) the Arduino, pymata-aio does not expect data from a pin that is not yet initialized, and hence, it throws the exception.

If you are using an Uno (I think this will work on a Leonardo as well, but I know it does not work with a Mega 2560), and you have loaded FirmataPlus onto the Arduino, if you issue a keep_alive pymata-aio call, it will enable the keep-alive feature on the Arduino . If pymata-aio goes away for longer than the keep-alive period, the Arduino will reset itself, and the probelm should no longer appear.

Here is the documentation for the keep_alive method:

def keep_alive(self, period=1, margin=.3):
        """
        Periodically send a keep alive message to the Arduino.
        Frequency of keep alive transmission is calculated as follows:
        keep_alive_sent = period - (period * margin)
        :param period: Time period between keepalives. Range is 0-10 seconds. 0 disables the keepalive mechanism.
        :param margin: Safety margin to assure keepalives are sent before period expires. Range is 0.1 to 0.9
        :returns: No return value

Please let me know if this solves your problem or if you have any other questions.

chelsell commented 7 years ago

@MrYsLab

Thanks for the information! Unfortunately, I am working on a Mega 2560. But my Mega must reset itself at some point, because as long as I don't try to run my python code again immediately, it will work. I tried setting the pins to another mode once I'm finished reading from them, but that didn't seem to work. Any idea why not? From what you said, it seems like changing the pin mode from an input to an output would prevent Firmata from prematurely reading it back.

MrYsLab commented 7 years ago

@chelsell Unlike digital pins, there is no mode setting available for analog input pins. You could turn analog reporting off before exiting your program. The disable_analog_reporting method will prevent the analog data from streaming to the serial port and is used on a per pin basis.

chelsell commented 7 years ago

@MrYsLab I somehow thought I had tried using disable_analog_reporting, but I gave it a second try and it worked perfectly. I'm going to go ahead and close this issue, thanks for your help!