python to arduino serial read & write

135,811

Solution 1

You shouldn't be closing the serial port in Python between writing and reading. There is a chance that the port is still closed when the Arduino responds, in which case the data will be lost.

while running:  
    # Serial write section
    setTempCar1 = 63
    setTempCar2 = 37
    setTemp1 = str(setTempCar1)
    setTemp2 = str(setTempCar2)
    print ("Python value sent: ")
    print (setTemp1)
    ard.write(setTemp1)
    time.sleep(6) # with the port open, the response will be buffered 
                  # so wait a bit longer for response here

    # Serial read section
    msg = ard.read(ard.inWaiting()) # read everything in the input buffer
    print ("Message from arduino: ")
    print (msg)

The Python Serial.read function only returns a single byte by default, so you need to either call it in a loop or wait for the data to be transmitted and then read the whole buffer.

On the Arduino side, you should consider what happens in your loop function when no data is available.

void loop()
{
  // serial read section
  while (Serial.available()) // this will be skipped if no data present, leading to
                             // the code sitting in the delay function below
  {
    delay(30);  //delay to allow buffer to fill 
    if (Serial.available() >0)
    {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    }
  }

Instead, wait at the start of the loop function until data arrives:

void loop()
{
  while (!Serial.available()) {} // wait for data to arrive
  // serial read section
  while (Serial.available())
  {
    // continue as before

EDIT 2

Here's what I get when interfacing with your Arduino app from Python:

>>> import serial
>>> s = serial.Serial('/dev/tty.usbmodem1411', 9600, timeout=5)
>>> s.write('2')
1
>>> s.readline()
'Arduino received: 2\r\n'

So that seems to be working fine.

In testing your Python script, it seems the problem is that the Arduino resets when you open the serial port (at least my Uno does), so you need to wait a few seconds for it to start up. You are also only reading a single line for the response, so I've fixed that in the code below also:

#!/usr/bin/python
import serial
import syslog
import time

#The following line is for serial over GPIO
port = '/dev/tty.usbmodem1411' # note I'm using Mac OS-X


ard = serial.Serial(port,9600,timeout=5)
time.sleep(2) # wait for Arduino

i = 0

while (i < 4):
    # Serial write section

    setTempCar1 = 63
    setTempCar2 = 37
    ard.flush()
    setTemp1 = str(setTempCar1)
    setTemp2 = str(setTempCar2)
    print ("Python value sent: ")
    print (setTemp1)
    ard.write(setTemp1)
    time.sleep(1) # I shortened this to match the new value in your Arduino code

    # Serial read section
    msg = ard.read(ard.inWaiting()) # read all characters in buffer
    print ("Message from arduino: ")
    print (msg)
    i = i + 1
else:
    print "Exiting"
exit()

Here's the output of the above now:

$ python ardser.py
Python value sent:
63
Message from arduino:
Arduino received: 63
Arduino sends: 1


Python value sent:
63
Message from arduino:
Arduino received: 63
Arduino sends: 1


Python value sent:
63
Message from arduino:
Arduino received: 63
Arduino sends: 1


Python value sent:
63
Message from arduino:
Arduino received: 63
Arduino sends: 1


Exiting

Solution 2

First you have to install a module call Serial. To do that go to the folder call Scripts which is located in python installed folder. If you are using Python 3 version it's normally located in location below,

C:\Python34\Scripts  

Once you open that folder right click on that folder with shift key. Then click on 'open command window here'. After that cmd will pop up. Write the below code in that cmd window,

pip install PySerial

and press enter.after that PySerial module will be installed. Remember to install the module u must have an INTERNET connection.


after successfully installed the module open python IDLE and write down the bellow code and run it.

import serial
# "COM11" is the port that your Arduino board is connected.set it to port that your are using        
ser = serial.Serial("COM11", 9600)
while True:
    cc=str(ser.readline())
    print(cc[2:][:-5])   

Solution 3

I found it is better to use the command Serial.readString() to replace the Serial.read() to obtain the continuous I/O for Arduino.

Share:
135,811

Related videos on Youtube

Boombrewer
Author by

Boombrewer

Updated on April 09, 2020

Comments

  • Boombrewer
    Boombrewer about 4 years

    I'm trying to "ping pong" info back and forth between some python code and arduino code. I want to send two setpoints to the arduino code periodically (for instance on the minute), read them on arduino & update variables then send status info from arduino back to python periodically (such as on the :30 second). Eventually python will be sending and pulling info from a mySQL db (later dev).

    Right now I can't get the info to bounce back and forth reliably. I haven't found anything close to this in the searches and everything I've tried to modify isn't working. Closest I have is this (and it doesn't actually switch back and forth between send and receive):

    Python

    #!/usr/bin/python
    import serial
    import syslog
    import time
    
    #The following line is for serial over GPIO
    port = '/dev/ttyS0'
    
    
    ard = serial.Serial(port,9600,timeout=5)
    
    i = 0
    
    while (i < 4):
        # Serial write section
    
        setTempCar1 = 63
        setTempCar2 = 37
        ard.flush()
        setTemp1 = str(setTempCar1)
        setTemp2 = str(setTempCar2)
        print ("Python value sent: ")
        print (setTemp1)
        ard.write(setTemp1)
        time.sleep(4)
    
        # Serial read section
        msg = ard.readline()
        print ("Message from arduino: ")
        print (msg)
        i = i + 1
    else:
        print "Exiting"
    exit()
    

    Arduino:

    // Serial test script
    
    int setPoint = 55;
    String readString;
    
    void setup()
    {
    
      Serial.begin(9600);  // initialize serial communications at 9600 bps
    
    }
    
    void loop()
    {
      while(!Serial.available()) {}
      // serial read section
      while (Serial.available())
      {
        if (Serial.available() >0)
        {
          char c = Serial.read();  //gets one byte from serial buffer
          readString += c; //makes the string readString
        }
      }
    
      if (readString.length() >0)
      {
        Serial.print("Arduino received: ");  
        Serial.println(readString); //see what was received
      }
    
      delay(500);
    
      // serial write section
    
      char ard_sends = '1';
      Serial.print("Arduino sends: ");
      Serial.println(ard_sends);
      Serial.print("\n");
      Serial.flush();
    }
    

    All I end up getting is the same values repeated (not what was actually sent, not sure if its a string or byte issue) and nothing back to the python script. Any help or ideas are greatly appreciated. Thanks.

    EDIT: Modified code to what I'm currently running as suggested below. Arduino is receiving fine and serial communication verified by minicom. But python script still prints a blank line after "Message from arduino: ".

    • Peter Gibson
      Peter Gibson almost 10 years
      Why do you close the serial port in python in between reads & writes?
    • Boombrewer
      Boombrewer almost 10 years
      I was using that method in an attempt to force swapping the read and write. I had read about doing that instead of flush on one of the forums.
    • Kostas
      Kostas almost 6 years
      I get the error 'serial' has no attribute 'Serial', when trying to run it on windows. Do you know what's wrong?
  • Boombrewer
    Boombrewer almost 10 years
    I modified the code per your suggestion and it works better but I'm still not receiving anything from arduino. I've extended the delay all the way to 30 seconds waiting for buffer but still nothing.
  • Boombrewer
    Boombrewer almost 10 years
    I get a blank line in terminal after "Message from arduino:" and the serial monitor on the Arduino IDE shows its sending and the readstring is growing with every read.
  • Peter Gibson
    Peter Gibson almost 10 years
    Have you confirmed that you're able to receive data from the Arduino outside of Python? In hyperterm or miniterm.py say?
  • Boombrewer
    Boombrewer almost 10 years
    No, I'm not familiar with how to do that. I'll have to google it and try to troubleshoot that way.
  • Peter Gibson
    Peter Gibson almost 10 years
    @user3681836 just open up a serial terminal program (miniterm.py is a good one you should already have installed if you're using python on linux), type something in and see what comes back. Get the Arduino side working in this fashion first, then worry about the Python integration. You may want to enable local echo of typed characters in miniterm.py with <Ctrl-T><Ctrl-E> so that you can see what you're typing in.
  • Boombrewer
    Boombrewer almost 10 years
    I used minicom and the serial communication is definitely going both ways. Although I had to change the arduino code from byte ard_sends = 1; to char ard_sends = '1'; Then it worked fine in minicom and the serial monitor in the arduino IDE. However, my python code is still having the same problem and just printing a blank line as the "Message from arduino:".
  • Boombrewer
    Boombrewer almost 10 years
    I've even tried several other answers found on here about reading serial data (such as with if statements, arrays, etc) with python and can't seem to find a solution. Thanks for the help by the way.
  • Peter Gibson
    Peter Gibson almost 10 years
    @user3681836 see my latest edits, I've tested it on my own Arduino Uno and I think you should be okay now
  • Boombrewer
    Boombrewer almost 10 years
    Thanks Peter! I'm still getting the same blank line result but I'm contacting Wyolum to see if maybe my alamode has an issue. I can't seem to figure out why it wouldn't be working for me when its clearly working for you (only difference is the port assignment).