Search code examples
pythonarduinopyserial

Arduino and Python Pyserial communication


I am trying to write a code that will allow me to send output to my microcontroller (Sparkfun Redboard) using Python code.

I want to pass different variables (CMJ or SJ) I want the built-in LED to turn on (and stay on) if CMJ is passed and turn off (and stay off) if SJ is passed. I would also like to print("invalid") if anything else is passed.

Here is my python code:

import serial
import time

# Setup serial communication
serialcomm = serial.Serial("COM4", 500000)
serialcomm.timeout = 1

# Define your variable
activity = "CMJ"  # Change this to "CMJ" or anything else to test different scenarios

while True:
    if activity == "done":
        print("finished")
        break
    elif activity == "CMJ":
        command = "on"
    elif activity == "SJ":
        command = "off"
    else:
        command = "invalid"

    # Send the command to the Arduino
    serialcomm.write(('command'+'\n').encode())  # Send command with newline character

    # Wait for a moment to ensure the command is processed
    time.sleep(0.5)

    # Read and print the response from the Arduino
    response = serialcomm.readline().decode('ascii').strip()
    print(response)

    # Close the serial communication when done
    serialcomm.close()

and my Arduino code:

String InBytes;

void setup() {
  Serial.begin(500000); // Ensure this matches the Python code
  pinMode(LED_BUILTIN, OUTPUT); // Set the LED pin as an output
  digitalWrite(LED_BUILTIN, LOW); // Ensure the LED is off initially
}

void loop() {
  if (Serial.available() > 0) {
    InBytes = Serial.readStringUntil('\n'); // Read the incoming string until newline
    InBytes.trim(); // Remove any leading or trailing whitespace/newline characters
    
    // Debugging output
    Serial.print("Received command: ");
    Serial.println(InBytes);

    if (InBytes == "on") {
      digitalWrite(LED_BUILTIN, HIGH); // Turn the LED on
      Serial.write("Led on"); // Send a response back
    } else if (InBytes == "off") {
      digitalWrite(LED_BUILTIN, LOW); // Turn the LED off
      Serial.write("Led off"); // Send a response back
    } else {
      Serial.write("Invalid"); // Handle invalid commands
    }
  }
}

The result is that the LED just blinks away for a sec no matter what variable I pass (CMJ, SJ, or anything else. There must be something wrong with the code but cannot figure out.


Solution

  • Taking a closer look at your code, the bug is that you are using ('command'+'\n').encode(). In this case, the Arduino will get the string "command\n".

    To fix it, use this on the Python side:

    # Setup serial communication
    serialcomm = serial.Serial("COM4", 500000)
    serialcomm.timeout = 1
    # Define your variable
    activity = "CMJ"  # Change this to "CMJ" or anything else to test different scenarios
    while True:
        try:
            if activity == "done":
                print("finished")
                break
            elif activity == "CMJ":
                command = "on"
            elif activity == "SJ":
                command = "off"
            else:
                command = "invalid"
            command += "\n"
            serialcomm.write(command.encode())  # Send command with newline character
            time.sleep(0.5)
            response = serialcomm.readline().decode('ascii').strip()
            print(response)
        except KeyboardInterrupt:
            print("Goodbye!")
            serialcomm.close()
            break
    

    Notice that I added a try:except statement, like this, the loop will continue until someone uses cntrl+c, at which point the script will end the serialcomm will be closed.

    Hope this helps.

    Also the "proof" on my side:

    arduino on

    Note: make sure that the Arduino/microcontroller board is not accessed by any other program or process than your Python script (f.e. don't use the Arduino IDE's Serial Monitor). Otherwise, the serial port is "open"/in use by another program and trying to access it in python will throw a permission error. Also check which COM port number you need to use before trying to access a port as well!