time — funzioni relative al tempo

Il modulo time fornisce funzioni per ottenere l’ora e la data correnti, misurare intervalli di tempo e gestire ritardi.

Epoca di riferimento: Le OpenMV Cam basate su Alif e i.MX RT utilizzano l’epoca POSIX del 1970-01-01 00:00:00 UTC. Le OpenMV Cam basate su STM32 utilizzano un’epoca del 2000-01-01 00:00:00 UTC. L’anno dell’epoca può essere determinato a runtime con gmtime(0)[0].

Mantenimento della data/ora di calendario effettiva: Questo richiede un Real Time Clock (RTC). Sulla OpenMV Cam l’ora di sistema è fornita dall’oggetto machine.RTC. L’ora di calendario corrente può essere impostata con machine.RTC().datetime(tuple) ed è mantenuta da uno tra:

  • Una batteria di backup (un componente opzionale su alcune OpenMV Cam).

  • Un protocollo di sincronizzazione dell’ora in rete come ntptime (richiede una connessione di rete).

  • Impostazione manuale a ogni accensione. L’RTC viene quindi tipicamente mantenuto attraverso i soft reset, ma viene perso in caso di interruzione dell’alimentazione a meno che non sia montata una batteria di backup.

Se l’ora di calendario non viene mantenuta, le funzioni seguenti che fanno riferimento all’ora assoluta corrente non si comporteranno come previsto.

Funzioni

time.gmtime(secs: int | None = None) Tuple[int, int, int, int, int, int, int, int]
time.localtime(secs: int | None = None) Tuple[int, int, int, int, int, int, int, int]

Converte il tempo secs espresso in secondi trascorsi dall’Epoca (vedere sopra) in una tupla di 8 elementi che contiene: (year, month, mday, hour, minute, second, weekday, yearday) Se secs non viene fornito o è None, viene utilizzata l’ora corrente dell’RTC.

La funzione gmtime() restituisce una tupla data-ora in UTC, mentre localtime() restituisce una tupla data-ora in ora locale.

Il formato delle voci nella tupla di 8 elementi è:

  • year include il secolo (ad esempio 2014).

  • month va da 1 a 12

  • mday va da 1 a 31

  • hour va da 0 a 23

  • minute va da 0 a 59

  • second va da 0 a 59

  • weekday va da 0 a 6 per Lun-Dom

  • yearday va da 1 a 366

time.mktime(date_time_tuple: Tuple[int, int, int, int, int, int, int, int]) int

Questa è la funzione inversa di localtime. Il suo argomento è una tupla completa di 8 elementi che esprime un tempo come quello di localtime. Restituisce un intero che è il numero di secondi trascorsi dall’epoca di riferimento.

time.sleep(seconds: float) None

Mette in pausa per il numero di secondi indicato. seconds può essere un numero in virgola mobile, per dormire per un numero frazionario di secondi. Per ritardi più precisi o esclusivamente interi usare le funzioni sleep_ms() e sleep_us().

La chiamata a sleep(), incluso sleep(0), garantisce l’esecuzione delle funzioni di callback in attesa.

time.sleep_ms(ms: int) None

Ritarda per il numero di millisecondi indicato, che deve essere positivo o 0.

Questa funzione ritarda per almeno il numero di millisecondi indicato, ma può richiedere più tempo se devono essere svolte altre elaborazioni, ad esempio gestori di interrupt o altri thread. Passando 0 come ms si consente comunque l’esecuzione di queste altre elaborazioni. Usare sleep_us() per ritardi più precisi.

La chiamata a sleep_ms(), incluso sleep_ms(0), garantisce l’esecuzione delle funzioni di callback in attesa.

time.sleep_us(us: int) None

Ritarda per il numero di microsecondi indicato, che deve essere positivo o 0.

Questa funzione tenta di fornire un ritardo accurato di almeno us microsecondi, ma può richiedere più tempo se il sistema deve svolgere altre elaborazioni a priorità più elevata.

time.ticks_ms() int

Restituisce un contatore di millisecondi crescente con un punto di riferimento arbitrario, che torna a zero dopo un certo valore.

Il valore di ritorno a zero (wrap-around) non è esplicitamente esposto, ma lo indicheremo come TICKS_MAX per semplificare la discussione. Il periodo dei valori è TICKS_PERIOD = TICKS_MAX + 1. È garantito che TICKS_PERIOD sia una potenza di due, ma per il resto può variare da port a port. Lo stesso valore di periodo è utilizzato per tutte le funzioni ticks_ms(), ticks_us(), ticks_cpu() (per semplicità). Pertanto, queste funzioni restituiranno un valore nell’intervallo [0 .. TICKS_MAX], inclusi, per un totale di TICKS_PERIOD valori. Si noti che vengono utilizzati solo valori non negativi. Per la maggior parte dei casi, dovresti trattare i valori restituiti da queste funzioni come opachi. Le uniche operazioni disponibili per essi sono le funzioni ticks_diff() e ticks_add() descritte di seguito.

Nota: Eseguire operazioni matematiche standard (+, -) o operatori relazionali (<, <=, >, >=) direttamente su questi valori porterà a risultati non validi. Eseguire operazioni matematiche e poi passare i loro risultati come argomenti a ticks_diff() o ticks_add() porterà anch’esso a risultati non validi da parte di queste ultime funzioni.

time.ticks_us() int

Proprio come ticks_ms() sopra, ma in microsecondi.

time.ticks_cpu() int

Simile a ticks_ms() e ticks_us(), ma con la massima risoluzione possibile nel sistema. Si tratta solitamente dei clock della CPU, ed è per questo che la funzione è chiamata in questo modo. Ma non deve necessariamente trattarsi di un clock della CPU: può essere utilizzata invece un’altra sorgente di temporizzazione disponibile nel sistema (ad esempio un timer ad alta risoluzione). L’unità di temporizzazione esatta (risoluzione) di questa funzione non è specificata a livello del modulo time, ma la documentazione di una port specifica può fornire informazioni più precise. Questa funzione è pensata per benchmark molto fini o cicli in tempo reale molto serrati. Evita di usarla in codice portabile. È disponibile su tutte le OpenMV Cam.

time.ticks_add(ticks: int, delta: int) int

Sposta un valore di tick di un dato numero, che può essere positivo o negativo. Dato un valore ticks, questa funzione consente di calcolare il valore di tick delta tick prima o dopo di esso, seguendo la definizione in aritmetica modulare dei valori di tick (vedere ticks_ms() sopra). Il parametro ticks deve essere il risultato diretto di una chiamata alle funzioni ticks_ms(), ticks_us() o ticks_cpu() (oppure di una precedente chiamata a ticks_add()). Tuttavia, delta può essere un numero intero arbitrario o un’espressione numerica. ticks_add() è utile per calcolare le scadenze di eventi/task. (Nota: devi usare la funzione ticks_diff() per lavorare con le scadenze.)

Esempi:

# Find out what ticks value there was 100ms ago
print(ticks_add(time.ticks_ms(), -100))

# Calculate deadline for operation and test for it
deadline = ticks_add(time.ticks_ms(), 200)
while ticks_diff(deadline, time.ticks_ms()) > 0:
    do_a_little_of_something()

# Find out TICKS_MAX used by this port
print(ticks_add(0, -1))
time.ticks_diff(ticks1: int, ticks2: int) int

Misura la differenza di tick tra i valori restituiti dalle funzioni ticks_ms(), ticks_us() o ticks_cpu(), come valore con segno che può andare incontro a wrap-around.

L’ordine degli argomenti è lo stesso dell’operatore di sottrazione: ticks_diff(ticks1, ticks2) ha lo stesso significato di ticks1 - ticks2. Tuttavia, i valori restituiti dalle funzioni ticks_ms(), ecc. possono andare incontro a wrap-around, quindi usare direttamente la sottrazione su di essi produrrà un risultato errato. È per questo che è necessaria ticks_diff(): implementa l’aritmetica modulare (o più specificamente, ad anello) per produrre il risultato corretto anche per valori soggetti a wrap-around (purché non siano troppo distanti tra loro, vedere sotto). La funzione restituisce un valore con segno nell’intervallo [-TICKS_PERIOD/2 .. TICKS_PERIOD/2-1] (che è una tipica definizione di intervallo per gli interi binari con segno in complemento a due). Se il risultato è negativo, significa che ticks1 si è verificato prima nel tempo rispetto a ticks2. Altrimenti, significa che ticks1 si è verificato dopo ticks2. Questo vale solo se ticks1 e ticks2 distano tra loro non più di TICKS_PERIOD/2-1 tick. Se ciò non vale, verrà restituito un risultato errato. In particolare, se due valori di tick distano TICKS_PERIOD/2-1 tick, tale valore verrà restituito dalla funzione. Tuttavia, se tra di essi sono trascorsi TICKS_PERIOD/2 tick in tempo reale, la funzione restituirà invece -TICKS_PERIOD/2, ovvero il valore del risultato andrà incontro a wrap-around nell’intervallo negativo dei valori possibili.

Spiegazione informale dei vincoli sopra descritti: Supponi di essere chiuso in una stanza senza alcun modo di monitorare lo scorrere del tempo se non un comune orologio a 12 tacche. Allora, se guardi il quadrante adesso e non lo guardi di nuovo per altre 13 ore (ad esempio, se cadi in un lungo sonno), quando finalmente lo guardi di nuovo potrebbe sembrarti che sia trascorsa solo 1 ora. Per evitare questo errore, basta guardare l’orologio regolarmente. La tua applicazione dovrebbe fare lo stesso. La metafora del «sonno troppo lungo» si applica direttamente anche al comportamento dell’applicazione: non lasciare che la tua applicazione esegua un singolo task per troppo tempo. Esegui i task a passi e tieni il conto del tempo nel mezzo.

ticks_diff() è progettata per adattarsi a vari schemi di utilizzo, tra cui:

  • Polling con timeout. In questo caso, l’ordine degli eventi è noto e dovrai gestire solo risultati positivi di ticks_diff()

    # Wait for GPIO pin to be asserted, but at most 500us
    start = time.ticks_us()
    while pin.value() == 0:
        if time.ticks_diff(time.ticks_us(), start) > 500:
            raise TimeoutError
    
  • Schedulazione di eventi. In questo caso, il risultato di ticks_diff() può essere negativo se un evento è in ritardo:

    # This code snippet is not optimized
    now = time.ticks_ms()
    scheduled_time = task.scheduled_time()
    if ticks_diff(scheduled_time, now) > 0:
        print("Too early, let's nap")
        sleep_ms(ticks_diff(scheduled_time, now))
        task.run()
    elif ticks_diff(scheduled_time, now) == 0:
        print("Right at time!")
        task.run()
    elif ticks_diff(scheduled_time, now) < 0:
        print("Oops, running late, tell task to run faster!")
        task.run(run_faster=true)
    

Nota: Non passare valori di time() a ticks_diff(), dovresti usare le normali operazioni matematiche su di essi. Ma tieni presente che time() può anche (e lo farà) andare in overflow. Questo è noto come https://en.wikipedia.org/wiki/Year_2038_problem .

time.time() int

Restituisce il numero di secondi, come intero, trascorsi dall’Epoca, supponendo che l’RTC sottostante sia impostato e mantenuto come descritto sopra. Se un RTC non è impostato, questa funzione restituisce il numero di secondi trascorsi da un punto di riferimento temporale specifico della port (per le schede embedded senza un RTC alimentato a batteria, di solito dall’accensione o dal reset). Se vuoi sviluppare un’applicazione MicroPython portabile, non dovresti fare affidamento su questa funzione per ottenere una precisione superiore al secondo. Se hai bisogno di una precisione maggiore con timestamp assoluti, usa time_ns(). Se i tempi relativi sono accettabili, usa le funzioni ticks_ms() e ticks_us(). Se hai bisogno dell’ora di calendario, gmtime() o localtime() senza argomenti sono una scelta migliore.

Differenze rispetto a CPython

In CPython questa funzione restituisce il numero di secondi trascorsi dall’epoca Unix (1970-01-01 00:00 UTC) come valore in virgola mobile, di solito con precisione al microsecondo. Sulla OpenMV Cam restituisce un intero con precisione al secondo – l’hardware non può rappresentare sia un ampio intervallo temporale sia una precisione inferiore al secondo in un float – e l’epoca differisce a seconda della scheda (vedere Epoca di riferimento sopra). Senza un RTC alimentato a batteria che sia stato impostato, conta invece i secondi trascorsi dall’accensione/reset.

time.time_ns() int

Simile a time() ma restituisce i nanosecondi trascorsi dall’Epoca, come intero (di solito un intero grande, quindi verrà allocato nello heap).

Costruttori

class time.clock

Restituisce un oggetto clock.

Metodi

tick() None

Avvia il tracciamento del tempo trascorso.

fps() float

Interrompe il tracciamento del tempo trascorso e restituisce gli FPS (frame al secondo) correnti.

Chiama sempre tick prima di chiamare questa funzione.

avg() float

Interrompe il tracciamento del tempo trascorso e restituisce il tempo medio trascorso corrente in millisecondi.

Chiama sempre tick prima di chiamare questa funzione.

reset() None

Reimposta l’oggetto clock.