Arduino python

Salve ragazzi, senza troppe presentazioni vi espongo il mi problema.
Ho un sensore di prossimità collegato al mio arduino, vorrei inviare il valore della distanza al mio pc - tramite la usb usando pySerial - e leggerlo tramite python.
Arduino code:

#include <Ultrasonic.h>

void setup(){ 
  Serial.begin(9600); 
  pinMode(13,OUTPUT);   // led integrato
  Serial.write(1);   //valore buleano per inizializzazione 
}

void loop() {
  
  inizia();    // per inizializzazione 

  Ultrasonic ultrasonic(6,7); // collego sensore e tramte la sua libreria "ultrasonic" ricevo indietro il valore in cm
  int a = ultrasonic.Ranging(CM);     // metto in a il valore in cm della distanza
  Serial.write(a);        /spedisco a sulla seriale
    
}

void inizia(){
    do { 
       if(Serial.read()== 5 ) {     // inizializzazione
        digitalWrite(13,HIGH);
	delay(500);  
	digitalWrite(13,LOW);
	delay(500);
	digitalWrite(13,HIGH);
	delay(500);
	digitalWrite(13,LOW);
	delay(500);
	Serial.write(0); // condizione per uscire dal ciclo do-while
       }
   }
   while( Serial.read()== 0 );
}

Python code:

import serial
import time

arduino = serial.Serial('/dev/ttyACM0', 9600, timeout=0)
print("initialising")   # waiting the initialization...

connected = False
while (connected == True):
	connected = arduino.read()

print ("initialised")
time.sleep(2)

arduino.write("5")  #per inizializzazione

for i in range(0,10):
	a = arduino.read()  #read ??
	print a

arduino.close()

Queste sono le mie considerazioni:
1_ tramite la serial.write(int) spedisco un'intero verso il python - nella guida arduino seriale write dice che invia automaticamente 1 Byte -
2_ tramite la arduino.read() leggo il dato spedito - nella guida Pyserial dice che legge 1 Byte

Tuttavia stampa o caratteri senza senso, o spazi vuoti. Qualcuno mi può aiutare?

arduino.write("5")  #per inizializzazione
if(Serial.read()== 5 )

Scrivi da Python un "5" e quindi devi leggere un '5' invece di un 5.

Credo comunque che vada fatto un po' diversamente, quei delay e l'assenza di un if Serial.available() mi convincono poco.

Inoltre ricordati che tutte le volte che lato PC apri la seriale resetti l'Arduino.

Mi sono riletto qualche guida ed ho semplificato il programma:
Arduino's code:

#include <Ultrasonic.h>

void setup(){
Serial.begin(9600);
pinMode(13,OUTPUT); // led integrato
}

void loop() {
if (Serial.available()>0) {
Ultrasonic ultrasonic(6,7); // (Trig PIN,Echo PIN)
int a = ultrasonic.Ranging(CM);
Serial.println(a);
Serial.write(a); // send single byte
}
}

aspetta che venga spedito un numero >0 , dopo scrive sulla seriale il valore del sensore. Il ciclo si ripete solo se arriva un valore >0.

Python's code:

import serial
import time

arduino = serial.Serial('/dev/ttyACM1', 9600)

for i in range(0,10):
arduino.write('5') # valore causale per aprire comunicazione
a = arduino.read() # valore restituito in cm da arduino
print a
time.sleep(2)

arduino.close()

Scrive un valore >0 per aprire la seriale , legge il valore trasmesso da arduino.

Ovviamente non funziona, aspetta l'arrivo d'un valore >0, che a quanto pare non arriva. Se inserisco un valore >0 dal terminale seriale di arduino funziona ( ma poi non si ferma più.... ed anche questo mi puzza perchè dovrebbe aspettare un altro valore >0 )

leo72:
Inoltre ricordati che tutte le volte che lato PC apri la seriale resetti l'Arduino.

Non tutte le Arduino, la Due sulla programming port, la Leonardo e tutte quelle basate sull'ATMega32u4 non si resettano se apri e chiudi la seriale sul PC.

Io ho arduino uno V3, quindi mi si resetta ogni volta che si apre la connessione? non ho ben capito cosa intendiate per "resettare"

@Federico:
era riferito alla scheda che ha lui, la UNO R3, lo ha specificato bene in precedenza.

@markcalaway:
"resettare" è un italianismo derivante dal "reset" inglese ossia il riavvio della scheda. Ogni volta che apri la seriale è come se premessi il pulsantino reset sull'Arduino: il microcontrollore viene riportato allo stato iniziale ed il programma riparte dall'inizio

Perchè hai messo Serial.write, non basta il Serial.println? Per sicurezza metti nel codice python dei controlli sul numero di byte nel buffer di arrivo (metodo inWaiting). Lato arduino svuota completamente il buffer quando ricevi il carattere 5 (il tuo programma non fa mai un Serial.read() se noti.

Ho fatto un piccolo test con una fotoresistenza e questo sketch andava, facendo piu o meno quello che serve a te

/* Semplice sketch per trasferimento dati tra arduino e pc */
int val = 0; // Valore letto da A0
int oldval = 0; // Valore del loop precedente
int tol = 100;
void setup() {
 /* Inizia comunicazione seriale e stampa un 3 */
 Serial.begin(9600);
 Serial.print('3'); 
}
void loop() {
  val = analogRead(A0);
  oldval = analogRead(A0);
  delay(50);
  val = analogRead(A0);
  if(val > oldval + tol || val < oldval - tol) {
    Serial.print(val);
  }
}

(avevo messo println ma probabilmente print va meglio, quindi l' ho sostituito nello sketch nuovo, dovrebbe andare comunque)

Codice python:
print("Pronto a ricevere comandi")
while True:
        import serial
        import subprocess
        s = serial.Serial("/dev/ttyACM0",9600,timeout=0.1)
        r = s.readline()
        if not r=='':
                print(r)

Prova a vedere se riesci ad adattarlo al tuo caso

EDIT:
Se ti da problemi, dai un' occhiata alle spie L TX RX: se quando apri python si resettano e poi continuano a farlo, inserisci un condensatore da 10 uF (microfarad) tra reset e gnd (positivo del condensatore nel reset, negativo del codensatore nel gnd)
Sul mio arduino uno R3, questo sketch va anche senza, tuttavia potrebbe essere necessario

Forte dei vostri consigli ho riscritto il codice, ora sembra funzionare alla perfezione.
Arduino's code:

#include <Ultrasonic.h>

void setup(){ 
  Serial.begin(9600); 
  pinMode(13,OUTPUT);   // led integrato
}

void loop() {
  if (Serial.available()>0) {
   int b = Serial.read();
   
   if ( b=='5' ){
       Ultrasonic ultrasonic(6,7); // (Trig PIN,Echo PIN)
       int a = ultrasonic.Ranging(CM);
       Serial.print(a); 
   } 
  }
}

Python's code:

import serial
import time

arduino = serial.Serial('/dev/ttyACM0', 9600, timeout=0.1)

for i in range(0,20):
   arduino.write('5') # valore causale per aprire comunicazione

   a = arduino.readline() # valore restituito in cm da arduino
   print a

   time.sleep(1)

arduino.close()

Tuttavia ho qualche domanda ^_^:

  1. ho aggiunto in python "timeout=0.1", è il tempo che aspetta per iniziare a trasmettere?
  2. in python "arduino.close" chiude la comunicazione , arduino si resetta anche qui?
  3. in python "readline" e "read" che differenze hanno? nella guida ho notato che:
  • read() dovrebbe leggere un byte; se inserisco un numero nelle parentesi è il numero di byte da leggere
  • readline() legge fino all'arrivo del timeout, che è quello del punto 1?

markcalaway:
Tuttavia ho qualche domanda ^_^:

  1. ho aggiunto in python "timeout=0.1", è il tempo che aspetta per iniziare a trasmettere?
  2. in python "arduino.close" chiude la comunicazione , arduino si resetta anche qui?
  3. in python "readline" e "read" che differenze hanno? nella guida ho notato che:
  • read() dovrebbe leggere un byte; se inserisco un numero nelle parentesi è il numero di byte da leggere
  • readline() legge fino all'arrivo del timeout, che è quello del punto 1?
  1. Indica il tempo prima che vada in timeout , se non lo metti aspetta fino a quando la non si collega alla seriale, così invece se entro tot non funziona, il loop va avanti.
    2 Penso di si, ma non ne sono sicuro
    3 Readline dovrebbbe leggere tutta la riga, read() un solo byte.