0

I'm trying to write a little sensor reading application with a light sensor attached to an Arduino, which writes the information from the sensor over serial. I have written a python program to read the data from the serial port. The good news, is that my program is working completely fine... only if I make sure that the Arduino USB is connected to my laptop before I launch my Python program.

I have myself forgotten to connect the Arduino before running the program before, which can leave it hanging... until you realise and plug the Arduino back in. It would be nice to have a window helping users if they ever make the same mistake.

Here is the Arduino sketch I have running on my Arduino.

int photoTran = A1; 
  int reading = 0;

void setup() {
  pinMode(photoTran, INPUT);
  Serial.begin(9600); 
}

void loop() {
  // We just read the value on the analogPin
  reading = analogRead(photoTran); 
  Serial.println(reading); 
  delay(100); 

}  

Here is the little catcher part of the Python script which checks whether the Arduino is connected before I get into the main part of my application. When I plug in the Arduino before running the Python script, it can still sometimes take a few attempts before connecting. (Just FYI: the window(), button, values, variables are from the PySimpleGUI framework that I'm using.)

connected = False
while connected == False:
    button, values = window.Read(timeout=300)
    if button in (None, 'Exit'):
        break
    try:
        print("Attempting to connect")
        SER = serial.Serial(serial_port, baud_rate, timeout=0.1)
        connected = True
        ser.append(SER)
    except:
        time.sleep(0.1)
        attempts += 1
        window.FindElement('attempts').Update(attempts)
window.close()

# User exited from the GUI connection window
if not connected:
    sys.exit(0)

Later on in my Python code, I want to read the sensor data coming to us from the Arduino. ReadArduino, and CleanThe are the functions that I use to read data from the Arduino.

def ReadArduino( serialCon ):
""" Try to read in a value from the Arduino. Sometimes we might read a value from the serial
    port before the arduino has sent anything. In such cases we will wait a small time, and read again.
    Until we pick up our first non empty integer value."""
while True:
    val = serialCon.readline()
    print(val)
    val = cleanThe(str(val))
    if val != '':
        return val

def cleanThe( lineVal ):
""" The Arduino returns non-clean data back to us.
    We need to remove all the non-integer values to get
    a nice plottable integer value. Will accept '.' unconditionally for now,
    we may have to add conditions later. """
S = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.'}
clean = ''
for char in lineVal:
    if char in S:
        clean += char
return clean

Now the confusing part. When I run the application without the Arduino connected to my computer. It gets stuck in the while connected == False: while loop above. This is exactly what I want. Then when I plug it in, the serial port sets up and we break out of the loop. I even have a serial port object that I read from.

However, when I read from the serial port, I get back garbage hex values, without any sign of any useful integer values that I would expect.

Here are some sample raw val values that get read back when the python script is run with the Arduino connected before running: b'336\r\n' b'349\r\n' b'343\r\n' b'322\r\n'

Then here is the output I receive when the Arduino was not connected to my computer before running the Python script.

b'\xe0\x00\xe0\x00\x00\xe0\x00\x00\x00\x00\x00\xe0\xe0\x00\x00\xe0\x00\xe0\x00\x00\xe0\x00\x00\x00\x00\x00\xe0\xe0\x00\x00\xe0\x00\xe0\x00\x00\xe0\x00\x00\xe0\x00\x00\xe0\xe0\x00\x00\xe0\x00\xe0\x00\x00\x00\x00\x00\xe0\x00\x00\xe0\xe0\x00\x00\xe0\x00\xe0\x00\x00\x00\x00\x00\xe0\xe0\x00\xe0\xe0\x00\x00\xe0\x00\xe0\x00\x00\x00\x00\x00\x00\xe0\x00\xe0\xe0\x00\x00\xe0\x00\xe0\x00\x00\x00\x00\x00\xe0\x00\x00\xe0\xe0\x00\x00\xe0\x00'

b'\x00\x00\x00\xe0\x00\x00\xe0\x00\x00\xe0'

I have noticed, that when I am running my script with the Arduino plugged in from the start (i.e. the working case). The first value I read back from the Arduino is the same type of garbage hex:

b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

It seems like in the working case, the hex is all sent on one line. Where as in the non-working case, these hex values, seem to be sent intermittently in smaller chuncks. Perhaps I could add a check to the Arduino code, to only write values back to serial if they are good? I do realise this may be more of a python serial issue than an Arduino issue, let me know if this is the case and I will move the post.

Has anyone experience some kind of problem like this before?

5
  • Depending on the bootloader you might receive its tries to connect to its counterpart on your PC. Did you check how the "garbage" maps with the bootloader's protocol? -- Another thought: The xe0 and x00 bytes might indicated an unmatched baudrate. May 13, 2020 at 10:44
  • I know I'm a month late to this question, but just out of curiosity, did you solve it? Have you tried with a Serial.flush() after the Serial.println in the Arduino code?
    – ChatterOne
    May 13, 2020 at 12:06
  • No I haven't managed to find a working solution so far. I would be very keen to find a fix thought. Will give this a go, thank you for the suggestion. May 14, 2020 at 17:34
  • Okay so after having a tinker around I have found a fairly reasonable solution to the problem.Previously my app would instantly enter a infinitely repeating while loop trying to connect to the arduino over serial port as soon as it started, waiting for a successful connection to indicate that the device was connect. May 14, 2020 at 18:48
  • Instead of this automatic repeated connection attempts, I've programmed a 'Connect' button into my apps GUI with a window saying to connect the device before attempting to connect. I think the automatic attempts to connect to the arduino, immediately after launch the app meant that the successful serial connection would happen while the arduino was in some kind of set up phase. By letting the user click connect, there is always some reasonable delay between plugging the arduino into my laptop, and the first attempt at a serial connection being made. May 14, 2020 at 18:48

2 Answers 2

1

Just to explicitly show what I changed to my python code I thought I would answer my own question. The solution I found ended up being in the Python, but the other suggestions were useful for cleaning up the output of my Arduino. Here is the old auto connecting solution.

connected = False
window = sg.Window('Arduino Connection').Layout(layout)
attempts = 0
while connected == False:
    print("In connection while loop")
    button, values = window.Read(timeout=300)
    if button in (None, 'Exit'):
        break

    try:
        print("Attempting to connect")
        SER = serial.Serial(serial_port, baud_rate, timeout=0.02)
        print(SER)
        connected = True
        ser.append(SER)
    except:
        time.sleep(0.1)
        attempts += 1
        window.FindElement('attempts').Update(attempts)

Here is the working solution where I ask the user to press a connect button.

    connected = False
window = sg.Window('Arduino Connection').Layout(layout)
attempts = 0
while connected == False:
    print("In connection while loop")
    button, values = window.Read(timeout=300)
    if button in (None, 'Exit'):
        break
    if button == 'Ok':
        try:
            print("Attempting to connect")
            SER = serial.Serial(serial_port, baud_rate, timeout=0.02)
            print(SER)
            connected = True
            ser.append(SER)
        except:
            time.sleep(0.1)
            attempts += 1
            window.FindElement('attempts').Update(attempts)
0

On the Arduino side make your code non blocking:

 unsigned long timeStamp = 0;
 unsigned long timerDelay = 1000; // 1 second

 setup(){....}

void loop() {
// We just read the value on the analogPin
 if (millis() - timestamp > timerDelay ) {
     reading = analogRead(photoTran); 
     Serial.print(reading); // instead of println which sends additional \r\n
     timeStamp =millis();  // reset timer instead of delay(100); 
 }
}

On the Phyton side try to implement a routine waiting for the first char and then start reading from the next message on. The 1 second between sends on Arduino should suffice to ensure its working. The garbagge chars could be an init sequence from the port driver - this can not come from your code,

1
  • Hey, thanks for the reply! I gave this a go on the Arduino side, but I'm still running into the same kind of problems. One thing I did try was closing the serial connection in python after it is first established. Then re-opening it later when I actually want to start reading data from the Arduino. This change produced a different kind of error. When I try to re-open the serial communication for the second time, I get an error message in my Python console saying: [Errno 16] could not open port /dev/ttyACM0: [Errno 16] Device or resource busy: '/dev/ttyACM0' Apr 13, 2020 at 19:08

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.