Projet Centrale d’acquisition multi-Bluetooth Arduino |
Maj : 12/11/16
Abstract :
Résumé : |
Introduction : Acquisition de paramètres multiples
La réalisation de départ comportait quelques centrales météos graphiques à base d’Arduinos, en différents points de la maison.
Ces réalisations ont gonflé en rajoutant de plus en plus de capteurs, mais chaque centrale avait ses propres capteurs indépendants, des afficheurs graphiques incompatibles entre eux, donc des logiciels spécifiques incompatibles.
Cette situation anarchique est devenue ingérable !
Certains capteurs sont uniques et les autres Arduinos ne peuvent pas les voir.
Les données redondantes ne sont pas cohérentes, les sondes sont inutilement multipliées avec des fils partout, et même placés au même endroit, toutes les mesures de temps, température, pression, tensions, impulsions, etc. divergent bien qu’étalonnées individuellement.
L’idée est de regrouper toutes les mesures sur un seul maître, avec des capteurs à un seul exemplaire, permettant ainsi de tout étalonner parfaitement et de fournir à tout le monde, sans fils, des données identiques et fiables pour des traitements différents, Arduinos, Android et PC (diffusant vers l’Internet).
L’Arduino maître pouvant fonctionner avec des piles doit consommer très peu, il est donc toujours éteint, sauf toutes les quatre minutes, une interruption de la broche SQW d’une horloge DS3231 (qui active via son état bas un Mosfet externe pour commander la mise sous tension) l’allume pour quelques secondes.
A la mise sous tension, le maître s’initialise, fait l’acquisition de données sur une quinzaine de capteurs très différents, traite et met en forme, et les sauve en mémoire sur une 24c512 (les 4 derniers jours tournants) et tous les minuits sauve les données du jour sur une carte SD.
Il envoie ensuite la trame des données récentes (une cinquantaine d’octets) en série.
L’opération totale prend quatre secondes (certains capteurs sont longs à stabiliser, initialiser et répondre !).
Le coeur du problème est ici : Il attend encore une seconde car un esclave quelconque peut l’appeler pour demander des données anciennes qui lui manquent (Voir note finale sur les esclaves) puis se suicide en coupant son alimentation.
Il ne peut pas chaque fois interroger pour refaire la liste de tous les esclaves et découvrir un nouveau, ou appeler un qui ne répond plus, c’est trop long !
L’opération se renouvelle dans moins de quatre minutes.
Consommation strictement nulle pendant 3 minutes 55 secondes, pendant les 5 secondes actives une dizaine de mA sous 3V (modes économies très travaillés !), soit:
10mA * 5s/240s, environ 0.2mA en moyenne (fonctionne plus d’an an avec 2 piles R6).
Cela ne pose pas de problème avec des esclaves reliés en série et éviter les collisions, mais je ne sais pas comment faire pour couper les fils et gérer cinq esclaves en Bluetooth simultanément.
Chacun est à un endroit différent et ne s’intéresse qu’à une partie des données transférées.
Un esclave reçoit toute la trame du maître toutes les quatre minutes, dont l’heure en cours pour que tout soit synchronisé et sauve aussi toutes les données sur sa ram et SD pour travailler sur les archives.
Si tous étaient banchés en permanence depuis le début, ils n’auraient rien à demander au maître, se contentant d’écouter les données toutes les quatre minutes.
Le problème est qu’un esclave peut rentrer et sortir de la liaison, être nouveau et vide, il doit alors demander les données d’archives qui lui manquent, il est donc nécessaire qu’il puisse générer une requête :
Envoie-moi la trame de <telle année, tel jour-heure-minute>.
Les autres esclaves qui ne sont pas demandeurs entendent mais ignorent cette trame qu’ils ont déjà.
Bluetooth HC05
Les cartes à base de l’excellente horloge DS3231 comportent une 24c32 qu’il est très simple de remplacer par une 24c512 pour un budget total de $2….
RTC Dallas DS3231 + 24C32
Il n’y a qu’une seule horloge DS3231 pour tout le monde, afin que tout soit exactement synchronisé, l’heure officielle GMT est transmise par la trame du maître toutes les quatre minutes.
Il est possible de baisser la consommation de l’Arduino autour du mA, en jouant sur de multiples paramètres (tension, fréquence, désactivation de l’inutile…), mais certains périphériques sont gourmands (ACS712) et ruinent un peu les efforts pour économiser l’énergie.
Voir les très bonnes pages : robot-maker.com/forum/...consommation
Pourquoi le choix de Bluetooth plutôt que Wi-Fi ?
La consommation est beaucoup plus faible en BT, une alimentation par piles ne peut être envisagée en Wi-Fi
Un des problèmes idiots quand on archive des données temporelles est le stupide changement d’heure été/hiver
Même si l’on archive en GMT, il y aura immanquablement un trou ou une perte les jours de changement d’heure sur les affichages graphiques qui doivent être en temps local sur 24h.
Un cauchemar pour une bonne ergonomie, je déteste le changement d’heure aberrant qui n’économise rien !
Réponse aux questions du forum :
En tant que radioamateur, je ne pouvais pas passer à côté des liaisons 2.4 gHz avec des NRF24l01, mais je ne les utilise pas pour ce projet car il n'y a pas que des Arduinos esclaves clients, mais aussi des tablettes et smartphones Android qui doivent fonctionner sans hardware externe et des PC (avec clef Bluetooth). C'est pour cela que je m'obstine en BT !
La solution de mettre une dizaine de HC05 sur le maître manquerait vraiment d’élégance et enlève tout le côté Zen du projet !
En résumé, il me faut des trames toutes les 1 ou 2 ou 3 ou 4 or 5 ou 10 minutes
Le maitre envoie maintenant une trame toute les minutes, et chaque client choisit la période qui l’intéresse.
Un des problèmes de ce projet fou est que le cahier des charges se modifie toutes les semaines à l’arrivée de chaque nouvel élément, ce n’est plus professionnel.
Il est inutile de lire les chapitres suivants pour la compréhension du projet,
ils ne servent qu’à préciser quelques détails pour les esprits curieux.
Annexe 1 : Exemple d’envoi d’une trame
Au départ j’utilisais un format de données très compacté, mais comme il n’y a que quelques dizaines d’octets à envoyer, le gain n’était pas significatif.
J’ai préféré envoyer en clair pour obtenir un format directement lisible sous Excel sans manipulations par le PC.
Voici le détail de la trame envoyée toutes les quatre minutes par le maitre au format ASCII très simple avec séparateurs virgule (CSV = comma separated values)
Chaque donnée est int16_t, entier signé l6 bits de -32k à +32k mais codée en uint16_t, entier non signé l6 bits de 0 à 64k, les valeurs négatives étant représentées par un nombre > 32k, exemple -1 sera codé 65535
(Voir dans la note annexe le codage du quantième et des pressions)
Premier chiffre = Identification de la date par DS3231
(Année%10)*1000 + quantième >>>> Exemp1e // 6365 pour 31 décembre 1016 // 0001 pour 1er janvier 2020
Deuxième chiffre = identification de l’heure
(Heure *100) + Minute >>>> Exemp1e // 2356 pour 23h56 //0104 pour 1heure 4 minutes ///
Troisième chiffre = Pression ramenée au niveau de la mer (QNH) par BMP280
Valeur exprimée en Pascals exemple 1015.88 hPa > 101588, mais ce nombre dépasse 16 bits (64k), aussi je retranche un offset de 10000 pour l’envoyer
1015.88 hPa > 1588
La valeur peut être négative : 999.99 hPa
Quatrième chiffre : une des températures en centième de degrés (positive ou négative) en particulier par DS18220 ou PT100
>>>> Exemp1e // 2134 pour 21 degrés 34 // 0001 pour – 1 centième de degré
….. autres températures
Chiffres suivant : éclairement solaire (capteurs multi spectraux)
Chiffres suivants : une des tensions (diverses batteries) par ponts résistifs.
Chiffres suivants : un des courants (solaire, utilisation…) via capteurs à effet Hall genre ACS712
Chiffres suivants : un des capteurs à impulsions (consommation compteur secteur, divers départs eau..., via d'autres circuits CMOS comptant les pulses pendant l'extinction du maitre)
etc.
Annexes 2 : Codage du quantième
Le quantième est le numéro d’ordre dans l’année : Exemples // 001 pour le premier janvier // 365 (ou 366) pour le 31 décembre //
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
byte calcMon, calcDay; // for reverse quantieme
int quant , topQuant ; // calculation quantieme
const int QUANT[] = {0,0,31,59,90,120,151,181,212,243,273,304,334} ; // Quantième (-1) du premier jour du mois
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int quantieme (byte qyear, byte qmon, byte qday) // 0..366
{
if ((qmon>2) && (0 == qyear%4)) // bisextile year
qday++ ;
return (QUANT [qmon]+ qday) ;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int quantNow() // 0..366
{
return quantieme (dt.year, dt.month, dt.day) ;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void recreateDateFromQuant (int quant) // Re create date fron quantieme
{
byte qyear = 16 ;//dt.year ; // today
// byte calcMmon , calcDay ;
for (calcMon = 1 ; calcMon < 13 ; calcMon++)
{
if (quantieme (qyear, calcMon+1, 1) > quant)
//const int QUANT[] = {0,0,31,59,90,120,151,181,212,243,273,304,334};
break ;
}
for (calcDay =1 ; calcDay < 32 ; calcDay++)
{
if (quantieme (qyear, calcMon, calcDay+1) > quant)
break ;
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void serialPrintQ () // Imprime quantieme
{
Serial.print (F("\t|||| Quantieme = ")) ;
Serial.print (quantNow()) ;
Serial.print (F(" \tQ%")) ;
Serial.print (NB_DAYS_TO_SAVE) ;
Serial.print (F(" = ")) ;
Serial.print (quantNow()%NB_DAYS_TO_SAVE) ;
Serial.print (F(" |||| ")) ;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Utilisation : //TopTime = NB_RECORDS *quantieme % NB_DAYS_TO_SAVE + (24 * hour) + min/INTERVAL_MIN // >>> 0..359 * 5 >> 0..1799 * 2
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Annexes 3 : Codage des pressions
////////////////// BMP085 Pressure ////////////////////////// Ancienne version, j’utilise maintenant le bmp280 bien meilleur !
#include <Adafruit_BMP085.h> // Initialise pressure sensor
Adafruit_BMP085 bmp;
// Pressions extremes Marseille : 1036 - 936 = 100 hPa : donneés stoquées en Pa : delta = 10240 : 93600 + 10240 = 103840
int Altitude = 288 ;// 288 ;
float CoefAltitude ; // Marseille 288 m : coef 1.03
float relativePress ;
float absolutePress ; // Direct reading on BMP280 in Pa
const int offsetPress = 100000 ;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
float getData0 () // Absolute press in Pascals exemple : 101300
{
return (bmp.readPressure() ) ;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void initSensors (void) // Read all periphericals
{
bmp.begin() ; // Pressure init BMP280
CoefAltitude = calcCoefAltitude(Altitude) ;
absolutePress = getData0 () ; // Pour équivalence niveau mer QNH
relativePress = calcSeaLevelPress (absolutePress) ; // Pa -> hPa…
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
float calcCoefAltitude (int Alt) // Wikipedia formula
{
// Base : 1013.25 hPa, 0 m // 954.61, 500 = 1.0614 // 898.76, 1000 = 1.1274 // 845.58, 1500 = 1.1983
// 794.98, 2000 // 746.86, 2500 // 701.12, 3000 // 657.68, 3500 // 226.37, 11000
float P0 ;
P0 = (288.15-0.0065 * Alt) ;
P0 = 288.15 / P0;
P0 = pow (P0, 5.255) ; // 1.03484 pour 288 metres
return P0 ;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
float calcSeaLevelPress(float abpress)
{
return (coefPressMult * CoefAltitude * (abpress + (100 * coefPressAdd))) ; // Coefficients multiplicatifs et additifs réglés avec precision pour chaque capteur
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Si ce projet réussit en Bluetooth, je mettrai en ligne le détail de cette liaison multiple sans fil .