# Communicating with syringe pump using PySerial

Let's first start of by explaining that I do not have a decent background in electronics and interfacing with them, so maybe this is a stupid question. I am currently trying to connect an old Harvard 33 syringe pump (website, PDF manual) to a computer, with the goal of controlling things like pump rates and direction. For this purpose, I connected the instrument to my computer using a D-sub/USB conversion dongle. I then connected to the dongle with PySerial without issues. However, whenever I try to send commands or request the instrument's output, for example write("RUN\r"), the instrument does not do anything at all. Requesting data (read(100)) returns only a couple of \x00. I suspect I am communicating with the dongle itself rather than the pump. When the pump is turned off or unplugged, I get exactly the same results!

Could anyone explain to me why my method does not work?

My Python code for reference:

import serial # PySerial module

# open the connection
ser = serial.Serial("/dev/ttyUSB0", baudrate=9600, bytesize=8, stopbits=2, timeout=1)
print ser # returns [Serial<id=0x1cc7610, open=True>(port='/dev/ttyUSB0', baudrate=9600, bytesize=8, parity='N', stopbits=2, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False)]

# see if the connection is truly open
print ser.isOpen() # prints True

# run the pump motor
ser.write("RUN\r")


Additional observations: when the instrument is plugged in but the above code is not running, the pump does all sorts of things at random (move one way, stop, move the other way, etc.). This behaviour is much less pronounced but still present when the code runs (and 'locks' the channel or something?). This seems to suggest that the reference voltages (logical high and low) are not properly set at 2-5V and 0-0.5V respectively

• Have you tried opening a serial terminal (hyperterminal, tera term, minicom, etc) and communicating with the instrument directly? – Ian Dec 3 '14 at 15:19

Thank you for directly linking to the manual -- that makes answering questions like this much quicker.

I connected the instrument to my computer using a D-sub/USB conversion dongle.

I'm assuming that you've already figured out that the thing that looks like a standard 9-pin D-sub connector on the Harvard Model 33 is completely incompatible with standard RS-232, and you have (or can make) something that looks like the proper cable between a PC and the pump.

The first thing I would do is "beep out" the cable: The cable should have a DB9 female on one end, and a RJ11 plug on the other end, and connections as shown on in Appendix D and Appendix F (p. 24-25) of the manual.

As far as I can tell, for your application, you don't wan't anything plugged in to the "I/O" D-sub connector on the back of the pump. Instead, you want the RJ-11 plug end of your cable plugged into the "Port #1" RJ-11 socket on the back of the pump; and the DB9 female end of your cable plugged into the male DB-9 connector on the USB-to-RS232 dongle.

Throwback1986 has many good tips.

Requesting data (read(100)) returns only a couple of \x00. ... Could anyone explain to me why my method does not work?

These pumps are designed to be connected in a chain, and they are designed to ignore commands sent to other pumps in a chain. Also, they ignore commands sent while the pump is in setting mode (see p. 16).

I might run a script like this to see which (if any) address the pump is responding to:

# communicate with a Harvard 33 syringe pump
# http://robotics.stackexchange.com/questions/5079/communicating-with-syringe-pump-using-pyserial
# pump website: http://www.harvardapparatus.com/webapp/wcs/stores/servlet/product_11051_10001_44004_-1_HAI_ProductDetail___
# pump manual: http://www.instechlabs.com/Support/manuals/HA33Manual.pdf
# WARNING: untested code

import serial # PySerial module: http://pyserial.sf.net/

# open the connection
ser = serial.Serial(port="/dev/ttyUSB0", baudrate=9600, stopbits=STOPBITS_TWO, timeout=0.5)
print ser

# see if the connection is truly open
print ser.isOpen()

# See if the pump is at address 0:
# try to get the software version of that pump
# using the VER command from p. 19 of the manual
command_string = "VER\r"
ser.write( command_string )
print "version: %r." % response

# guess every possible address 0 to 99
for guessed_address in range (0, 100):
# request prompt
ser.write( prompt_request )
print "prompt: %r." % response

# try to get the software version of that pump
# using the VER command from p. 19 of the manual
ser.write( command_string )
print "version: %r." % response

print "All done."


Does this script show any "interesting" responses?

If I had this pump in front of me, I would follow the "Configuring the Pump Chain" process on p. 14 to figure out the current pump address and baud rate.

Does the pump display "b:9600" on the pump's front LED display when I do that? Does the pump display "Adr:00" on the pump's front LED display when I do that? If not, I would go through the "Configuring the Pump Chain" on p. 14 to get that set.

I might try getting pyserial to communicate through that USB dongle to and from some other device, perhaps a simple loop-back wire, just to make sure that pyserial works with that USB dongle.

Good luck!

• Thanks a lot for your reply, it was very helpful. I will follow up on it once I found the required connectors. Do you think I could directly use a RJ-11 to USB adapter rather than a RJ11 > RS232 > USB chain? – MPA Dec 3 '14 at 19:49
• In principle, there might exist a RJ-11 to USB adapter that works with this device. In practice, all off-the-shelf RJ-11 to USB adapters I've ever used have either (a) had telephone modem tones at the RJ-11 end, or (b) had bidirectional RS-485 signals at the RJ-11 end. Neither one of those is compatible with the Harvard 33 syringe pump or with each other. – David Cary Dec 4 '14 at 4:45
• And so I expect you'll probably end up with a USB to RS232-on-DB9 adapter, plus a "just wires" DB9-to-RJ11 adapter something like MJD9F6P6C; ADM-9F6-GR; CP-232A-6C-9F; ZT1312000; etc. – David Cary Dec 4 '14 at 5:04
• Setting up the right connectors did the trick, after that I could issue commands right away. Thanks! – MPA Dec 5 '14 at 10:12

ser.write is always returning number of bytes written. It is not the response to your command. In order to get the response, you need to perform a read command.

I don't know how it would be specifically in Python, but generally speaking, when you open a file, you get a handle which you may possibly write to or read from. Again, generally speaking, the read and write system calls return the number of bytes they have read or written.

In your case, you are writing "VER\r" to serial port. You get 4 because all four characters are sent. The write function is not responsible for waiting and retrieving a result for you. In short, it's not an API that's specifically designed to talk with your specific device.

I imagine you should call ser.read to read from the serial port.

• Yes, you are right. When I perform a read, I get only a couple of \x00, depending on how many bytes I request. But still I can't seem to establish a connection with the pump (for instance, ser.write("RUN\r" does not do anything) – MPA Dec 2 '14 at 15:39
• You might want to update the question with that information – Airuno2L Dec 2 '14 at 17:03
• @mpa, first thing's first, are you sure the RS232 parameters are correct? Second, do you have access to an oscilloscope? – Shahbaz Dec 3 '14 at 12:48
• @Shahbaz 1) I have no idea what parameters are used, PySerial handles those I think. 2) Yes I do, but I'm not sure if I can find one with RS232 connector. – MPA Dec 3 '14 at 14:20
• @mpa, the function arguments are your parameters: serial.Serial("/dev/ttyUSB0", baudrate=9600, bytesize=8, stopbits=2, timeout=1) so first make sure your baudrate, bytesize and stopbits are correct. – Shahbaz Dec 3 '14 at 17:00
1. First, ensure that your wiring is consistent with the wiring diagram on p. 24-25. I've seen similar "random" behavior when the grounds are not connected properly.

2. Before attempting to programmatically talk to the pump, try it manually. I use TeraTerm to talk to my Harvard 33 during testing - but any like terminal software will do (even Hyperterminal). First, check the pump's address (p. 16) - is it correct? If so, issue a "VER" command a few times. Note that the pump's Remote LED becomes illuminated once the pump chain command is established. If the LED does not illuminate, your serial commands will not work. If the VER command works, then move on to setting run modes. When I use the pump, I issue the following sequence before attempting to run the pump: PAR ON, MOD PRO, DIA A 26.600, DIR INF. A meaningful sequence of configuration commands is key: the pump has a bit of intelligence and will respond appropriately to erroneous and/or conflicting commands.

3. If the pumped responded positively to those commands, attempt to run the configured syringe: RAT A 1.0000 MM and then RUN. If that works, you can issue the stop command: STP.

4. If the pump checks out manually, then proceed to programmatic use. When doing so, take extra care to follow the formatting rules for rates, etc. The interpretation of the ffffff rate and diameter specifications is inflexible, and the rules must be followed exactly (see p.18 for example). Note that the pump also has a strict set of rules for command usage during operation (i.e. don't issue a DIA command while the pump is running). Likewise, note that the pump chain commands are ignored if the device is in SET mode (p. 16).

5. When looking for return characters, keep in mind how mind-boggling slow 9600 baud actually is. You'll likely have to set up a polling routine to handle the pump's response. As shown on p.16, the response should lead with a '\r' and end with a '\n'. For example: you might set up a loop to wait until the '\n' char is seen once a command has been issued.

6. Likewise, be prepared to parse and handle the pump's command responses: ?, NA, and OOR (p.20).

Good luck!

• Thanks for your answer, I will look into it when I got proper connectors for the pump. – MPA Dec 3 '14 at 19:51