numat / alicat

Python driver and command line tool for Alicat mass flow controllers.
GNU General Public License v2.0
21 stars 27 forks source link

Cannot Read two Flow Meters/controllers at the same time #5

Closed rmoein closed 6 years ago

rmoein commented 6 years ago

Hi,

I have two Alicat flow meters. When I connect each one individually to my computer through a BB9-232 multi-drop breakout box, I can read their outputs through the alicat python module (see my test code below). However, when I connect both controllers to the box and run the same code, I see the following error. How can I solve this issue?

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 12: ordinal not in range(128)

import alicat
import time

i = 0
while True:
   try:
       flow_meter_1 = alicat.FlowMeter(port = 'COM4', address = 'A')
       flow_meter_2 = alicat.FlowMeter(port='COM4', address='B')
       if i == 0:
           print("Flow meter's numbers: ")
       print (flow_meter_1.get())
       print(flow_meter_2.get())
       time.sleep(2)
       i+=1
   except KeyboardInterrupt:
       flow_meter_1.close()
       flow_meter_2.close()
       break
patrickfuller commented 6 years ago

It's hard for me to figure out what's wrong with your setup, but I can say that I know this exact setup works.

First, have you tried sleeping for ~0.1s between flow_meter_1.get() and flow_meter_2.get()? Your error might be flow_meter_2.get() picking up some unhandled bits.

Second, what version of python is this? If 2, have you tried with 3? (It should be compatible with both, but maybe this is a bug that's snuck in).

rmoein commented 6 years ago

I use python 3.6. For some reason, I cannot get it to work at all on Python 2.

I tried sleeping for 0.1 sec between the two commands but I still get the same error.

One thing I noticed though: It does not matter if the unit ID on the controller is A or C. Even if it's set to C, the line for flow_meter_1 will collect the data from that controller. But, it changes the Unit ID to A on the controller without me even touching it (so it seems like the program forces the change of ID). I tried the same thing with two controllers and the program (somehow) changes the IDs of both controllers to A and that's probably what that is causing the error. I tried setting a sleep time between flow_meter_1 and flow_meter_2 lines and the program still syncs up the unit IDs. I'm not sure what to do to fix that.

patrickfuller commented 6 years ago

That is very weird. I didn’t even think you could programmatically change the device address through Alicat’s standard serial commands.

If you’re comfortable with serial debugging, you can test with the commands in the code. You should be able to send *@=C\r to get device C. If that doesn’t work, then it’s an issue to bring up with Alicat.

rmoein commented 6 years ago

The thing is, I'm quite new to serial debugging so that's why I was hoping you could help. Oh well, it seems like I have to start reading the PySerial Documentation.

As for Alicat, I already contacted them. Their support team doesn't seem to have an idea about using python. They just told me to go to their website and download the programs that show whether the controllers are communicating with the PC or not. But I know they do since I can see their outputs on Flow Vision without any issue.

patrickfuller commented 6 years ago

Sorry I can’t help more. All I can say is that I’ve used this library without issue in a similar setup.

The only difference I see is that I don’t run on windows, but I doubt that’s it.

patrickfuller commented 6 years ago

One other quick thing to try. You should probably have your flow meter constructor out of your read loop. Here's a cleaned up version, also with exception handling to see if your error is a one-off:

import alicat
import time

flow_meter_1 = alicat.FlowMeter(port='COM4', address='A')
flow_meter_2 = alicat.FlowMeter(port='COM4', address='B')

print("Flow meter's numbers: ")
while True:
    try:
        print(flow_meter_1.get())
        print(flow_meter_2.get())
        time.sleep(1)
    except KeyboardInterrupt:
        flow_meter_1.close()
        flow_meter_2.close()
        break
    except Exception as e:
        print(e)

Let me know how this works.

rmoein commented 6 years ago

I get the same 'ascii' codec error with the new code and the flow meter's IDs also sync up again. What OS did you use with your setup?

rmoein commented 6 years ago

I just tried the same code on a mac and get the same error.

patrickfuller commented 6 years ago

I just tried on a mac and can reproduce the address changing issue:

# Address is B
▶ alicat /dev/tty.usbserial --address B
{
  "flow_setpoint": 0.0,
  "gas": "Air",
  "mass_flow": 0.0,
  "pressure": 14.1,
  "temperature": 24.48,
  "volumetric_flow": 0.0
}
# Address is A

This is interesting because we've had many flow controllers running since ~2015 without issue. This got me curious, so I decided to look through my Alicat manuals to see if the serial commands changed in newer models.

Rev36 (11/12/2014) on left, Rev42 (5/22/2017) on right.

2018-04-03 14 20 10

The important part here is that the command *@=A means stop streaming and read a line of data from A in 2014, but the same command means set all addresses to A in 2017.

I find this very weird, but, fortunately, it's an easy fix. I'll push a change to github and pypi in a few minutes.

patrickfuller commented 6 years ago

I just uploaded 0.2.3 to pypi. You can upgrade with pip install --no-cache-dir --upgrade alicat. Let me know if this fixes your issue.

rmoein commented 6 years ago

Your new update fixed the issue, thanks a lot!

No wonder why all of the controllers' IDs would change to the same letter. It's strange that Alicat decided to change the function of that command like that. Anyway, thanks again!

patrickfuller commented 6 years ago

Thank you for pointing this out!