Nick Heiner
Nick Heiner

Reputation: 122600

Serial ports on Windows or Ubuntu VBox to talk to Arduino from Python

I have an Arduino microcontroller listening on COM3. Using the arduino IDE and the Serial monitor works fine to send and receive data.

I would like to send and receive data from Python, but it's not immediately obvious how to do so. (I'd also be fine doing it in C# if it was substantially easier.)

I found arduino_serial.py, but it only works for Unix. Fortunately, I have a Ubuntu 10.10 VBox set up. However, I have no idea if that VM can access serial ports or if special steps are required to do so.

I also found pySerial, which looks pretty legitimate. However, I'm also unsure how to use it. It wants serial port names. How do I find out what valid values for these are?

For example, pySerial mentions that you can "Open named port at “19200,8,N,1”, 1s timeout" with the following command:

>>> ser = serial.Serial('/dev/ttyS1', 19200, timeout=1)

But I have no idea how you would know that /dev/ttyS1 was a valid port name.

Is there good documentation for getting started on this?

Update: I'm using Ubuntu with arduino_serial, but still having trouble.

This program is running on the Arduino:

void setup() { 
  Serial.begin(9600);
}

void loop() { 
  if (Serial.available()) {
    Serial.print((char)Serial.read());
  }
}

I see that a port called tty0 is available:

foo@bar:~/baz$ dmesg | grep tty
[    0.000000] console [tty0] enabled

I then try to connect with arduino_serial:

foo@bar:~/baz$ sudo python
[sudo] password for foo: 
Python 2.6.6 (r266:84292, Sep 15 2010, 15:52:39) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import arduino_serial
>>> sp = arduino_serial.SerialPort("/dev/tty0", 9600)
>>> sp.write("foo")
>>> sp.read_until("\n")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "arduino_serial.py", line 107, in read_until
    n = os.read(self.fd, 1)
OSError: [Errno 11] Resource temporarily unavailable

Why am I getting this error? What am I doing wrong?

Upvotes: 4

Views: 10323

Answers (4)

whatnick
whatnick

Reputation: 5480

The serial ports are named COM1 onwards on Windows, /dev/ttyS0->COM1. I wrote some code in Python for our Quadcopter controller which works both on Windows and Linux (given you supply the port name properly) using Pyserial.

Try passing COM3 to Pyserial on Windows. On the VM you will have to first pass the USB-to-serial adapter to the VM or set up the serial ports section (I use VirtualBox). If you go the USB route the serial devices are enumerated under /dev/ttyUSBxx.

Upvotes: 2

Phil
Phil

Reputation: 6679

pySerial may or may not be built in to Python. Regardless, if it's not, pySerial is the library to download and install.

And since you already know the Arduino is on COM3, just use this:

import serial
ser = serial.Serial("COM3", 19200, timeout=1)
ser.write("Whatever")

For a Linux box, it's relatively easy to find out what serial port your Arduino is using:

dmesg | grep tty

This will give you some output similar to this: [ 7.944654] usb 1-1.6: FTDI USB Serial Device converter now attached to ttyUSB0

So my Arduino is on ttyUSB0. This means you can use the following code to talk to the Arduino on a Linux box:

import serial
ser = serial.Serial("/dev/ttyUSB0", 19200, timeout=1)
ser.write("Whatever")

Note: If you use a baud rate of 9600 on the Arduino, as most people do, you can simply use serial.Serial("COM3") or serial.Serial("/dev/ttyUSB0") without any other parameters.

EDIT: You should also keep in mind that in the real world, it may take a second to actually open the port and get it ready for transmitting data. This means that performing a write IMMEDIATELY after the serial.Serial() call may not actually do anything. So the code I would use is as follows:

import serial
import time
ser = serial.Serial("/dev/ttyUSB0", 19200, timeout=1)
time.sleep(1.5)
ser.write("Whatever")

Kind of a hack, but it's the only way I know how to get it to work on my system.

Upvotes: 4

detly
detly

Reputation: 30342

"But I have no idea how you would know that /dev/ttyS1 was a valid port name."

PySerial's serial port initialiser accepts a number instead of a name as an argument. These numbers will correspond to "normal" serial ports (/dev/ttySX on Linux, COMX on Windows). You can then get the name from the created object. There's no way to know in advance what numbers to try, though, so as you'll see in the following code, you just have to try and fail.

This won't always discover simulated ports (created using socat or com0com), or USB ports though, so for those you need to use the glob module (I don't think it makes a huge difference whether you use globbing or indices for the dev/ttySX device nodes). This is what pySerial's own examples do. The following code is adapted from those examples:

import glob, os

import serial

USB_SERIAL_GLOB = "/dev/ttyUSB*"

def try_open(port, args = (), kwargs = {}):
    try:
        port = serial.Serial(port, *args, **kwargs)
    except serial.SerialException:
        return None
    else:
        return port

def serial_scan(max_range = 32, args = (), kwargs = {}):
    for i in range(max_range):
        port = try_open(i, args, kwargs)
        if port is not None:
            yield port

    # Look for USB serial ports:     
    if os.name == 'posix':
        for fn in glob.glob(USB_SERIAL_GLOB):
            port = try_open(fn)
            if port is not None:
                yield port

if __name__ == "__main__":
    for port in serial_scan(kwargs = {'baudrate':9600, 'timeout':0.5}):
        port.close()
        print "Found: %s" % port.name

Upvotes: 0

nithins
nithins

Reputation: 3192

I have a project called Yaam on CodePlex that uses C# to send data through the serial port. Check that out for an example. On the C# side (see Yaam\Yaam.xaml.cs), simply use the SerialPort class in the System.IO.Ports namespace. Once you instantiate the object and set the properties (baud rate, com port, etc), simply call.Open() . There are also plenty of other examples on the web. Take a look at these:

Upvotes: 0

Related Questions