Strano comportamento seriale

Vi descrivo il mio problema con la seriale, nella speranza che a qualcuno sia già capitato e che mi possa aiutare.

Ho il codice PHP che tramite la php.serial.class manda una stringa alla seriale e riceve una risposta.
Ecco il codice PHP

<?php
  include "php_serial.class.php";
  $serial = new phpSerial;
  $serial->deviceSet("/dev/ttyACM0");
  $serial->confBaudRate(9600);
  $serial->deviceOpen();
  $serial->sendMessage("b1");
  sleep(1);
  $read = $serial->readPort();
  $array = explode(";",$read);
  $SP_PH = $array[0];
  $SP_TE = $array[1];
  $serial->deviceClose();
?>

Il codice funziona perfettamente, tranne la prima volta che lo eseguo dopo un riavvio. La prima volta non mi arriva nessuna risposta. Sembra quasi che la seriale debba essere "svegliata".
Per svegliarla uso il seguente codice python (bottarissposta.py):

import serial

arduino=serial.Serial('/dev/ttyACM0') 

arduino.write('b1')
print arduino.readline()

Eseguendo questo codice, sempre la prima volta dopo un riavvio, capita che alla prima esecuzione si "pianta" e devo interrompere con un ctrl z e rieseguendolo subito dopo tutto funziona correttamente fino al riavvio successivo, compreso il codice php.
Ecco cosa succede quanddo eseguo bottarisposta.py

root@raspberrypi:/var/www/controlpes# python bottarisposta.py
^Z
[1]+  Stopped                 python bottarisposta.py
root@raspberrypi:/var/www/controlpes# python bottarisposta.py
1202;3.3

root@raspberrypi:/var/www/controlpes#

Avete qualche idea?

Penso che il problema risieda nel fatto che in realta dialoghi con il bootloader.
Per usare la seriale arduino, quando da pc la apri va giù la linea reset connessa al DTR, subito dopo si può dialogare con il bootloader, se questo non
riconosce il dato inviatogli come un comando avvia il programma nella sezione utente della flash.

Per cui metti un delay dopo aver aperto la porta di almeno un secondo e riprova solo con php o solo con python. Di php non sono esperto, ma mi sembra entrambe i programmi facciano la stessa cosa.

Nota che inviando una sequenza giusta di comandi arduino risponde, dicendo più meno chi è, cioè se monta un 328, o altro. Tempo addietro ne ne è parlato qui, anche con astrobeed e in quel post c'è anche del codice python che ho scritto io. Prova a cercare post miei e di astrobeed ecc, mi pare io avessi chiesto come funziona in merito ad un programma che stavo scrivendo. Davvero è passato tanto tempo e un rifrescata a quelle info male non fa di certo, il bello sarebbe trovare quei post.

Ciao.

Sei un grande, grazie 1000.
Mettendo una pausa di un paio di secondi funziona perfettamente.

pespes:
Sei un grande, grazie 1000.
Mettendo una pausa di un paio di secondi funziona perfettamente.

Non ringraziarmi, ti voglio vedere qui sul forum fare quello che ho appena fatto io con te. :wink:

Ciao.

Magari, ho appena cominciato e per adesso mi devo fare un tot di esperienza;
credevo fosse più semplice...

Adesso per esempio ho un altro problema che mi sta facendo diventare matto...

Da php invio una stringa sulla seriale; arduino la riceve e mi deve scrivere dei valori dentro alla Eprom.
Se tengo aperto il serial monitor da Arduino IDE mentre mando la stringa sulla seriale tutto ok, invece se chiudo il serial monitor non mi scrive i valori sulla Eprom.
Cosa potrà mai fare il serial monitor aperto per fare la differenza?

Ogni volta che apri e chiudi il serial monitor Arduino riceve un reset, questo lo hai verificato tu con il tuo codice, quindi non usare il serial monitor, ma usa python o php se ti trovi più a tuo aggio, e non chiudere la seriale, invia i dati e mettiti in ascolto e ciò che arriva lo stampi.

Se vuoi disabilitare l'autoreset cerca nel forum, cerca l'utente Menniti e la sua guida.

Inizia da qui per l'autoreset http://arduino.cc/forum/index.php/topic,155190.0.html

Ciao.

Purtroppo non è questo...
Ho provato a togliere il "$serial->deviceClose();" ma purtroppo non funziona. Ci deve essere qualcos'altro.
Il motivo per cui ho aperto il serial monitor è che stavo cercando di capire come mai non avviene la scrittura sulla Eprom e da li mi sono accorto che con il monitor aperto il problema non si presenta.
Devo però riuscire a farlo andare solo con PHP.

Trovato il post di cui parlavo, però leggilo tutto da l'inizio: http://arduino.cc/forum/index.php/topic,60774.msg439414.html#msg439414

Non ho ben capito con quale sequenza apri il device file, e il serial monitor, io ora penso che il device aperto da un programma e poi riaperto da un'altro programma dovrebbe dare come errore Busy o lock o simile.

Comuque, se la sequenza da php è apri device invii chiudi, e poi apri il serial monitor arduino viene resettato.

Posta il codice che usi per scrivere in eeprom, vediamo perchè non funge.

Ciao.

Dopo svariati tentativi ci sono arrivato (spero!!!).
Dalla pagina setpoint.php faccio immettere all'utente due valori: SP_PH e SP_TE.
Li passo a salvataggioSP.php che a sua volta li da a Arduino tramite seriale.
Ecco il codice di salvataggioSP.php:

<?php
  $dainviare = "a;".$_POST['SP_PH'].";".$_POST['SP_TE'];
  include "php_serial.class.php";
  $serial = new phpSerial;
  $serial->deviceSet("/dev/ttyACM0");
  $serial->confBaudRate(9600);
  $serial->deviceOpen();
  sleep(2);
  $serial->sendMessage($dainviare);
  sleep(2);
  header('Location: setpoint.php');
?>

Il primo carattere (a) serve ad arduino per capire di che tipo di riga si tratta per poi fargli compiere la scrittura sulla eprom dei due valori successivi separati da ";".
Dopo aver passato la stringa su seriale ritorno alla pagina setpoint
Per risolvere il problema ho dovuto mettere i due sleep di 2 secondi (uno non basta).
Quello dopo l'apertura della seriale l'avevo già messo mentre quello prima di tornare alla apgina setpoint no e questo causava il problema della non scrittura.
Sicuramente così funziona ma sono abbastanza perplesso di questa cosa.
E' logico così?

Io non conosco php, leggo il codice e ne intuisco cosa fà, ma ho un dubbio?

<?php ?>

Mi sembra un blocco { code... }, li dentro le variabili sono locali se abbandoni quel blocco tornando alla pagina principale, la variabile $serial esce dallo scope e il garbage la fa fuori, ci potrebbe anche essere un meccanismo automatico tipo distruttore C++, dove viene detto di chiudere il device in uso.

In C++, specie con Qt un device viene aperto ma non è necessario chiamare close, perchè appena l'oggetto esce fuori scope viene chiamato il distruttore di oggetto che prima di ogni cosa chiude il file.

Cosa accade se il file viene chiuso, si resetta Arduino? Giuro non me lo ricordo per adesso ho altro per la testa, prova il codice python al link cerca di capirci qualcosa, fai esperimenti vedi tu, indaga sul codice del bootloader di arduino per vedere come si comporta ecc.

Allora un barlume di luce, inizialmente aperta la connessione parli con il bootloader, attendi che questo avvi il programma utente e invia i dati. Quanto devi attendere, cambia da Arduino ad arduino o meglio in base al bootloader.

Se hai bisogno di altro, spara pure.

Ciao.

Riprendo questo topic perchè ho nuovamente dei problemi con la seriale che non mi spiego.

Tralasciando il codice utlizzato per recuperare i dati dalla seriale, Arduino restituisce il seguente tracciato record:
EC; PH; Temperatura; Stato Digital PIN 2; Stato Digital PIN 4; Stato Digital PIN 7; Data
I primi tre valore sono rilevati da delle sonde ma questo non importa, mi importerebbe invece capire il perchè del diverso comportamente a seconda delle condizioni che descrivo sotto. E' molto importante, per ogni caso, seguire tutti i passi che ho effettuato
Con sketch caricato su arduino:

  1. riavvio il pc a cui è collegato Arduino su USB; apro Arduino IDE; apro il serial monitor.
    Mi viene restituita la seguente stringa:
    2399;14.0;18.12;1;1;0;3/4/2013 10:15
    Perfetto, tutto funziona correttamente
  2. riavvio il pc a cui è collegato Arduino su USB;
    lancio il seguente programma scritto il python:
import serial
arduino=serial.Serial('/dev/ttyACM0')
arduino.write('c1') #quando Arduino riceve questa string, mi risponde mandandomi certi dati 
print arduino.readline()

Il programma "si pianta".
Faccio un CTRL z
Rilancio il programma e adesso tutto funziona perfettamente e mi viene restituito
2279;14.0;18.15;1;1;0;3/4/2013 10:20
3) riavvio il pc a cui è collegato Arduino su USB;
lancio il seguente programma scritto il python:

import serial
import time
arduino=serial.Serial('/dev/ttyACM0')
time.sleep (2)
arduino.write('c1') #quando Arduino riceve questa string, mi risponde mandandomi certi dati 
print arduino.readline()

(ho aggiunto una pausa di 2 secondi dopo aver apero il collegamento con la seriale)
Il programma mi restituisce:
2100;0.0;0.00;0;0;0;3/4/2013 10:24
In pratica non vengono rilevati i valori di PH; Temperatura; Stato Digital PIN 2; Stato Digital PIN 4; Stato Digital PIN 7
mentre vengono rilevati l'EC e la data.
Se rilancio il programma il comportamento è sempre lo stesso.

A questo punto apro Arduino IDE, apro il serial monitor e vedo
2479;14.0;18.06;1;1;0;3/4/2013 10:26
Sul serial monitor è OK

Chiudo il serial monitor e rilancio il solito programma di python e ottengo
2343;0.0;0.00;0;0;0;3/4/2013 10:27
Ho nuovamento perso i soliti valori

Riapro Arduino IDE e il suo serial monitor e lo lascio aperto
Eseguo il solito programma in python e vedo che i valori compaiono sul serial monitor di Arduino e tra l'altro sono corretti:
2322;14.0;18.06;1;1;0;3/4/2013 10:28

Esiste un comando da lanciare sulla seriale per fare in modo che dopo un riavvio la seriale risponda a python nella maniera corretta, come dopo un CTRL z?

A distanza e senza il codice di arduino non so dirti altro. Io ho usato Arduino 2009, con su un programma che deve dialogare tramite seriale con un ATmega644, quando ho scritto il codice per 2009 non avevo scritto il codice per il 644 e quindi usavo python per testare la comunicazione. Ti allego il file che nel mio caso simula ciò che fa il 644.

Ti consiglio di prendere il codice che hai scritto per arduino e purgarlo di ciò che non è utile per la comunicazione, i dati che spedisci rendili statici nella stessa forma, cioè rispettando il protocollo "2279;14.0;18.15;1;1;0;3/4/2013 10:20", e usa questo codice per fare i testi di comunicazione, in questo modo puoi anche postare il codice senza superare il limite di caratteri per post.

Non mi chiedere dettagli sul codice python perchè non so rispondere, il programma risale a 2 anni fa. Ricordo solo che io ho avuto problemi con il ritorno carrello "\n" e qualche problema simile al tuo, cioè ora funziona ora no, ora si ecc, ora funziona solo con python ora solo con il serial monitor, ecc.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import serial  
import time   
# imposto la porta  
ser = serial.Serial(port='/dev/ttyUSB0',  
    baudrate=115600,  
    bytesize=8,  
    parity='N',  
    stopbits=serial.STOPBITS_ONE,  
    timeout=None,  
    xonxoff=False,  
    rtscts=False,  
    writeTimeout=None,  
    dsrdtr=False)  
    

ser.open()
#ser.flushInput()

#print dir(ser)
cb = ''
message = ''
identity = False
#for i in xrange(10):
    #time.sleep(2)

    
#    ser.write('g5000')
#    ser.write('g0')
    #time.sleep(2)
    #ser.write('A')

#print "Clear DTR and RTS to unload the RESET capacitor"  
#ser.setRTS(False)
#ser.setDTR(False)
#print "attende x tempo"
#time.sleep(1)
#print "Set DTR and RTS back to high"
#ser.setRTS(True)
#ser.setDTR(True)
#print "attende x tempo"
#time.sleep(0.6)
#print "scrive 0x30, 0x20"
#ser.write(chr(0x30))
#ser.write(chr(0x20))
#print ord(ser.read())
#print "scrive 0x75, 0x20"
#ser.write(chr(0x75))
#ser.write(chr(0x20))
#print hex(ord(ser.read()))
#print hex(ord(ser.read()))
#print hex(ord(ser.read()))
#print hex(ord(ser.read()))
#print hex(ord(ser.read()))
# reset e identificazione arduino terminata, probabilmente 
# arduino 2009 non ha più il bootloader
# legge byte, si aspetta 0x2 dal master
SLAVE_ID = 5
THERE_IS_RESUME = 48 # 0x31 "1"  49
NO_RESUME = 48       # 0x30 "0"
masterIdRequest = ord(ser.read(1))

# entrano solo numeri pari
if (masterIdRequest & 1) == 0:
  if masterIdRequest == 2:
    print "ricevuta richiesta di idendificazione da Master: ",masterIdRequest
    print "rispondo inviando SLAVE_ID", SLAVE_ID
    ser.write(chr(SLAVE_ID))
    ser.write(chr(SLAVE_ID))
    ser.flushInput();
    # controllo ridondante sullo slave da fare in loop
    # il master invia e riceve ciclando 3 volte qui e la stessa cosa
    # invertita riceve e invia
    checkResume = ord(ser.read(1))      
    ser.write(chr(THERE_IS_RESUME))
    
    checkResume = ord(ser.read(1))
    ser.write(chr(THERE_IS_RESUME))
    checkResume = ord(ser.read(1))
    ser.write(chr(THERE_IS_RESUME))
      
    
    





#print "scrive 65, 80"
#ser.write(chr(0x41))
#ser.write(chr(0x80))
#ser.write(chr(0x20))
#print ord(ser.read())
#print ord(ser.read())
#print ord(ser.read())
#print ser.read()

i = 0
#pulse_width = []
lines = []
#ser.write("S")
#ser.write("Z")
busy = 0
#while True: 
    
#    i += 1
#    if i > 212000:
#        break
    #if i == 0:
        ###break
        #time.sleep(4.2)
        #ser.write("g6000")
        #i = 1
    #elif i == 1:    
        #time.sleep(4.2)
        #ser.write("g0")
        #i = 0
#    cn = ser.inWaiting()

#    if cn != 0:
#        date = ''
#        for t in xrange(cn):
#            date = date + ser.read()
#            print(date)
        
        #if True:
        #lines.append(date)    
            #if i == 2:
                #i = 1
            #elif i == 3:
                ##print i
                #i = 0 
        #else:
            #busy += 1
            #print "busy"
            #if busy > 3:
                #ser.write("\n")
                #busy = 0
ser.close()

Niente, non ci salto fuori, se uso il serial monitor di arduino i valori sono corretti mentre se uso python (o php) alcuni dati non mi arrivano corretti.

Ho struttato il codice

import serial  
import time   
# imposto la porta  
ser = serial.Serial(port='/dev/ttyUSB0',  
    baudrate=115600,  
    bytesize=8,  
    parity='N',  
    stopbits=serial.STOPBITS_ONE,  
    timeout=None,  
    xonxoff=False,  
    rtscts=False,  
    writeTimeout=None,  
    dsrdtr=False)  
ser.open()

per inizializzareil collegamento ma il problema persiste.
Spero che qualcun'altro abbia avuto lo stesso problema e mi aiuti.
Rimango del parere che ci possa essere un comando da "sparare" all'inizio della comunicazione per "svegliare" arduino. Tipo:
eseguo il codice python

import serial

arduino=serial.Serial('/dev/ttyACM0') 

arduino.write('b1')
print arduino.readline(

e si pianta. Premo CTRL z e prende a funzionare alla perfezione. Ecco, bisognerebbe anticipare quel "si pianta e premo CTRL z".
Vi prego, se avete idee ditemi pure....

Mi pare di capire che hai problemi quando lanci il programma prima che Arduino abbia inizializzato la seriale.
Dopo l'inizializzazione fai accedere ad esempio il pin 13. Cosi vedi visivamente cosa sta combinando Arduino.

Se apri il serial monitor Arduino si resetta, viene reinizializzato e lo sketch parte dall'inizio. Non che il problema e nel codice Arduino e non in Pyton?
Anche perché questo contrasta con la tesi di prima, ovvero fai ripartire Arduino con il programma Pyton già in esecuzione.

Esiste un comando in pyton per bloccare l'esecuzione attendendo che sia stata inizializzata la seriale da parte di Arduino?

PaoloP:
Mi pare di capire che hai problemi quando lanci il programma prima che Arduino abbia inizializzato la seriale.
Dopo l'inizializzazione fai accedere ad esempio il pin 13. Cosi vedi visivamente cosa sta combinando Arduino.

Se apri il serial monitor Arduino si resetta, viene reinizializzato e lo sketch parte dall'inizio. Non che il problema e nel codice Arduino e non in Pyton?
Anche perché questo contrasta con la tesi di prima, ovvero fai ripartire Arduino con il programma Pyton già in esecuzione.

In teoria è il contrario: io alimento arduino con un alimentatore e quindi rimane sempre acceso.
Quello che riavvio è il pc collegato a Arduino con USB.

quando il pc apre la porta seriale invia un comando di reset, che riavvia l'arduino. Cerca il sistema per disattivare l'autorest

Ma questo reset lo manda solo la prima volta dopo aver riavviato il pc o lo fa sempre?
Perchè se lo facesse sempre non mi spiego come mai, dopo aver fatto la procedura "si pianta, CTRL z" (scusate la terminologia, è per cercare di farmi capire), dovrebbe sempre mandare il reset e sarei sempre al punto di partenza invece fino al riavvio successivo del pc tutto funziona correttamente. Posso aprire la connessione seriale tutte le volte che vohlio senza avere problemi, i dati che arrivano sono sempre perfetti.

Ne approfitto per ringraziare tutti dell'aiuto che mi state dando.

lo invia non al riavvio del PC, ma ogni volta che apri la porta seriale.

esempio: apri il SerialMonitor? viene inviato un reset. Chiudi il serialMonito e lo riapri? altro reset. Riavvi il PC? non succede nulla. Apri arduino e poi il SerialMonitor? reset!

Allora non penso proprio che disabilitare l'autoreset possa risolvere il mio problema...
Mi ci vuole qualcosa che dopo aver riavviato il pc riesca a ristabilire il collegamento seriale con Arduino nella maniera corretta.

ah, ok, ho riletto qualche messaggio, il problema pare della libreria phyton.

Quale usi? hai il link? se è quella che penso io il suo sviluppo è fermo al 2009... non mi stupisco che sia buggata