Interfacing Python and Arduino
Arduino is a physical computing platform, supported by an assortment of microcontroller boards, such as the Diecimila. Since it's an open specification, one could make their own board by hand if desired. Let's look at scripting an Arduino board with Python.
Python is a general-purpose high-level programming language, drawing from the object-oriented, imperative, and functional paradigms, and featuring strong duck typing. It provides built-in data structures like lists, tuples, and dictionaries, a classical object system, and very clean syntax. While functions are first-class citizens, they lack the flexibility of function literals in Lisp, JavaScript, and Ruby (lambdas can only include a single line, or else must be named). It's a very fine language, and particularly noteworthy for its extensive standard library.
Python can easily talk to an Arduino board over a serial interface. While serial devices can be read from and written to like files on Unix-like systems, the pySerial wrapper makes this easier across operating systems.
Let's try reading some data:
>>> import serial
>>> arduino = serial.Serial('/dev/tty.usbserial', 9600)
>>> while 1:
... arduino.readline()
'1 Hello world!\r\n'
'2 Hello world!\r\n'
'3 Hello world!\r\n'
And writing:
>>> ser.write('5')
Let's write an Arduino-specific class.
#!/usr/bin/env python# Arduino
# Maxwell Terry
# MIT license import sys, os, time, serialclass Arduino: connection = None def __init__(self, path):
self.connection = serial.Serial(path, 9600)
pass def __del__(self):
self.connection.close()
pass def isOpen(self):
return self.connection.isOpen() def readLine(self):
if self.isOpen():
if self.connection.inWaiting() > 0:
return self.connection.readLine()
else:
print "---"
else:
return None
pass def writeLine(self, line):
if self.isOpen():
for i in range(0, len(line)):
self.connection.write(line[i])
time.sleep(0.1) def flush(self):
self.connection.flushInput()
self.connection.flushOutput() def readPin(self, pin, line):
self.flush()
self.writeLine(line + str(pin))
result = self.readLine()
result = result[result.find("Value: ")+7:result.find("Value: ")+10]
if result[2] == '-':
result = result[:1]
return result def setPin(self, pin, value):
self.writeLine("S1" + str(pin) + str(value))
return True
If you're already familiar with Python, this should be pretty straightforward. Feedback and comments welcome. I'm going to elaborate on the implementation, to serve as a general introduction to Python (assuming one has reasonable experience with other high-level languages).
First notice that with Python, nesting is denoted with indentation rather than braces (C-style languages) or parentheses (Lisp). We start out with the connection instance variable, which is defaulted to None. [1] Python requires one to explicitly pass around the current object, done with the self parameter. [2] __init__ and __del__ are special methods, called on initialization and deletion, allowing one to add polymorphism to built-in operators. [3] Here the methods open and close the serial connection.
isOpen tests whether a connection is open, which is used by readLine and writeLine to determine if the board can be read from or written to, and does so if possible. flush clears the input and output, while readPin and setPin respectively read and write to a given pin.
Obviously, this is only a minimal wrapper over pySerial. We don't need it, but these convenience methods make actions more clear and easier both to debug and extend.
1. Python's None is equivalent to JavaScript's null or Arc's nil.
example = function() { this.method = function(x) {
return x
} this.property = 1 return this}