CRONOGRAFO BALISTICO con Arduino Uno
Di Piton (del 18/09/2019 @ 16:39:35, in Arti e Mestieri,  3312 lettori)
E’ uno strumento per misurare la velocità dei proiettili, un progetto del 2017 che in questi anni ha funzionato benissimo.

Praticamente ci sono due sensori messi a una distanza precisa tra loro.
Il primo appena sente il proiettile fa partire il tempo.
Il secondo appena sente il proiettile ferma il tempo.
Se la distanza tra i due era ad esempio un metro ed il tempo indicato era un secondo il proiettile viaggiava a un metro al secondo.
Se il tempo era un decimo di secondo, il proiettile viaggiava a 10 metri al secondo e via così.
Oggi come sensori si usano dei fotodiodi o dei fototransistors, nei cassetti avevo fotodiodi e quindi ho usato quelli e tra quelli che ho scegliendo i più sensibili.

Come supporto ai due fotodiodi ho usato un tubo da idraulica dotato di tappi a cui ho praticato due fessure con la sega circolare.

I fotodiodi li ho collocati all’interno di un pezzo di tubo di plastica, a cui ho eliminato uno spicchio, un po’ più grande del diametro interno del tappo in modo che ci entri a forza e in modo stabile.
I fotodiodi che ho usato sono cilindrici, di vetro e molto sottili, circa due millimetri di diametro, quindi li ho inseriti in un foro praticato in un pezzetto di acrilato tagliato da una lastrina spessa circa un centimetro che avevo da qualche parte, avvitando poi il blocchetto dentro allo spezzone di tubo da inserire nel tappo.



Detta così sembra complicato ma, se guardate le immagini capite tutto
Una volta assemblato il tappo lo si spinge dentro il tubo fino a far arrivare la testa del fotodiodo proprio sotto la fessura nel tubo.

Le alette metalliche che vedete sorrette dai collari servono per innestare i portalampade delle luci a LED necessarie se si vuole usare lo strumento al buio o di notte.
Di giorno non servono, basta la luminosità del cielo ad eccitare i fotodiodi.
Come generatori di luce ho usato quei supportini flessibili con tre led bianchi da collegare alla porta USB del PC che regalavano insieme alle apparecchiature.



Ho sostituito i tre LED con uno ad alta efficenza alimentato attraverso una resistenza da circa 300 Ohm a dargli circa 30 mA a 9 volt e fanno una luce sufficiente ad eccitare i fotodiodi.

Per connetterli al tubo portante e fargli arrivare i nove volt, ho usato degli spinotti microfonici maschi e femmine.
Ho dovuto saldare a stagno una linguetta sui maschi ed un alloggiamento sulla base della femmina perché dentro al buco tondo tendevano a girare con piccole sollecitazioni.
Il vento, ad esempio li avrebbe mossi spostando il fascio di luce dal fotodiodo e guastando la misura.
Durante gli esperimenti con le versioni precedenti sparavo sopra lo strumento a mano libera, cercando di far passare il colpo il più vicino possibile ai sensori e una volta sparai tanto vicino da portarmi via il secondo fotodiodo con tutto il tubo.
Serviva un supporto certo per la canna del fucile e meccanicamente separato dalla barra dei sensori perché il rinculo, se connessi, avrebbe smosso tutto.
Avevo in soffitta la base di un ventilatore brandeggiante ed ho usato quella.
In cantina c’era un blocchetto di legno di buona qualità, gli ho fatto un foro del diametro del tubo del portaventilatore e ce l’ho ficcato sopra.
Pensavo che i lati del blocchetto di legno fossero in squadra... e invece no.
Il buco non è venuto perfettamente verticale, ai fini delle prestazioni non importa ma alla vista non è piacevole ed ho dovuto correggere l’inclinazione portandola orizzontale con dei blocchetti sagomati per contenere le canne.


Dentro alla scatola da elettricista c’è Arduino Uno con sopra un dislay due righe da 16 caratteri, sei batterie da 1,5 Volt, una schedina millefori sulla quale ho montato degli amplificatori/squadratori del segnale che arriva dai fotodiodi, l’altra femmina da pannello per connettere il cavo e sul coperchio della scatola un pulsante di RESET, l’interruttore di accensione e due LED uno rosso che si accende quando il primo fotodiodo capta un segnale e uno blu connesso al secondo.
Servono, passando la mano sui sensori, a verificare che il “coso” abbia luce a sufficienza.

In questa nuova versione del software il pulsante di RESET oltre che azzerare tutte le variabili, visualizza la tensione di batteria che, con i LED per l’illuminazione di notte accesi scende rapidamente.
Nelle prime versioni avevo scelto la strada più facile per contare il tempo tra i due eventi.
Arduino Uno ha degli ingressi in cui legge la tensione ad essi applicata e la trasforma in un numero, si chiamano piedini o porte analogiche.
L’idea era quella di leggere direttamente la tensione ai capi dei fotodiodi, che si alzava quando passava un’ombra e far scattare o fermare il tempo.
Funziona benissimo solo che alla prova sul campo “dava i numeri”, nel senso che per lo stesso tipo di cartuccia a volte dava 425 m/s e a volte 380 m/s.
Il problema sta nel tempo che Arduino impiega per leggere la tensione, trasformarla in numero e fare i confronti con quella normale, 135 microsecondi.
Sembra poco ma un proiettile che viaggia intorno ai 400 metri al secondo impiega 1350 microsecondi a percorrere il mezzo metro circa che c’è tra i sensori, quindi il sistema introduce un errore di più o meno il 10% che è un’enormità.

Ho scoperto da poco che c’è un modo per ridurre questo tempo leggendo direttamente “il ferro” come si diceva una volta, cioè leggendo direttamente il convertitore analogico/digitale che c’è su Arduino ma, anche così il tempo necessario sta intorno ai 20 microsecondi, sempre troppo.
Ho scelto di usare gli ingressi digitali di Arduino Uno che, ho misurato, impiegano tra gli 8 ed i 12 microsecondi per testare se il piedino sta On o se sta Off e coi tempi quasi ci siamo, se fossero più piccoli sarebbe meglio e ho scoperto da poco che si può migliorare, sempre leggendo “il ferro”.
Sarà la versione 8.2 del mio Software
Per leggere i segnali digitali è necessario che i sensori mandino ad Arduino segnali digitali, cioè o zero Volt o +5Volt, netti.
Bisogna quindi amplificare e squadrare i deboli segnali captati dai fotodiodi.
Per farlo ho usato il circuito qua sotto.


Nello schema manca la resistenza da 10K ohm tra i +5Volt ed il piedino due per tenerlo alto, piedino che sbatto a massa attraverso il pulsante reset.
Resistenza che ho saldato direttamente su Arduino.

Qui il listato del software necessario
Nel listato sono ancora presenti dichiarazioni di variabili che servono solo in fase di test ed interi blocchi di programma sono trasformati in commenti da riattivare sempre in caso di ulteriori test.

I commenti sono diretti a qualcuno, come mia figlia, che sta iniziando i primi passi in questo strano mondo, quindi sono anche troppo prolissi, con instruzioni esplose invece che compattate.
Siate clementi
Quella proposta non è LA soluzione al problema ma la mia soluzione che può sempre essere migliorata ed usata come spunto per altre soluzioni.
Scrivendo questa nota spero di aver fatto cosa gradita a qualcuno.

P.S.
Funziona e non da più i numeri.
Ho fatto dei cambiamenti per leggere i pin direttamente sui registri di Arduino portando il tempo di lettura ad alcune centinaia di nanosecondi, quindi a livelli trascurabili.
Trovare il modo di farlo però non è stato facile.
Dopo aver esplorato la rete e provato improbabili istruzioni di cui non capivo il senso ma sperando nella competenza di colui che le aveva scritte non ho cavato un ragno dal buco.
Allora mi sono messo a sperimentare cosa ritornavano i registri ed a pensare in proprio.
Da quanto risulta il piedino dodici, ad esempio, si trova nel quarto bit del registro PINB.
Allora leggo il registro e sposto a destra di quattro posizioni tutti i bit del registro, così il primo a destra diventa lui , poi faccio un AND logico in binario col il byte 00000001.
Dato che l'AND torna UNO solo se entrambi i bit sono a UNO nella pratica leggo le variazioni di stato di quel bit, se varia varia perché è variato lo stato del pin, quindi in pratica leggo lo stato del pin che mi interessa, messo in prima posizione, il primo, che poi confronto col primo bit del mio byte di confronto messo a UNO.
Le spiegazioni di dettaglio le trovate nei commenti del listato che linko sotto.
Ho cancellato tutto l’inutile ed ora è pulito e molto più leggibile, spero.
Listato versione 8.2

Ulteriori modifiche


Dato che ormai l’errore della misura è dato solo dalla lettura del tempo in microsecondi che fa l’orologio di Arduino, che non li conta ad uno ad uno ma a quattro a quattro, l’errore può essere di più o meno 0,3 % per un proiettile che viaggia a 400 metri al secondo.
Usare la seconda riga del display per scriverci i microsecondi misurati è uno spreco dato che quel dato non è di alcuna utilità e non serve a nessuno allora ho pensato ad un dato importante per chi prova le cartucce che è la temperatura e l’umidità dell’aria.
A quanto dicono, modificano fortemente le caratteristiche della polvere usata per caricarle.

Avevo nei cassetti un sensore DHT22 e l’ho inserito nel circuito aggiungendo solo alcune linee di codice al programma, il cui listato lo trovate al link sotto.
Adesso sulla prima riga mostra i metri al secondo misurati e nella seconda riga mostra la temperatura dell’aria e la sua umidità al momento della misura.
Listato Versione 9

Nuova Release del 29 Agosto 2017


Alle versioni precedenti ho aggiunto una funzione per calcolare la velocità media dei colpi sparati, massimo 10, ed ho calcolato il tempo di volo del proiettile usando il Timer T2 di Arduino invece che l’istruzione micros() che scatta di quattro microsecondi alla volta.
I Timer di Arduino hanno dei prescaler, cioè dei divisori delle “battute” (clock) del sistema che oscilla a 16 Megahertz.
I Timer zero e uno usano lo stesso prescaler quindi modificando uno dei due si modifica anche l’altro influenzando così molte funzioni di sistema.
Il Timer T2 invece ha un suo prescaler che, modificandolo, non influenza le prestazioni del sistema se non per l’uso in PWM (modulazione di ampiezza di impulso) di alcuni piedini che non uso in quella modalità, quindi è il candidato ideale.
I registri sono zone di memoria di solito di otto bits a cui è stato dato un nome e anche ai loro bit è stato dato un nome perché, anche se posti in registri diversi operano sulla stessa funzione.

Il Timer T2 ha due registri attraverso i quali si può modificare il prescaler.

Pag. 127 del datasheet dell'ATmega328P

Pag. 130 del datasheet dell'ATmega328P

Pag 131 del datasheet dell'ATmega328P
In soldoni nel setup del programma modifico il Timer T2 facendo dividere per 8 il clock di sistema, così il contatore scatta ogni mezzo microsecondo, scrive questi click in un byte quindi al massimo può contare fino a 256 poi azzera e ricomincia.
Allora abilito l’interrupt di overflow e ogni volta che raggiunge il massimo me lo segno così per sapere quanti mezzi microsecondi sono passati dall’evento basta leggere quanto segna il contatore ed aggiungere quante volte ha raggiunto il massimo moltiplicando il numero di volte per 256.
Per verificare che il metodo funziona davvero ho provato ad usare contemporaneamente entrambi i metodi di lettura del tempo di volo, con micros() e con il conteggio dei mezzi microsecondi scrivendo il risultato sulle due righe del display.
I numeri erano identici fino al secondo decimale ma, l’ho provato passandoci la mano sopra con una velocità massima misurata di poco più 5 m/s.
Penso che le differenze nell’errore si vedranno misurando velocità superiori ai 400 m/s.
Nella versione con l’uso di micros l’errore era + o - 8 microsecondi (quattro misurando il primo diodo e quattro misurando il secondo).
In questa versione l’errore è mezzo microsecondo misurando il primo diodo e mezzo microsecondo misurando il secondo, quindi in totale +o- un microsecondo che sui 1350 di volo del proiettile è davvero poco.
Nel listato del programma al link sotto trovate l'ultima versione del software e nei commenti ci sono i dettagli sul come modificare in binario il valore dei bit di quei registri.
Ultima versione 9.2

Spiego meglio le istruzioni che modificano i tick del timer 2 perché dai commenti che ho scritto sul listato non si capiscono bene.
Ho dato per scontate un mucchio di cose, provo a rimediare.
// Modifiche al Timer T2

TCCR2B = TCCR2B & 0b11111000 | 0x02;
TIMSK2 |= 0b00000001;
TCCR2A &= 0b11111100;
TCCR2B &= 0b11110111;

Come mostrano le tabelle sopra, per
ottenere la divisione dei 16 Mhz
del clok per 8 bisogna operare sul
registro TCCR2B che ha otto bit, scrivendo sui suoi primi tre bit "010" e sul quarto bit "0".

Bisogna anche modificare il registro TCCR2A mettendo a zero i bit in prima e seconda posizione.

Per ottenere questo, senza modificare il valore dei bit che stanno in altre posizioni all'interno del
registro e che non vogliamo disturbare, prima faccio un'operazione logica booleana AND tra i bit del registro e gli otto bit che scrivo io e che sono "11111000".

La logica AND ritorna il valore "1" se e solo se entrambi gli ingressi sono "1", quindi avendo messo tre "0" nelle prime tre posizioni, la logica AND metterà a zero i primi tre bit del registro qualunque fosse il valore che c'era, lasciando invariati gli altri.

Però a noi serve anche che in seconda posizione ci sia anche un "1" e allora scriviamo un altro numero binario, in questo caso l'ho scritto in forma esadecimale 0x02 che esplosa in binario diventa un byte fatto così 00000010.

Operando una logica OR tra questo byte e quello nel registro ottengo di mettere un "1" in seconda posizione perché per la
logica OR basta che tra i due confronti ci sia un "1" per avere un "1" in uscita, solo gli ingressi entrambi a zero danno in uscita zero.
La logica OR è il contrario della logica AND.

Per la AND l'uscita va a "1" solo se entrambi gli ingressi stanno a "1". Quindi se volete lasciare inalterati dei bit di un byte fate un AND con un numero binario che ha quei bit a “1”.

Per la OR l'uscita va a zero solo se entrambi gli ingressi stanno a "0".

Se volete lasciare inalterati dei bit di un byte fate un OR con un numero binario che ha quei bit a “0”.

Insomma, per scrivere degli zero in un byte usate la logica AND per scrivere degli uno usate la logica OR.

Il simbolo dell'istruzione AND è "&", il simbolo dell'istruzione OR è "|".