Agrowtek pumps with PLR

I started this discussion with @rickwierenga via email, but opening it up here for more input, particularly from @marielle who did the initial contributions with the Agrowtek pumps in PLR.

I have an array of Agrowtek pumps that I’m trying to get working with PLR and not having much luck. I am able to initialize them fine on a windows computer using the default software from Agrowtek.

I’m trying to piece together the initial setup from the docs regarding the master-flex pumps, and trying this:

from pylabrobot.pumps.agrowpumps.agrowdosepump import AgrowPumpArray
pump = AgrowPumpArray(port='/dev/tty.usbserial-D30AKVJF', address="0")

Which executes without error in my notebook. Then when calling setup():

await pump.setup()

I get this error and trace:

Failed to connect [Errno 35] Could not exclusively lock port /dev/tty.usbserial-D30AKVJF: [Errno 35] Resource temporarily unavailable
---------------------------------------------------------------------------
ConnectionError                           Traceback (most recent call last)
Cell In[59], line 1
----> 1 await pump.setup()

File ~/Documents/FutureHouse/Lab/PyLabRobot/pylabrobot/pylabrobot/pumps/agrowpumps/agrowdosepump.py:110, in AgrowPumpArray.setup(self)
    106 async def setup(self):
    107   """ Sets up the Modbus connection to the AgrowPumpArray and creates the
    108   pump mappings needed to issue commands.
    109   """
--> 110   await self._setup_modbus()
    111   register_return = await self.modbus.read_holding_registers(19, 2, unit=self.address)
    112   self._num_channels = \
    113     int("".join(chr(r // 256) + chr(r % 256) for r in register_return.registers)[2])

File ~/Documents/FutureHouse/Lab/PyLabRobot/pylabrobot/pylabrobot/pumps/agrowpumps/agrowdosepump.py:122, in AgrowPumpArray._setup_modbus(self)
    120 await self.modbus.connect()
    121 if not self.modbus.connected:
--> 122   raise ConnectionError("Modbus connection failed during pump setup")

ConnectionError: Modbus connection failed during pump setup

It obviously seems like a connection issue, which makes some sense because I’m not sure I know how to identify the proper port on my Mac and put the above (port='/dev/tty.usbserial-D30AKVJF') based on some googling, as that’s the change I see when calling ls on /dev/ with the USB adapter with the pump plugged in vs. not.

I’m also not sure what to use for address=, but I put 0 as that is what I put as the address when initializing with the windows program. This may be referring to something else though.

Any help is appreciated.

2 Likes

Hi Jon!

I think your setup is correct. The first thing I would try is to set address to the integer 0.
Additionally, these are intended as backends, so I would not call setup directly on the agrowpump object.

from pylabrobot.pumps import PumpArray
from pylabrobot.pumps.agrowpumps.agrowdosepump import AgrowPumpArray

agrow_pump = AgrowPumpArray(port='/dev/tty.usbserial-D30AKVJF', address=0)
pump = PumpArray(backend=agrow_pump)

Then, I would make sure that there is no other program that might be interfacing with the port. I am a bit occupied at the moment, but I did work out a way to see if the port is in use, I would just have to dig in my notes to find it.

Also, just to not, when I defined pumps in the way you describe here, I had to restart the python kernel each time after calling setup when I was running from a notebook, or it would produce this error as there was already a connection established.

If you want to avoid this, I would use a context manager or try-except-finally and ensure the pumps are disconnected and the port is open regardless of code outcome. Here is what that might look like:

from pylabrobot.pumps import PumpArray
from pylabrobot.pumps.agrowpumps.agrowdosepump import AgrowPumpArray

agrow_pump = AgrowPumpArray(port='/dev/tty.usbserial-D30AKVJF', address=0)
with PumpArray(backend=agrow_pump) as pump:
  await pump.setup()
2 Likes

Wouldn’t this lead to the same error (or similar) because opening the context manager already calls setup?

Thanks @marielle! You were right and I went total space-cadet on the int 0. I restarted my notebook kernel and did that and I have them running now.

While this works, is there a more PLR-y way I should be doing my imports compared to what I posted above?

2 Likes

Good catch! I also think it should be async with.

@jonlaurent I think this code is closer to what you want.

from pylabrobot.pumps import PumpArray
from pylabrobot.pumps.agrowpumps.agrowdosepump import AgrowPumpArray

agrow_pump = AgrowPumpArray(port='/dev/tty.usbserial-D30AKVJF', address=0)
async with PumpArray(backend=agrow_pump) as pump:
  await pump.run_for_duration(...)
2 Likes

Got it, will give that a shot.

2 Likes

just so it’s explicit here: having context managers is great for runs, but in notebooks it can sometimes be helpful to keep a connection open longer (using setup and stop). As long as you’re careful to not run into the issue Marielle mentioned above.

1 Like