![]() |
Construction d'un anémomètre |
novembre 2019 |
En habitant à La Rochelle et en s'intéressant à la voile, il aurait été étonnant de ne pas s'intéresser au vent et à la météo ! Il y a deux ans j'avais fabriqué un anémomètre autonome à base de l'esp8266 qui permet un suivi des vitesses enregistrées à distance par transfert en wifi, mais j'ai rencontré de nombreux problèmes avec celui-ci, alors je vous présente ici la V2...
La V1 avec ses nouvelles pales (type V2) et à droite la version 2 avec ses deux rangées de cellules solaires que l'on ne voit pas sur la vidéo ! Et son grand mat de 5 mètres. |
Je me suis retrouvé à exploiter deux versions électronique avec chacune leurs avantages et inconvénients :
- La version avec TPL5111 qui permet une bonne maitrise de l'énergie (testée sur presque deux ans (très bonne tenue des batteries)) mais qui repose sur la fragilité du circuit TPL5111
(qui m'a lâché deux fois), cette version est également basé sur une version dépouillée de l'esp qui a une portée wifi moindre.
- La version qui exploite le Deep Sleep (mise en veille complète de l'esp), il n'est pas évident de vérifier les 20 uA annoncé avec le système qui recharge les batteries
(je n'ai pas de recul sur cette méthode, à vérifier dans le temps mais sur le papier la consommation devrait être la même qu'avec le TPL...) Par contre sur cette deuxième version
de l'électronique j'ai utilisé un Wemos ESP8266 D1 mini Pro qui permet le raccordement d'une antenne wifi externe donc d'améliorer la portée.
Le TP4056 s'occupe d'alimenter le montage soit par batterie soit par le solaire, le TPL5111 minimise la consommation et l'ESP compte les tours de roue et envoie le résultat par wifi. (Voir plus bas détail câblage fourche).
Le TP4056 s'occupe d'alimenter le montage soit par batterie soit par le solaire, Le mode veille de l'esp minimise la consommation et l'ESP compte les tours de roue et envoie le résultat par wifi.
Ne pas oublié pour exploiter l'antenne externe de déplacer le strap ! (Voir plus bas détail câblage fourche).
La fourche (même schèma pour les deux versions TPL5111 ou Deep Sleep) est alimentée par l'ESP, les résistances doivent être intégrées dans le bloc des roulements sous la fourche. Il faut ajouter un petit condensateur de 1uF (plutôt au niveau des broches de l'esp) entre les broches Gpio 4 et la masse afin d'améliorer un peu la forme des créneaux générés par la fourche !
- Pour version TPL : le support de l'esp avec l'alim intégré : chercher "Module plaque d'adaptation avec io conduit pour esp-12"
- Pour version TPL : l'esp : chercher "Esp-8266-12" prendre un modèle nue comme sur les photos.
- Pour version Deep Sleep : l'esp : chercher "Wemos 8266 d1 mini Pro".
- Pour version TPL : l'esp : le TPL5111 : facile.
- Pour version Deep Sleep : Un régulateur 3v3, un condo 1000uF et un de 100nF.
Pour les deux versions :
- le TP4056 : facile.
- les cellules : chercher "cellule solaire 5v"
- fourche optique : facile
- autres : des résistances 680 ohms, 15 ko (fourche), 33 ko (délai), un petit condo de 1uF, une petite plaque à trous, un petit inter et un bouton de reset.
- les roulements et la tige de 6mm (perso récup imprimante).
- L'esp est alimenté et donc démarre environ toutes les (trois minutes version TPL, deux minutes version deepsleep).
- La connexion au serveur mosquitto est effectuée.
- L'esp alimente la fourche optique avec la sortie Gpio 5 au démarrage.
- Sur chaque front detecté sur l'entrée Gpio 4 une interruption est lancée au microprocesseur qui va immédiatement compter le trou.
- Au bout de dix secondes on fait le point du nombre de tours fait et on calcul une vitesse (libre à vous d'affiner le calcul !).
- Le résultat de la mesure est envoyé vers le serveur Mosquitto par wifi.
- Tout est ok : sur version TPL, on envoi le top arret au TPL5111 qui fait tomber le signal "enable" ce qui coupe tout y compris l'alim de la fourche
Sur la version "Deepsleep" on commande la mise en veille.
Dans les deux versions, il faut bien sur mettre à jour vos propres infos (box, passe, adr IP, serveur MQTT, passe...)
Il faut aussi agir à votre convenance sur le "facteur variable" dans le sous calcul de vitesse afin d'adapter l'anémomètre à son environnement
ce facteur permet de compenser la contre-résistance qu'offre l'anémomètre au vent ainsi que la hauteur à laquelle il est installé...
Ici c'est la version avec le TPL 5111 d'Adafrui
// Carte Anémometre V2.3 / ESP8266 sur pile et solaire
// retour des infos vers mosquitto
// mai 2018 modif nov 2019 et avril 2020
// https://castoo.fr
//
#include "ESP8266WiFi.h"
#include "PubSubClient.h"
//#define debug_anemo
#define OPTO 4 // broche Anémometre
#define ALIM_FOURCH 12 // broche qui va alimenter la fourche que quand l'esp sera en fonction (économie)
#define DONEPIN 5 // GPIO5 quand etat haut coupe l'alim du montage (economie pile) grace au TPL5111
const char* box = "raspi-mqtt"; // Nom de la box
const char* m_passe = "*******************"; // Passe WiFi
const char* mqtt_server = "10.3.141.1"; // Adr de serveur mosquitto
const char* mqtt_user = "admin"; // login sur serveur mosquitto
const char* mqtt_password = "*********************"; // Passe sur serveur mosquitto
long h_der_envoi = 0;
char msg_envoye[50];
bool lect_ok = false; // Passe à true quand lecture ok
volatile static byte nb_trou = 0; // comptage du nb trou de 1 à 6
const byte nb_top_par_tour = 4; // Nb de trou par tour de l'anémometre
volatile long comptage_Tours = 0; // Anemometre
const long interval = 10000; // interval de 10 secondes entre deux calculs de la vitesse
float sous_calcul = 2 * 3.14159265 * 0.13 * 1.35; // 2 pi * rayon anémometre * facteur variable
float vitesse = 0; // Anemometre en km/h
WiFiClient espClient; // déclaration Objet wifi
PubSubClient client(espClient); // déclaration objet mosquitto
void ICACHE_RAM_ATTR interrupt_top(); // pour eviter une erreur d'execution qui n'apparait pas à la compilation !
long ch_garde_mesure = 0; // Chien de garde problème mesure
// ------------------------------- Cnx à la BOX -----------------------------------
void setup_wifi() {
int cpt = 0;
delay(10);
WiFi.begin(box, m_passe);
delay(200);
#ifdef debug_anemo
Serial.println("Entree cnx setup_wifi");
#endif
while (WiFi.status() != WL_CONNECTED) {
if(cpt > 100){
#ifdef debug_anemo
Serial.println("Erreur : Boucle Chien setup_wifi");
#endif
// Chien de garde cnx serveur
// fin on coupe l'alim on essaira plus tard...
// il semble que le tpl5111 ne detecte pas toujours le changement d'état du signal alors on boucle
while(true){
delay(5);
digitalWrite(DONEPIN, HIGH);
delay(5);
digitalWrite(DONEPIN, LOW);
}
}
cpt ++;
delay(500);
#ifdef debug_anemo
Serial.print(".");
#endif
}
randomSeed(micros()); // initialise le générateur de nombres pseudo-aléatoire sera utile pour id mosquitto
#ifdef debug_anemo
Serial.println("Sortie cnx setup_wifi réussite ! ");
#endif
}
// ----------------------------- Cnx à mosquitto -----------------------------------
void reconnect() {
int cpt = 0;
#ifdef debug_anemo
Serial.println("Entree reconnect");
#endif
while (!client.connected()) {
String clientId = "ESPanemo2-"; // Creatation d'un ID aléatoire (identification ESP sur mosquitto)
clientId += String(random(0xffff), HEX);
if (!client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
delay(5000);
#ifdef debug_anemo
Serial.print(".");
#endif
}
if(cpt > 1000){
#ifdef debug_anemo
Serial.println("Erreur : Boucle Chien reconnect");
#endif
// Chien de garde cnx serveur
// fin on coupe l'alim on essaira plus tard...
// il semble que le tpl5111 ne detecte pas toujours le changement d'état du signal alors on boucle
while(true){
delay(5);
digitalWrite(DONEPIN, HIGH);
delay(5);
digitalWrite(DONEPIN, LOW);
}
}
cpt ++;
}
#ifdef debug_anemo
Serial.println("Sortie reconnect réussite ! ");
#endif
}
// --- Se declenche à chaque trou et permet de compter les tours complets de l'anemometre ----
void ICACHE_RAM_ATTR interrupt_top()
{
nb_trou++;
if ( nb_trou == nb_top_par_tour) {
comptage_Tours++;
nb_trou = 0;
}
}
// -- Effectue une requete sur le capteur que si un délai de 2 secondes est respecté --
void get_data_anemo() {
unsigned long temp_ecoule = millis() - h_der_envoi;
#ifdef debug_anemo
Serial.println("Entrée get_data_anemo");
Serial.println("H milliseconde : " + String(millis()));
Serial.println("H temp_ecoule : " + String(temp_ecoule));
Serial.println("Comptage tours : " + String(comptage_Tours));
#endif
delay(100);
if(temp_ecoule >= interval){
#ifdef debug_anemo
Serial.println("Temp_ecoulé on detach interuption get_data_anemo");
#endif
detachInterrupt(OPTO); // On arrete les appels de l'interruption
digitalWrite(ALIM_FOURCH, LOW); // On coupe l'alim de la fourche
if (comptage_Tours > 0){
comptage_Tours = comptage_Tours / 10; // Nb tours en 1 sec
vitesse = sous_calcul * comptage_Tours * 3.6; // en km/h
} else {
vitesse = 0;
}
lect_ok = true;
}
if(ch_garde_mesure > 50000){
lect_ok = true;
vitesse = -1;
}else{
ch_garde_mesure ++;
}
#ifdef debug_anemo
Serial.println("Sortie get_data_anemo");
#endif
}
// ------------------------------------- Setup -------------------------------------
void setup(void){
#ifdef debug_anemo
Serial.begin(9600);
Serial.println("Entrée setup");
#endif
pinMode(OPTO, INPUT_PULLUP); // Broche OPTOcoupleur anémometre configurée en entrée
pinMode(ALIM_FOURCH, OUTPUT); // Broche d'alim de la fourche
digitalWrite(ALIM_FOURCH, HIGH);
pinMode(DONEPIN, OUTPUT); // Broche de coupure du circuit
digitalWrite(DONEPIN, LOW);
ch_garde_mesure = 0; // On initialise le chien de mesure
setup_wifi(); // cnx wifi
client.setServer(mqtt_server, 1883); // cnx mosquitto
attachInterrupt(digitalPinToInterrupt(OPTO), interrupt_top, FALLING); // Interuption pour l'anemometre
h_der_envoi = millis(); // On initialise le temps de lecture
nb_trou = 0;
comptage_Tours = 0;
#ifdef debug_anemo
Serial.println("H der envoie : " + String(h_der_envoi));
Serial.println("Sortie setup");
#endif
}
// --------------------------------------- Loop -------------------------------------
void loop(){
get_data_anemo();
if (lect_ok) {
#ifdef debug_anemo
Serial.println("Boucle loop : lect_ok");
#endif
if (!client.connected()) { reconnect(); }
delay(100);
snprintf (msg_envoye, 50, "Vitesse %d km/h", int(vitesse));
client.publish("anemo", msg_envoye);
delay(500);
//snprintf (msg_envoye, 50, "Nb tours %ld tours", comptage_Tours);
//client.publish("Anemometre", msg_envoye);
// fin on coupe l'alim on essaira plus tard...
// il semble que le tpl5111 ne detecte pas toujours le changement d'état du signal alors on boucle
#ifdef debug_anemo
Serial.println("Boucle loop : fin on coupe l'alim");
Serial.println("Vitesse calculee : " + String(vitesse));
delay(500);
#endif
while(true){
delay(5);
digitalWrite(DONEPIN, HIGH);
delay(5);
digitalWrite(DONEPIN, LOW);
}
}
client.loop();
#ifdef debug_anemo
Serial.println("Boucle loop : client.connected : " + String(client.connected()));
#endif
}
Ici c'est la version sans le TPL 5111 la coupure est réalisée avec le mode Deep Sleep de l'esp
// Carte Anémometre V3 / ESP8266 D1 mini Pro sur pile et solaire
// retour des infos vers mosquitto
// avril 2020
// https://castoo.fr
//
#include "ESP8266WiFi.h"
#include "PubSubClient.h"
//#define debug_anemo
#define OPTO 4 // broche Anémometre (D2)
#define ALIM_FOURCH 12 // broche qui va alimenter la fourche que quand l'esp sera en fonction (économie) (D6)
#define durationSleep 120 // secondes (duree du sommeil entre deux mesures
#define nb_top_par_tour 4 // Nb de trou par tour de l'anémometre
const char* box = "raspi-mqtt"; // Nom de la box
const char* m_passe = "*********************"; // Passe WiFi
const char* mqtt_server = "10.3.141.1"; // Adr de serveur mosquitto
const char* mqtt_user = "admin"; // login sur serveur mosquitto
const char* mqtt_password = "********************"; // Passe sur serveur mosquitto
long h_der_envoi = 0;
char msg_envoye[50];
bool lect_ok = false; // Passe à true quand lecture ok
volatile byte nb_trou = 0; // comptage du nb trou de 1 à 6
volatile long comptage_Tours = 0; // Anemometre nb tours en 2 secondes
const long interval = 10000; // interval de 10 secondes (temps de mesure) (donc comptage_tour est a div par 10)
float sous_calcul = 2 * 3.14159265 * 0.13 * 1.35; // 2 pi * rayon anémometre(m) * facteur variable
float vitesse = 0; // Anemometre en km/h
WiFiClient espClient; // déclaration Objet wifi
PubSubClient client(espClient); // déclaration objet mosquitto
void ICACHE_RAM_ATTR interrupt_top(); // pour eviter une erreur d'execution qui n'apparait pas à la compilation !
long ch_garde_mesure = 0; // Chien de garde problème mesure
// ------------------------------- Cnx à la BOX -----------------------------------
void setup_wifi() {
int cpt = 0;
delay(10);
WiFi.begin(box, m_passe);
delay(200);
#ifdef debug_anemo
Serial.println("Entree cnx setup_wifi");
#endif
while (WiFi.status() != WL_CONNECTED) {
if(cpt > 100){
#ifdef debug_anemo
Serial.println("Erreur : Boucle Chien setup_wifi");
#endif
// Chien de garde cnx serveur
// fin on coupe l'alim on essaira plus tard...
ESP.deepSleep(durationSleep * 1000000);
}
cpt ++;
delay(500);
#ifdef debug_anemo
Serial.print(".");
#endif
}
randomSeed(micros()); // initialise le générateur de nombres pseudo-aléatoire sera utile pour id mosquitto
#ifdef debug_anemo
Serial.println("Sortie cnx setup_wifi réussite ! ");
#endif
}
// ----------------------------- Cnx à mosquitto -----------------------------------
void reconnect() {
int cpt = 0;
#ifdef debug_anemo
Serial.println("Entree reconnect");
#endif
while (!client.connected()) {
String clientId = "ESPanemo2-"; // Creatation d'un ID aléatoire (identification ESP sur mosquitto)
clientId += String(random(0xffff), HEX);
if (!client.connect(clientId.c_str(), mqtt_user, mqtt_password)) {
delay(5000);
#ifdef debug_anemo
Serial.print(".");
#endif
}
if(cpt > 1000){
#ifdef debug_anemo
Serial.println("Erreur : Boucle Chien reconnect");
#endif
// Chien de garde cnx serveur
// fin on coupe l'alim on essaira plus tard...
ESP.deepSleep(durationSleep * 1000000);
}
cpt ++;
}
#ifdef debug_anemo
Serial.println("Sortie reconnect réussite ! ");
#endif
}
// --- Se declenche à chaque trou et permet de compter les tours complets de l'anemometre ----
void ICACHE_RAM_ATTR interrupt_top()
{
nb_trou++;
if ( nb_trou == nb_top_par_tour) {
comptage_Tours++;
nb_trou = 0;
}
}
// -- Effectue une requete sur le capteur que si un délai de 2 secondes est respecté --
void get_data_anemo() {
unsigned long temp_ecoule = millis() - h_der_envoi;
#ifdef debug_anemo
Serial.println("Entrée get_data_anemo");
Serial.println("H milliseconde : " + String(millis()));
Serial.println("H temp_ecoule : " + String(temp_ecoule));
Serial.println("Comptage tours : " + String(comptage_Tours));
#endif
delay(100);
if(temp_ecoule >= interval){
#ifdef debug_anemo
Serial.println("Temp_ecoulé on detach interuption get_data_anemo");
#endif
detachInterrupt(OPTO); // On arrete les appels de l'interruption
digitalWrite(ALIM_FOURCH, LOW); // On coupe l'alim de la fourche
if (comptage_Tours > 0){
comptage_Tours = comptage_Tours / 10; // Nb tours en 1 sec
vitesse = sous_calcul * comptage_Tours * 3.6; // en km/h
} else {
vitesse = 0;
}
lect_ok = true;
}
if(ch_garde_mesure > 50000){
lect_ok = true;
vitesse = -1;
}else{
ch_garde_mesure ++;
}
#ifdef debug_anemo
Serial.println("Sortie get_data_anemo");
#endif
}
// ------------------------------------- Setup -------------------------------------
void setup(void){
#ifdef debug_anemo
Serial.begin(115200);
Serial.println("Entrée setup");
#endif
pinMode(OPTO, INPUT_PULLUP); // Broche OPTOcoupleur anémometre configurée en entrée
pinMode(ALIM_FOURCH, OUTPUT); // Broche d'alim de la fourche
ch_garde_mesure = 0; // On initialise le chien de mesure
setup_wifi(); // cnx wifi
client.setServer(mqtt_server, 1883); // cnx mosquitto
digitalWrite(ALIM_FOURCH, HIGH);
attachInterrupt(digitalPinToInterrupt(OPTO), interrupt_top, FALLING); // Interuption pour l'anemometre
h_der_envoi = millis(); // On initialise le temps de lecture
nb_trou = 0;
comptage_Tours = 0;
#ifdef debug_anemo
Serial.println("H der envoie : " + String(h_der_envoi));
Serial.println("Sortie setup");
#endif
}
// --------------------------------------- Loop -------------------------------------
void loop(){
get_data_anemo();
if (lect_ok) {
#ifdef debug_anemo
Serial.println("Boucle loop : lect_ok");
#endif
if (!client.connected()) { reconnect(); }
delay(100);
snprintf (msg_envoye, 50, "Vitesse %d km/h", int(vitesse));
client.publish("anemo", msg_envoye);
delay(500);
// fin on coupe l'alim
#ifdef debug_anemo
Serial.println("Boucle loop : fin on coupe l'alim");
Serial.println("Vitesse calculee : " + String(vitesse));
delay(500);
#endif
ESP.deepSleep(durationSleep * 1000000);
while(true){ delay(10); }
}
client.loop();
#ifdef debug_anemo
Serial.println("Boucle loop : client.connected : " + String(client.connected()));
#endif
}
Si on dé-commente la ligne #define debug_anemo il est possible de vérifier le fonctionnement du programme, l'exemple d'exécution ci-dessous
aide à la compréhension des actions du programme.
Exemple de compte rendu d'execution avec #define debug_anemo
Ici le cr est pour une mesure sur 2 secondes, le programme est lui réglé sur 10 secondes donc un cr 5 fois plus long !
............Sortie cnx setup_wifi réussite !
H der envoie : 4496
Sortie setup
Entrée get_data_anemo
H milliseconde : 4496
H temp_ecoule : 0
Comptage tours : 30
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 4614
H temp_ecoule : 94
Comptage tours : 30
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_aneMo
H milliseconde : 4767
H temp_ecoule : 247
Comptage tours : 30
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 4921
H temp_ecoule : 401
Comptage tours : 30
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_aneMo
H milliseconde : 5076
H temp_ecoule : 555
Comptage tours : 30
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 5230
H temp_ecoule : 709
Comptage tours : 31
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 5384
H temp_ecoule : 864
Comptage tours : 39
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 5538
H temp_ecoule : 1018
Comptage tours : 39
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemO
H milliseconde : 5693
H temp_ecoule : 1173
Comptage tours : 39
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 5849
H temp_ecoule : 1328
Comptage tours : 39
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 6004
H temp_ecoule : 1483
Comptage tours : 39
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 6159
H temp_ecoule : 1639
Comptage tours : 39
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 6314
H temp_ecoule : 1794
Comptage tours : 39
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 6469
H temp_ecoule : 1949
Comptage tours : 47
Sortie get_data_anemo
Boucle loop : client.connected : 0
Entrée get_data_anemo
H milliseconde : 6625
H temp_ecoule : 2104
Comptage tOurs : 47
Temp_ecoulé on detach interu`tion get_data_anemo
Sortie get_data_anemo
Boucle loop : lect_ok
EntreEreconnect
Sortie reconnect réussite !
Boucle loop : fin on coupe l'alim
Vitesse calculee : 26.01
Pour Node-red une petite construction permet d'adapter les valeurs renvoyées par l'anémomètre à l'aide d'une fonction et la mémorisation dans la base de données InfluxDB pour graphique avec Grafana...
La petite fonction Node-red qui permet d'adapter le texte reçu par wifi de l'anémomètre pour la mémorisation dans la base de données InfluxDB.
Il peut arriver (rarement !) que des données incohérentes (vitesse exagérée ou valeur inférieur à zéro apparaissent, la fonction écrête donc ces valeurs douteuses car
une fois qu'elles sont mémorisées dans influxDB, impossible de les effacer ! (ou je n'ai pas trouvé comment faire !).
Pour Grafana on va extraire les données d'InfluxDB et on les affiche avec la présentation souhaitée et sur la période voulue...
Je vais mettre à dispo tous les fichiers STL dans la partie Imp3D du site afin que vous puissiez les imprimer à votre convenance pour une éventuelle construction.
Le projet est terminé, j'espère qu'il vous donnera des idées de réalisations, pour ma pârt je suis content de cette deuxième version qui me permet d'avoir des valeurs beaucoup plus proche (y compris en hivers (mis février je n'ai toujours pas été obligé d'utiliser la prise usb, le système est bien autonome !) de la réalité que la premiere version ! Je vous laisse le vent commence à souffler, la mer m'appelle...