Abonnement aux commentaires

S'abonner pour recevoir les commentaires suivants par email

まこと の ブログ

MaKoTo no burogu — Journal de bord…

Aller au contenu | Aller au menu | Aller à la recherche

Un Anémomètre Radio Multifonction -4-

Edition du 23 Fevrier 2020, code Arduino et esp8266 mis à jour.
Suite des études précédentes : Anémomètre et Monitoring.

À ce stade, vu tous mes bidules radio, il serait légitime de se demander pourquoi avoir 2 ou 3 appareils différents (l'un pour surveiller le vent, un pour la rotation de l'éolienne et un autre pour la charge de la batterie).
En fait lors du développement il est naturel d'avancer par étape en ajoutant peu à peu des fonctions, cette suite de billet n'en est finalement que le reflet.

Il est maintenant temps de fusionner tout ça !

  • Cette fois donc, l'appareil sera chargé de récupérer les 4 informations que sont la vitesse du vent, la rotation de l'éolienne, l'énergie produite par la génératrice, et l'état de charge de la batterie; afin de les transmettre à des afficheurs et à une base de donnée pour être tracé.

La partie émetteur :

  • J'ai donc câblé un nouveau circuit :


Matériel requis :

- 1 Arduino Pro Mini 5V.
- Un ordi avec port USB et le soft Arduino IDE.
- 1 plaquette HC-12 et son antenne.
- 1 diode 1N4007.
- 2 résistances 10kΩ.
- 1 Capteur à effet Hall US1881 (anémo).
- 1 Capteur à effet Hall 3144 (éolienne).
- 1 Régulateur Négatif 9V L7909CV.
- 1 condensateur électrochimique polarisé de 220µF.
- 1 condensateur électrochimique polarisé de 2,2µF.
- 1 condensateur électrochimique polarisé de 1µF.
- 1 module ACS712 (20A) (Attention cependant !! > Je sais que mon générateur ne dépassera pas 5A, à moins d'une tempête de vent de fin du monde…).

Principe de fonctionnement :
- À intervalle régulier, l'Arduino va envoyer les valeurs lues sur les entrées analogiques A0 et A1, sur le port série du HC-12.
- A0 pour mesurer la valeur de la tension aux bornes de la batterie ( On a fabriqué un voltmètre très précis câblé en parallèle ).
- A1 pour mesurer le courant sortant du générateur ( Un Ampèremètre câblé en série ).
- Dés que le vent fera tourner l'anémomètre, l'interruption déclenche l'envoie des valeurs lues sur l'entrée numérique 2 (int0).
- Dés que le vent fera tourner l'éolienne, l'interruption déclenche l'envoie des valeurs lues sur l'entrée numérique 3 (int1).

  • Programme pour l’Arduino Pro Mini de transmission :

Édit du 15 mai 2020 !
Électro-Bidouilleur a enfin sorti une vidéo sur le module HC-12 et nous informe que la librairie <SoftwareSerial.h> est à éviter, ce que j'aurais bien voulu savoir à l'époque étant donné que j'ai effectivement rencontré des problèmes de réception. Il faut donc lui préférer la librairie <AltSoftSerial.h>. Je n'ai pas le temps de me pencher dessus, donc j'ai laissé tel quel le code suivant, sur github et en annexe du billet, à vous de changer la librairie.

/* Arduino Anemometer and Tachometer Éolienne
IN : capteur à effet Hall Anémomètre est connecté à la pin 2 = int0
IN : capteur à effet Hall Éolienne est connecté à la pin 3 = int1  
OUT : HC-12 Radio Default Mode 9600bps
*/

#include <Arduino_CRC16.h>  // Librairie à ajouter via le gestionnaire de lib de l'appli arduino
#include <SoftwareSerial.h>
#include <avr/sleep.h>
/****************/
/* DÉCLARATIONS */
/****************/
// Partie ANEMO
SoftwareSerial HC12(10, 11); // HC-12 TX Pin, HC-12 RX Pin
unsigned long rpmVent = 0;
unsigned long rpmEol = 0;
unsigned long vitVentKMH = 0;
unsigned long vitEolRPM = 0;
unsigned long dateDernierChangementVent = 0;
unsigned long dateDernierChangementEol = 0;
unsigned long dateDernierChangementRPM = 0;
unsigned long dateDernierChangementKMH = 0;
unsigned long vitVentCourante = 0;
unsigned long vitVentDernierChangement = 0;  
float intervalleKMH = 0;
float intervalleRPM = 0;
const char char_VT = 124; // vertical tab (VT)
const char char_LF = 10; // charactère saut de ligne ascii
const char char_SPACE = 32; // charactère ESPACE ascii, le meilleur caractère pour la détection de string de sscanf !
String chaine;
String message;
int rotaAnemo = 0;
int rotaEol = 0;
#define ATpin 7 // used to switch HC-12 to AT mode

// Partie MONITORING
float Courant=0;
float SupplyVoltage=12;
const int Voie_0=0; // declaration constante de broche analogique
int mesure_brute=0; // Variable pour acquisition résultat brut de conversion analogique numérique
float mesuref=0.0;  // Variable pour calcul résultat décimal de conversion analogique numérique
float tension=0.0;  // Variable tension mesurée
float tension_batterie=0.0; // Variable tension batterie calculée
float tension_regulateur=8925.0;  // Variable tension réelle aux bornes du régulateur -9V (en mV)

int PIN_ACS712 = A1;
double Voltage = 0;
double Current = 0;
char MessageTensionBatterie[] = " VOL / "; // message to be sent; '\n' is a forced terminator char
char MessageCourant[] = " AMP"; // message to be sent; '\n' is a forced terminator char
Arduino_CRC16 crc16;

/*********/
/* SETUP */
/*********/  
void setup() {
  HC12.begin(9600);               // Serial port to HC12
  // debug uniquement, penser à commenter toutes les lignes «Serial…» pour éviter les erreurs de valeur (calcul trop long pour l'interruption)
  Serial.begin(9600);             // Serial port to computer
  // Pin capteurs
  attachInterrupt(digitalPinToInterrupt(2), rpm_vent, FALLING);  // le capteur à effet Hall Anémomètre est connecté à la pin 2 = int0
  attachInterrupt(digitalPinToInterrupt(3), rpm_eol, FALLING);  // le capteur à effet Hall Éolienne est connecté à la pin 3 = int1  
  pinMode(PIN_ACS712, INPUT);
  
  pinMode(ATpin, OUTPUT);
  digitalWrite(ATpin, LOW); // Set HC-12 into AT Command mode
  delay(500);
  HC12.print("AT+C010");  // passer sur le canal 036 (433.4Mhz + 36x400KHz)
  delay(500);
  digitalWrite(ATpin, HIGH); // HC-12 en normal mode
}

/*************/
/* PROGRAMME */
/*************/
void loop() {
  MesureCourant();
  MesureBrute();
  TensionMesuree();
  TensionBatterie();
  RemiseZeroVitVentKMHnew2 ();
  RemiseZeroVitEolRPMnew2 ();

// Construction de la chaine
  chaine =  char_VT + String(vitVentKMH)+ char_SPACE + String(vitEolRPM) + char_SPACE + String(tension_batterie,3) + char_SPACE + String(Current,3);  // construction du message
  Serial.println ( "chaine String :" +chaine );
  // Message de la forme suivante : 49 338 11.405 -12.500

// Calcul du Checksum
  uint16_t const crc16_res = crc16.calc((uint8_t const *)chaine.c_str(), strlen(chaine.c_str()));
  Serial.print("CRC16 = 0x");
  Serial.println(crc16_res, HEX);
  
// Checksum joint au message
  message = chaine + char_SPACE + String(crc16_res, HEX) + char_SPACE + char_LF;
  Serial.println ( "message :" +message ); 
   
// send radio data
//  HC12.print(chaine);
  HC12.print(message);
  // Message de la forme suivante : 49 338 11.405 -12.500 3cfe1c9
  
  delay(100);
}

/*************/
/* FONCTIONS */
/*************/

void rpm_vent()   // appelée par l'interruption, Anémomètre vitesse du vent.
{ 
  unsigned long dateCourante = millis();
  intervalleKMH = (dateCourante - dateDernierChangementVent);
//  Serial.print ( "intervalle en s : " );
//  Serial.println (intervalleKMH/1000); // affiche l'intervalle de temps entre deux passages
  if (intervalleKMH != 0)  // attention si intervalle = 0, division par zero -> erreur
  {
    rpmVent = 60 / (intervalleKMH /1000);  
  }
  vitVentKMH = ( rpmVent + 6.174 ) / 8.367;
  Serial.print ( "vitVentKMH : " );
  Serial.println ( vitVentKMH ); // affiche les rpm  
  Serial.println ( "" );
  dateDernierChangementVent = dateCourante;
  rotaAnemo = 1;

}

void rpm_eol()    // appelée par l'interruption, Tachymétre rotation éolienne.
{
  unsigned long dateCourante = millis();
  intervalleRPM = (dateCourante - dateDernierChangementEol);
//  Serial.print ( "intervalle en s : " );
//  Serial.println (intervalleRPM/1000); // affiche l'intervalle de temps entre deux passages
  if (intervalleRPM != 0)  // attention si intervalle = 0, division par zero -> erreur
  {  
    vitEolRPM = 60 / (intervalleRPM /1000);
  }
  Serial.print ( "rpm : " );
  Serial.println ( vitEolRPM ); // affiche les rpm  
  Serial.println ( "" );
  dateDernierChangementEol = dateCourante;
  rotaEol = 1;
}


void RemiseZeroVitVentKMHnew2 ()
{
  unsigned long dateCouranteKMH = millis();
  if (rotaAnemo == 1 ){   // teste si l'Anémomètre tourne
 //   Serial.println ( "Anémo tourne ");
    float dureeKMH = (dateCouranteKMH - dateDernierChangementKMH);
    if (dureeKMH > 10000) {
      rotaAnemo = 0;
      dateDernierChangementKMH = dateCouranteKMH; 
    }
  }
  else    // Si ça ne tourne plus (valeur plus mise à jour)
  {  
    float dureeKMH = (dateCouranteKMH - dateDernierChangementKMH);
    if (dureeKMH > 6000) // Si ça ne tourne plus depuis 16 secondes, délai un peu augmenté vis à vis du mode veille.
    {
 //     Serial.print ( "dureeKMH : " );
  //    Serial.println ( dureeKMH ); // affiche les rpm  
      vitVentKMH = 0;  // Remsise à zero !
      dateDernierChangementKMH = dateCouranteKMH;   
    }
  }
}

void RemiseZeroVitEolRPMnew2 ()
{
  unsigned long dateCouranteRPM = millis();
  if (rotaEol == 1 ){ // teste si l'éolienne tourne
//    Serial.println ( "Éolienne tourne ");
    float dureeRPM = (dateCouranteRPM - dateDernierChangementRPM);
    if (dureeRPM > 10000) {
      rotaEol = 0;
      dateDernierChangementRPM = dateCouranteRPM;
    }
  }
  else    // Si ça ne tourne plus (valeur plus mise à jour)
  {  
    float dureeRPM = (dateCouranteRPM - dateDernierChangementRPM);
    if (dureeRPM > 6000) // Si ça ne tourne plus depuis 65 secondes (soit moins de 1 rpm), changé pour 8 sec en charge
    {
//      Serial.print ( "dureeRPM : " );
//      Serial.println ( dureeRPM ); // affiche les rpm  
      vitEolRPM = 0;  // Remsise à zero !
      dateDernierChangementRPM = dateCouranteRPM;    
    }
  }
}


// Partie MONITORING

void MesureCourant() {
//  Serial.print("Courant : ");
//  Serial.print(Courant);
//  Serial.print(" A | Puissance : ");
//  Serial.print(Courant*SupplyVoltage);
//  Serial.println(" Watt");

// Voltage is Sensed 1000 Times for precision
for(int i = 0; i < 1000; i++) { // ça ralentis tout, mais c'est indispensable !
Voltage = (Voltage + (0.004882812 * analogRead(PIN_ACS712))); // (5 V / 1024 (Analog) = 0.0049) which converter Measured analog input voltage to 5 V Range
delay(1);
}
Voltage = Voltage /1000;

Current = (Voltage -2.5)/ 0.100; // Sensed voltage is converter to current (0.100 pour modèle 20A)

//Serial.print("\n Voltage Sensed (V) = "); // shows the measured voltage
//Serial.print(Voltage,3); // the ‘2’ after voltage allows you to display 2 digits after decimal point
//Serial.print("\t Current (A) = "); // shows the voltage measured
//Serial.println(Current,3); // the ‘2’ after voltage allows you to display 2 digits after decimal point
}

void MesureBrute() {
//-------- mesure brute --------
  mesure_brute=analogRead(Voie_0);
//  Serial.print ("Valeur brute = "); 
//  Serial.print (mesure_brute); 
//  Serial.println (" "); // espace de propreté
}

void TensionMesuree() {
//---------- tension mesurée ---------
  mesuref=float(mesure_brute)*5000.0/1024.0;
  tension=mesuref/1000.0; // en Volts
//  Serial.print ("Tension = "); 
//  Serial.print(tension,3);  // float avec 2 décimales 
//  Serial.println(" V ");  // unité et espace de propreté
}

void TensionBatterie() {
//---------- tension batterie ---------
  tension_batterie=mesuref+tension_regulateur;
  tension_batterie=tension_batterie/1000.0; // en Volts
//  lcd.setCursor(0,1) ; // positionne le curseur à l'endroit voulu (colonne, ligne)
//  lcd.print ("Batt:"); 
//  lcd.print (tension_batterie,2); // float avec 2 décimales
//  lcd.print ("V "); // unité et espace de propreté
//  Serial.print ("Batterie = "); 
//  Serial.print(tension_batterie,3); // float avec 2 décimales 
//  Serial.println(" V ");
//  Serial.println("  ");
}


Le boîtier client, partie récepteur avec affichage :

  • J'ai conservé mes deux systèmes d'affichage distinct (et donc deux Arduino à programmer), mais rien n'empêcherait d'utiliser un seul afficheur LCD à 4 lignes !


Matériel requis :

- 2 Arduino Pro Mini 5V.
- Un ordi avec port USB et le soft Arduino IDE.
- 1 plaquette HC-12 et son antenne.
- 1 diode 1N4007.
- 1 afficheur LCD type HD44780 16 ou 20 x 2.
- 1 NodeMCUv3 LoLin.
- 1 condensateur électrochimique polarisé de 220µF.
- 12 afficheurs DLG7137.


Principe de fonctionnement :
- Les deux Arduino reçoivent les valeurs transmises par le port série du HC-12 et les affichent instantanément sur l'écran LCD (courant et tension) et les afficheurs DLG (vent et éolienne).
- Le NodeMCU reçoit les valeurs transmises par le port série du HC-12 et les transmet à la Base de données InfluxDB.
- Grafana s'occupera de tracer les graphiques à partir des données.

  • Programme pour l’Arduino Pro Mini de réception LCD : Voir en annexe du billet[1].
  • Programme pour l’Arduino Pro Mini de réception DLG7137 : Voir en annexe du billet[2].
  • Programme pour le NodeMCU de réception : Voir en annexe du billet[3].

Configuration de la Grafana :

  • Concernant cette partie, je vous laisse voir la fin de ce billet, vu que c'est la même chose !

Vous pourriez obtenir ce genre de chose :


L'observateur attentif aura remarqué que la vitesse du vent n'est ici pas logique avec la rotation de l'éolienne… Normal, je faisais des tests en rotation manuelle afin de pouvoir tracer ces graphiques.

Le code est aussi documenté ici, et en annexe du billet.

Notes

[1] ci-dessous

[2] ci-dessous

[3] ci-dessous

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

Fil des commentaires de ce billet