Search code examples
pythonarduinodelay

Does Python serial readline interupt Arduino loop?


I am trying to post twitter updates from a sensor interfaced with an Arduino. The Adruino loop has a 1s delay between reading sensor voltages. The Python code has a 1 hour delay between Twitter updates.

It seems that the Python script actually interupts the Arduino loop until it reads a new line on the serial port. Is this correct?

For example, despite the Arduino program running on a loop for 1 hour, it will only show a millis() counter value of 1001, after 2 hours it will show 2002. Without the Python script running and observing the serial monitor only, the Arduino code counts milliseconds as expected.

This wouldn't normally be a problem, but if you wanted, for example, to simultaneously run a data logger with millis() running continuously at a high acquisition rate it will be an issue. It's difficult to know what's going on since the serial monitor can't share the same port as the Python program.

Here's a sample of the Arduino code

void loop() {
    unsigned long ms=millis();
    // read the input on analog pin 1:
    int sensorValue = analogRead(A1);
    float Temp = sensorValue * Vref * (100.0/1023.0); 
    // print out the value you read:
    Serial.print(Temp); 
    Serial.print(" degC");
    Serial.print(" , ");
    Serial.print(ms);
    Serial.println(" milliseconds");
    delay(1000);        // delay in miliseconds between reads for stability
}

And here's the section of the Python code in question:

arduino = serial.Serial('COM6', 9600)

while 1:  ##Infinite Loop
    status = arduino.readline() ##Wait for new line to come across Serial
    api.PostUpdate(status) ##Post message to Twitter
    time.sleep(3600) ##Wait 3600 seconds

Solution

  • Serial.write (and any functions that depend on it, like Serial.print) will block if the output buffer is full. The output buffer can only be drained if the other end (i.e. your Python script or the Serial Monitor) reads from the port.

    Serial Monitor constantly reads the serial port output, so the buffer doesn't fill up. However, since your Python script reads only a single line of output each hour, the buffer is persistently full. Because the serial port is buffered, every hour, you read the next second of output.

    What's happening here is that your Arduino code runs, say, 10 loops and writes 10 lines before its buffer fills. Your Python code will read the 10 lines, once per hour. After 10 hours, the newer lines that the Arduino has been putting in the buffer will have different timestamps.

    The solution, then, is to either send hourly updates from the Arduino (letting arduino.readline block for an hour in Python) or read updates constantly (every second) from Python and firing your Twitter updates every hour (e.g. use two threads, one to read and update the temperature, the other to post updates every hour using the newest local data).