dimanche 12 décembre 2021

HC-12

Le HC-12 est un petit module radio bon marché pour faire de la communication sans fil entre Arduino et trucs du genre. La communication se fait par ligne série et ne nécessite que 4 fils (GND, VDD, TX, Rx). Il est possible de changer les paramètres de communication au moyen de commandes 'AT' après avoir mis la ligne 'SET' à la masse (elle est équipée d'une pull-up et, par défaut, le module est en mode transmission/réception sur 433.4 MHz et 9600 bauds 8 bits, un stop bit et pas de parité. La communication radio utilise un Si4463 de Silicon Labs piloté par un microcontrôleur STM8S avec un code non public (ici, il se propose d'en modifier le firmware...).

Raspberry Pi

Les quatre fils peuvent facilement être connectés à un Raspberry Pi. La documentation du module semble être une traduction du chinois et l'utilisation des commandes 'AT' n'est pas claire... En principe, il suffirait de prendre minicom et de faire
$ minicom -b 9600 -D /dev/ttyS0
et de taper 'AT' pour voir apparaître 'OK' mais le Diable se cache dans les détails et plusieurs obstacles doivent d'abord être franchis. D'abord, pour pouvoir accéder au ttyS0 comme utilisateur normal, il faut qu'il appartienne au groupe 'dialout' (sudo usermod -a -G dialout <user>). Ensuite, comme rien ne fonctionne comme prévu, revenons à la base et connectons le TX du Raspberry Pi au TX. On s'aperçoit alors qu'il y a un getty qui tourne par défaut. Il faut le désactiver (via sudo raspi-config). Après avoir raccordé le SET du module au GND du Raspberry, on s'aperçoit que le 'T' doit suivre de très près le 'A' pour que le firmware comprenne 'AT' (copier/coller dans minicom). Et donc, tout va bien, le module semble fonctionner. Déconnectons SET et utilisons le module en configuration standard (433.4 MHz, 9600 bauds 8 bits, un stop bit et pas de parité et ...puissance radio maximum).

Il est sûrement possible de communiquer entre deux modules (c'est fait pour ça) mais, ce qui m'intéresse c'est de voir à quoi ressemble le signal radio... Pour cela, je vais émettre de manière répétée une petite chaîne de caractères constante, ou même un caractère unique. Un 'U', par exemple, dont le code ASCII est 0x55 (0101.0101). Comme le message envoyé ne va pas être très long, je peux le répéter très souvent, genre 200 fois par seconde (après avoir testé avec un rythme moins soutenu).
$ while sleep .005; do echo -n "U" > /dev/ttyS0; done

GnuRadio

Pour voir si le module émet quelque chose, j'utilise GnuRadio avec un RTL-SDR (ou équivalent à quelques euros).
Le truc de base : un module source, rtl-sdr, et deux sink QT pour la visualisation, frequency et waterfall. Je prends une fréquence d'échantillonnage raisonnable et centre le tout sur 433.4 MHz.
Donc le module fonctionne et je peux générer du signal à volonté.

rtl-sdr et GNU Octave

Maintenant, enregistrons une courte séquence avec l'utilitaire 'rtl-sdr' sur le portable :
$ rtl_sdr -f 433400000 -s 512000 -n 64000 U.iq8
et utilisons GNU Octave pour visualiser le signal que l'on suppose être un type de modulation de fréquence (GFSK ou GMSK?). On s'intéresse donc à la phase (arg(i+j.q)). On utilise unwrap() pour éviter les saut 0/360°. Et, par tâtonnement, on sélectionne un intervalle contenant le signal recherché.
$ cat print_phase.m 
s=loadFile("U.iq8");
au=unwrap(arg(s));
plot(au(10000:14100));
print -dpng "signal.png"
Et nous obtenons :
NB: loadFile() lit un fichier IQ 8 bits de rtl-sdr pour en faire un vecteur complexe flottant.
$ cat loadFile.m 
function y = loadFile(filename)
%  y = loadFile(filename)
%
% reads  complex samples from the rtlsdr file 
%

fid = fopen(filename,'rb');
y = fread(fid,'uint8=>double');

y = y-127;
y = y(1:2:end) + i*y(2:2:end);
Si j'extrais une partie intéressante, la sors dans un fichier texte et l'affiche avec une grille adéquate dans Gnuplot, cela donne (après avoir zoomé dans le graphique) :
octave> ua2=unwrap(arg(loadFile("U.4399500l.256k.iq8")));
octave> plot(ua2)
octave> zz=ua2(4030:8102);
octave> plot(zz);
octave> csvwrite ('msg.dat', zz);
---
gnuplot> set style line 100 lt 1  lw 2
gnuplot> set grid ls 100
gnuplot> set xtics autofreq 17 
gnuplot> plot 'msg.dat' with lines lw 2
On observe des intervalles où la courbe (qui représente la phase du signal) change de pente et d'autres où elle conserve sa pente.

dimanche 21 novembre 2021

Gravier luminescent 2

Le TSL230R n'ayant pas donné de très bon résultats, j'ai commandé un kit TSL2591 d'Adafruit...
Le composant TSL2591, plus sophistiqué, communique en i2c et donc, je dois utiliser autre chose que le clone Saleae... Deux possibilités faciles : utiliser un Arduino ou un Raspberry Pi. Va pour le Raspberry. J'ai justement un Pi 4 dans un boîtier Argon One qui ne demande qu'à servir.

Première étape, télécharger et installer le Raspberry Pi OS. Dans le temps, l'installation se faisait avec dd (ou en copiant les fichiers sur une FAT32?). Ce temps-là, semble révolu. Pas moyen de trouver la moindre information technique sur le processus de démarrage, tous les chemins mènent au Pi imager qui, malheureusement, refuse de s'installer sur mon vieil Ubuntu pour une question de dépendance (libc, qt,...) et donc, ce sera une alternative : BalenaEtcher... 90 MB pour remplacer dd... Il est bien loin le temps où tout un environnement Linux tournait sur une disquette 3.5' de 1.6 MB. Enfin, c'est vrai que si on fait confiance au programme, cela fonctionne et on ne se fait pas trop peur à choisir entre les /dev/sdb, /dev/sdc,... On met la carte SD dans le lecteur de carte SD du portable, on clique, on confirme et ça flashe.

Maintenant, le Raspberry, c'est bien mais si il faut rajouter une souris, un clavier et écran, un câble Ethernet, ça fait vite beaucoup de fils. Donc, la route à suivre est l'option headless. On ré-insère la carte SD dans le portable et on met deux fichiers dans /media/moi/boot/ : un fichier 'ssh' vide et un fichier 'wpa_supplicant.conf' qui contient :
country=BE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
scan_ssid=1
ssid="mon-réseau-wifi"
psk="mon-mot-de-passe-wifi"
}
À partir de là, quand on allume le Raspberry Pi avec le bouton de l'Argon One, il va chercher une adresse IP par DHCP sur le bidule WiFi (sur ma b-Box 3 de Proximus). Reste à connaître son adresse IP... Soit en allant voir sur http://mymodem (http://192.168.1.1) soit en scannant le subnet avec nmap, puis en se connectant avec l'utilisateur 'pi' (mot de passe, à changer 'raspberry'). Par je ne sais plus quel mécanisme, le RPi parvient à faire connaître son nom et il n'est pas nécessaire de faire le ssh sur une adresse IP (mais le scan de nmap semble quand même nécessaire).
$ nmap -sP 192.168.1.*
...
$ ssh pi@raspberripy # or ssh pi@192.168.1.47
pi@raspberrypi:~ $
Tant qu'à faire, installons le script de shutdown lié au bouton de l'Argon One. On pourra ainsi l'arrêter proprement en maintenant le bouton appuyé quelques secondes.
$ curl https://download.argon40.com/argon1.sh | bash 
Reste maintenant à configurer le Rpi pour pouvoir utiliser l'interface i2c. Cela se passe du côté de 'raspi-config' avec des menus texte.
$ sudo raspi-config
Le branchement est trivial : on connecte le fil vert sur le bouton vert,... (3.3 Volt, GND, SCL, SDA) Il est préférable de le faire avec le Rpi éteint. Il faut maintenant charger les utilitaires et librairies pour le faire fonctionner...
$ sudo apt-get install wiringpi
$ sudo apt-get install i2ctools
$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- 1a -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- 29 -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
Le TSL2591 est bien détecté en 0x29.

Il ne reste plus qu'à lire la datasheet et à trouver quelques exemples de programmes (i2c et tsl2591) pour (la facilité) et en faire une version minimaliste (pour la compréhension) :
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <wiringPiI2C.h>

#define DEVICE_ID 0x29


int main (int argc, char **argv)
        {
        int     fd;
        int     i, id, status;
        int     gain, itime;

        if (argc != 3)
                {
                fprintf(stderr, "%s: usage is %s <gain> <itime>\n", argv[0], argv[0]);
                fprintf(stderr, "\tgain : 0-3 (low/medium/high/max)\n");
                fprintf(stderr, "\titime : 0-5 (100/200/300/400/500/600 ms)\n");
                exit(-1);
                }
//      setbuf(stdout, NULL);
        gain = atoi(argv[1]);
        itime = atoi(argv[2]);
        if ((fd = wiringPiI2CSetup(DEVICE_ID)) < 0)
                {
                printf("Failed to init I2C communication.\n");
                return -1;
                }

        id = wiringPiI2CReadReg8(fd, 0xA0 | 0x12);
        fprintf(stderr, "tsl2591 id=0x%02x gain=%d itime=%d\n", id, gain, itime);

        wiringPiI2CWriteReg8(fd, 0xA0 | 0x00, 0x93);                                            // ENABLE_REG = POWERON | AEN | AIEN | NPIEN
        wiringPiI2CWriteReg8(fd, 0xA0 | 0x01, ((gain & 0x03) << 4) | (itime & 0x07));             // CONTROL_REG = GAIN | TIME
        wiringPiI2CWriteReg8(fd, 0xA0 | 0x0C, 0x00);                                            // PERSIST_REG = 0

//      status = wiringPiI2CReadReg8(fd, 0xA0 | 0x13);
//      fprintf(stderr, "status=0x%02x\n", status);

        while (1)
                {
                int x = wiringPiI2CReadReg16(fd, 0xA0 | 0x14);
                fprintf(stdout, "%d\n", x);
                sleep(1);
                }
        return 0;
        }
Et compiler le tout avec un Makefile naïf :
tsl2591: tsl2591.c
	gcc -o tsl2591 tsl2591.c -lwiringPi
Pour mesurer des intensités lumineuses faibles, la LED verte est assez génante... Mais bon... Plutôt que de la désouder, je décide de la masquer tant bien que mal.
Avec un gravier bleu, cela donne :
Pour bien faire, il faudrait convertir les comptages en unités lumineuses... (Ici, c'est avec le gain maximum intégré sur le temps prédéfini maximum (600 ms))

Puis, il faudrait bien sûr refaire l'expériences de nombreuses fois pour en maîtriser tous les paramètres...

lundi 13 septembre 2021

Gravier luminescent

Lors de la nuit des étoiles à l'Euro Space Center de Transinne, le 12 août 2021, nous avons visité leur nouveau chemin des planètes. On a appris que cela avait été réalisé par la société Interblocs de Libramont. Il s'agit d'un chemin bétonné dans lequel sont incrustés des graviers luminescents. Il s'agit, en fait, d'aluminate de strontium dopé avec des terres rares du genre europium. Bien après minuit, c'était encore très lumineux et on pouvait se balader en plein champ par une nuit sans Lune sans le moindre problème. C'est magique. Ayant observé à côté du chemin ce qui ressemblait à des lucioles, j'ai rapporté chez moi un gravier de quelques millimètres pour faire des tests. La rémanence est étonante. Cela reste phosphorescent pendant des heures. C'est en partie dû à la sensibilité de l'oeil humain dans le vert.



Constater, c'est bien, mesurer, c'est mieux. Je dois avoir quelque part le capteur utilisé dans les Sky Quality Meter mais impossible de remettre la main dessus. J'ai donc commandé sur eBay quelque chose de plus ou moins équivanet, un TSL230R qui convertit lui-aussi le flux lumineux en fréquence. Le premier composant avait 3 pattes, celui-ci 8 mais cela reste raisonnable et il suffit simplement de connecter toutes les pattes (sauf une) à VDD ou à la terre pour obtenir un signal plus ou moins carré en sortie. Je dis plus ou moins parce qu'en fait, ce n'est a priori pas très stable. Il y a, comme qui dirait, un 'jitter' important. Je ne sais pas si c'est dû à l'approximation de mon montage sur une plaquette d'expérimentation (breadboard), si c'est une propriété de ce composant en particulier ou à ce type de composant en général. D'abord observé à l'oscillo, j'ai bien un signal dont la fréquence varie avec le flux lumineux. Bien.

Maintenant, ce qui m'intéresse, c'est de voir comment cela évolue dans le temps. Pour cela, j'ai utilisé un clone Saleae Logic avec PulseView de sigrok (ici, à la lumière du jour). Un petit bidule génial de quelques euros qui échantillonne jusqu'à 24 MHz. En fait, c'est juste un microcontrolleur Cypress EZ-USB FX2LP qui envoie l'état des portes sur l'USB.

Mais, pour pouvoir suivre l'évolution dans le temps, rien ne vaut la ligne de commande.





while true
do 
sigrok-cli --driver fx2lafw --samples 1m --config samplerate=1m  --channels D0=x --output-format bits \
|./count01 > AlSr.`now`.txt; sleep 9;  done


À la lumière du jour, sigrok-cli donne :

$ sigrok-cli --driver fx2lafw --samples 1m --config samplerate=1m  --channels D0=x --output-format bits

libsigrok 0.5.0
Acquisition with 1/9 channels at 1 MHz
x:11100001 11111000 00011111 00000111 11000000 11110000 00111111 00001111
x:11000011 11110000 00111111 00001111 11000011 11110000 00111110 00001111
x:10000001 11110000 01111110 00001111 10000001 11100000 01111110 00011111
x:10000001 11100000 01111110 00011111 10000011 11110000 01111100 00001111
x:10000011 11110000 01111100 00001111 10000011 11110000 01111100 00001111
x:10000011 11110000 01111100 00001111 10000011 11110000 01111110 00001111
...
On compte 5 '1' suivis de 5 '0'. Avec un millionième de seconde par échantillon, cela donne une période de 10 millionnième de seconde, soit une fréquence de 100 kHz.

Maintenant, plaçons le gravier sur le TSL230R, mettons le tout dans le noir le plus total (un couvercle noir sous un T-shirt noir) et observons l'évolution.

Et nous obtenons, comme attendu, une belle décroissance exponentielle.



Ce qui est amusant, c'est ma configuration avec le petit programme 'count01' ne fonctionne plus quand la fréquence s'approche du herz. En fait, je demande au Cypress fx2lafw de me fournir un million d'échantillons de D0 à un million d'échantillons par seconde et 'count01' compte les nombres de '0' et de '1' consécutifs. Quand la fréquence approche du herz, il n'y a plus de transition '0' vers '1' et '1' vers '0' et je n'arrive donc plus à mesurer la demi-période. Cependant, dans le noir, on distingue encore une faible phosphorescence.

Il faudrait adapter le programme pour mesurer les (très) faibles intensités. Après tout, si ce genre de composant est capable de mesurer la noirceur d'un ciel astronomique, il doit toujours fonctionner bien en dessous du herz.

À noter que le temps de chargement ne semble pas affecter le temps de rémanence. 'core.freq' est obtenu après avoir éclairé le caillou pendant 10 secondes avec un lampe de poche LED pas très puissante. 'core2.freq', c'est environ une minute avec un spot LED beaucoup plus puissant. Le résultat semble quasi identique.

On trouve une thèse, Phosphorescence : mécanismes et nouveaux matériaux de Frédéric Clabau (Nantes, 2005), sur ce type de matériau.

Ci-dessous, l'évolution sur plusieurs recharges. D'abord une dizaine de seconde sur le caillou qui a pris la lumière toute la journée. Une courte recharge de quelques secondes et une recharge de près d'une minute et une dizaine de seconde après une longue décharge d'environ 9 heures (5 heures retirées du graphe). Chaque tic vaut 10 secondes.



En principe, toutes les 10 secondes, on perd x % de luminosité. Comme la fréquence est proportionnelle au flux lumineux, f(t)/f(t-10sec) devrait être constant.



Et ce n'est pas tout-à-fait le cas... C'est dû au manque de stabilité du signal (dont j'ignore toujours la source) et à la méthode de mesure : je calcule la moyenne des périodes pendant une seconde toutes les 10 secondes. Au début, j'ai beaucoup de mesures courtes mais cela n'a pas beaucoup de sens de calculer une moyenne sur une exponentielle et à la fin, je n'ai plus assez de mesures pour pouvoir faire une moyenne convenable et la dispersion correspond à l'instabilité du signal... Je viens de commander un Adafruit TSL2591, ce sera peut-être meilleur...

À suivre...

mardi 18 mai 2021

Portapack GNU Octave

Le Portapack permet d'enregistrer un signal radio capté par un HackRF One sur une carte micro-SD sans trimbaler un PC portable. En fait, j'ai un clone -H2 avec le logiciel Mayhem. Gnu Octave permet de traiter le signal sans trop d'effort (logiciel libre quasi compatible avec MATLAB). En fait, ici, je joue plus avec le signal que je le traite mais bon...
Pas sûr que le screenshot corresponde au signal traité ci-dessous, mais c'est l'idée. L'écran permet de repérer un signal qui semble intéressant, les boutons permettent la configuration de la réception et de lancer/stopper l'enregistrement sur la carte micro-SD.
En fait, le signal capté semble être quelque chose comme du dPMR (?). À mon souvenir, il était plus 'propre' et je ne suis même pas sûr que le filtre était indispensable.
$ dd if=BBD_0001.C16 of=_1.c16 bs=1M count=1
Histoire d'avoir un fichier de taille raisonnable (à 500ksamples/sec, cela fait 2MB/sec). On peut ensuite charger le fichier composé alternativement de I et de Q 16 bits signés dans un vecteur de nombres complexes en virgule flottante.
function y = loadC16File(filename)
%  y = loadC16File(filename)
%
% reads  complex samples from the portapack file 
%

fid = fopen(filename,'rb');
y = fread(fid,'int16=>double');

y = y(1:2:end) + i*y(2:2:end);
Ensuite, traiter le signal... Dans ce cas-ci, le filtre est trop large, la bande passante du signal est beaucoup plus étroite mais cela permet déjà d'y voir plus clair.
x0=loadC16File("_1.c16");
Ts=1/500000;
freqs=[0 0.2 0.21 1];
amps=[1 1 0 0];
b=remez(100, freqs, amps);
x=filter(b, 1, x0);
a=abs(x);
p=arg(x);
pp=unwrap(p);
fig=figure();
subplot(2,1,1);
plot(a);
title("abs(x) - magnitude");
subplot(2,1,2);
plot(pp);
title("unwrap(arg(x)) - argument/phase");
print(fig, "plot011.png", "-S800,800");
return; 
On prend une partie utile du signal (entre 5001 et 24500), on corrige légèrement la fréquence : ajout de 50 pi-radians sur 20000 échantillons pour redresser le graphe (je l'avais fait manuellement an ajoutant un linspace(), mais detrend() est fait pour cela) et on obtient :
ppp=pp(5001:24500);
pppdt = detrend(ppp,1);
fig=figure();
plot(pppdt);
axis([0 1 -50 50], "autox");
title("detrend(unwrap(arg(filter(x)))(5001:24500))");
print(fig, "coresigdt.png", "-dpng", "-S1280,360");
Tadaah... Il ne reste plus qu'à traduire ça en bits et bytes... (hum...; Ce n'est pas vraiment comme ça qu'il faut faire, mais bon...)

vendredi 12 février 2021

MysondyGO

Chaque jours des ballons-sondes sont lancés un peu partout dans le monde (en principe à midi/minuit). Ils émettent de la télémétrie que l'on peut capter. Ayant vu une vidéo de Andreas Spiess, je n'ai pas pu résister à l'achat d'un récepteur TTGO pour lequels des radioamateurs italiens ont réalisé un logiciel de réception (mysondyGO). Sur AliExpress, c'était un 'LILYGO® TTGO ESP32-Paxcounter LoRa32 V2.1 1.6 Version 433/868/915MHZ LoRa ESP-32 OLED 0.96 Inch SD Card Bluetooth WIFI Module' pour une petite vingtaine d'euros (si je me souviens bien.

J'ai dû un peu chercher avant de trouver le moyen facile de flasher le logiciel italien. Je ne trouvais que des SDK de développement complexes pour ESP-32 alors que je voulais juste flasher un .bin. Et j'ai finalement trouvé exactement ce qu'il me fallait dans cet article de Anthony Le Cren F4GOH – KB1GOH.
 2024  ls -l ./MySondyGO_1_40/MySondyGO.bin
 2025  ls -l
 2026  git clone https://github.com/espressif/esptool.git
 2027  cd esptool/
 2028  ls -l
 2029  ./esptool.py
 2030  ./esptool.py --port /dev/ttyUSB0 read_flash_status
 2031  ./esptool.py --port /dev/ttyUSB0 erase_flash
 2032  ./esptool.py --port /dev/ttyUSB0 write_flash -z 0x0000 ../MySondyGO_1_40/MySondyGO.bin


Ne restait plus qu'à guêter sur radiosondy.info le passage d'un ballon dans le coin... C'est ennuyeux que le bidule ne semble configurable qu'en BlueTooth avec un smartphone mais bon... Je le configure sur une sonde RS41 sur 403.5 MHz comme celles qui sont lancées vers midi à l'observatoire de Uccle.

Comme l'antenne d'origine, mesurée avec nanoVNA clone, ne me paraîssait pas trop bonne, j'ai bricolé un dipôle coupé pour 403.5 Mhz et ça y est, aujourd'hui, un ballon est passé dans les parages.

Dans une rue est-ouest, j'ai bien capté le ballon du côté sud.

R3420743 a été suivie sur Radiosondy et on peut retrouver la télémétrie captée ici. À l'heure de la photo, elle était à environ 25 kilomètres et 28.002 mètres d'altitude. Elle a été retrouvée du côté de Malmedy.


La prochaine fois, il faudra essayer de la capter avec un RTL-SDR. Éventuellement avec RS ou, essayer d'extraire les messages moi-même (avec ou sans GNUradio), c'est du BFSK; cela ne devrait pas être trop sorcier (?).

Quelqu'un m'a invité à remplacer le lien nanovna.com (qui vendrait des clones de mauvaise qualité) par nanorfe.com qui vend une version V2, utiliserait des composants de meilleure qualité et serait plus 'officiel'. Il existe donc une controverse... Là, j'ai utilisé un clone V1, je ne sais pas d'où il vient ni quelle est sa qualité.