Anthias
mail

arduino

Projet Centrale d’acquisition multi-Bluetooth

Arduino

arduino


Introduction
Concept
Notes
Divergences du projet
Annexe trame
Annexe Quantième
Annexe Pression
Conclusion

Maj : 12/11/16

Abstract :
This project is part of Arduino's applications (see my Arduino main page).
It seeks to create communication between a swarm of controllers connected via Bluetooth.

Résumé :
Ce projet s'inscrit dans le cadre des applications Arduino (voir ma page principale Arduino).
Il cherche à faire communiquer ensemble un essaim d’automates reliés en Bluetooth.

 

arduino  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).

 

Haut de page


arduino  Le concept

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.

Haut de page

 

arduino  Note sur les esclaves

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

-Remarque 1 :

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

-Remarque 2 :

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.

-Remarque 3 :

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

-Remarque 4 :

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

-Remarque 5 :

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 !

 Haut de page

 

arduino Divergences du projet

J’ai d’autres versions de ce projet pour des réalisations différentes.
J’utilise toutes sortes de cartes graphiques. J’affiche des courbes sur 24 heures ou quelques jours ou semaine ou mois
La période des acquisitions dépend de la taille de l’écran pour rentrer 24 h complètes !

Vue glabale d'un morceau de la ménagerie :

La première réalisation était sur afficheur 4 lignes 20 caractères sur Uno

Les cartes suivantes utilisaient du 320x240.

Cela autorise une période de 5 minutes car 24 *60 / 5  = 244 (2*12 au carré).

Il reste une petite marge de 320-244 = 76 pixels, c’est peu pour afficher les ordonnées…

Les cartes suivantes utilisaient du 480*320.

Cela autorise une période de 4 minutes car 24 *60 / 4 = 360.

 

Il reste une petite marge de 480-360 = 120 pixels de marge, on respire mieux, bien meilleure visibilité.

Les cartes suivantes utilisaient du 800*480.

Cela autorise une période de 3 minutes car 24 *60 /3 = 480

avec une très grande marge de 800-480= 320, ou 2 minutes avec 720 points et 80 pixels de marge.

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.

arduino

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.

Haut de page

 

arduino  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.

arduino

 Haut de page

 

arduino  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

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++  

arduino

 Haut de page

 

arduino  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

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arduino

 Haut de page

 

arduino  Conclusion

Si ce projet réussit en Bluetooth, je mettrai en ligne le détail de cette liaison multiple sans fil .

 

Retour vers ma page principale Arduino arduino

© Christian Couderc 1999-2019     Toute reproduction interdite sans mon autorisation


* Page vue   81   fois       IP : 18.207.249.15

 Haut de page         Dernière retouche le 27 Juin 2019 à 15 h         Retour page précédente

   Collector