Comunicazione Seriale Python

ciao ragazzi,
ho creato un firmware per arduino per comunicare con un radiocomando per modellismo.
Ora volevo creare un piccolo software di diagnostica in Python, che mi consenta di leggere in una finestra via seriale tutti i valori ricevuti in ingresso da arduino tramite il radiocomando.
In linea di massima più o meno lo fatto, solo che ho un problema grande, la connessione e lentissima. Praticamente ce una piccola interfaccia che ti fa selezionare la porta COM giusta, fatto ciò impiega anche 2 minuti prima di restituire i valori letti da arduino, ecco il codice di python. Potete aiutarmi? Avete qualche altra soluzione per creare una diagnostica per ingressi ed uscite?

import PySimpleGUI as cingolo
import sys 
import glob 
import serial 


def serial_ports(): 

    if sys.platform.startswith('win'): 
     ports = ['COM%s' % (i + 1) for i in range(256)] 
    elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): 
     # this excludes your current terminal "/dev/tty" 
     ports = glob.glob('/dev/tty[A-Za-z]*') 
    elif sys.platform.startswith('darwin'): 
     ports = glob.glob('/dev/tty.*') 
    else: 
     raise EnvironmentError('Unsupported platform') 

    result = [] 
    for port in ports: 
     try: 
      s = serial.Serial(port) 
      s.close() 
      result.append(port) 
     except (OSError, serial.SerialException): 
      pass 
    return result 


if __name__ == '__main__':
    pcom=[serial_ports()]
    print(serial_ports())
    selport = [
     
        [cingolo.Text('Porta COM'), cingolo.InputCombo((serial_ports()), size=(20, 3)),cingolo.Submit()],
        ]
    window = cingolo.Window('Diagnosi').Layout(selport)
    button, values = window.read()
    pcom=values[0]
    print(pcom)
ard=serial.Serial(pcom,9600)
ch1=ard.readline()
ch2=ard.readline()
ch3=ard.readline()
ch4=ard.readline()
ch5=ard.readline()
ch6=ard.readline()
layout = [      
 
          [cingolo.Text('Diagnosi radiocomando')],      
          [cingolo.Text('Accelleratore', size=(15, 1)), cingolo.Text(ch1)],      
          [cingolo.Text('Quadro', size=(15, 1)), cingolo.Text(ch2)],      
          [cingolo.Text('Direzione', size=(15, 1)), cingolo.Text(ch3)],
          [cingolo.Text('Rotazione', size=(15, 1)), cingolo.Text(ch4)],      
          [cingolo.Text('Direzione', size=(15, 1)), cingolo.Text(ch5)],      
          [cingolo.Text('Cingolo_DX', size=(15, 1)), cingolo.Text(ch6)],      
          [cingolo.Text('Cingolo_SX', size=(15, 1)), cingolo.Text(ch1)],      

         ]

window = cingolo.Window('Diagnosi').Layout(layout)         
button, values = window.read()

Buonasera,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

Fatto mi sono presentato

Non è una domanda inerente al forum arduino! Sul forum si parla della programmazione arduino in C-C++ e non dei vari linguaggi lato PC.

Quindi dovresti porre le tue domande in un forum di programmazione che tratta il linguaggio Python, e avresti anche più possibilità di ricevere risposte.

Più che altro volevo capire come mai e così lenta la connessione seriale. Se è un problema di Python o di Arduino

E sicuramente un problema lato Python, la seriale di Arduino non ha ritardi ... se non quelli introdotti da un codice scritto male :wink:

Guglielmo

Ma in C sarebbe meglio che in Python ? Alla fine per me e la stessa cosa C o Python non mi cambia. Lo avevo scelto solo perché multi piattaforma

senza vedere anche il programma di arduino non si può dire tanto di più....

Io devo solo creare un software di diagnostica che mi visualizza in maniera ordinata e leggibile tutto i segnali che ho in ingresso ed uscita su Arduino per capire se tutto funziona come dovrebbe.

dennyxx82:
Più che altro volevo capire come mai e così lenta la connessione seriale. Se è un problema di Python o di Arduino

A 9600 mandi circa 960 byte al secondo, vedo che leggi 6 stringhe (ossia 6 valori) quindi non ha alcun senso che ci metta 2 minuti prima di avere i primi 6 valori a meno che non siano in totale più di 100k byte in totale. Per cui hai qualche problema o di handshake o di implementazione non corretta tra Arduino e Python (che però conosco solo di nome non ci ho mai programmato).

Per dire, tu in Python leggi 6 righe di testo ma la readLine() del Python cosa attende come fine riga? Solo un LF (10)? Solo un CR (13)? La coppia CR+LF? Perché se tu da Arduino non mandi il terminatore lui attende fino ad un qualche suo timeout immagino... Poi in Python la seriale come l'hai impostata? Su Arduino hai solo RX e TX, niente handshake, neanche software, niente parità. Magari leggi bene il reference della pySerial per capire le impostazioni e la readLine cosa richiede come terminatore...

Quindi in sostanza, o ci fai vedere anche il codice Arduino e ci dici cosa si aspetta il tuo programma, oltre a descriverci COME hai connesso Arduino al PC, oppure non possiamo dirti nulla di più di questo.

Ok ora verifico. Comunque in definitiva invio semplicemente degli interi con Serial.println() quindi mi sa che davvero gli devo aggiungere il fine linea.

Con la println() hai entrambi i caratteri 13+10 ovvero \r\n quindi devi capire in che modo su Python gestire questi terminatori.

Python me li restituisce entrambi. Sia \r che \n quindi immagino non li consideri fine linea.

Che readLine() ti restituisca anche il terminatore neline \n è normale (ma hai letto il reference del linguaggio che usi ossia Python, o vai a casaccio?), quello che dovresti fare oltre a newLine() sarebbe di rimuovere sia \r (che per pySerial non è il terminatore a meno che non venga impostato appositamente come EOL) sia \n, in tal modo hai una stringa "pulita".
Comunque sia, visto che nella documentazione Python leggo:

Be careful when using readline(). Do specify a timeout when opening the serial port otherwise it could block forever if no newline character is received.

mi chiedo se nella Serial tu abbia anche impostato il timeout ed a quanto corrisponde.

Ma resta il dubbio del perché non riconosca le linee che mandi da Arduino, il che significa, ripeto, che o ci fai vedere anche il codice lato Arduino e ci dai una descrizione precisa dell'esito dei tuoi test (es. i "2 minuti" di cui parli sono proprio esattamente 2 minuti? Il tempo di attesa è sempre identico ogni volta o cambia? E cosa ricevu ti con la readLine?) incluso il relativo esatto codice usato per quei test che ci descriverai, oppure temo che debba tu studiarti meglio la comunicazione seriale Arduino-Python.

non ce un tempo prestabilito…cmq ora ti giro il codice di arduino.
per quanto riguarda il timeout non ne ho messo perchè mi perdeva parte della stringa…io credo che il problema forse e proprio data dal timeout o dal delimitatore perchè e come se il codice in python sia in attesa.

#include <Servo.h>
#define ch_1 7
#define ch_2 6
#define ch_3 5
#define ch_4 4
#define ch_5 3
#define ch_6 2
#define cingolodx 9
#define cingolosx 10
#define quadro 8
#define accelleratore 11
#define accensione 12
int direzione=0;
int rotazione=0;
int pos_dx=0;
int pos_sx=0;
int r_dx=0;
int r_sx=0;
int manopola=0;
int interruttore=0;
boolean avvio=true;
Servo c_dx;
Servo c_sx;
Servo acc;
void setup()                         
{
  pinMode(ch_1, INPUT_PULLUP);
  pinMode(ch_2, INPUT_PULLUP);
  pinMode(ch_3, INPUT_PULLUP);
  pinMode(ch_4, INPUT_PULLUP);
  pinMode(ch_5, INPUT_PULLUP);
  pinMode(ch_6, INPUT_PULLUP);
  pinMode(cingolodx, OUTPUT);
  pinMode(cingolosx, OUTPUT);
  pinMode(quadro, OUTPUT);
  pinMode(accelleratore, OUTPUT);
  pinMode(accensione, OUTPUT);
  Serial.begin(9600);
  Serial.setTimeout(100);
  c_dx.attach(cingolodx);
  c_sx.attach(cingolosx);
  acc.attach(accelleratore);     
  

}

void loop() 
{
   while(avvio){ 
   manopola=map(pulseIn(ch_6, HIGH),993,1986,0,100);
   direzione=map(pulseIn(ch_2, HIGH),1260,1758,0,100);
   rotazione=map(pulseIn(ch_4, HIGH),993,1986,0,100);
   interruttore=map(pulseIn(ch_5, HIGH),993,1986,0,100);
   if(direzione<5 && rotazione > 70 && pulseIn(ch_1, HIGH)>1650 && pulseIn(ch_3, HIGH)>1680){
    avvio=false;
  //  Serial.println("acceso");
    delay(5000);
   
  }
   }
   manopola=map(pulseIn(ch_6, HIGH),993,1986,0,180);
   direzione=map(pulseIn(ch_2, HIGH),1240,1758,-100,100);
   rotazione=map(pulseIn(ch_4, HIGH),1240,1758,-100,100);
   interruttore=map(pulseIn(ch_5, HIGH),993,1986,-100,100);  
   /*
   if(direzione>53)
   Serial.println("avanti");
   if(direzione<48)
   Serial.println("indietro");
   if(rotazione>53)
   Serial.println("destra");
   if(rotazione<48)
   Serial.println("sinistra");*/
   if(rotazione>0)
   r_dx=rotazione;
   else
   r_dx=0;
   if(rotazione<0)
   r_sx=rotazione;
   else
   r_sx=0;
   pos_dx=direzione-r_dx;
   pos_sx=direzione-r_sx;
   Serial.println(map(rotazione,-100,100,0,180));
   //Serial.println(map(pos_dx,-100,100,0,180));
   //Serial.println(pulseIn(ch_4, HIGH));
   acc.write(manopola);
   c_dx.write(map(pos_dx,-100,100,0,180));
   c_sx.write(map(pos_sx,-100,100,0,180));/*
   Serial.print("A");
   Serial.println(pulseIn(ch_1,HIGH));
   Serial.print("B");
   Serial.println(pulseIn(ch_2,HIGH));
   Serial.print("C");
   Serial.println(pulseIn(ch_3,HIGH));
   Serial.print("D");
   Serial.println(pulseIn(ch_4,HIGH));
   Serial.print("E");
   Serial.println(pulseIn(ch_5,HIGH));
   Serial.print("F");
   Serial.println(pulseIn(ch_6,HIGH));*/
}

non sono sicuro...ma il problema potrebbe essere in queste righe:

   Serial.println(pulseIn(ch_1,HIGH));

   Serial.println(pulseIn(ch_2,HIGH));

   Serial.println(pulseIn(ch_3,HIGH));

   Serial.println(pulseIn(ch_4,HIGH));

   Serial.println(pulseIn(ch_5,HIGH));

   Serial.println(pulseIn(ch_6,HIGH));*/

prova a commentarle ed inserire solo le println con le "lettere"...cioè senza eseguire letture di "pulseIn"...magari cadenzate da una pausa

ok stasera provo e ti faccio sapere, cmq nel monitor seriale dell'ide di arduino i println vengono visualizzati molto molto veloce.....quindi non so se si riesce a risolvere

cmq nel monitor seriale dell'ide di arduino i println vengono visualizzati molto molto veloce

per questo ho scritto di cadenzarli con una pausa (delay) :wink:

dennyxx82:
per quanto riguarda il timeout non ne ho messo perchè mi perdeva parte della stringa.....

Non ho capito perché dovrebbe. Ora il codice Arduino lo hai messo, ma le altre mie richieste e domande che fine hanno fatto?
Ti ricordo:
...e ci dai una descrizione precisa dell'esito dei tuoi test (es. i "2 minuti" di cui parli sono proprio esattamente 2 minuti? Il tempo di attesa è sempre identico ogni volta o cambia? E cosa ricevi con la readLine?)

Dal listato vedo che l'unico print sulla seriale la fai così:

Serial.println(map(rotazione,-100,100,0,180));

Dove stanno le 6 variabili (ossia le 6 righe con i valori) che invece ti aspetti di ricevere?
Sei sicuro che questo listato che hai mandato sia l'ultimo che hai usato (e del quale ci dirai COSA vedi lato Python)?

Insomma, se ci dai informazioni parziali e poco comprensibili come possiamo aiutarti?

Ripeto, prepara il codice che pensi debba funzionare (con le SEI variabili inviate ad ogni loop), testalo con il programma Python (quello che hai già postato) e riporta quindi il codice usato e cosa esattamente ricevi nelle 6 readLine lato Python.

Considera comunque alcune cose.

Primo, nel loop vedo un while() con un delay(5000), sicuro che esca da quel loop rapidamente?

Poi tu stai a 9600 bps, come detto sono 960 byte circa al secondo, ma se scrivi nel loop() continuamente, dato che la loop() viene eseguita MIGLIAIA di volte al secondo, rischi di saturare il piccolissimo buffer di Arduino, e rischi di perdere molti caratteri. Tu devi distanziare di più gli invii, prendi una certa frequenza per te accettabile (forse 10 misurazioni al secondo bastano) e metti il corrispondente delay() nel loop dopo che hai mandato i 6 parametri (quindi con un delay(100) avrai circa 10 campioni al secondo).

ORSO2001:
non sono sicuro...ma il problema potrebbe essere in queste righe:
prova a commentarle ed inserire solo le println con le "lettere"...cioè senza eseguire letture di "pulseIn"...

Ehm, veramente quelle righe sono già commentate (almeno nel listato del post #14)... :wink:

Le sei variabili sono quelle ch_1.....ch_6.

Praticamente sto interfacciando un radio comando ad Arduino per controllate dei servo motori. E voglio fare un
Software di diagnosi, semplicemente una schermata fissa dove in tempo reale si aggiornino delle caselle al cui interno vanno le variabili ch_X.

Praticamente voglio eliminare l’oscilloscopio per verificare le uscite e le le entrate di Arduino. Apparte che non sempre lo posso usare e poi non riesco a guardare tutti i segnali insieme con loscilloscopio.

Per quanto riguarda le pause nel Serial.println() non posso metterle altrimenti in quegli istanti i servo motori andranno per fatti loro.
Il while iniziale serve a far si che i servo comandi si avviino solo con una sequenza precisa di passaggi inviati dal radio comando.

Per quanto riguarda i 2 minuti ti avevo già risposto. Che è un tempo tanto per dirlo spesso sta fermo anche 5 minuti altre volte 40secondi.

Spero di essere stato chiaro.