Python talks to the Arduino…

Sort of a followup to my previous post ‘Arduino talks to Processing, Python…‘, I thought I’d try going the other way:  Send commands to the Arduino from Python over the serial port.

My son and I recently soldered together a lolshield (‘lots of LEDs’) for the Arduino.  The ultimate goal for this is to have Python, via Pygame (most likely) run graphics on the lolshield as if it was a mini-flatscreen.  But first I need to get something sent from Python to Arduino, and this was surprisingly hard.

First, the internets came to my aid and I got some sample code allowing the Arduino to read a single character from the serial port, and blink an LED that number of times.  The source was by Tod E. Kurt, and I got it off his  page here.  My modified version is below (modified mainly with docs so I could understand what’s going on…)

// Arduino Code:
// Below, 'character' types are defined:  They hold 1 byte of data, 256 values.
// A char can be interpreted as a small number (0-255) or as a member of the
// ASCII set (which is what we deal with below).  Characters expressed as
// ASCII are surrounded in single-quotes, like '5'.
// Thus each char has a corresponding numeric value can thus be tested against.

int ledPin = 13;   // select the pin for the LED
int val = 0;       // variable to store the data from the serial port

void setup() {
 pinMode(ledPin,OUTPUT);    // declare the LED's pin as output
 Serial.begin(9600);        // connect to the serial port
}

void loop () {
  if (Serial.available()) {
    // For the below examples, let's pretend that the passed-in serial 
    // value is character '5'.
    // Since the declared variable val is an int, it converts the char 
    // value passed in into an int.
    // If char val = '5', the numeric representation is 53.
    val = Serial.read();      // read the serial port

    // If the stored value is a single-digit number, blink the LED 
    // that number of times.
    // Here we compare the int value of val against the int values 
    // of the string.
    // Characters '0' and '9' are equivalent to integer 48 and 57.
    if (val > '0' && val <= '9' ) {
      Serial.println(val);
      // Convert from char to int:
      // From above, int conversion of val, which is char '5', is 53.
      // int conversion of char '0' is 48.
      // 53-48 = 5  : blink that # of times
      val = val - '0';  
      for(int i=0; i<val; i++) {
        Serial.println("blink!");
        digitalWrite(ledPin,HIGH);
        delay(150);
        digitalWrite(ledPin, LOW);
        delay(150);
      }
    }
  }
}

Now for the Python stuff.  On the ‘Arduino: Playground‘ site, I found this example Python code using the pySerial libary:

>>> import serial # if you have not already done so
>>> ser = serial.Serial('/dev/tty.usbserial', 9600)
>>> ser.write('5')

And it works, presuming you’re in the interactive Python shell.  If however you try to make a module out of the same code and execute it, it will fail:  No multi-blinking LED.  After researching several posts of other people that had similar issue (here, here, here, and here) I tracked down the main culprit:  When you make a connection to the serial port via Python, it sends a reset command to the Arduino. If you immediately send your data to the port immediately after, the Arduino won’t be initialized and ready to receive it.  To solve this, we simply pause the module for a bit while the Arduino does its thing:

# simpleSerialSend.py
import sys
import serial
import time
PORT = 'COM4' # The port my Arduino is on, on my WinXP box.

def main(val=5):
    # Open a connection to the serial port.  This will reset the Arduino, and
    # make the LED flash once:
    ser = serial.Serial(PORT)

    # Must given Arduino time to rest.
    # Any time less than this does not seem to work...
    time.sleep(1.5)

    # Now we can start sending data to it:
    written = ser.write(val)
    ser.close()
    print "Bytes Written to port:", written
    print "Value written to port: '%s'"%val

if __name__ == '__main__':
    args = sys.argv
    try:
        main(args[1])
    except IndexError:
        main()

This module can now be ran from the command prompt, and you can optionally pass in (from 0->9) the number of times you want the LED to blink:

c:\pyModules\simpleSerialSend.py 5

When this runs, you’ll see the LED blink once when the reset happens, a 1.5 second pause, and then the LED will blink 5 times.

What’s interesting is I tried this same thing with Processing, and failed, and I presume for the same reason:  The Processing sketch was executing too fast to allow the Arduino time to warm up.  And, there doesn’t seem to be a ‘pauses \ sleep \ wait’ function in Processing.  I tried using java.lang.Thread, but it didn’t seem to pause the sketch until it was done running.  So I need to do some more research there.  Had I got that working, then the title of this blog post would probably be different 😉

verletCloth01
Python lolshield graphics
    • project
    • April 1st, 2011 5:03pm

    I love you !! finally i got it to work !!!!!!!!

    • mahendar
    • September 15th, 2011 11:28pm

    is it possible to run this script on an android phone?? what modifications need to be done?

    • Tim
    • December 29th, 2011 4:11pm

    A note about cancelling the reset – you can cut the RESET_EN trace on the Arduino or use a resistor between RESET and 3.3v or 5v… I’m using a 47Ω resistor between 3.3 and RESET, and that stops the arduino from being reset by the incoming connection. You have to remove the resistor to program the device, though.

    Tim

  1. Cool, good to know.

    • Alex Wallar
    • April 23rd, 2012 5:36pm

    I have been looking over your code and it is a very nice tutorial. I have just found one problem, your simpleSerialSend code is a bit confusing. There is no real need for it because when you are programming, you can simply import serial and do all of the commands that you would use from the terminal. Thank you for your post

  2. You are correct, and the middle block of code is an example of that: If you’re in the shell, this is unneeded. But the post is an example of what you need to do when you’re *not* in a shell: The above problems arise.

    • Alex Wallar
    • April 28th, 2012 5:46pm

    The problems you are depicting, I have not encountered. I open the serial port in the beginning of the code and write to it every iteration (it is a kinect based application so it iterates at around 20fps) and then I close it once the iteration ends.

    • Leandro Castilho
    • October 6th, 2012 2:32pm

    Very good information. I was having a problem to make it work, now I got, but I have to put (val = ‘5’).

    Best Regards!

    • Andrea
    • June 19th, 2014 7:56am

    I needed a 2 second delay (Windows 7), 1.5 did not work at all for me.
    Thanks for the tutorial!

    • Brian
    • October 7th, 2014 1:00pm

    Thanks— after struggling for 2 days with this issue and nearing madness because it worked fine in interactive mode but failed as a run script , It seemed to be some sort of timing issue but I couldn’t nail it down Using your solution as a starting point I finally had success! The only additional problem I had was after the script had completed, the Arduino reset again!! Am trying to find out more about the reset issue that won’t require a hardware fix! Thanks again for your work.

    • janab
    • October 31st, 2015 12:55pm

    Dear Akeric,
    i want to send signal on arduino pins say pin 10 and pin 11 kindly guide me that how i code on arduino to read for two signals for pin 10 and pin 11.
    And how can i code for that on python.
    For example if x>y then led on pin 10 of arduino will glow & if y>x then led on pin 11 of arduino will glow. please help.
    Also tell is it important that i add libirary pyserial in arduino tool option?

  1. June 1st, 2013