8

I have written some code to simulate some hardware I'm working with and uploaded it to the Arduino board. This code works. I know this, because I get the expected response from HyperTerminal.

However, when I try to connect using PySerial the connection does not error, but I get no response to the commands I send.

Why might this be?

Python code

import serial

def main():
    sp = serial.Serial()
    sp.port = 'COM4'
    sp.baudrate = 19200
    sp.parity = serial.PARITY_NONE
    sp.bytesize = serial.EIGHTBITS
    sp.stopbits = serial.STOPBITS_ONE
    sp.timeout = 0.5
    sp.xonxoff = False
    sp.rtscts = False
    sp.dsrdtr = False

    sp.open()

    sp.write("GV\r\n".encode('ascii'))
    value = sp.readline()
    print value
    sp.write("GI\r\n".encode('ascii'))
    value = sp.readline()
    print value

    sp.close()
 
if __name__ == "__main__":
    main()

NB: the code on the Arduino sends back \r\n at the end of a response to a command.

HyperTerminal configuration:

COM4 configuration in HyperTerminal

Edit

I have found that if I increase the timeout to 10 seconds and add a sp.readline() before I send anything, then I get responses to both commands.

How long is the hardware handshake usually between PySerial and an Arduino or USB RS-232 ports?

1
  • One small comment about sending commands to a REPL (command processor) as is being done here. I notice the commands you are sending are terminated with \r\n. Although regular text lines are typically terminated \r\n, Sent commands are usually only terminated by the single character \r, as they would be typed in by a human user. If the \n is sent, it might be interpreted as the start of the next command and potentially hang or trigger other spurious undesirable results. Commented Oct 22, 2018 at 15:17

5 Answers 5

5

Can not verify this but it could be that you try and read before there is any data there, thus you get no reply back.

To test this you could try and poll until there is data

value = None
while not value:
   value = sp.readline()
print value

Edit

The Arduino will reset when you open a serial connection, any data written during bootup will likely go to bit heaven. You could use a sleep for 2 seconds (could not find the exact time it takes, will likely vary anyway) before you do any reads/writes.

Alternatively you could write to it until you get a response back, after you get a return you start doing "real work".

Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately, readline returns an empty string after a timeout. This is not working for me. I tried waiting for a non-empty string, but that just resulted in an infinite loop.
Ah too bad, have you tried a basic arduino test that just spams Serial.println to see if you are able to get any output at all?
Yes, I can get output. Initially I could get it only through HyperTerminal, but I have found that the issue is a delay between connecting and being able to send/receive data. I've updated the question. Thanks for your help so far.
3

For the time being I am using a workaround. I have set the timeout to 1.5 seconds and put a readline call in before the first write.

So now the Python code looks like:

import serial

def main():
    sp = serial.Serial()
    sp.port = 'COM4'
    sp.baudrate = 19200
    sp.parity = serial.PARITY_NONE
    sp.bytesize = serial.EIGHTBITS
    sp.stopbits = serial.STOPBITS_ONE
    sp.timeout = 1.5 #1.5 to give the hardware handshake time to happen
    sp.xonxoff = False
    sp.rtscts = False
    sp.dsrdtr = False

    sp.open()

    sp.readline() #to give the hardware handshake time to happen

    sp.write("GV\r\n".encode('ascii'))
    value = sp.readline()
    print value
    sp.write("GI\r\n".encode('ascii'))
    value = sp.readline()
    print value

    sp.close()

if __name__ == "__main__":
    main()

2 Comments

I didn't understand why this is required but adding a readline() before in front of write worked also for me.
@wizofwor it's not required, as such, it's just a convenient way to make the software wait for the hardware to be ready.
2

I've also encountered this problem recently and here's my solution:

import serial

ser = serial.Serial(4, timeout=2)
ser.setRTS(True)
ser.setRTS(False)
while 1:
    line = ser.readline()
    print(line)
ser.close

Turns out this will successfully reset the Arduino board.

Comments

2

Add a delay after you open the port as Arduino is reset and the bootloader starts listening for new firmware. If something is sent at that moment, the MCU remains stuck in bootloader. The delay causes the bootloader to timeout.

sp.open()
time.sleep(2) # 2 seconds or possibly a bit less
sp.write("blahblah")

Comments

0

You can easily and robustly connect and communicate between Python and Arduino boards using the compatible libraries SerialTransfer.h and pySerialTransfer. These libraries automatically packetize and parse serial packets using start/end markers, cyclic redundancy checking, consistent overhead byte stuffing, and dynamic payload lengths.

SerialTransfer.h is installable through the Arduino IDE's Libraries Manager and pySerialTrasnfer is pip-installable.

Example Python:

from pySerialTransfer import pySerialTransfer as txfer

if __name__ == '__main__':
    try:
        link = txfer.SerialTransfer('COM13')

        link.txBuff[0] = 'h'
        link.txBuff[1] = 'i'
        link.txBuff[2] = '\n'

        link.send(3)

        while not link.available():
            if link.status < 0:
                print('ERROR: {}'.format(link.status))

        print('Response received:')

        response = ''
        for index in range(link.bytesRead):
            response += chr(link.rxBuff[index])

        print(response)
        link.close()

    except KeyboardInterrupt:
        link.close()

Example Arduino:

#include "SerialTransfer.h"
#include <SoftwareSerial.h>


SoftwareSerial mySerial(2, 3); // RX, TX
SerialTransfer myTransfer;


void setup()
{
  Serial.begin(115200);
  mySerial.begin(9600);
  myTransfer.begin(mySerial);
}

void loop()
{
  myTransfer.txBuff[0] = 'h';
  myTransfer.txBuff[1] = 'i';
  myTransfer.txBuff[2] = '\n';

  myTransfer.sendData(3);
  delay(100);

  if(myTransfer.available())
  {
    Serial.println("New Data");
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      Serial.write(myTransfer.rxBuff[i]);
    Serial.println();
  }
  else if(myTransfer.status < 0)
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.