Showing posts with label pySerial. Show all posts
Showing posts with label pySerial. Show all posts

Monday, April 6, 2015

Python auto detect Arduino connected serial port

This example TRY to detect Arduino Uno connected serial port automatically, such that no need to hard code "'ttyACM0", "'ttyACM1"... It run on both Python 2 and 3. I test it on Ubuntu Linux only. It's a trial experience only, not a complete solution.



PySerial (ref: http://pyserial.sourceforge.net/pyserial_api.html) provide a function serial.tools.list_ports.comports(), it return an iterable that yields tuples of three strings:
- port name as it can be passed to serial.Serial or serial.serial_for_url()
- description in human readable form
- sort of hardware ID. E.g. may contain VID:PID of USB-serial adapters.

Items are returned in no particular order. It may make sense to sort the items. Also note that the reported strings are different across platforms and operating systems, even for the same device.

To simplify, I assume the port name (eg. /dev/ttyACM0) is in the 1st item returned, and have not handle any other case.

As shown in the post "Get idVendor and idProduct of your Arduino/USB devices", we know VID:PID of Arduino Uno is 2341:0043. So we can compare it with what returned from serial.tools.list_ports.comports() to determine is it Arduino Uno. And for simplify also, I assume it's in VID:PID=2341:0043 format.

findUno.py
import serial.tools.list_ports
import sys
import atexit
import platform

print("=== Auto scan for Arduino Uno connected port===")
print("")
print(platform.system(), platform.release())
print(platform.dist())
print("Python version " + platform.python_version())
print("")

def findArduinoUnoPort():
    portList = list(serial.tools.list_ports.comports())
    for port in portList:
        if "VID:PID=2341:0043" in port[0]\
            or "VID:PID=2341:0043" in port[1]\
            or "VID:PID=2341:0043" in port[2]:
            print(port)
            print(port[0])
            print(port[1])
            print(port[2])

            #please note: it is not sure [0]
            #returned port[] is no particular order
            #so, may be [1], [2]
            return port[0]

def doAtExit():
    if serialUno.isOpen():
        serialUno.close()
        print("Close serial")
        print("serialUno.isOpen() = " + str(serialUno.isOpen()))

atexit.register(doAtExit)

unoPort = findArduinoUnoPort()
if not unoPort:
    print("No Arduino Uno found")
    sys.exit("No Arduino Uno found - Exit")

print("Arduino Uno found: " + unoPort)
print()

serialUno = serial.Serial(unoPort, 9600)
print("serialUno.isOpen() = " + str(serialUno.isOpen()))

while True:
    while (serialUno.inWaiting()==0):
        pass
    valueRead = serialUno.readline(500)
    print(valueRead)



In Arduino Uno side, just a simple program to repeatly call Serial.println() for testing.
AnalogInSerialOut.ino
const int analogIn = A0;
int analogVal = 0;

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

void loop() {

  analogVal = analogRead(analogIn);
  Serial.println(analogVal);
  delay(1000);
}

Thursday, April 2, 2015

Python to plot graph of serial data from Arduino Uno analog input

It's a simple example to read analog input from Arduino Uno, send to PC via USB serial. In the PC side, running Python on Linux, plot the received serial graphically using matplotlib and drawnow library.




Arduino side:


AnalogInSerialOut.ino
const int analogIn = A0;
int analogVal = 0;

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

void loop() {

  analogVal = analogRead(analogIn);
  Serial.println(analogVal);
  delay(1000);
}

PC side running Python 2.7.6, plotArduino.py. It's the example code run in the demo video.
import serial
import matplotlib.pyplot as plt
from drawnow import *

values = []

plt.ion()
cnt=0

serialArduino = serial.Serial('/dev/ttyACM0', 19200)

def plotValues():
    plt.title('Serial value from Arduino')
    plt.grid(True)
    plt.ylabel('Values')
    plt.plot(values, 'rx-', label='values')
    plt.legend(loc='upper right')

#pre-load dummy data
for i in range(0,26):
    values.append(0)
    
while True:
    while (serialArduino.inWaiting()==0):
        pass
    valueRead = serialArduino.readline()

    #check if valid value can be casted
    try:
        valueInInt = int(valueRead)
        print(valueInInt)
        if valueInInt <= 1024:
            if valueInInt >= 0:
                values.append(valueInInt)
                values.pop(0)
                drawnow(plotValues)
            else:
                print "Invalid! negative number"
        else:
            print "Invalid! too large"
    except ValueError:
        print "Invalid! cannot cast"
    



Modified version of plotArduino.py:
- It seem that 19200 baud is not stable in my unit, so change to 9600. (Have to modify Arduino side also)
- Add some line to indicate status.
- Add atexit handling.
- Make it work on both Python 2 and 3.

import serial
import matplotlib.pyplot as plt
from drawnow import *
import atexit

values = []

plt.ion()
cnt=0

serialArduino = serial.Serial('/dev/ttyACM0', 9600)

def plotValues():
    plt.title('Serial value from Arduino')
    plt.grid(True)
    plt.ylabel('Values')
    plt.plot(values, 'rx-', label='values')
    plt.legend(loc='upper right')

def doAtExit():
    serialArduino.close()
    print("Close serial")
    print("serialArduino.isOpen() = " + str(serialArduino.isOpen()))

atexit.register(doAtExit)

print("serialArduino.isOpen() = " + str(serialArduino.isOpen()))

#pre-load dummy data
for i in range(0,26):
    values.append(0)
    
while True:
    while (serialArduino.inWaiting()==0):
        pass
    print("readline()")
    valueRead = serialArduino.readline(500)

    #check if valid value can be casted
    try:
        valueInInt = int(valueRead)
        print(valueInInt)
        if valueInInt <= 1024:
            if valueInInt >= 0:
                values.append(valueInInt)
                values.pop(0)
                drawnow(plotValues)
            else:
                print("Invalid! negative number")
        else:
            print("Invalid! too large")
    except ValueError:
        print("Invalid! cannot cast")




To install matplotlib, drawnow and pyserial:

for Python 2
$ sudo apt-get install python-matplotlib
$ sudo apt-get install python-pip
$ sudo pip install drawnow
$ sudo pip install pyserial

for Python 3
$ sudo apt-get install python3-matplotlib
$ sudo apt-get install python3-pip
$ sudo pip3 install drawnow
$ sudo pip3 install pyserial


Updated@2017-06-17:
It's a similarity example without using drawnow, tested on Raspberry Pi and PC/Ubuntu 17.04/Python 3.6 ~ Python run on Raspberry Pi (and PC running Ubuntu) to plot serial data from ESP8266/NodeMCU


Tuesday, March 26, 2013

Control Arduino LED using Python with GUI

This example demonstrate how to control Arduino LED using Python with GUI, using tkinter library.


#tkinter for Python 3.x
#Tkinter for Python 2.x

import serial
import time
import tkinter

def quit():
    global tkTop
    tkTop.destroy()

def setCheckButtonText():
    if varCheckButton.get():
        varLabel.set("LED ON")
        ser.write(bytes('H', 'UTF-8'))
    else:
        varLabel.set("LED OFF")
        ser.write(bytes('L', 'UTF-8'))

ser = serial.Serial('/dev/ttyACM1', 9600)
print("Reset Arduino")
time.sleep(3)
ser.write(bytes('L', 'UTF-8'))

tkTop = tkinter.Tk()
tkTop.geometry('300x200')

varLabel = tkinter.StringVar()
tkLabel = tkinter.Label(textvariable=varLabel)
tkLabel.pack()

varCheckButton = tkinter.IntVar()
tkCheckButton = tkinter.Checkbutton(
    tkTop,
    text="Control Arduino LED",
    variable=varCheckButton,
    command=setCheckButtonText)
tkCheckButton.pack(anchor=tkinter.CENTER)

tkButtonQuit = tkinter.Button(
    tkTop,
    text="Quit",
    command=quit)
tkButtonQuit.pack()

tkinter.mainloop()

For the code in Arduino side, refer to the post "Communicate with Arduino in Python programmatically".

Thursday, March 21, 2013

Talk with Arduino Due in Python Shell

With pySerial installed, it's easy to communicate with Arduino board in Python Shell.

Connect Arduino Due with sketch of former post downloaded.

For Python 2.x, enter the commands in Python Shell to turn ON/OFF LED on Arduino Due Board

>>>import serial
>>>ser = serial.Serial('/dev/ttyACM0', 115200)
>>>ser.write('H')
>>>ser.write('L')


For Python 3.x, the String in write() have to be casted to bytes.

>>>import serial
>>>ser = serial.Serial('/dev/ttyACM0', 115200)
>>>ser.write(bytes('H', 'UTF-8'))
>>>ser.write(bytes('L', 'UTF-8'))





Related:


Install pySerial on Ubuntu

To check if pySerial installed, open Python Shell, type the command:

>>>import serial

if error message returned, means pySerial not installed.

pySerial not installed
pySerial not installed with error

- To install pySerial on Ubuntu, download and unpack pyserial, open Terminal and change to the unpacked folder.

- To install for Python 2.x, type the command:

$sudo python setup.py install


- To install for Python 3.x, type the command:

$sudo python3 setup.py install

(To install the module for all users on the system, administrator rights (root) is required, run with sudo.)


pySerial installed
import serial with pySerial installed