Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait on Arduino auto-reset using pySerial

I'm trying to read lines from an Arduino board with a very simple code (for the sake of showcasing the problem) on Linux.

Python code:

# arduino.py
import serial
arduino = serial.Serial('/dev/ttyACM0')

with arduino:
    while True:
        print(arduino.readline())

Arduino code:

// simpleWrite.ino
long ii = 0;

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  Serial.println(ii);
  ii++;
}

As the board auto-resets when the serial connection is opened, the first bytes are likely garbage. After a second or two everything works fine.

This is a typical output:

$ python arduino.py 
b'09\r\n'
b'540\r\n'
b'541\r\n'
b'542\r\n'
b'543\r\n'
b'544\r\n'
b'545\r\n'
b'546\r\n'
b'547\r\n'
b'548\r\n'
b'549\r\n'
b'550\r\n'
b'551\r\n'
b'552\r\n'
b'553\r\n'
b'554\r\n'
b'555\r\n'
b'556\r\n'
b'557\r\n'
b'55\xfe0\r\n'  # <---- Here the board restarted
b'1\r\n'
b'2\r\n'
b'3\r\n'
b'4\r\n'
b'5\r\n'
b'6\r\n'
b'7\r\n'
b'8\r\n'
b'9\r\n'
b'10\r\n'

However, I see the Arduino IDE Serial Monitor doesn't have this problem, and properly shows a delay (while restarting) and then prints all the lines starting from the first one.

Is there a way to emulate this behaviour in Python using pySerial? That is, discarding all the output before restarting and nothing more? Perhaps through some low-level functions?

I tried looking at the relevant Arduino source code, but I don't know Java and it didn't help.

Note: Of course I could sleep for, say, three seconds, discard everything and start from there, but I would probably discard some of the first lines too.

Edit: Apparently, this problem doesn't exist on Windows and the accepted solution was not necessary.

like image 356
astrojuanlu Avatar asked Jan 12 '14 09:01

astrojuanlu


People also ask

How do I turn off auto reset on Arduino?

To disable the automatic reset of the Arduino board upon serial connection, just stick a 120 Ohm resistor between the RESET and +5V pins. This is especially useful when the running application is expected to communicate over serial port, and thus you don't want a reset each time a connection is made.

Can Arduino reset itself?

As you open the Serial Terminal, the Arduino automatically gets reset. The third way of resetting Arduino is by pressing the push button.

How do I reset my Arduino serial?

Press and hold the reset button on the Leonardo or Micro, then hit the upload button in the Arduino software. Only release the reset button after you see the message “Uploading…” appear in the software's status bar. When you do so, the bootloader will start, creating a new virtual (CDC) serial port on the computer.

Why does Arduino reset when open monitor?

The Arduino is configured to reset on startup to enable a quick check to see if there is new code waiting to be uploaded. This is accomplished by the USB hardware monitoring DTR which is supplied by the monitor application.


2 Answers

The Arduino IDE's monitor toggle's the assigned DTR pin of the port when connected. Where this toggling causes a reset on the Arduino. Noting that the DTR is toggled after the Monitor has opened the Serial port and is ready to receive data. In your case the below example should do the same.

Import serial

arduino = serial.Serial('/dev/ttyS0',
                     baudrate=9600,
                     bytesize=serial.EIGHTBITS,
                     parity=serial.PARITY_NONE,
                     stopbits=serial.STOPBITS_ONE,
                     timeout=1,
                     xonxoff=0,
                     rtscts=0
                     )
# Toggle DTR to reset Arduino
arduino.setDTR(False)
sleep(1)
# toss any data already received, see
# http://pyserial.sourceforge.net/pyserial_api.html#serial.Serial.flushInput
arduino.flushInput()
arduino.setDTR(True)

with arduino:
    while True:
        print(arduino.readline())

I would also add the compliment to the DTR for the Arduino's with AVR's using built-in USB, such as the Leonoardo, Esplora and alike. The setup() should have the following while, to wait for the USB to be opened by the Host.

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
}

It will have no effect for FTDI's based UNO's and such.

like image 125
mpflaga Avatar answered Sep 19 '22 16:09

mpflaga


I realize this is an old question, but hopefully this can be useful to somebody else out there with the same problem.

I had an issue where if I used any baudrates other than 9600, the serial connection in python would just receive gibberish all the time, even if Serial.begin(...) is properly set on the arduino and matches the value used in the python code. I read online that the bootloader or watchdog may take a second to load (when the board is power-cycled) and it may send stuff over serial at some specific baudrate (for chip programming possibly). I'm guessing that this is what messes up the serial communication in python.

Here's the piece of code that gives me reliable results:

import serial
from time import sleep
arduino = serial.Serial('/dev/ttyACM0') # dummy connection to receive all the watchdog gibberish (unplug + replug) and properly reset the arduino
with arduino: # the reset part is actually optional but the sleep is nice to have either way.
  arduino.setDTR(False)
  sleep(1)
  arduino.flushInput()
  arduino.setDTR(True)

# reopen the serial, but this time with proper baudrate. This is the correct and working connection.
arduino = serial.Serial('/dev/ttyACM0',baudrate=57600)

with arduino:
    while True:
        print(arduino.readline())

The code used on the arduino side for testing is as simple as this:

void setup() {
  Serial.begin(57600);
  Serial.println("setup");
}

void loop() {
  Serial.println("hello");
  delay(200);
}
like image 37
Weboide Avatar answered Sep 19 '22 16:09

Weboide