Go Down

Topic: Send multiple strings from Python to Arduino (Read 648 times) previous topic - next topic

Oxylium

Jan 30, 2019, 06:31 pm Last Edit: Jan 30, 2019, 06:33 pm by Oxylium
Hello everybody,

I'm a beginner in Arduino and I need for a school project to send data from Python to Arduino. So I decided to do it with the SrerialSoftwrae, but the main problem is that I have to send a various number of character (from 5 to 1700+). Sending 5 characters is something very easy, but sending more than 1700 characters is more difficult (the Arduino buffer size is set to 64 bytes, and every char = 1byte). So, what I did is to divide the main string in multiple character strings into the Python program. Then I have to send the 30 "packets" (every single one composed of 64 char),every 150ms to the Arduino via Serial.
But the thing is that it doesn't work and I've searched a solution for hours without finding it...
So if someone more qualified than me could tell me a way to do it without using serial, or what's wrong in my program, I would be very grateful !

The python communication part program (c is the main string) and for the delay, each 0.0000 will corresponds to 150ms :
Code: [Select]

c1 = len(c)


c2 = c[(63*0):(63*1)]           #paquet 1 etc..
c3 = c[(63*1):(63*2)]
c4 = c[(63*2):(63*3)]
c5 = c[(63*3):(63*4)]
c6 = c[(63*4):(63*5)]
c7 = c[(63*5):(63*6)]
c8 = c[(63*6):(63*7)]
c9 = c[(63*7):(63*8)]
c10 = c[(63*8):(63*9)]
c11 = c[(63*9):(63*10)]
c12 = c[(63*10):(63*11)]
c13 = c[(63*11):(63*12)]
c14 = c[(63*12):(63*13)]
c15 = c[(63*13):(63*14)]
c16 = c[(63*14):(63*15)]
c17 = c[(63*15):(63*16)]
c18 = c[(63*16):(63*17)]
c19 = c[(63*17):(63*18)]
c20 = c[(63*18):(63*19)]
c21 = c[(63*19):(63*20)]
c22 = c[(63*20):(63*21)]
c23 = c[(63*21):(63*22)]
c24 = c[(63*22):(63*23)]
c25 = c[(63*23):(63*24)]
c26 = c[(63*24):(63*25)]
c27 = c[(63*25):(63*26)]
c28 = c[(63*26):(63*27)]
c29 = c[(63*27):(63*28)]


print(c1)
str.encode(c)

int1 = 0
str1 = ""
str2 = ""

ports = list(serial.tools.list_ports.comports())
for p in ports:
   print (p) # This causes each port's information to be printed out.
           # To search this p data, use p[1].

   while int1 < 9:   # Loop checks "COM0" to "COM8" for Adruino Port Info.

      if "Arduino" in p[1]:  # Looks for "CH340" in P[1].
            str2 = str(int1) # Converts an Integer to a String, allowing:
            str1 = "COM" + str2 # add the strings together.

      if "Arduino" in p[1] and str1 in p[1]: # Looks for "CH340" and "COM#"
         print ("Found Arduino on " + str1)
         int1 = 9 # Causes loop to end.

      if int1 == 8:
         print ("Arduino not found!")
         sys.exit() # Terminates Script.

      int1 = int1 + 1

c1 = str(c1)

ser = serial.Serial()
ser.port = str1
ser.baudrate = 9600
ser.timeout = 10
ser.close()
ser.open()
time.sleep(2)
ser.write(c1.encode('utf-8'))


time.sleep(0.0000)
ser.write(c2.encode('utf-8'))

time.sleep(0.0000)
ser.write(c3.encode('utf-8'))

time.sleep(0.0000)
ser.write(c4.encode('utf-8'))

time.sleep(0.0000)
ser.write(c5.encode('utf-8'))

time.sleep(0.0000)
ser.write(c6.encode('utf-8'))

time.sleep(0.0000)
ser.write(c7.encode('utf-8'))

time.sleep(0.0000)
ser.write(c8.encode('utf-8'))

time.sleep(0.0000)
ser.write(c9.encode('utf-8'))

time.sleep(0.0000)
ser.write(c10.encode('utf-8'))

time.sleep(0.0000)
ser.write(c11.encode('utf-8'))

time.sleep(0.0000)
ser.write(c12.encode('utf-8'))

time.sleep(0.0000)
ser.write(c13.encode('utf-8'))

time.sleep(0.0000)
ser.write(c14.encode('utf-8'))

time.sleep(0.0000)
ser.write(c15.encode('utf-8'))

time.sleep(0.0000)
ser.write(c16.encode('utf-8'))

time.sleep(0.0000)
ser.write(c17.encode('utf-8'))

time.sleep(0.0000)
ser.write(c18.encode('utf-8'))

time.sleep(0.0000)
ser.write(c19.encode('utf-8'))

time.sleep(0.0000)
ser.write(c20.encode('utf-8'))

time.sleep(0.0000)
ser.write(c21.encode('utf-8'))

time.sleep(0.0000)
ser.write(c22.encode('utf-8'))

time.sleep(0.0000)
ser.write(c23.encode('utf-8'))

time.sleep(0.0000)
ser.write(c24.encode('utf-8'))

time.sleep(0.0000)
ser.write(c25.encode('utf-8'))

time.sleep(0.0000)
ser.write(c26.encode('utf-8'))

time.sleep(0.0000)
ser.write(c27.encode('utf-8'))

time.sleep(0.0000)
ser.write(c28.encode('utf-8'))

time.sleep(0.0000)
ser.write(c29.encode('utf-8'))




ser.close()




Arduino program :
Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <LiquidCrystal.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

int lu = 0; 
int donneesALire = Serial.available();
int index = 0;
String test = "";
String serial = "STRINGRAW";
String longueurstr = "";
int longueur = 0;
int currentchar = 0;
String serial1 = "";
String serial2 = "";
String serial3 = "";
String serial4 = "";
String serial5 = "";
String serial6 = "";
String serial7 = "";
String serial8 = "";
String serial9 = "";
String serial10 = "";
String serial11 = "";
String serial12 = "";
String serial13 = "";
String serial14 = "";
String serial15 = "";
String serial16 = "";
String serial17 = "";
String serial18 = "";
String serial19 = "";
String serial20 = "";
String serial21 = "";
String serial22 = "";
String serial23 = "";
String serial24 = "";
String serial25 = "";
String serial26 = "";
String serial27 = "";
String serial28 = "";
String serial29 = "";

void setup() {

Serial.begin(9600);
Serial.println("Ecrivez votre texte");
lcd.begin(16, 2);
lcd.print("On imprime :");
lcd.setCursor(0, 1);
}

void loop() {

donneesALire = Serial.available();
 
if ((donneesALire > 0) and (lu == 0) and (longueur<=currentchar)
       longueurstr=Serial.readString();
       longueur = longueurstr.toInt() ;
       delay(150.00000);
       delay(150.00000/2);
     
       serial1 =Serial.readString();
       delay(150.00000);
       currentchar = currentchar + 64;
       
       serial2 =Serial.readString();
       delay(150.00000);
       currentchar = currentchar + 64;

       serial3 =Serial.readString();
       delay(150.00000);
       currentchar = currentchar + 64;

       serial4 =Serial.readString();
       delay(150.00000);
       currentchar = currentchar + 64;

       [....] --> exactly the same code for all the strings

       serial29 =Serial.readString();
       delay(150.00000);
       currentchar = currentchar + 64;
       
       
       
       lu = 1;
    }


serial = serial1 + serial2 + serial3 + serial4 + serial5 + serial6 + serial7 +serial8 +serial9 + serial10 + serial11 + serial12 +serial13 +serial14 +serial15 +serial16 +serial17 +serial18 +serial19 +serial20 +serial21 +serial22 +serial23 +serial24 +serial25 +serial26 +serial27 +serial28 +serial29 ;
Serial.println(serial);

AWOL

#1
Jan 30, 2019, 06:40 pm Last Edit: Jan 30, 2019, 06:41 pm by AWOL
Code: [Select]
  delay(150.00000);Even at 9600 bits per second, your serial buffer would overflow in 64 milliseconds, so the delays are going to have to go.

(And delay doesn't take float arguments)

Oxylium

#2
Jan 30, 2019, 07:16 pm Last Edit: Jan 30, 2019, 07:17 pm by Oxylium
Okay than you a lot for answering, so what would you advise in term of baud rate ?
Or do you have any alternative solution ?

(And by the way my bad for the delay)

Robin2

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable.

You can send data in a compatible format with code like this (or the equivalent in any other programming language)
Code: [Select]
Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker


In the examples it is assumed that you won't receive more than 32 bytes but you can extend that by changing the value of numChars.

You will have to call the receiveXXX()  function very frequently to avoid the serial input buffer from overflowing.

If you can organize your Python program to send the data in chunks that don't exceed 64 bytes you will have an easier life.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Oxylium

Ok, thank you a lot Robin. I will test your method and your code tomorrow, I keep you tuned if it works !

Oxylium

Sooooo ... I have tested the code but it appeared that your program Robin didn't wait until the final mark ">" to stop getting the information from the Serial port. I've tried with python through serial port and with the serial monitor, but the Arduino is still getting only a part of the information. After modifying the code, creating new variables and all sorts of tricks, I must admit that I don't understand why. Because when I look at the code, I don't see any problem  ::)


Here is my program :

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <LiquidCrystal.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

int lu = 0; 
int donneesALire = Serial.available();
int index = 0;
int indexlongueurstr = 0;

String test = "";
String serial = "";
String longueurstr = "";
String longueurascii ="";
String longueurencharac = "";
int taille = 0;
int longueur = 0;
byte longueurbyte = 0;
int currentchar = 0;
const byte numChars = 20000;
char receivedChars[numChars];
boolean FIN = false;

boolean newData = false;

void(* resetFunc) (void) = 0;

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
               
                //if (ndx >= byte(longueur)) {
                    //ndx = byte(longueur) - 1;
                //}
            }
            else if (rc == endMarker){
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
                FIN = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
       
    }
}

void setup() {

Serial.begin(9600);
Serial.println("Ecrivez votre texte");
lcd.begin(16, 2);
lcd.print("On imprime :");
lcd.setCursor(0, 1);
}

void loop() {
 
while (lu == 0)
{     longueurstr=Serial.readString();
       indexlongueurstr = longueurstr.indexOf(',');
       longueurascii = longueurstr.substring(0,indexlongueurstr);
       longueurencharac = longueurstr.substring(indexlongueurstr + 1);
       
       longueur = longueurascii.toInt() ;
       const byte longueurbyte = byte(longueur);
       taille = longueurencharac.toInt();
     

       if (longueur != 0)
       {lu = 1;
       //char receivedChars[longueurbyte];
       Serial.end();
       }
      Serial.begin(9600);

      lcd.setCursor(0, 1);
      lcd.print(longueur);
}



delay(5000);

while (FIN == false) {
recvWithStartEndMarkers();}

lcd.setCursor(0, 1);
lcd.print("Check");


serial = String(receivedChars);
delay(10000);


Oxylium

#7
Jan 31, 2019, 09:28 pm Last Edit: Jan 31, 2019, 09:33 pm by Oxylium
What is missing ?

AWOL

We don't know what is missing, because it is not there.

Robin2

Sooooo ... I have tested the code but it appeared that your program Robin didn't wait until the final mark ">"
It looks like you have changed my code so that invalidates the warranty.

Try my example code with NO changes and if it does not work then let me know.


Separately, this is never going to work
Code: [Select]
const byte numChars = 20000;
because the maximum value you can hold in a byte is 255.

What Arduino are you using that has enough memory to receive 20,000  characters?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Oxylium

#10
Feb 02, 2019, 10:52 pm Last Edit: Feb 02, 2019, 10:55 pm by Oxylium
Ok, Robin I have reconstructed my program from your program and corrected my mistakes (it was 2000 char and not 20000), and if it doesn't work, It's because I convert the char "receivedChars" into a string in order to do some string operations (such as .subString). But in fact, considering the large amount of characters, the Arduino runs out of SRAM and can't convert all the char into the string, but just a part.
So, thanks to Awol and to you, your program works perfectly and now I'm just going to optimize all my variables just to reduce the amount of SRAM used  :D

Topic closed

Go Up