0

I am trying to use Serial reading from a python serial code (which is running on my Jetson Nano) in my project, but in some loop in my code, my data is receiving wrong.

  • I use Serial.readBytesUntil() function for interrupt-like reading.
  • I use standart blue mini-USB cable for communication.
  • My Arduino Nano also connected a nRF24L01 module with SPI.
  • Baudrate is 9600 for both devices. I tried 115200 but there is no difference.
  • The data loss is about %10 of all loops with both test codes (image-1, image-2).
  • There is no positive difference when I use RX/TX pins on both boards with level shifter.
  • When I use the test code in my main code with USB connection, the data loss increases %50 of all loops. But Arduino serial monitor is fine like image-3.
  • When I use the test code in my main code with RX/TX pins, Arduino serial monitor looks like image-4 and Arduino IDE gives error like image-5.

Here is my receiver test code on my Arduino Nano.

void setup() {

  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  while (!Serial) {}

}

void loop() {
  char buffer[4];
  int deger = 0;
  if (Serial.available() > 0) {
    int size = Serial.readBytesUntil('\n', buffer, 4);

    if (size == 4) {
      Serial.print("deger: ");
      Serial.write(buffer);
      Serial.print("  size: ");
      Serial.print(size);

      // Bytes to integer
      deger = (buffer[1] - 48) * 100 + (int(buffer[2]) - 48) * 10 + (buffer[3] - 48);
      if (buffer[0] == '1') {
        deger = -1*deger; }

      Serial.print(" Sayi: ");
      Serial.println(deger);
      }

    if (deger < 0) {
      digitalWrite(LED_BUILTIN, HIGH);
    }
    else {
      digitalWrite(LED_BUILTIN, LOW);
    }
  }
}

And the python serial transmitter test code.

import serial

ser = serial.Serial('/dev/ttyUSB0',baudrate=9600,timeout=10)
while True:
    hata = -58

    if hata > 0:
        hata = str(hata)
        if len(hata) == 2:
            hata = '00' + hata
        elif len(hata) == 1:
            hata = '000' + hata
        else:
                hata = '0' + hata    #Pozitive, Added 0
    elif hata < 0:
        hata = -1 * hata
        hata = str(hata)
        if len(hata) == 2:
            hata = '10' + hata
        elif len(hata) == 1:
            hata = '100' + hata
        else:
            hata = '1' + hata    #Negative, Added 1
    else:
        hata = str(hata)
        hata = '000' + hata

    # For every loop, sends 4 character and "\n"  Example: 1058\n
    gonder = hata + '\n'       # For readBytesUntil function
    ser.write(gonder.encode('utf-8'))
    print(gonder.encode('utf-8'))

image-1: Arduino test code serial monitor screenshot

enter image description here

image-2: Python test code serial terminal screenshot

enter image description here

image-3: Arduino main project code monitor with USB cable screenshot

enter image description here

image-4: Arduino main project code monitor with RX/TX pins on GPIO screenshot

enter image description here

image-5: Arduino main project code IDE error

enter image description here

So, what did i do wrong? Thank you!

1
  • Already answered on the Arduino forum here
    – P_B
    Commented May 25, 2020 at 22:00

1 Answer 1

1

You are overflowing your buffer, and also allowing garbage reads.

First you need 5 bytes for your buffer not 4, and you need to ensure it is zeroed out before using it. This is because you are treating it like a C string, which means it must b zero terminated.

Secondly your use of Serial.readBytesUntil() is flawed. From the manual:

The function terminates (checks being done in this order) if the determined length has been read, if it times out (see Serial.setTimeout()), or if the terminator character is detected (in which case the function returns the characters up to the last character before the supplied terminator).

You are sending 5 bytes (1058\n) but telling it to read up to 4. Which leaves the \n in the buffer. The next time through you read another 4 bytes, which gives you \n which is the terminating character.

If you must use readBytesUntil then you need to specify a buffer that is bigger than the whole string including the terminator so that the terminator always occurs before the maximum number of bytes read. Including the trailing zero you would thus need at least 6 bytes in your buffer, maybe a couple more "just in case" (one can never tell with Arduino API functions...)

So to roll it all up:

  char buffer[8]; // <- Bigger buffer
  memset(buffer, 0, 8); // <- Clear it out
  int deger = 0;
  if (Serial.available() > 0) {
    int size = Serial.readBytesUntil('\n', buffer, 7); // <- Tell it to read more leaving room for the terminating NULL
    ... etc ...
if (size == 4) {
4
  • readBytesUntil doesn't put the terminating character in the buffer. but it is read.
    – Juraj
    Commented May 25, 2020 at 15:49
  • 1
    @Juraj Not if it's the 5th character and you're only telling it to read up to 4...
    – Majenko
    Commented May 25, 2020 at 16:00
  • Thank you! I will try to code like you said. What do say about the second problem (image-4, broken serial monitor) ?
    – dcwaves
    Commented May 26, 2020 at 11:53
  • That is most likely buffer overflow from your unterminated buffer.
    – Majenko
    Commented May 26, 2020 at 11:53

Your Answer

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

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