Introduction: Pyduino, Interfacing Arduino With Python Through Serial Communication

About: Sometimes a bot, always pythonic

Learn how to interface arduino through serial communication with python using the pyduino library. There are few other tutorials out there on instructables on how to interface arduino with python but they don't show you how to do everything, where hopefully this tutorial will give you a foundation for creating more advanced arduino projects with the pyduino library. For a basic overview on how serial communication works between arduino and python check out http://playground.arduino.cc/interfacing/python. Before we begin let me inform you on some of the limitations that python has when creating arduino projects. Python does not create arduino sketches, nor are you going to be uploading more than 1 sketch to your board this entire time. Instead, python is going to be sending small strings (only a few chars) to our arduino board, our arduino board will have a preloaded sketch associated with the pyduino library to interpret our small message then perform said task.


Requirements:

Arduino Uno

1 LED

1 Photoresistor

1 10k ohm Resistor

1 Resistor, anything between 220 ohm and 1k ohm

Wires

Breadboard

Arduino USB cable

Computer

Python Dependencies:

Python

pySerial ( $pip install pyserial )

pyduino library ( will be supplied in tutorial )


Steps:

Create our arduino circuit

Set up the Pyduino Library

Set up our arduino sketch

Create our first blinking pyduino script

Step 1: Setting Up the Arduino Circuit

Once you have all your materials and dependencies situated its time to make our arduino circuit. Follow the diagram above. We are going to create the same circuit that is in the arduino blink example (http://arduino.cc/en/tutorial/blink).

Make sure that your arduino is connected to your computer via USB.

Step 2: Setting Up the Pyduino Library

Save the piece of code below to a file named pyduino.py

This piece of code will send a serial message instruction to our arduino. The arduino will then interpret the instruction and perform said task. These serial messages are only a few characters. The pyduino library must be paired with an arduino sketch on the next step in order for it to work.

This library only supports a few of the functions that the arduino has.

set_pin_mode(pin_number, mode) == pinMode(led, OUTPUT);

digital_write(pin_number, digital_value) == digitalWrite(led, HIGH);

digital_read(pin_number) == digitalRead(pin);

analog_read(pin_number) == analogRead(pin);

analog_write(pin_number, analog_value) == analogWrite(pin, value);

Take a look at the source code below to see exactly how it works. The python code will connect to the arduino when you first initialize an instance of the Arduino class. Afterwords the class has various functions where it will generate a small message that we'll send to our arduino.

"""
A library to interface Arduino through serial connection """ import serial

class Arduino(): """ Models an Arduino connection """

def __init__(self, serial_port='/dev/ttyACM0', baud_rate=9600, read_timeout=5): """ Initializes the serial connection to the Arduino board """ self.conn = serial.Serial(serial_port, baud_rate) self.conn.timeout = read_timeout # Timeout for readline()

def set_pin_mode(self, pin_number, mode): """ Performs a pinMode() operation on pin_number Internally sends b'M{mode}{pin_number} where mode could be: - I for INPUT - O for OUTPUT - P for INPUT_PULLUP MO13 """ command = (''.join(('M',mode,str(pin_number)))).encode() #print 'set_pin_mode =',command,(''.join(('M',mode,str(pin_number)))) self.conn.write(command)

def digital_read(self, pin_number): """ Performs a digital read on pin_number and returns the value (1 or 0) Internally sends b'RD{pin_number}' over the serial connection """ command = (''.join(('RD', str(pin_number)))).encode() self.conn.write(command) line_received = self.conn.readline().decode().strip() header, value = line_received.split(':') # e.g. D13:1 if header == ('D'+ str(pin_number)): # If header matches return int(value)

def digital_write(self, pin_number, digital_value): """ Writes the digital_value on pin_number Internally sends b'WD{pin_number}:{digital_value}' over the serial connection """ command = (''.join(('WD', str(pin_number), ':', str(digital_value)))).encode() self.conn.write(command) def analog_read(self, pin_number): """ Performs an analog read on pin_number and returns the value (0 to 1023) Internally sends b'RA{pin_number}' over the serial connection """ command = (''.join(('RA', str(pin_number)))).encode() self.conn.write(command) line_received = self.conn.readline().decode().strip() header, value = line_received.split(':') # e.g. A4:1 if header == ('A'+ str(pin_number)): # If header matches return int(value)

def analog_write(self, pin_number, analog_value): """ Writes the analog value (0 to 255) on pin_number Internally sends b'WA{pin_number}:{analog_value}' over the serial connection """ command = (''.join(('WA', str(pin_number), ':', str(analog_value)))).encode() self.conn.write(command)

def close(self): """ To ensure we are properly closing our connection to the Arduino device. """ self.conn.close() print 'Connection to Arduino closed'

Step 3: Arduino Sketch for Pyduino

Inorder to control the arduino with python we have to send the arduino small pieces of code one at a time through the serial port on our computer. How does the arduino then interpret that message? The code below tells us how.

Copy and paste the code into your arduino software and upload it to your arduino device.

When you do that you should get an image that looks like the one above. At the very bottom right of the window you'll notice some information about where the arduino is located, save that information we'll need it for our python code.

/*
* Sketch to control the pins of Arduino via serial interface * * Commands implemented with examples: * * - RD13 -> Reads the Digital input at pin 13 * - RA4 - > Reads the Analog input at pin 4 * - WD13:1 -> Writes 1 (HIGH) to digital output pin 13 * - WA6:125 -> Writes 125 to analog output pin 6 (PWM) */

char operation; // Holds operation (R, W, ...) char mode; // Holds the mode (D, A) int pin_number; // Holds the pin number int digital_value; // Holds the digital value int analog_value; // Holds the analog value int value_to_write; // Holds the value that we want to write int wait_for_transmission = 5; // Delay in ms in order to receive the serial data

void set_pin_mode(int pin_number, char mode){ /* * Performs a pinMode() operation depending on the value of the parameter * mode : * - I: Sets the mode to INPUT * - O: Sets the mode to OUTPUT * - P: Sets the mode to INPUT_PULLUP */

switch (mode){ case 'I': pinMode(pin_number, INPUT); break; case 'O': pinMode(pin_number, OUTPUT); break; case 'P': pinMode(pin_number, INPUT_PULLUP); break; } }

void digital_read(int pin_number){ /* * Performs a digital read on pin_number and returns the value read to serial * in this format: D{pin_number}:{value}\n where value can be 0 or 1 */

digital_value = digitalRead(pin_number); Serial.print('D'); Serial.print(pin_number); Serial.print(':'); Serial.println(digital_value); // Adds a trailing \n }

void analog_read(int pin_number){ /* * Performs an analog read on pin_number and returns the value read to serial * in this format: A{pin_number}:{value}\n where value ranges from 0 to 1023 */

analog_value = analogRead(pin_number); Serial.print('A'); Serial.print(pin_number); Serial.print(':'); Serial.println(analog_value); // Adds a trailing \n }

void digital_write(int pin_number, int digital_value){ /* * Performs a digital write on pin_number with the digital_value * The value must be 1 or 0 */ digitalWrite(pin_number, digital_value); }

void analog_write(int pin_number, int analog_value){ /* * Performs an analog write on pin_number with the analog_value * The value must be range from 0 to 255 */ analogWrite(pin_number, analog_value); }

void setup() { Serial.begin(9600); // Serial Port at 9600 baud Serial.setTimeout(100); // Instead of the default 1000ms, in order // to speed up the Serial.parseInt() }

void loop() { // Check if characters available in the buffer if (Serial.available() > 0) { operation = Serial.read(); delay(wait_for_transmission); // If not delayed, second character is not correctly read mode = Serial.read(); pin_number = Serial.parseInt(); // Waits for an int to be transmitted if (Serial.read()==':'){ value_to_write = Serial.parseInt(); // Collects the value to be written } switch (operation){ case 'R': // Read operation, e.g. RD12, RA4 if (mode == 'D'){ // Digital read digital_read(pin_number); } else if (mode == 'A'){ // Analog read analog_read(pin_number); } else { break; // Unexpected mode } break;

case 'W': // Write operation, e.g. WD3:1, WA8:255 if (mode == 'D'){ // Digital write digital_write(pin_number, value_to_write); } else if (mode == 'A'){ // Analog write analog_write(pin_number, value_to_write); } else { break; // Unexpected mode } break;

case 'M': // Pin mode, e.g. MI3, MO3, MP3 set_pin_mode(pin_number, mode); // Mode contains I, O or P (INPUT, OUTPUT or PULLUP_INPUT) break;

default: // Unexpected char break; } } }

Step 4: Setting Up Our Python Code

Now we will set up a basic LED blink program in python with our new arduino interfacing library. Make sure you save the piece of code below in the same directory as where you saved the pyduino library to.

Our code will look like something below. Once you run it through the terminal you should hopefully get something that looks like the video above.

from pyduino import *
import time

if __name__ == '__main__': a = Arduino() # if your arduino was running on a serial port other than '/dev/ttyACM0/' # declare: a = Arduino(serial_port='/dev/ttyXXXX')

time.sleep(3) # sleep to ensure ample time for computer to make serial connection

PIN = 13 a.set_pin_mode(PIN,'O') # initialize the digital pin as output

time.sleep(1) # allow time to make connection

for i in range(0,1000): if i%2 == 0: a.digital_write(PIN,1) # turn LED on else: a.digital_write(PIN,0) # turn LED off

time.sleep(1)