Tsuyo
Tsuyo

Reputation: 31

Communication between my arduino and my Python code doesn't seem to work

I need to use data collected from a sensor connected to an arduino Uno in a Python code. It's a basic question of getting the state of the digitalPin to my Python code. I first wanted to try my hand at just making a communication going both ways, from Python to Arduino, and after from Arduino to Python.

So I tried doing a ping-pong with Python sending a command, and Arduino sending back 0 if it didn't reach or 1 if it worked. The thing is: I can see the command test in Arduino, but the back data is not working.

Here's my Arduino code :

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

void loop() {
  
    if (Serial.available() > 0) {  // check if there's data from python
    String command = Serial.readStringUntil('\n');  // read python command
    Serial.println(command);  // show command in Arduino monitor
    Serial.write("command\n");
      if (command == "test") {  // if command is "test"
        Serial.write(1);}  // Envoie 1 en tant que byte
      else {
        Serial.write(0);}  // Envoie 0 en tant que byte
      Serial.flush();
  }
}

And here's my Python code:

import serial
import time

capt = serial.Serial('COM5',9600,timeout=5)

def testcomm(test):  
    out = 0
    com = (test + '\n').encode()  # Send test command with end ligne indicator \n
    print(f"Commande envoyée : {com}")
    capt.write(com)  # send command to Arduino
    time.sleep(4)  
    # Check if there's data
    if capt.in_waiting > 0 :
        testout = capt.readline()  # read
        print(f'testout val (raw): {testout}')  # show raw
        if testout:
            out = testout.strip()  # clean answer
        print(f'testout val (cleaned): {out}')
    else:
        print("Doesn't work")
    
    return out

test1 = testcomm('test')
capt.close()

And here's the result in my Python console:

Commande envoyée : b'test\n'
Doesn't work

I checked whether the command line in itself worked inside the Arduino monitor, it does, and it sends back 1, but really, I can't read it in Python.

I also tried read(), readline() and readlines() just in case. I tried a lot of different things, but I didn't keep track, and I was also learning the pyserial library in parallel, so a lot of my tries were just weird. What can I try next?

Upvotes: 2

Views: 57

Answers (2)

Tsuyo
Tsuyo

Reputation: 31

So, after looking a bit more into it, again, I played with time.sleep(). The problem was that I was sending a command too quickly after I opened the port, so it was unable to catch the command. The solution was to add a time.sleep() after the port was opened (in my case I put it before the capt.write() command).

Upvotes: 1

rizzling
rizzling

Reputation: 1008

The issue you're encountering is likely due to the way you're handling the serial communication between your Arduino and Python. In your Arduino code, you're using Serial.write(1) and Serial.write(0) to send back the response. This sends the values as raw bytes, which might not be what you expect on the Python side. Instead, you should send the response as a string to make it easier to read in Python.

Updated Arduino code:

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

void loop() {
  if (Serial.available() > 0) {  // check if there's data from python
    String command = Serial.readStringUntil('\n');  // read python command
    Serial.println(command);  // show command in Arduino monitor
    if (command == "test") {  // if command is "test"
      Serial.println(1);  // Send 1 as a string
    } else {
      Serial.println(0);  // Send 0 as a string
    }
    Serial.flush();
  }
}

and updated python code:

import serial
import time

capt = serial.Serial('COM5', 9600, timeout=5)

def testcomm(test):
    out = 0
    com = (test + '\n').encode()  # Send test command with end line indicator \n
    print(f"Commande envoyée : {com}")
    capt.write(com)  # send command to Arduino
    time.sleep(1)  # Give some time for Arduino to process and respond
    capt.flushInput()  # Clear the input buffer
    capt.flushOutput()  # Clear the output buffer
    time.sleep(1)  # Give some time for Arduino to send the response
    if capt.in_waiting > 0:
        testout = capt.readline().decode().strip()  # read and decode the response
        print(f'testout val (raw): {testout}')  # show raw
        if testout:
            out = testout  # clean answer
        print(f'testout val (cleaned): {out}')
    else:
        print("Doesn't work")
    return out

test1 = testcomm('test')
capt.close()

The Arduino code now uses Serial.println() to send the response back as a string. This ensures that the response is sent with a newline character, which makes it easier to read on the Python side. The Serial.flush() is used to ensure that all data is sent out of the serial buffer.

The python code uses capt.flushInput() and capt.flushOutput() functions to clear the input and output buffers, ensuring that any residual data is cleared before reading the response. The capt.readline().decode().strip() function is used to read the response from the Arduino, decode it from bytes to a string, and strip any leading or trailing whitespace.

Upvotes: 0

Related Questions