/* Ejercicio entregable 100
Deben de utilizar este archivo los alumnos con c>=5, d<5, u<5
siendo c,d,u las tres últimas cifras del DNI 22000cdu-W
Anemómetro con encoder y motor paso a paso con encoder
Para cambiar la velocidad del viento haz click sobre el anemometro durante la simulacion
rellenar vuestro nombre y DNI
NOMBRE ALUMNO: Joan Agost Bellés
DNI: 20922843L
ENLACE WOKWI: https://wokwi.com/projects/417719262986595329
*/
#include <WiFi.h>
#include <PubSubClient.h>
#include <Stepper.h>
// Pines del motor paso a paso
Stepper myStepper(200, 14, 27, 26, 25);
// Pines del encoder absoluto
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_BIT3 4
#define ENCODER_BIT2 5
#define ENCODER_BIT1 6
#define ENCODER_BIT0 7
#define ANEMOMETRO_PIN 17
int lastClk = HIGH;
volatile unsigned long numeroPulsos = 0;
unsigned long tiempoAnterior = 0;
float frecuencia = 0.0;
float velocidadViento = 0.0;
int orientacionPalas = 10;
float posicionesAnteriores[5] = {0};
int indiceVectorPosicion = 0;
unsigned long contadorPulsos = 0; // Contar los pulsos en 1 minuto
int contadorSegundos = 0;
float velocidadMediaMinuto = 0.0;
float acumuladorVelocidad = 0.0; // Sumar velocidades durante una hora
int contadorSegundosHora = 0; // Contar segundos la hora
float velocidadMediaHora = 0.0;
// MQTT
const char* mqttServer = "instrumentacion-uji.dynv6.net";
const int mqttPort = 1883;
const char* topic_velocidad = "anemometro_843/velocidad";
const char* topic_historico = "anemometro_843/historico";
const char* client_name = "ESP_32_843";
WiFiClient espClient;
PubSubClient client(espClient);
// Función para conectar WiFi
void conectarWiFi() {
WiFi.begin("SSID", "PASSWORD"); // Introducir los datos de red
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Conectando a WiFi...");
}
Serial.println("Conectado a la WiFi");
}
// Función para conectar MQTT
void conectarMQTT() {
client.setServer(mqttServer, mqttPort);
while (!client.connected()) {
Serial.println("Conectando a MQTT...");
if (client.connect(client_name)) {
Serial.println("Conectado");
} else {
Serial.print("Error al conectar ");
Serial.println(client.state());
delay(2000);
}
}
}
// Publicar datos en MQTT
void publicarDatos(float velocidadMediaMinuto) {
// Publicar velocidad media
char velocidadStr[10]; // Almacenar la velocidad
snprintf(velocidadStr, sizeof(velocidadStr), "%.2f", velocidadMediaMinuto);
client.publish("anemometro_843/velocidad", (uint8_t*)velocidadStr, strlen(velocidadStr), true);
Serial.println(velocidadStr);
// Construir el histórico en el formato solicitado
char historicoStr[50]; // Cadena para almacenar el histórico
snprintf(historicoStr, sizeof(historicoStr), "[%.2f, %.2f, %.2f, %.2f, %.2f]",
posicionesAnteriores[0],
posicionesAnteriores[1],
posicionesAnteriores[2],
posicionesAnteriores[3],
posicionesAnteriores[4]);
client.publish("anemometro_843/historico", (uint8_t*)historicoStr, strlen(historicoStr), true);
Serial.print("Publicado en MQTT (Histórico): ");
Serial.println(historicoStr);
// Reiniciar acumuladores
acumuladorVelocidad = 0.0;
contadorSegundos = 0;
}
// Convertir de Gray a binario
int grayToBinary(int gray) {
int binario = gray;
while (gray >>= 1) {
binario ^= gray;
}
return binario;
}
// Contar los pulsos del anemómetro
void contarPulsos() {
numeroPulsos++;
}
void setup() {
myStepper.setSpeed(10);
Serial.begin(115200);
// Pines del encoder
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
pinMode(ENCODER_BIT3, INPUT);
pinMode(ENCODER_BIT2, INPUT);
pinMode(ENCODER_BIT1, INPUT);
pinMode(ENCODER_BIT0, INPUT);
pinMode(ANEMOMETRO_PIN, INPUT_PULLUP); //Pin del anemómetro como input
attachInterrupt(digitalPinToInterrupt(ANEMOMETRO_PIN), contarPulsos, FALLING); //Se ejecuta la interrupción contarPulsos cada bajada de flanco
//Colocamos las palas en la posición de 10 grados (0 km/h)
myStepper.step((orientacionPalas / 180.0) * 200);
conectarWiFi();
conectarMQTT();
}
void loop() {
unsigned long tiempoActual = millis();
// Calcular velocidad del viento cada segundo
if (tiempoActual - tiempoAnterior >= 1000) {
velocidadViento = numeroPulsos * 2.0; // Pulsos a velocidad del viento (km/h)
numeroPulsos = 0;
tiempoAnterior = tiempoActual;
// Actualizar la velocidad a los valores de la hora
acumuladorVelocidad += velocidadViento;
contadorSegundosHora++;
Serial.print("Velocidad del viento (km/h): ");
Serial.println(velocidadViento);
}
// Limitar la velocidad del viento
if (velocidadViento > 100.0) {
velocidadViento = 100.0;
}
if (contadorSegundosHora >= 3600) { //Cada hora
velocidadMediaHora = acumuladorVelocidad / contadorSegundosHora;
// Guardar la velocidad media en el vector
posicionesAnteriores[indiceVectorPosicion] = velocidadMediaHora;
indiceVectorPosicion = (indiceVectorPosicion + 1) % 5;
Serial.print("Velocidad media de la hora (km/h): ");
Serial.println(velocidadMediaHora);
// Reiniciar valores
acumuladorVelocidad = 0.0;
contadorSegundosHora = 0;
}
//---------ENCODER--------------------
// Lectura de la posición del encoder
int newClk = digitalRead(ENCODER_CLK);
// Detectar cambio en el encoder
if (newClk != lastClk) {
lastClk = newClk;
int dtValue = digitalRead(ENCODER_DT);
// Leer posición del encoder
if (newClk == LOW) {
int gray = (digitalRead(ENCODER_BIT3) << 3) |
(digitalRead(ENCODER_BIT2) << 2) |
(digitalRead(ENCODER_BIT1) << 1) |
digitalRead(ENCODER_BIT0);
// Convertir de Gray a binario mediante una interrupoción
int binario = grayToBinary(gray);
// Pasar de binario a grados
int grados = binario * 12;
// Mostrar dirección de rotación y posición
if (dtValue == HIGH) {
Serial.println("Rotated clockwise ⏩");
} else {
Serial.println("Rotated counterclockwise ⏪");
}
Serial.print("Posición absoluta (grados): ");
Serial.println(grados);
}
}
// Calcular la velocidad del viento cada minuto
if (tiempoActual - tiempoAnterior >= 60000) { // Cada minuto
velocidadMediaMinuto = (numeroPulsos * 2.0); // Transformar pulsos a velocidad del viento
numeroPulsos = 0;
tiempoAnterior = tiempoActual;
// Almacenar los resultados calculados en el vector
posicionesAnteriores[indiceVectorPosicion] = velocidadViento;
indiceVectorPosicion = (indiceVectorPosicion + 1) % 5;
// Publicar datos en MQTT
if (!client.connected()) {
conectarMQTT();
}
publicarDatos(velocidadMediaMinuto);
}
// Calcular la orientación de las palas a partir de la velocidad del viento
float nuevaOrientacion = 10 + (velocidadViento * 80.0 / 100.0);
if (nuevaOrientacion > 90) nuevaOrientacion = 90;
if (nuevaOrientacion < 10) nuevaOrientacion = 10;
// Mover el motor paso a paso
float pasos = ((nuevaOrientacion - orientacionPalas) / 180.0) * 200.0;
if (pasos != 0) {
myStepper.step(pasos);
orientacionPalas = nuevaOrientacion;
Serial.print("Moviendo motor, pasos: ");
Serial.println(pasos);
}
delay(100); // Retraso breve para estabilizar las lecturas
}