Vous êtes sur la page 1sur 57

Smart Buoy [Étanchéité, Tableaux de bord et Déploiement]

Cette série de bouées intelligentes illustre notre tentative (ambitieuse)


de construire une bouée scientifique capable de prendre des mesures
significatives sur la mer à l'aide de produits prêts à l'emploi. Ceci est
notre dernier didacticiel. Assurez-vous d'être à jour et si vous avez
besoin d'une introduction rapide au projet, consultez notre résumé.

Partie 1 : Réalisation de mesures de vagues et de températures

Partie 2 : Module GPS, radio (NRF24) et carte SD

Partie 3 : Planification de l'alimentation de la bouée

Dans cet article, nous vous montrons comment nous avons conçu le
boîtier pour protéger notre Smart Buoy de l'eau, des vagues et des
attaques de requins. Nous expliquons également comment nous
l'avons connecté à la station de base, qui hébergeait une base de
données et un tableau de bord interactif pour explorer les données en
temps réel.

Fourniture
Comme il s'agit de la dernière étape du projet, vous aurez besoin de
TOUTES les fournitures :

 Arduino Nano — Amazon

 Raspberry Pi Zero — Amazon

 Batterie (18650) — Amazone

 Panneaux solaires — Amazon

 Diodes de blocage — Amazon

 Contrôleur de charge — Amazon

 Booster de Buck — Amazon


 Module GPS — Amazon

 GY-86 (accéléromètre, gyroscope, baromètre, boussole) — Amazon

 Capteur de température de l'eau — Amazon

 Module de surveillance de l'alimentation — Amazon

 Module horloge temps réel — Amazon

 Modules radio — Amazon

 Module multiplexeur i²c — Amazon


 Imprimante 3D — Amazon

 Filaments PETG — Amazon

 Époxy — Amazon

 Peinture en aérosol d'apprêt — Amazon

 Corde — Amazone

 Flotteurs — Amazon

 Colle — Amazon

Obtenez le code Smart Buoy sur Github

3 Plus d'images
Étape 1 : Panneaux solaires
La bouée intelligente comportait quatre panneaux solaires également
espacés autour de sa circonférence. Chaque cellule était capable de
produire 5V à 60mA. Un Arduino nano typique nécessite environ 20
mA, nous espérions donc que cela conviendrait à notre
système. Nous avons soudé des fils à l'arrière des panneaux solaires
et les avons connectés au reste du système de charge.

Nous avons enfilé les fils à travers puis collé les panneaux solaires en
position étanche.
Étape 6 : Carte mère — Perfboard
Avec beaucoup de détermination, de soudure et de fil, nous avons
connecté l'électronique ensemble sur perfboard.

Nous avons poussé l'antenne radio et les capteurs de température de


l'eau à travers leurs trous respectifs et les avons collés en place.
Le perfboard s'est parfaitement inséré dans la bouée et nous l'avons
collé en position.

Comme nous l'avons mentionné dans le deuxième tutoriel, nous


avons supprimé le module de carte SD car il causait d'énormes maux
de tête.

Étape 7 : Flottabilité

La logique (et probablement la science) dictait que la bouée flotterait


si elle était moins dense que l'eau. Nous pensions que la bouée
flotterait. Mais nous n'avions pas beaucoup de confiance dans sa
stabilité.

De nombreuses bouées disponibles à l'achat sur le marché sont


construites de manière à se redresser automatiquement. Nous avons
opté pour couper un morceau d'isolant de tuyau et le coller autour de
la circonférence du milieu de la bouée. Cela avait pour effet
supplémentaire de donner à la bouée un aspect OVNI, et offrait
également potentiellement un peu de protection si des bateaux
décidaient qu'ils voulaient regarder de plus près.
Étape 8 : Station de base

Avec tous les capteurs à bord de la bouée, nous avons pu mesurer :


la hauteur des vagues, la période des vagues, la puissance des
vagues, la température de l'eau, la température de l'air, la pression
atmosphérique, la tension, l'utilisation actuelle et l'emplacement. Ces
valeurs ont été envoyées de la bouée à la station de base à l'aide des
modules radio.

Nous aurions adoré mesurer la direction des vagues et nous étions


sur le point de le faire fonctionner, mais c'était une lutte énorme
(regardez le premier tutoriel pour voir notre douleur et notre confusion
plus en détail) donc à la fin nous l'avons abandonné (s'il vous plaît
aide ❤).

Étape 9 : Tableau de bord


L'interface du tableau de bord Smart Buoy a été créée à l'aide
de VueJs . Nous n'expliquerons pas en profondeur comment nous
avons fait cela, mais nous pouvons vous montrer comment le faire
fonctionner. Les étapes détaillées peuvent être trouvées dans
le référentiel Github.

 SSH dans la station de base Raspberry Pi


 Installer les dépendances et créer la base de données
 Télécharger le code et le fichier de configuration env.json
 Ajouter l'adresse IP Raspberry Pi et la clé Google Maps
 Démarrer le serveur

Une fois que la station de base commence la communication radio


avec la bouée, les messages sont stockés dans la base de données
ainsi que les utilisateurs diffusés en continu du tableau de bord en
temps réel. En accédant à la page d'accueil du tableau de bord dans
votre navigateur, vous devriez voir les données en continu.
La série chronologique de mesures peut être visualisée simplement
en basculant le contrôle de vue sur chaque carte de mesure. Si vous
souhaitez examiner les données de plus près, la page des tendances
comporte un outil graphique qui interroge la base de données
exécutée sur la station de base.

Étape 10 : Placer - Où le mettre ?


La Grenade est une île merveilleuse du sud des Caraïbes. La côte
est, qui fait face à l'Atlantique, reçoit généralement plus d'énergie des
vagues que la côte ouest plus abritée. L'amplitude des marées
(distance entre la marée haute et la marée basse) est faible, ce qui
signifie que les effets de l'élévation du niveau de la mer sont ressentis
plus intensément. La fréquence et l'intensité croissantes des tempêtes
tropicales dans les Caraïbes constituent également une menace
inquiétante, et les tempêtes majeures peuvent causer des dommages
importants aux zones côtières.

Quoi qu'il en soit, assez de cela. Nous avons cherché un endroit pour


déployer initialement la bouée, en tenant compte de notre
connaissance de l'île et de ses régions côtières. Un spot idéal qui
nécessitait des vagues petites mais dynamiques, peu de pêcheurs
voyous, et facile d'accès… Nous avons donc d'abord testé en piscine.

Pendant notre séjour à la Grenade, nous avons également eu la


chance de parler avec un ami qui possède un magasin de plongée en
bord de mer. Il a sa propre mission environnementale - créer un récif
de corail artificiel - dont vous pouvez en savoir plus ici. Nous avons
été ravis lorsqu'il nous a donné la permission d'attacher notre bouée à
l'une de ces lignes.
Nous avons ancré la bouée à d'autres en nouant un morceau de
corde autour du crochet latéral inférieur (oui, nous sommes assez
légitimes). Il n'a pas coulé. ÇA A MARCHÉ!

Étape 11 : V2

Le projet Smart Buoy a été une excellente source


d'apprentissage. Nous sommes très satisfaits du système que nous
avons réussi à créer, en particulier compte tenu des contraintes de
temps et de coût (auto-imposées).

Cependant, le but de la bouée était de prendre des mesures


océaniques significatives. Nous n'avons réussi à faire fonctionner la
bouée que quelques jours avant de devoir quitter la Grenade
ensoleillée. De retour au Royaume-Uni, le bord de mer est un peu
moins séduisant… Pour ne pas dire que ce projet ne se poursuivra
pas. Nous avons beaucoup appris, et maintenant nous pouvons
appliquer ces améliorations et, espérons-le, faire un autre voyage
merveilleux.

Principales améliorations

 Possibilité d'ouvrir et de refermer la bouée


 LoRa ESP32 pour remplacer Arduino dans Buoy
 Traitement des données sur les mesures de vagues sur la Bouée
Smart Buoy - [Faire des mesures de vagues et
de température]
Cette série de bouées intelligentes illustre notre tentative (ambitieuse)
de construire une bouée scientifique capable de prendre des mesures
significatives sur la mer à l'aide de produits prêts à l'emploi. Ceci est
le tutoriel un des quatre. Si vous avez besoin d'une présentation
rapide du projet, consultez notre résumé .
Dans ce tutoriel, nous vous montrons comment nous avons pris des
mesures de vagues et de température sur notre Smart Buoy.
Ajouter un pourboirePoser une questionCommentaireTélécharger

Fournitures

 Arduino Nano - Amazone


 GY-86 (accéléromètre, gyroscope, baromètre, boussole) - Amazon
 Capteur de température de l'eau - Amazon

Obtenez le code Smart Buoy sur Github


Ajouter un pourboirePoser une questionCommentaireTélécharger

Étape 1 : GY-86 : Accéléromètre et gyroscope


Le capteur principal de la bouée est un GY-86, qui contient le
gyroscope accéléromètre MPU6050, le magnétomètre HMC5883L et
le baromètre MS5611. Ces capteurs nous permettent de mesurer la
température de l'air, la hauteur des vagues, la période des vagues et
l'énergie des vagues (et la direction des vagues si quelqu'un est assez
intelligent pour faire les calculs).

Le GY-86 communique via i2C - voir le schéma. C'est le code que


nous avons utilisé pour accéder aux lectures de l'accéléromètre et du
gyroscope.

#include "Fil.h"

#include "I2Cdev.h"
#include "MPU6050.h"

carte mère MPU6050 ;

int16_t ax, ay, az ;


int16_t gx, gy, gz ;

void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("Initialisation du MP6050...");
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connexion MPU6050 réussie" : "Échec de la
connexion MPU6050");}

boucle vide() {
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
printResults();
retard(10);
}

annuler printResults(){
Serial.print("Acc (x,y,z) m/s/s : ");
Serial.print(ax); Serial.print(" ");
Serial.print(ay); Serial.print(" ");
Serial.print(az);
Serial.print(" Gyro(x,y,z) °/s: ");
Serial.print(gx); Serial.print(" ");
Serial.print(gy); Serial.print(" ");
Serial.println(gz);
}

Étape 2 : GY-86 : Magnétomètre (Boussole)

Le GY-86 contient un magnétomètre qui nous sert de boussole. Vous


n'avez pas besoin de modifier les connexions - woo ! Voici le code
pour obtenir la valeur de la boussole

N'oubliez pas d'utiliser la valeur de déclinaison spécifique à votre


emplacement, sinon vos résultats pourraient être inexacts.

#include "Fil.h"

#include "I2Cdev.h"
#include "MPU6050.h"
#include "HMC5883L.h"

carte mère MPU6050 ;


Chargeur HMC5883L ;

int16_t mx, ma, mz ;

// Trouvez la déclinaison d'où vous êtes depuis http://www.magnetic-declination.com

// -14° 59'
déclinaison du flotteur = (-14,0 - (59,0 / 60,0)) * (PI/180) ;

void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("Initialisation des périphériques I2C...");
mpu.setI2CMasterModeEnabled(false);
mpu.setI2CBypassEnabled(true) ;
mpu.setSleepEnabled(false);
mpu.initialize();
mag.initialize();
Serial.println(mpu.testConnection() ? "Connexion MPU6050 réussie" : "Échec de la
connexion MPU6050");
Serial.println(mag.testConnection() ? "Connexion HMC5883L réussie" : "Échec de la
connexion HMC5883L");

boucle vide() {
mag.getHeading(&mx, &my, &mz);
printResults();
retard(200);
}
annuler printResults(){
en-tête flottant = atan2(my, mx);
titre += déclinaison ;
si (cap < 0) cap += 2 * PI ;
si (cap > 2 * PI) cap -= 2 * PI ;
cap *= 180/M_PI;

Serial.print("Entête °:");
Serial.println(en-tête);
}

Étape 3 : GY-86 : Baromètre et température

Voici comment nous avons obtenu les valeurs du baromètre MS5611.

#include "Fil.h"

#include "I2Cdev.h"
#include "MPU6050.h"
#inclure <ms5611.h>

carte mère MPU6050 ;


bar MS5611 ;

double température ;
longue pression;
double altitude;

void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("Initialisation des périphériques I2C...");
mpu.setI2CMasterModeEnabled(false);
mpu.setI2CBypassEnabled(true) ;
mpu.setSleepEnabled(false);
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connexion MPU6050 réussie" : "Échec de la
connexion MPU6050");
tandis que (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
Serial.println("Échec de la connexion MS5611, vérifiez le câblage !");
retard (500);
}
}

boucle vide() {
temp = baro.readTemperature(true);
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
printResults();
retard(200);
}

annuler printResults(){
Serial.print("Pression hPa : "); Serial.print(pression);
Serial.print(" Altitude m : "); Serial.print(altitude);
flotteur tempC = temp / 340,00 + 36,53 ;
Serial.print(" Temp °C : "); Serial.println(tempC);
}

Étape 4 : Hauteur de vague brute

Une fois tous ces capteurs configurés, vous pouvez les utiliser pour
commencer à mesurer les propriétés des vagues.

À partir de la hauteur des vagues... l'altitude de la bouée peut être


calculée à l'aide de la valeur de la pression atmosphérique. Nous
pouvons utiliser l'altitude relative de la bouée sur une période de
temps pour calculer la hauteur des vagues comme ceci :

#include "Fil.h"
#include "I2Cdev.h"
#include "MPU6050.h" // ^
#include <ms5611.h> //

carte mère MPU6050 ;


bar MS5611 ;

longue pression;
double altitude, min_height, max_height, wave_height ;

void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("Initialisation des périphériques I2C...");
mpu.setI2CMasterModeEnabled(false);
mpu.setI2CBypassEnabled(true) ;
mpu.setSleepEnabled(false);
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connexion MPU6050 réussie" : "Échec de la
connexion MPU6050");
tandis que (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
Serial.println("Échec de la connexion MS5611, vérifiez le câblage !");
retard (500);
}
}

boucle vide() {
start_time long non signé = millis();
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
hauteur_max = altitude ;
hauteur_min = altitude ;

// pendant 15 secondes
while(millis() - start_time < 15000){
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
si (altitude < hauteur_min) hauteur_min = altitude ;
si (altitude > hauteur_max) hauteur_max = altitude ;
}
hauteur_onde = (hauteur_max - hauteur_min)/2.0 ;
Serial.print("Hauteur d'onde m : ");
Serial.println(wave_height);
}

Étape 5 : Période de vague de brut

La prochaine chose est la période des vagues. Nous avons utilisé la


théorie des ondes aérées - une belle théorie des ondes de base qui
dit que les ondes de surface de l'eau peuvent être décrites comme
des ondes sinusoïdales. C'est génial à utiliser car cela facilite les
calculs, mais c'est bien sûr une simplification et comporte certaines
mises en garde, notamment qu'il est inexact dans les eaux peu
profondes où les vagues se transforment et se brisent. En utilisant
cette théorie, nous devrions être en mesure d'obtenir une valeur de la
période des vagues en utilisant le point médian entre nos altitudes
relatives maximale et minimale et en trouvant à quelle fréquence la
bouée traverse ce point.

#include "Fil.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#inclure <ms5611.h>

carte mère MPU6050 ;


bar MS5611 ;
longue pression;
double altitude, min_height, max_height, mid_point, smudge_factor ;
octet échappé, commencé ;
period_start long non signé, period_end ;
float avg_period = -1 ;

void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("Initialisation des périphériques I2C...");
mpu.setI2CMasterModeEnabled(false);
mpu.setI2CBypassEnabled(true) ;
mpu.setSleepEnabled(false);
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connexion MPU6050 réussie" : "Échec de la
connexion MPU6050");
tandis que (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
Serial.println("Échec de la connexion MS5611, vérifiez le câblage !");
retard (500);
}
}

boucle vide() {
start_time long non signé = millis();
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
hauteur_max = altitude ;
hauteur_min = altitude ;

// pendant 15 secondes
while(millis() - start_time < 15000){
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
si (altitude < hauteur_min) hauteur_min = altitude ;
si (altitude > hauteur_max) hauteur_max = altitude ;
}
point_milieu = (hauteur_max + hauteur_min)/2.0 ;
smudge_factor = (max_height - mid_point)*0.15 ;
Serial.print("Mid Point m : "); Serial.print(mid_point);

heure_début = millis();
// pendant 15 secondes
while(millis() - start_time < 15000){
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
// si dans une plage de 30 % de la hauteur des vagues à partir du point médian
// démarre le minuteur sinon l'arrête
if (altitude < mid_point + smudge_factor && altitude > mid_point - smudge_factor)
{
si ( ! commencé){
period_start = millis();
commencé = vrai ;
}
autre{
si (échappé){
// s'il a commencé et s'est échappé et revient maintenant
period_end = millis();
commencé = faux ;
échappé = faux ;
// si la variable a déjà été affectée
// utilise sa valeur précédente et sa nouvelle valeur pour calculer avg
if(avg_period != -1){
avg_period = (avg_period + (period_end-period_start)*2) / 2.0 ;
}
// l'assigne
autre{
avg_period = (period_end-period_start)*2 ;
}
}
}
}
autre{
échappé = vrai ;
}
}
Serial.print(" Période s : "); Serial.println(avg_period/1000);
}

Étape 6 : Direction des vagues (AIDEZ-NOUS)

Nous n'avons jamais réussi à mesurer la direction des vagues.

Cependant, les capteurs à bord de la bouée devraient pouvoir le


faire. Vous pouvez mesurer les accélérations dynamiques avec
l'accéléromètre GY-86 en soustrayant les effets de la force
gravitationnelle. Vous pouvez également obtenir la direction de cette
accélération. L'utilisation de la direction de l'accélération de la bouée
avec la valeur de la boussole pour une position donnée devrait vous
permettre de déterminer la direction des vagues. Nous l'avons essayé
dans le code ci-dessous.

---- Si quelqu'un pouvait nous aider, ce serait génial <3 ----

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "HMC5883L.h"
#include "Fil.h"
carte mère MPU6050 ;
Chargeur HMC5883L ;

int16_t mx, ma, mz ;

#define INTERRUPT_PIN 2 // utilise la broche 2 sur Arduino Uno et la plupart des


cartes
déclinaison du flotteur = -14,0 - (59,0 / 60,0) ;

// Variables de contrôle/état MPU


booléen dmpReady = faux ; // définit vrai si l'initialisation DMP a réussi
uint8_t mpuIntStatus ; // contient l'octet d'état d'interruption réel du MPU
uint8_t devStatus ; // renvoie l'état après chaque opération sur l'appareil (0 =
succès, !0 = erreur)
uint16_t taillepaquet ; // taille de paquet DMP attendue (la valeur par défaut est de
42 octets)
uint16_t fifoCount ; // compte de tous les octets actuellement dans FIFO
uint8_t fifoBuffer[64] ; // Tampon de stockage FIFO

// variables d'orientation/mouvement
Quaternion q ; // [w, x, y, z] conteneur de quaternions
VectorInt16 aa ; // [x, y, z] mesures du capteur d'accélération
VectorInt16 aaReal ; // [x, y, z] mesures du capteur d'accélération sans gravité
VectorInt16 aaMonde ; // [x, y, z] mesures du capteur d'accélération de trame
mondiale
Gravité VectorFloat ; // [x, y, z] vecteur de gravité
volatile bool mpuInterrupt = faux ; // indique si la broche d'interruption du MPU est
passée à l'état haut
void dmpDataReady() {
mpuInterrupt = vrai ;
}

void setup() {
Serial.begin(115200);
Wire.begin();
Wire.setClock(400000);

mpu.setI2CMasterModeEnabled(false);
mpu.setI2CBypassEnabled(true) ;
mpu.setSleepEnabled(false);
mpu.initialize();
mag.initialize();
// initialise l'appareil
Serial.println(F("Initialisation des périphériques I2C..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
Serial.println(mpu.testConnection() ? F("Connexion MPU6050 réussie") : F("Échec
de la connexion MPU6050"));
devStatus = mpu.dmpInitialize();
// fournissez vos propres décalages gyroscopiques ici, mis à l'échelle pour une
sensibilité minimale
mpu.setXGyroOffset(112);
mpu.setYGyroOffset(5);
mpu.setZGyroOffset(-15);
mpu.setZAccelOffset(1487);
si (devStatus == 0) {
mpu.setDMPEnabled(true);
Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
dmpReady = vrai ;
packetSize = mpu.dmpGetFIFOPacketSize();
}

boucle vide() {
si (!dmpReady) retour ;
tandis que (!mpuInterrupt && fifoCount < taillepaquet) {
si (mpuInterrupt && fifoCount < taillepaquet) {
fifoCount = mpu.getFIFOCount();
}
}
mpuInterrupt = faux ;
mpuIntStatus = mpu.getIntStatus();
fifoCount = mpu.getFIFOCount();
si ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024)
{
mpu.resetFIFO();
fifoCount = mpu.getFIFOCount();
}
sinon si (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT)) {
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
mpu.getFIFOBytes(fifoBuffer, taillepaquet);
fifoCount -= taillepaquet ;

// OUTPUT_READABLE_WORLDACCEL
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravité, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
Serial.print("Accélération (x,y) m/s/s : ");
Serial.print(aaWorld.x);
Serial.print(" ");
Serial.println(aaWorld.y);

// Trouver l'angle d'accélération


// double angle_of_acc = atan2(aaWorld.y, aaWorld.x);
// angle_of_acc *= 180/M_PI ;

// Obtenir le cap de la boussole


// mag.getHeading(&mx, &my, &mz);
// en-tête flottant = atan2(my, mx);
// si (en-tête < 0) en-tête += 2 * PI ;
// si (en-tête > 2 * PI) en-tête -= 2 * PI ;
// cap *= 180/M_PI;
// titre += déclinaison ;

// Décalage de l'angle d'accélération par l'angle de cap


// direction_onde = angle_off_acc + cap

}
}
Étape 7 : Énergie brute des vagues

Une définition de l'énergie des vagues est définie par :

P = 0,5 hauteur ** 2 * période


[ https://en.wikipedia.org/wiki/Wave_power ].

En utilisant nos valeurs pour la période et la hauteur des vagues, nous


pouvons calculer l'énergie des vagues comme ceci :

#include "Fil.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#inclure <ms5611.h>

carte mère MPU6050 ;


bar MS5611 ;
longue pression;
double altitude, min_height, max_height, wave_height, mid_point, smudge_factor,
wave_power ;
octet échappé, commencé ;
period_start long non signé, period_end ;
float avg_period = -1 ;

void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("Initialisation des périphériques I2C...");
mpu.setI2CMasterModeEnabled(false);
mpu.setI2CBypassEnabled(true) ;
mpu.setSleepEnabled(false);
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connexion MPU6050 réussie" : "Échec de la
connexion MPU6050");
tandis que (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
Serial.println("Échec de la connexion MS5611, vérifiez le câblage !");
retard (500);
}
}

boucle vide() {
start_time long non signé = millis();
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
hauteur_max = altitude ;
hauteur_min = altitude ;

// pendant 15 secondes
while(millis() - start_time < 15000){
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
si (altitude < hauteur_min) hauteur_min = altitude ;
si (altitude > hauteur_max) hauteur_max = altitude ;
}
point_milieu = (hauteur_max + hauteur_min)/2.0 ;
wave_height = (max_height - mid_point) / 2.0 ;
smudge_factor = wave_height * 0,15 ;
Serial.print("Hauteur d'onde m : "); Serial.print(wave_height);

heure_début = millis();
// pendant 15 secondes
while(millis() - start_time < 15000){
pression = baro.readPressure(true);
altitude = baro.getAltitude(pression);
// si dans une plage de 30 % de la hauteur des vagues à partir du point médian
// démarre le minuteur sinon l'arrête
if (altitude < mid_point + smudge_factor && altitude > mid_point - smudge_factor)
{
si ( ! commencé){
period_start = millis();
commencé = vrai ;
}
autre{
si (échappé){
// s'il a commencé et s'est échappé et revient maintenant
period_end = millis();
commencé = faux ;
échappé = faux ;
// si la variable a déjà été affectée
// utilise sa valeur précédente et sa nouvelle valeur pour calculer avg
if(avg_period != -1){
avg_period = (avg_period + (period_end-period_start)*2) / 2.0 ;
}
// l'assigne
autre{
avg_period = (period_end-period_start)*2 ;
}

}
}
}
autre{
échappé = vrai ;
}
}
Serial.print(" Période s : "); Serial.print(avg_period/1000);
wave_power = (0.5 * wave_height * wave_height * avg_period / 1000);
Serial.print(" Puissance des vagues kW/m : "); Serial.println(wave_power);
}
Étape 8 : Température de l'eau

Enfin, nous voulons pouvoir mesurer la température de l'eau. Le


capteur de température de l'eau DS18B20 dépassera du bas de la
bouée dans la mer et l'Arduino communiquera avec lui à l'aide d'un fil.

La seule modification que vous devez apporter est d'ajouter une


résistance de rappel sur le fil de signal, puis nous pouvons en parler
comme ceci :

#include <unfil.h>
#include <dallastemperature.h>

Un fil un fil(6);
Capteurs de température Dallas(&oneWire);
float water_temperature ;

void setup() {
Serial.begin(115200);
capteurs.begin();
}

boucle vide() {
capteurs.requestTemperatures();
température_eau = capteurs.getTempCByIndex(0);
Serial.print("Température de l'eau C ");
Serial.println(water_temperature);
retard(200);
}

Étape 9 : Merci

Merci d'avoir lu ce tutoriel, cela a été la première étape dans la


construction de notre bouée intelligente. Découvrez bientôt notre
prochain tutoriel pour voir comment nous envoyons et stockons des
données et utilisons le GPS.
Smart Buoy [GPS, radio (NRF24) et un module
de carte SD]
Cette série de bouées intelligentes illustre notre tentative (ambitieuse)
de construire une bouée scientifique capable de prendre des mesures
significatives sur la mer à l'aide de produits prêts à l'emploi. Il s'agit du
didacticiel deux sur quatre. Assurez-vous d'être à jour et si vous avez
besoin d'une introduction rapide au projet, consultez notre résumé .

Partie 1 : Réalisation de mesures de vagues et de températures

Dans ce didacticiel, nous vous montrons comment obtenir des


données GPS, les stocker sur une carte SD et les envoyer quelque
part à l'aide de la radio.

Nous avons fait cela afin de pouvoir suivre l'emplacement de notre


bouée maritime. La radio signifie que nous pouvons le regarder à
distance et la carte SD signifie qu'au cas où quelque chose se casse
et qu'il se promène, nous pouvons télécharger les données qu'il a
collectées lors de son excursion imprévue - si jamais nous sommes
en mesure de le récupérer !

Fournitures

Module GPS - Amazon

Module carte SD - Amazon

Carte SD - Amazon

2 modules radio (NRF24L01+) - Amazon

2 X Arduino - Amazone
Étape 1 : Obtenir des données GPS

La bouée intelligente effectue des mesures de capteur lorsqu'elle se


trouve dans la mer, y compris la localisation GPS et la date et
l'heure. Jetez un oeil au schéma qui montre comment nous avons mis
en place le circuit. Le module GPS communique via une connexion
série, nous utilisons donc la bibliothèque série du logiciel Arduino ainsi
que la minuscule bibliothèque GPS pour communiquer avec lui. Ces
bibliothèques rendent tout super simple. Passons en revue le code…

#include <TinyGPS++.h>
#include <SoftwareSerial.h>

// The TinyGPS++ object


TinyGPSPlus gps;

// The serial connection to the GPS device


SoftwareSerial ss(4, 3);

struct dataStruct{
double latitude;
double longitude;
unsigned long date;
unsigned long time;
}gpsData;

void setup(){
Serial.begin(115200);
ss.begin(9600);
}

void loop(){
while (ss.available() > 0){
if (gps.encode(ss.read())){
getInfo();
printResults();
}
}
}

void getInfo(){
if (gps.location.isValid()){
gpsData.latitude = gps.location.lat();
gpsData.longitude = gps.location.lng();
}
else{
Serial.println("Invalid location");
}
if (gps.date.isValid()){
gpsData.date = gps.date.value();
}
else{
Serial.println("Invalid date");
}
if (gps.time.isValid()){
gpsData.time = gps.time.value();
}
else{
Serial.println("Invalid time");
}
}

void printResults(){
Serial.print("Location: ");
Serial.print(gpsData.latitude, 6); Serial.print(", ");
Serial.print(gpsData.longitude, 6);
Serial.print(" Date: ");
Serial.print(gpsData.date);
Serial.print(" Time: ");
Serial.print(gpsData.time);
Serial.println();
}

(Check out the video for this code at https://youtu.be/xz1ix76U28E)


Étape 2 : Envoi de données GPS par radio
Supposons que la bouée est en mer en train de prendre des mesures,
mais nous voulons voir les données sans nous mouiller les pieds ni
ramener la bouée à terre. Pour obtenir les mesures à distance, nous
utilisons un module radio connecté à un Arduino des deux côtés de la
communication. À l'avenir, nous remplacerons l'Arduino côté
récepteur par un raspberry pi. La radio fonctionne de la même
manière avec ces deux interfaces, il est donc assez simple de les
échanger.

Le module radio communique en utilisant SPI, ce qui nécessite un peu


plus de connexions que I2C mais reste très facile à utiliser grâce à la
bibliothèque NRF24. En utilisant le module GPS pour les mesures du
capteur, nous transmettons ses données d'un Arduino à l'autre. Nous
allons connecter le module GPS et radio à l'Arduino et de l'autre côté
un Arduino avec le module radio - regardez le schéma.

Émetteur
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>

TinyGPSPlus gps;
SoftwareSerial ss(4, 3);
RF24 radio(8, 7); // CE, CSN

struct dataStruct{
double latitude;
double longitude;
unsigned long date;
unsigned long time;
}gpsData;
void setup() {
Serial.begin(115200);
ss.begin(9600);

Serial.println("Setting up radio");
// Setup transmitter radio
radio.begin();
radio.openWritingPipe(0xF0F0F0F0E1LL);
radio.setChannel(0x76);
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_250KBPS);
radio.stopListening();
radio.enableDynamicPayloads();
radio.powerUp();
Serial.println("Starting to send");
}

void loop() {
while (ss.available() > 0){
if (gps.encode(ss.read())){
getInfo();
radio.write(&gpsData, sizeof(gpsData));
}
}
}

void getInfo(){
if (gps.location.isValid()){
gpsData.longitude = gps.location.lng();
gpsData.latitude = gps.location.lat();
}
else{
gpsData.longitude = 0.0;
gpsData.latitude = 0.0;
}
if (gps.date.isValid()){
gpsData.date = gps.date.value();
}
else{
gpsData.date = 0;
}
if (gps.time.isValid()){
gpsData.time = gps.time.value();
}
else{
gpsData.time = 0;
}
}

DESTINATAIRE
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(8, 7); // CE, CSN

struct dataStruct{
double latitude;
double longitude;
unsigned long date;
unsigned long time;
}gpsData;
void setup() {
Serial.begin(115200);
// Setup receiver radio
radio.begin();
radio.openReadingPipe(1, 0xF0F0F0F0E1LL);
radio.setChannel(0x76);
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_250KBPS);
radio.startListening();
radio.enableDynamicPayloads();
radio.powerUp();
}

void loop() {
if (radio.available()) {
radio.read(&gpsData, sizeof(gpsData));
Serial.print("Location: ");
Serial.print(gpsData.latitude, 6);
Serial.print(", ");
Serial.print(gpsData.longitude, 6);
Serial.print(" Date: ");
Serial.print(gpsData.date);
Serial.print(" Time: ");
Serial.print(gpsData.time);
Serial.println();}
}

(Check out the video for this code at https://youtu.be/xz1ix76U28E)


Étape 3 : Stocker des données à l'aide d'un module de SD
carte

Le module radio est assez fiable, mais parfois vous avez besoin d'un
plan d'urgence en cas de coupure de courant côté récepteur ou si la
radio se déplace hors de portée. Notre plan d'urgence est un module
de carte SD qui nous permet de stocker les données que nous
collectons. La quantité de données collectées n'est pas si grande,
donc même une petite carte SD pourra facilement stocker la valeur
d'une journée de données.
#include <SPI.h>
#include <SD.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>

GPS TinyGPS Plus ;


LogicielSerial ss(4, 3);

struct dataStruct{
latitude double ;
longitude double;
date longue non signée ;
longtemps non signé;
}DonnéesGps ;

void setup() {
Serial.begin(115200);
ss.begin(9600);

si (!SD.begin(5)) {
Serial.println("La carte a échoué ou n'est pas présente");
retour;
}
Serial.println("carte initialisée.");

Fichier dataFile = SD.open("gps_data.csv", FILE_WRITE);


si (fichierdonnées) {
dataFile.println("Latitude, Longitude, Date, Heure");
dataFile.close();
}
autre{
Serial.println("Non, je ne peux pas ouvrir le fichier");
}
}

boucle vide() {
tandis que (ss.disponible() > 0){
si (gps.encode(ss.read())){
getInfo();
printResults();
saveInfo();
}
}
}

annuler getInfo(){
si (gps.location.isValid()){
gpsData.latitude = gps.location.lat();
gpsData.longitude = gps.location.lng();
}
autre{
Serial.println("Emplacement invalide");
}
si (gps.date.isValid()){
gpsData.date = gps.date.value();
}
autre{
Serial.println("Date invalide");
}
si (gps.time.isValid()){
gpsData.time = gps.time.value();
}
autre{
Serial.println("Heure invalide");
}
}

annuler printResults(){
Serial.print("Emplacement : ");
Serial.print(gpsData.latitude, 6); Serial.print(", ");
Serial.print(gpsData.longitude, 6);
Serial.print(" Date : ");
Serial.print(gpsData.date);
Serial.print(" Heure : ");
Serial.print(gpsData.time);
Serial.println();
}

annuler saveInfo(){
Fichier dataFile = SD.open("gps_data.csv", FILE_WRITE);
si (fichierdonnées) {
dataFile.print(gpsData.latitude);
dataFile.print(", ");
dataFile.print(gpsData.longitude);
dataFile.print(", ");
dataFile.print(gpsData.date);
dataFile.print(", ");
dataFile.println(gpsData.time);
dataFile.close();
}
autre{
Serial.println("non pas de fichier de données");
}
}

(Nous parlons de ce code dans la


vidéo https://youtu.be/xz1ix76U28E )
Étape 4 : Envoi et stockage des données GPS
Smart Buoy - Programmation de l'alimentation
du système
Et donc au prochain défi - comment contrôler la puissance de la
bouée intelligente !

La bouée n'a pas besoin de faire constamment des mesures -


quelques-unes à intervalles réguliers sont plus que suffisantes et
nettement meilleures que la couverture actuelle. Cela facilite
légèrement son alimentation, car il peut être éteint de temps en
temps. Une autre chose qui simplifie le processus d'alimentation est
que la bouée et ses capteurs sont assez petits - cela signifie que nous
pouvons utiliser de petits panneaux solaires à faible
puissance. Cependant, avoir une faible puissance signifie que nous
devons prendre des mesures pour la gérer plus efficacement afin de
garantir que la bouée peut produire des mesures régulières, sans
laisser de grandes parties de la journée sans mesures. Nous avons
décidé que nous voulions programmer l'alimentation de la bouée en
fonction de la quantité d'énergie qu'il y a dans la batterie.

Fournitures

Pour ce build, vous aurez besoin de :

Batterie 18650 - https://amzn.to/2ZOMuCq

 Buck booster - https://amzn.to/2ZS1a3q


 Contrôleur de charge - https://amzn.to/2ZS1a3q
 Panneau solaire - https://amzn.to/2ZS1a3q
 Diodes de blocage - https://amzn.to/2ZS1a3q
 Module de surveillance de l'alimentation - https://amzn.to/2ZS1a3q
 Horloge en temps réel - https://amzn.to/2ZS1a3q
 Arduino - https://amzn.to/2ZS1a3q
 Transistor à canal P - https://amzn.to/2ZS1a3q

La bouée intelligente est alimentée par une batterie 18650 qui est
chargée par quatre panneaux solaires de 5 V, 60 mA en
parallèle. Dans notre conception, les quatre panneaux solaires se
trouvent autour du sommet de la bouée, capturant un maximum de
lumière solaire.

Nous avons mis des diodes de blocage pour empêcher le courant


inverse dans les panneaux.
Nous avons utilisé un contrôleur de charge pour contrôler la sortie de
la batterie et la charge des panneaux solaires. La sortie du contrôleur
de charge n'est pas assez élevée pour alimenter le système de
manière stable, nous utilisons donc un booster buck pour augmenter
la tension à environ 6V.

En tant qu'appareil uniquement alimenté à l'énergie solaire, il est peu


probable que la bouée passe la nuit avec suffisamment de puissance
pour continuer à prendre des mesures. Pour s'assurer qu'il a toujours
assez de puissance pour faire fonctionner les capteurs, nous avons
utilisé un module d'horloge en temps réel pour allumer et éteindre le
système. Ce module fonctionne à l'aide de la batterie mais utilise une
très faible quantité de courant afin qu'il puisse fonctionner pendant
des années.

Nous avons programmé le module d'horloge en temps réel pour avoir


une alarme, réglée en fonction de la puissance de la batterie. Cette
valeur est déduite sur la base de la tension de la batterie qui est
mesurée à l'aide d'un module de surveillance de
l'alimentation. Lorsque l'alarme est déclenchée, elle change la broche
d'alarme de haut en bas. Nous pouvons l'utiliser pour allumer un
transistor, qui permet d'alimenter l'arduino. Le système effectue ses
mesures et s'éteint en effaçant l'alarme, en remettant la broche sur
haut, ce qui éteint le transistor.
Étape 2 : contrôle de l'alimentation à l'aide des alarmes RTC

Voici un exemple de la façon de programmer une alarme pour


contrôler l'alimentation de l'Arduino. Dans cet exemple, nous allons
utiliser un Arduino pour allumer une LED pendant trois secondes et
régler une alarme pendant 15 secondes, puis s'éteindre. Une fois les
15 secondes écoulées, l'alarme se déclenchera, la LED se rallumera
et le cycle se répétera.

(Nous expliquons le code dans cette vidéo


- https://youtu.be/5guIB8_YIGQ )
<p>#include <DS3232RTC.h></p><p>#include <Adafruit_INA219.h></p><p>
#include <Wire.h></p><p>int led = LED_BUILTIN ; </p><p>// INA219 - Moniteur de
puissance
Adafruit_INA219 ina219 ;</p><p>
void setup() {
Wire.begin();
pinMode(led, SORTIE);

// initialise INA219 - Power Monitor


ina219.begin();
ina219.setCalibration_32V_1A();
}</p><p>boucle vide() {
digitalWrite (led, HIGH);
retard (3000);
reset_alarm();
}</p><p>annuler reset_alarm(){
RTC.alarmInterrupt(ALARM_1, vrai);
RTC.squareWave(SQWAVE_NONE);
setHeure(0, 0, 0, 0, 0, 1970);
RTC.set(maintenant());
int wait_time = get_wait_time_from_voltage();
// définir une nouvelle alarme
RTC.setAlarm(ALM1_MATCH_MINUTES, 0, temps d'attente, 0, 0);
// effacer l'ancien drapeau d'alarme - éteindre le système
RTC.alarme(ALARM_1);
}</p><p>int get_wait_time_from_voltage(){
float shuntvoltage = ina219.getShuntVoltage_mV();
float busvoltage = ina219.getBusVoltage_V();
float loadvoltage = busvoltage + (shuntvoltage / 1000);</p><p> // Samsung 18650 %
de capacité à une tension donnée
// batt_voltages 0.0, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.5
// batt_percentages 0, 0, 9, 22, 52, 64, 75, 84, 93, 100, 100
temps d'attente entier ;
si (tension de charge < 3,6) temps d'attente = 55 ;
sinon si (loadvoltage < 3.8) wait_time = 25 ;
sinon si (loadvoltage < 4.0) wait_time = 15 ;
sinon si (loadvoltage < 4.1) wait_time = 10 ;
sinon temps_attente = 3 ;

retourner wait_time ;
}</p>

Étape 3 : Surveillance de l'alimentation

C'est ainsi que nous avons surveillé la tension de la batterie et


l'utilisation du courant à l'aide du moniteur de courant continu
INA219. Ce module communique en utilisant I^2C - reportez-vous au
schéma pour les connexions que vous devez effectuer. Une belle
bibliothèque pour parler au module existe déjà, ce qui rend ce
processus vraiment facile.
(Nous expliquons le code dans cette vidéo
- https://youtu.be/5guIB8_YIGQ )

<p>#include <Wire.h></p><p>#include <Adafruit_INA219.h></p><p>// INA219 - Moniteur de


puissance
Adafruit_INA219 ina219 ;
flotteur tension shunt = 0 ;
flotteur tension de bus = 0 ;
courant flottant_mA = 0 ;
tension de charge flottante = 0 ;
float power_mW = 0 ;</p><p>annuler setup() {
Serial.begin(115200);
tandis que (!Série) {
retard(1);
}</p><p> // initialise INA219 - Power Monitor
ina219.begin();
ina219.setCalibration_32V_1A();

}</p><p>boucle vide() {
shuntvoltage = ina219.getShuntVoltage_mV();
tension de bus = ina219.getBusVoltage_V();
courant_mA = ina219.getCurrent_mA();
puissance_mW = ina219.getPower_mW();
tension de charge = tension de bus + (tension shunt / 1000);
Serial.print("Tension de charge : "); Serial.print (tension de charge);
Serial.println(" V");
Serial.print("Actuel : "); Serial.print(current_mA); Serial.println(" mA");
Serial.print("Alimentation : "); Série.print(power_mW); Serial.println(" mW");
Serial.println();
retard(1000);
}</p>
Étape 4 : Utilisation du moniteur d'alimentation pour définir la prochaine
alarme RTC

Enfin, c'est ainsi que nous avons utilisé la tension pour prédire la
durée optimale entre les alarmes. La méthode est un peu grossière -
si quelqu'un a de meilleures idées, veuillez nous en informer dans les
commentaires ci-dessous.
(Nous expliquons le code dans cette vidéo
- https://youtu.be/5guIB8_YIGQ )

<p>#include <DS3232RTC.h></p><p>#include <Adafruit_INA219.h></p><p>


#include <Wire.h></p><p>int led = LED_BUILTIN ; </p><p>// INA219 - Moniteur de
puissance
Adafruit_INA219 ina219 ;</p><p>
void setup() {
Wire.begin();
pinMode(led, SORTIE);

// initialise INA219 - Power Monitor


ina219.begin();
ina219.setCalibration_32V_1A();
}</p><p>boucle vide() {
digitalWrite (led, HIGH);
retard (3000);
reset_alarm();
}</p><p>annuler reset_alarm(){
RTC.alarmInterrupt(ALARM_1, vrai);
RTC.squareWave(SQWAVE_NONE);
setHeure(0, 0, 0, 0, 0, 1970);
RTC.set(maintenant());
int wait_time = get_wait_time_from_voltage();
// définir une nouvelle alarme
RTC.setAlarm(ALM1_MATCH_MINUTES, 0, temps d'attente, 0, 0);
// effacer l'ancien drapeau d'alarme - éteindre le système
RTC.alarme(ALARM_1);
}</p><p>int get_wait_time_from_voltage(){
float shuntvoltage = ina219.getShuntVoltage_mV();
float busvoltage = ina219.getBusVoltage_V();
float loadvoltage = busvoltage + (shuntvoltage / 1000);</p><p> // Samsung 18650 %
de capacité à une tension donnée
// batt_voltages 0.0, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.5
// batt_percentages 0, 0, 9, 22, 52, 64, 75, 84, 93, 100, 100
temps d'attente entier ;
si (tension de charge < 3,6) temps d'attente = 55 ;
sinon si (loadvoltage < 3.8) wait_time = 25 ;
sinon si (loadvoltage < 4.0) wait_time = 15 ;
sinon si (loadvoltage < 4.1) wait_time = 10 ;
sinon temps_attente = 3 ;

retourner wait_time ;
}</p>

Vous aimerez peut-être aussi