berndporr / pyFirmata2

Turn your Arduino into a realtime data acquisition card under Python
MIT License
55 stars 24 forks source link

Multiple Arduinos #10

Open polomarco87 opened 1 year ago

polomarco87 commented 1 year ago

I am working with multiple ArduinoMega units. I've gotten this code to work extremely well when only 1 single Arduino is hooked up, but as soon as I hook up 2 or more, the input functions (related to the register callback, enable reporting, etc) default to the last defined Arduino board.

I have written an extremely simplified version of what I'm seeing:

import pyfirmata2
from pyfirmata2 import ArduinoMega, util

def pinCallback(value):
    if value:
        print("Button 1 released")
    else:
        print("Button 1 pressed")

def pinCallback1(value):
    if value:
        print("Button 2 released")
    else:
        print("Button 2 pressed")    

# Creates a new board
board = pyfirmata2.ArduinoMega('COM18')
board2 = pyfirmata2.ArduinoMega('COM19')
print("Setting up the connection to the board ...")

# default sampling interval of 19ms
board.samplingOn()
board2.samplingOn()

# Setup the digital pin with pullup resistor: "u"
digital_0 = board.get_pin('d:6:u')
digital_1 = board2.get_pin('d:6:u')

# points to the callback
digital_0.register_callback(pinCallback)
digital_1.register_callback(pinCallback1)

# Switches the callback on
digital_0.enable_reporting()
digital_1.enable_reporting()

print("To stop the program press return.")

input()

# Close the serial connection to the Arduino
board.exit()
board2.exit()

What I am seeing -- adjusting the pin (acting as a button) on board 1 will print "Button 2..." and likewise, adjust the pin on board 2 will print "Button 2..." If I swap the order of the board definitions, board2 following by board, then the opposite happens, and only "Button 1..." will print.

Is there a core function I'm missing to allow multiple, simultaneous serial communications with multiple Arduino boards?

berndporr commented 1 year ago

I think you are the 1st who tried it with two Arduinos. As you say it should work as they are totally separate in their instances. I can only guess that the previous maintainer has introduced a global variable somewhere.

polomarco87 commented 1 year ago

If that is the case, I'd have to potentially search for and edit out some kind of global variable in the pyfirmata2.py code itself?

berndporr commented 1 year ago

It would be nice to find the bug and send me a pull request. :)

polomarco87 commented 1 year ago

I don't have the longest experience with Python. From my short basic code I'm experimenting with, I confirmed that the initial board setups are being established, but I am wondering if one of the three input portions are overwriting each other: samplingOn, callback_register(), or enable_reporting()

I'll be looking more into how these are handled, but if you have any ideas if those may be defaulting to the "last called board" that would be great to know.

polomarco87 commented 1 year ago

Okay, by moving each board into its own function and calling them one at a time, I've isolated the fault to be either due to the enable_reporting(), or register_callback() functions. Note my comments on those lines -- that describes the behavior when only one of those are disabled at a time. I do not understand enough about the pyfirmata2.py lines, particularly how there are two classes (Pin and Port) that have enable_reporting() in it.

I'm honestly baffled why this is happening, so any help would be greatly appreciated!

import pyfirmata2
from pyfirmata2 import ArduinoMega, util

def pinCallback(value):
    if value:
        print("Button 1 released")
    else:
        print("Button 1 pressed")

def pinCallback1(value):
    if value:
        print("Button 2 released")
    else:
        print("Button 2 pressed")    

# Creates a new board
def setupArd1():
    board = pyfirmata2.Arduino('COM18', name='Ard1')
    board.samplingOn()
    digital_0 = board.get_pin('d:6:u')
    digital_0.register_callback(pinCallback) #disabling this line only, both physical Arduino print Button 2
    digital_0.enable_reporting() #disabling this line only, both physical Arduino print Button 2

def setupArd2():
    board2 = pyfirmata2.Arduino('COM19', name='Ard2')
    board2.samplingOn()
    digital_1 = board2.get_pin('d:6:u')
    digital_1.register_callback(pinCallback1) #disabling this line only, neither Arduino will print anything
    digital_1.enable_reporting() #disabling this line only, both physical Arduino print Button 2

setupArd1()
setupArd2()

print("To stop the program press return.")

input()

# Close the serial connection to the Arduino
board.exit()
board2.exit()