• Benvenuti su RaspberryItaly!
Benvenuto ospite! Login Login con Facebook Registrati Login with Facebook


Valutazione discussione:
  • 0 voto(i) - 0 media
  • 1
  • 2
  • 3
  • 4
  • 5

[-]
Tags
nuovo progetto con difficoltà pico

Difficoltà con nuovo progetto con PICO
#1
Buonasera a tutti, 

l'oggetto che sto cercando di realizzare è molto semplice: 
1) un PICO senza wireless
2) un pacco da 3 batterie AA
3)un sensore UR e temperatura BME280

l'idea è questa: l'oggetto dovrebbe essere collegato al PC per ilprimo rilievo così registra la data e l'ora e i dati del sensore in logger.csv, poi si accende il pacco batterie, si sconnette dal PC e per i successivi rilievi che avvengono ogni 15 minuti aggiorna in automatico la data ora aggiungendo 15 minuti e riscrive tutto nel file insieme al nuovo rilievo. 

l'ambiente è Circuitpython
Tra un rilievo l'altro il pico va in deepsleep per consumare meno e per fare durare di più le batterie. 

il codice è il seguente: 
Codice:
import traceback
try:

    #prova deep sleep senza scrittura file che aggiungo dopo

    import time
    import alarm
    import board
    import busio
    import adafruit_bme280.basic as adafruit_bme280
    import analogio
    import digitalio
    import usb_cdc #per la verifica della connessione del Pico
    import rtc
    import adafruit_datetime as datetime


    print("ci sono 20 secondi prima che si avvii il codice per interromperlo e scaricare il logger.csv")
    time.sleep(20)
    print()

    # Qui fai lettura sensore
    print("Leggo sensore")
    i2c = busio.I2C(scl=board.GP9,sda=board.GP8)

    # BME280
    bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c,address=0x76)
    time.sleep(2)
    Temperatura = round(bme280.temperature, 2)
    Umidità = round(bme280.humidity, 2)

    # Leggi la tensione reale dal Pin 39 (VSYS)
    vsys_adc = analogio.AnalogIn(board.VOLTAGE_MONITOR)
    def get_vsys_voltage():
        # Legge il valore ADC a 16-bit (0-65535)
        adc_value = vsys_adc.value
       
        # Converte il valore in tensione letta dall'ADC (3.3V di riferimento)
        adc_voltage = (adc_value * 3.3) / 65535
       
        # Il circuito del Pico dimezza VSYS sul pin 39, quindi moltiplichiamo per 2
        vsys_actual = adc_voltage * 2
        return vsys_actual
    vsys = get_vsys_voltage() 



    print()
    print("Temperatura:", Temperatura)
    print("Umidità:", Umidità)
    print("il voltaggio su vsys è ", vsys," deve essere maggiore di 3.3 volt altrimenti il Pico non funziona correttamente, il sensore funziona anche con tensione inferiore")
    print("potrei inserire una condizione per cui quando il valore è minore di 3.3 si accende un led")
    print("che indica di cambiare la batteria, ma al momento il valore lo scrivo solo sul logger")
    print("----------------")

    #inserire qui la condizione per la data ed eventuale calcolo della data
    orologio = rtc.RTC() # Crea l'oggetto RTC per l'orologio interno

    if usb_cdc.console.connected:
        print("il Pico è connesso al computer può scrivere la data sul logger.csv")
        # Crea l'oggetto RTC per l'orologio interno
        orologio = rtc.RTC()#sincronizza l'orologio
        # Ottieni il timestamp corrente
        ora_corrente = datetime.datetime.now()#con questo faccio i calcoli
        print (ora_corrente)
        print(type(ora_corrente))
        strOraCorrente=str(ora_corrente)#per trasformarlo in str devo creare un a nuova variabile
        print(type(strOraCorrente))
        print (strOraCorrente)#con questo lo scrivo su Excell
        data=strOraCorrente
        # Formatta la data e ora in una stringa pulita (Es: "2026-05-23 15:30:00")
        #data_formattata = ora_corrente.strftime("%Y-%m-%d %H:%M:%S") #strftime non funziona in circuitpython
        #print(data_formattata)   
    else:
        print("il Pico non è connesso al computer aggiungere alla data ora precedente 15 minuti")
        # 1. Legge l'ultima riga del file
        f = open("logger.csv", "r")
        #with open(logger.csv, "r") as f:
        righe = f.readlines()
        ultima_riga = righe[-1].strip()
        # 2. Isola la stringa della data (es: "2026-05-23 16:10:00")
        stringa_dataora = ultima_riga.split(";")[0] #prende il primo termine prima del ;
        # 3. Separa i pezzi usando gli spazi, i trattini e i due punti
        data_pezzi, ora_pezzi = stringa_dataora.split(" ")
        anno, mese, giorno = data_pezzi.split("-")
        ora, minuto, secondo = ora_pezzi.split(":")

        # 4. Ricrea l'oggetto datetime puro
        ultima_dataora = datetime.datetime(
            int(anno), int(mese), int(giorno),
            int(ora), int(minuto), int(secondo))
        print(ultima_dataora)

        # 5. Aggiunge 15 minuti
        nuova_dataora = ultima_dataora + datetime.timedelta(minutes=15)
        print(nuova_dataora)
        data=str(nuova_dataora)
       

    #print("qui dovrei inserire la scrittura su file logger che al momento non eseguo")
    # apertura file
    with open("logger.csv", "a") as file:#è un append
        file.write(
            data
            + ";"
            +str(Temperatura)
            + ";"
            + str(Umidità)
            +";"
            + str(vsys)
            + "\n"
        )
        file.flush()#salva il file

    print("SCRITTO")

    print("parte un deep sleep di 900 secondi")
    # Attendi eventuali operazioni
    time.sleep(1)

   

except Exception as e:

    with open("errore.txt", "a") as f:

        f.write("\n----- NUOVO ERRORE -----\n")

        traceback.print_exception(e, file=f)

# Wake tra 15 minuti
time_alarm = alarm.time.TimeAlarm(
    monotonic_time=time.monotonic() + 877
)


# deep sleep


alarm.exit_and_deep_sleep_until_alarms(
    time_alarm
)

Non funziona. Secondo me perché

connetto al PC, parte in automatico code.py il primo rilievo compresa la data, se non ho capito male, non la scrive materialmente nel file logger.csv ma la tiene nella ram del Pico fino a che non si spegne il pico e lo si riaccende. Questo lo deduco dal fatto che se tra un rilievo e l'altro apro il logger.csv lo trovo vuoto, se spengo e riacendo il Pico anche se alla riaccensione arresto il code.py in logger.csv trovo il dato. 
Pertanto il secondo rilievo non legge nessuna data a cui aggiungere i 15 minuti. 
Insomma se faccio le prove con la procedura che ho ipotizzato e lo lascio per una o 2 orette lì a rilevare alla fine il file logger.csv è vuoto. 

nel file errore trovo questo 

----- NUOVO ERRORE -----
Traceback (chiamata più recente per ultima):
  File "code.py", riga 80, in <module>
IndexError: index oltre il limite
 in riga 80
Codice:
ultima_riga = righe[-1].strip()

in pratica nell riga 80 c'è la lettura del file per estrarre la data  con un indice che però non trova perché la data non è scritta nel file fino a quando non si spegne e riaccende il Pico (se non ho capito male). 

Potrei cambiare la procedura, devo provare. 
1) primo rilievo con pico connesso attendo la scrittura poi disconnetto il il Pico dal PC
2) attendo 877 secondi e riaccendo il pico con le batterie. 

però mi sembra molto rozzo ..... 

Suggerimenti?

Un grazie anticipato e per tutto

Un salutone


LaPa
Risposta
#2
Ciao
non ho capito, a livello hardware, come sono collegate le batterie.
Per alimentare il Raspberry Pi Pico a batterie mantenendo la possibilità di collegare la porta USB al PC, collega il pacco batterie al pin VSYS.
Grazie al circuito di protezione integrato, il Pico passerà automaticamente all'alimentazione USB quando il cavo è collegato, senza rischiare di danneggiare la porta del computer o le batterie.

Guida ai collegamenti:
Positivo della batteria (+): Pin 39 (VSYS)
Negativo della batteria (-): A qualsiasi pin GND (es. Pin 38 o 3)
Tensione supportata: Tra 1.8 V e 5.5 V

Come funziona:
La scheda è progettata con un diodo di blocco (D1) tra il pin VBUS (alimentazione USB) e VSYS (alimentazione di sistema). Questo diodo impedisce alla corrente proveniente dalla porta USB di caricare o danneggiare la batteria, e viceversa.
Se scolleghi il cavo USB: il Pico si alimenta esclusivamente dalle batterie.
Se colleghi il cavo USB: il Pico prenderà l'alimentazione dalla porta USB (tensione leggermente più alta).
Alcuni utenti inseriscono un diodo Schottky aggiuntivo sul pin VSYS per una sicurezza ancora maggiore.


Volendo, puoi anche misurare la tensione applicata al VSYS per sapere quando le batterie sono da cambiare.
ecco un esempio trovato in rete:
Codice:
import machine
import time

# Configura il pin ADC3 (GPIO 29) che è collegato internamente a VSYS
vsys_adc = machine.ADC(29)

# === GESTIONE PICO W (Rimuovi i commenti sotto se usi la versione con Wi-Fi) ===
# Sul Pico W, il pin GPIO 25 controlla l'alimentazione del chip Wi-Fi.
# Se non viene impostato su HIGH, la lettura di VSYS risulterà errata o instabile.
#
# wifi_power_pin = machine.Pin(25, machine.Pin.OUT)
# wifi_power_pin.value(1)
# ==============================================================================

# Fattore di conversione:
# 3.3V (tensione di riferimento) * 3 (rapporto del partitore interno) / 65535 (risoluzione 16-bit)
CONVERSION_FACTOR = (3.3 * 3) / 65535

while True:
    # Leggi il valore grezzo dall'ADC (valore compreso tra 0 e 65535)
    raw_value = vsys_adc.read_u16()
    
    # Converti il valore grezzo in Volt reali della batteria
    battery_voltage = raw_value * CONVERSION_FACTOR
    
    # Stampa il risultato a schermo
    print(f"Tensione Batteria: {battery_voltage:.2f} V")
    
    # Attendi 2 secondi prima della prossima lettura
    time.sleep(2)



il datasheet di Raspberry Pi Pico
Risposta
#3
I dati non possono essere "conservati" nella RAM poichè togliendo alimentazione al pico verrebbero cancellati. Sono in un buffer creato nella flash. Il metodo flush() in Python (e credo anche in circuitpython) forza lo svuotamento immediato del buffer di output, inviando i dati in sospeso direttamente al file. flush() non chiude però il file, aperto precedentemente con "a" (append). Un esempio: https://www.w3schools.com/python/ref_file_flush.asp. Prova semplicemente a chiudere il file al posto di flush() o chiudilo dopo. Similmente chiudi il file "logger.csv" dopo averlo letto (lo riapri successivamente con append senza verlo precedentemente chiuso):
---------------------------------
# 1. Legge l'ultima riga del file
f = open("logger.csv", "r")
---------------------------------
Risposta
#4
appunto, collegando la batteria su VSYS non disalimenti mai il dispositivo, nemmeno quando lo colleghi al pc
Risposta
#5
Salve, grazie delle risposte.
Forse non sono stato chiaro.
Il positivo delle batterie è collegato al pin 39 del Pico.

Nel file logger.csv ci sono 4 colonne: data ora, Temperatura, UR, voltaggio

Il problema è che volendo usare il dispositivo completamente disconnesso e alimentato a batterie non c'è la possibilità di scrivere la data e l'ora del rilievo.

Per ovviare a questo problema ho pensato d'iniziare i rilevi con pacco batterie spento e connettendo il Pico al PC in questo modo la data e l'ora vengono rilevate e scritte in prima riga e prima colonna perché sincronizzato al PC.

Prima che avvenga il rilievo successivo accendo il pacco batterie e disconnetto il pico dal computer. Ma se il Pico è disconnesso non può rilevare la data ora pertanto l'idea è di ricostruire data ora aggiungendo 15 minuti alla precedente data ora dal secondo rilievo in poi. Ma al momento ho qualche difficoltà.
@Zzed
Ritieni che tale stratagemma sia sbagliato o inapplicabile?
Suggerimenti?
@ippogrifo se non ho capito male il tuo suggerimento è di sostituire nel mio codice
file.flush()
con
file.close()
Giusto?
Ci provo

Ci ho provato: 2 casi
1) se connetto il Pico al PC e lascio scorrere il code.py senza intervenire non scrive niente nel file logger.csv
2) se connetto il Pico al PC arresto il codice via Thonny (per questo c'è uno sleep di 20 secondi prima che il codice parta) e lo faccio ripartire mi scrive i dati nel file logger.csv.
Se a questo punto disconnetto il PICO dal PC e lo tengo spento per 15 minuti e poi lo riavvio da batteria e lo lascio acceso per un'oretta o più mi scrive la data corretta e i rilievi ogni 15 minuti.
Ora il problema è perché nel caso 1 non scrive del logger.csv e di conseguenza anche i successivi rilevi falliscono?
Saluti
LaPa
Risposta
#6
Puoi anche aggiungere file.close() dopo file.flush(). Importante che il file venga chiuso dopo le operazioni sullo stesso.
Similmente va chiuso il file dopo la lettura (f = open("logger.csv", "r") con f.close().
Avendo chiuso il file (istruzione file.close() ) è anche possibile verificare se c'è stata la scrittura dei dati riaprendolo subito dopo.
Risposta
#7
la batteria lasciala sempre accesa, fai in modo che quando lo colleghi al pc e acquisisce data e ora, lampeggi un led o ti dia qualche altra indicazione visiva, a quel punto potrai scollegarlo.
l'alternativa è, per pochi euro, aggiungere un modulo RTC che mantenga data e ora anche senza alimentazione.
Risposta
#8
Le tre batterie, alcaline immagino, puoi lasciarle connesse purchè la loro tensione si avvicina ai 5 VDC. Vi è di fatto un diodo al silicio di disaccoppiamento verso la porta USB. La caduta di tensione su un diodo al silicio (non Schottky ) in conduzione è di circa 0,5 - 0,6 Volt (mediamente, funzione della corrente circolante). Se le 3 batterie fossero al massimo della carica, il diodo sarebbe inversamente polarizzato e quindi non conducendo quando la porta USB fosse connessa al PC. Appena sconnesso dal PC il pico sarebbe istantaneamente alimentato. (come già suggerito da Zzed). Il problema può però presentarsi se le batterie fossero scariche (intorno ai 4,3 V) ; in questo caso il diodo sarebbe polarizzato correttamente conducendo anche verso le batterie (l'impiego di un interruttore elettronico potrebbe risolvere il problema). L'utilizzo di un modulo RTC (come suggerito da Zzed) autoalimentato (con batteria a bottone CR2032 normalmente) con cui comunicare in SPI al momento del risveglio del pico potrebbe essere la soluzione più "precisa" a livello dei tempi.

P.S.
Il problema della bassa tensione della batteria rispetto alla  5 VDC della porta USB quando collegato al PC è risolvibile con un diodo al silicio: anodo collegato al positivo della batteria, catodo al Vsys. Un diodo Schottky è preferibile per la bassa caduta di tensione sui reofori quando attraversato  da corrente.
Risposta
#9
Mi piacerebbe lasciare, se possibile, l'attrezzino così com'é senza aggiungere altro e agire se possibile solo sul codice. 
Ho cercato di comprendere e mettere in pratica qualche suggerimento.
il codice ora è
Codice:
import traceback
try:

    #prova deep sleep senza scrittura file che aggiungo dopo

    import time
    import alarm
    import board
    import busio
    import adafruit_bme280.basic as adafruit_bme280
    import analogio
    import digitalio
    import usb_cdc #per la verifica della connessione del Pico
    import rtc
    import adafruit_datetime as datetime


    print("ci sono 20 secondi prima che si avvii il codice per interromperlo e scaricare il logger.csv")
    time.sleep(20)
    print()

    # Qui fai lettura sensore
    print("Leggo sensore")
    i2c = busio.I2C(scl=board.GP9,sda=board.GP8)

    # BME280
    bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c,address=0x76)
    time.sleep(2)
    Temperatura = round(bme280.temperature, 2)
    Umidità = round(bme280.humidity, 2)

    # Leggi la tensione reale dal Pin 39 (VSYS)
    vsys_adc = analogio.AnalogIn(board.VOLTAGE_MONITOR)
    def get_vsys_voltage():
        # Legge il valore ADC a 16-bit (0-65535)
        adc_value = vsys_adc.value
       
        # Converte il valore in tensione letta dall'ADC (3.3V di riferimento)
        adc_voltage = (adc_value * 3.3) / 65535
       
        # Il circuito del Pico dimezza VSYS sul pin 39, quindi moltiplichiamo per 2
        vsys_actual = adc_voltage * 2
        return vsys_actual
    vsys = get_vsys_voltage() 



    print()
    print("Temperatura:", Temperatura)
    print("Umidità:", Umidità)
    print("il voltaggio su vsys è ", vsys," deve essere maggiore di 3.3 volt altrimenti il Pico non funziona correttamente, il sensore funziona anche con tensione inferiore")
    print("potrei inserire una condizione per cui quando il valore è minore di 3.3 si accende un led")
    print("che indica di cambiare la batteria, ma al momento il valore lo scrivo solo sul logger")
    print("----------------")

    #inserire qui la condizione per la data ed eventuale calcolo della data
    orologio = rtc.RTC() # Crea l'oggetto RTC per l'orologio interno

    if usb_cdc.console.connected:
        print("il Pico è connesso al computer può scrivere la data sul logger.csv")
        # Crea l'oggetto RTC per l'orologio interno
        orologio = rtc.RTC()#sincronizza l'orologio
        # Ottieni il timestamp corrente
        ora_corrente = datetime.datetime.now()#con questo faccio i calcoli
        print (ora_corrente)
        print(type(ora_corrente))
        strOraCorrente=str(ora_corrente)#per trasformarlo in str devo creare un a nuova variabile
        print(type(strOraCorrente))
        print (strOraCorrente)#con questo lo scrivo su Excell
        data=strOraCorrente
        # Formatta la data e ora in una stringa pulita (Es: "2026-05-23 15:30:00")
        #data_formattata = ora_corrente.strftime("%Y-%m-%d %H:%M:%S") #strftime non funziona in circuitpython
        #print(data_formattata)   
    else:
        print("il Pico non è connesso al computer aggiungere alla data ora precedente 15 minuti")
        # 1. Legge l'ultima riga del file
        f = open("logger.csv", "r")
        #with open(logger.csv, "r") as f:
        righe = f.readlines()
        f.close()
        ultima_riga = righe[-1].strip()
       
        # 2. Isola la stringa della data (es: "2026-05-23 16:10:00")
        stringa_dataora = ultima_riga.split(";")[0] #prende il primo termine prima del ;
        # 3. Separa i pezzi usando gli spazi, i trattini e i due punti
        data_pezzi, ora_pezzi = stringa_dataora.split(" ")
        anno, mese, giorno = data_pezzi.split("-")
        ora, minuto, secondo = ora_pezzi.split(":")

        # 4. Ricrea l'oggetto datetime puro
        ultima_dataora = datetime.datetime(
            int(anno), int(mese), int(giorno),
            int(ora), int(minuto), int(secondo))
        print(ultima_dataora)

        # 5. Aggiunge 15 minuti
        nuova_dataora = ultima_dataora + datetime.timedelta(minutes=15)
        print(nuova_dataora)
        data=str(nuova_dataora)
       

    #print("qui dovrei inserire la scrittura su file logger che al momento non eseguo")
    # apertura file
    with open("logger.csv", "a") as file:#è un append
        file.write(
            data
            + ";"
            +str(Temperatura)
            + ";"
            + str(Umidità)
            +";"
            + str(vsys)
            + "\n"
        )
        file.flush()#salva il file
        file.close()#chiude il file

    print("SCRITTO i dati nel file logger.csv")

    print("parte un deep sleep di 900 secondi")
    # Attendi eventuali operazioni
    time.sleep(1)

   

except Exception as e:

    with open("errore.txt", "a") as f:

        f.write("\n----- NUOVO ERRORE -----\n")

        traceback.print_exception(e, file=f)

# Wake tra 15 minuti
time_alarm = alarm.time.TimeAlarm(
    monotonic_time=time.monotonic() + 877
)


# deep sleep


alarm.exit_and_deep_sleep_until_alarms(
    time_alarm
)

ho applicato la seguente procedura:
Accendo l'interruttore delle batterie con il Pico disconnesso dal PC, connetto il Pico al PC entro 10 secondi: il code.py non dovrebbe recuperare la data in quanto ha uno sleep di 20 secondi. Dopo 2 minuti disconnetto il Pico dal PC in quanto sicuramente in quel tempo il code.py avrà scritto il primo rilievo ed è andato in Deep Sleep. 
Ma non funziona in quanto non scrive il primo rilievo e quindi, non avendo la prima data, non scrive neanche gli altri rilievi.
Sembrerebbe che non parta in automatico il code.py come dovrebbe succedere con in Circuitpython. nel file errore trovo il solito problema relativo ai rilievi successivi al primo in quanto non trova la prima data ore nel file logger,csv

Se io connetto il Pico al PC, entro i 20 secondi arresto loscript code.py e poi lo faccio ripartire mi scrive correttamente il primo rilievo in logger.csv .

Saluti 
LaPa
Risposta
#10
Il diodo posto in serie al positivo del pacco batterie si rende necessario per separarle dalla 5 Volt della porta USB. Puoi inserirlo al posto dell'interruttore che diverrebbe superfluo. Così facendo il pico sarebbe sempre alimentato.
Per test potresti creare una funzione di scrittura file con il codice già presente ed inserirla nel codice di verifica di connessione al PC prima dell'else.

P.S.
Utilizzando un gestore di contesto (with) viene assicura la chiusura corretta del file dopo l'uso. Prova quindi a commentare le istruzioni file.flush() e file:close(), quest'ultima non necessaria poichè il file risulta già chiuso.
Risposta
  


Vai al forum:


Navigazione: 1 Ospite(i)
Forum con nuovi Post
Forum senza nuovi post
Forum bloccato
Forum Redirect