Skip to content

Interacting with the Real World

As we already know, Python is able to interact with tons of things. In this section, we will interact with tangible objects, and learn how to connect with sensors and actuators branched, or not, with the computer.

Better with interaction

Check this week’s code in gitlab code club repo

Serial

Serial communication is an standard asynchronous protocol for communication.

RS-232.jpeg
CC BY-SA 3.0, Enlace

RS232 are not that common anymore, but all your computers have at least one serial port, also known as… USB!.

Python comes with a library supporting serial communication. It’s called pyserial:

Installation

As usual, python packages are available through pip:

pip search pyserial
pyserial (3.4)            - Python Serial Port Extension
pip install pyserial

Usage

We can create a serial object by using:

import serial

ser = serial.Serial(PORT, BAUDRATE)

To check the PORT, in the terminal, we can use (sorry, only for MAC):

ls /dev/cu.*
/dev/cu.Bluetooth-Incoming-Port

Or we can use this function in python:

def serial_ports():
  """Lists serial ports

  :raises EnvironmentError:
    On unsupported or unknown platforms
  :returns:
    A list of available serial ports
  """
  if sys.platform.startswith('win'):
    ports = ['COM' + str(i + 1) for i in range(256)]

  elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
    # this is to exclude your current terminal "/dev/tty"
    ports = glob.glob('/dev/tty[A-Za-z]*')

  elif sys.platform.startswith('darwin'):
    ports = glob.glob('/dev/tty.*')

  else:
    raise EnvironmentError('Unsupported platform')

  result = []

  for port in ports:
    try:
      s = serial.Serial(port)
      s.close()
      result.append(port)
    except (OSError, serial.SerialException):
      pass
  return result

This will return a list of ports:

>>> ports = serial_ports()
>>> ports
['/dev/tty.Bluetooth-Incoming-Port', '/dev/tty.usbmodem1411']

If we take the first port, we can open it with a BAUDRATE of 115200:

ser = serial.Serial(ports[1], 115200)

Now, to read the serial, removing :

def ReadSerial(serial):

    return serial.readline().replace("\r\n", "")

Write to the serial

serial.write('Hello')

If now we continuosly read and print the input, we have a data logger!:

while True:
    timestamp = datetime.datetime.now()
    reading = ReadSerial(ser)
    #~ print reading
    #  Print it and flush standard output
    print "{},{}".format(timestamp,reading)
    sys.stdout.flush()

Terminal like a pro

Send the output of your program to a file with the output redirection >>:

python read_serial.py >> log.dat

Altogether:

#!/usr/bin/python

# Import packages
import serial
import datetime
import glob
import sys
from sys import stdout

# Numpy
import numpy as np

# I2C device definition
PORT = '/dev/cu.usbmodem1411'
BAUDRATE = 115200

def serial_ports():
    """Lists serial ports
    :raises EnvironmentError:
        On unsupported or unknown platforms
    :returns:
        A list of available serial ports
    """
    if sys.platform.startswith('win'):
        ports = ['COM' + str(i + 1) for i in range(256)]

    elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
        # this is to exclude your current terminal "/dev/tty"
        ports = glob.glob('/dev/tty[A-Za-z]*')

    elif sys.platform.startswith('darwin'):
        ports = glob.glob('/dev/tty.*')

    else:
        raise EnvironmentError('Unsupported platform')

    result = []

    for port in ports:
        try:
            s = serial.Serial(port)
            s.close()
            result.append(port)
        except (OSError, serial.SerialException):
            pass
    return result

def ReadSerial(serial):

    return serial.readline().replace("\r\n", "")

# Retrieve constants (ports, time, header)
ports = serial_ports()
ser = serial.Serial(ports[1], 115200)
# print (ser)

# Create header
print ("TIME, LIGHT")

# Create the reading
while True:
    timestamp = datetime.datetime.now()
    reading = ReadSerial(ser)
    #~ print reading
    #  Print it and flush standard output
    print "{},{}".format(timestamp,reading)
    sys.stdout.flush()