Buenos días, estoy trabajando con un arduino MKR 1010 WiFi y tengo problemas a la hora de usarlo con batería externa Li-Po. La cuestión es que estoy mandando datos RSSi de tres nodos diferentes cada ciertos segundos y al cabo de 10 minutos deja de enviarlos, teniendo que ir a la posición donde está el arduino y pulsar el botón reset incorporado en la placa para reiniciar el sistema y que vuelva a funcionar otros 10 minutos aproximadamente. Alguno sabe a que se puede deber esto?. Adjunto el programa por si fuera un error de software aunque no lo creo.
#include <DHT.h>
#include <WiFiNINA.h>
#include <SPI.h>
#include <ThingsBoard.h>
#include <ArduinoJson.h>
#define TOKEN "L9LveISHoDQvZ"
#define THINGSBOARD_SERVER "thingsboard.cloud"
String pto_acceso_1 = "Prueba_Geolocalizamiento_S1";
String pto_acceso_2 = "Prueba_Geolocalizamiento_S2";
String pto_acceso_3 = "Prueba_Geolocalizamiento_S3";
int rssi_1 = 0;
int rssi_2 = 0;
int rssi_3 = 0;
float r1, r2, r3 = 0;
int c = 4;
int a = 4;
int b = 4;
// DHT
//Credenciales para conexion WiFi
const char* ssid = "xxxxx";
const char* password = "124574";
// Inicializamos el cliente y el objeto
WiFiClient mkr1010Client;
ThingsBoard tb(mkr1010Client);
//Función para conectar arduino a la red WiFi
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while( WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void setup() {
//Inicializamos monitor serie
Serial.begin(9600);
setup_wifi();
}
void loop() {
Serial.println("Localizando redes WiFi cercanas.");
int n = WiFi.scanNetworks();// Localiza WiFis
Serial.println("Completado.");
if (n == 0)
Serial.println("No se ha encontrado ninguna red.");
else
{
Serial.print(n);
Serial.println(" Redes WiFi encontradas");
for (int i = 0; i < n; ++i)
{
// Nombre de red (SSID) y potencia (RSSI).
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(" dBm)");
Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*");
delay(10);
if (WiFi.SSID(i)== pto_acceso_1 ){
rssi_1 = WiFi.RSSI(i);
r1 = (rssi_1+38.821)/-1.9405;
Serial.print("r1: ");
Serial.println(r1);
a=1;
}
else if (WiFi.SSID(i)== pto_acceso_2 ){
rssi_2 = WiFi.RSSI(i);
Serial.print("r2: ");
r2 = (rssi_2+37.857)/-4.994;
Serial.println(r2);
b=1;
}
else if (WiFi.SSID(i)== pto_acceso_3 ){
rssi_3 = WiFi.RSSI(i);
Serial.print("r3: ");
r3 = (rssi_3+31.063)/-5.7083;
Serial.println(r3);
c = 1;
}
if (a = 0){
rssi_1 = 0;
}
if (b = 0){
rssi_2 = 0;
}
if (c = 0){
rssi_3 = 0;
}
}
}
Serial.println("");
delay(1000);
setup_wifi();
//Se comprueba si esta conectado a la red wifi
if (!tb.connected()) {
// Connect to the ThingsBoard
Serial.print("Connecting to: ");
Serial.print(THINGSBOARD_SERVER);
Serial.print(" with token ");
Serial.println(TOKEN);
if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
Serial.println("Failed to connect");
return;
}
}
Serial.println("Conectado con el broker");
delay(500);
tb.sendTelemetryInt("nodo1", rssi_1);
tb.sendTelemetryInt("nodo2", rssi_2);
tb.sendTelemetryInt("nodo3", rssi_3);
Serial.println(rssi_1);
Serial.println(rssi_2);
Serial.println(rssi_3);
c = 0;
tb.loop();
delay(1000);
}
Tu sistema esta a full consumo de energía todo el tiempo y no tienes un modo que los ponga a dormir para ahorrar energía.
Yo ahora procedería asi: agrega unos Serial.print que muestren la tensión de la bateria cada 30 segundos via monitor serie.
Como regla general es mas lógico que se hagan las lecturas, y luego se pongan a dormir, se despierten, lean de nuevo y a dormir para guardar energia.
De todos modos verifica como cae la tensión de la bateria cada 30 segundos.
Tienes muchos delays y ahora hacer eso es complicado.
Aprende a evitar delays en un buen código.
Usa millis() y crea una maquina de estados. De ese modo siempre puedes agregar todo lo que gustes sin comprometer funciones.
Ahora que lo pienso si tus tres MKR deben monitorear todo el tiempo mi idea de ponerlos a dormir tal vez no es válida. De todos modos ver como cae la tensión te dará elementos para tomar medidas.
Gracias por el tema de consumo de energía, lo miraré para mejorar el código. Sin embargo no creo que sea motivo de consumo o eso pienso, ya que no se apaga el arduino, simplemente deja de enviar datos y pulsando el boton reset vuelve a la carga.
He comprobado si conectado vía cable usb ocurre esto y no ocurre, por lo que tiene que ser algo relacionado con la batería, la batería usada es la siguiente:
Con respecto a tu último parrafo, no puedo echar a dormir el arduino mkr ya que necesito que tome medidas de manera continua. Decirte también que es un solo arduino que recibe potencia RSSi de 3 nodos o AP diferentes. El tema de los delays están puestos para no saturar el servidor con tantos datos ya que se necesita un tiempo de recepción
Tu código esta enviando en cada loop salvo los delay() a ThingsBoard.
Otra cosa que no me gusta es
setup_wifi();
para qué en cada ciclo vuelves a conectarte? No tiene sentido.
Lo que se hace es conectarse en el setup() y verificar que es difierente si no estas conectado y en ese caso intentar reconectarse.
Ahora voy a modificar tu código y poner estas sugerencias en un nuevo código. Luego edito y lo agrego o si respondes en otro post.
Bueno, me ha costado encontrar la librería thingsboard-arduino-sdk para ver como funciona ahora.
Esta es mi versión y no digo que solucione tu problema. Prueba y me cuentas.
#include <DHT.h>
#include <WiFiNINA.h>
#include <SPI.h>
#include <ThingsBoard.h>
#include <ArduinoJson.h>
#define TOKEN "L9LveISHoDQvZ"
#define THINGSBOARD_SERVER "thingsboard.cloud"
unsigned long envioDatos, buscoRedes;
String pto_acceso_1 = "Prueba_Geolocalizamiento_S1";
String pto_acceso_2 = "Prueba_Geolocalizamiento_S2";
String pto_acceso_3 = "Prueba_Geolocalizamiento_S3";
int rssi_1 = 0;
int rssi_2 = 0;
int rssi_3 = 0;
float r1, r2, r3 = 0;
int c = 4;
int a = 4;
int b = 4;
// DHT
//Credenciales para conexion WiFi
const char* ssid = "xxxxx";
const char* password = "124574";
// Inicializamos el cliente y el objeto
WiFiClient mkr1010Client;
ThingsBoard tb(mkr1010Client);
//Función para conectar arduino a la red WiFi
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void localizoRedesCercanas() {
Serial.println("Localizando redes WiFi cercanas.");
int n = WiFi.scanNetworks();// Localiza WiFis
Serial.println("Completado.");
if (n == 0)
Serial.println("No se ha encontrado ninguna red.");
else {
Serial.print(n);
Serial.println(" Redes WiFi encontradas");
for (int i = 0; i < n; ++i) {
// Nombre de red (SSID) y potencia (RSSI).
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(" dBm)");
Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*");
delay(10);
if (WiFi.SSID(i) == pto_acceso_1 ) {
rssi_1 = WiFi.RSSI(i);
r1 = (rssi_1 + 38.821) / -1.9405;
Serial.print("r1: ");
Serial.println(r1);
a = 1;
}
else if (WiFi.SSID(i) == pto_acceso_2 ) {
rssi_2 = WiFi.RSSI(i);
Serial.print("r2: ");
r2 = (rssi_2 + 37.857) / -4.994;
Serial.println(r2);
b = 1;
}
else if (WiFi.SSID(i) == pto_acceso_3 ) {
rssi_3 = WiFi.RSSI(i);
Serial.print("r3: ");
r3 = (rssi_3 + 31.063) / -5.7083;
Serial.println(r3);
c = 1;
}
if (a = 0) {
rssi_1 = 0;
}
if (b = 0) {
rssi_2 = 0;
}
if (c = 0) {
rssi_3 = 0;
}
}
}
Serial.println("");
}
void setup() {
//Inicializamos monitor serie
Serial.begin(9600);
setup_wifi();
}
void reconnect() {
// Loop until we're reconnected
while (!tb.connected()) {
status = WiFi.status();
if ( status != WL_CONNECTED) {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
Serial.print("Connecting to ThingsBoard node ...");
// Attempt to connect (clientId, username, password)
if (tb.connect(THINGSBOARD_SERVER, TOKEN)) {
Serial.println( "[DONE]" );
} else {
Serial.print( "[FAILED] [ rc = " );
Serial.println( " : retrying in 5 seconds]" );
delay( 500 );
}
}
}
void loop() {
// hago 2 busquedas de redes por cada envío
if (millis() - buscoRedes > 500UL) {
localizoRedesCercanas();
buscoRedes = millis();
}
// envio datos a Thingboard
if (millis() - envioDatos > 1000UL) { // cambia 1000 por el valor de tu agrado
//Se comprueba si esta conectado a la red wifi
if (!tb.connected() ){
reconnect();
}
Serial.println("Conectado con el broker");
tb.sendTelemetryInt("nodo1", rssi_1);
tb.sendTelemetryInt("nodo2", rssi_2);
tb.sendTelemetryInt("nodo3", rssi_3);
Serial.println(rssi_1);
Serial.println(rssi_2);
Serial.println(rssi_3);
c = 0;
tb.loop();
envioDatos = millis();
}
}
Me conectaba en cada ciclo, porque al buscar las redes disponibles se me desconectaba la red y dejaba de funcionar y opté por esa solución. He probado tu código y funciona correctamente, aunque faltaba por declarar la variable status, que lo he hecho de la siguiente manera, al principio del código.:
int status = WL_IDLE_STATUS;
Hay una cosa de tu código que no logro entender, a ver si me puedes echar una mano con esto. En la función loop, millis() se usa para contar tiempo según tengo entendido. Entonces no entiendo muy bien lo que haces en los dos if de búsqueda y envío de datos, porque si millis() cuenta el tiempo transcurrido desde que se inició el programa, pues tarda aproximadamente 5 segundos en llegar al primer if, lo que nos da que millis() tiene un valor de 5000. Obviamente mayor que 500 y entramos dentro de este if, aclaras arriba que haces dos búsquedas de redes por cada envío pero solo se realiza una verdad?.
Lo que no llego a entender muy bien que aporta la variable millis() o cual es su función dentro del programa, creo que no llego a entender la condición de los if.
Si tarda 5 segundos es porque tu rutina de búsqueda es mas lenta de lo que crees.
Esta todo hecho para que no demore nada.
Asi que algo que puedes hacer es tomar tiempos. Crea nuevas variables y toma el tiempo antes y despues de cada rutina para asegurarte que tarda X mseg.
Yo supuse que la localizacion de las 3 redes era veloz.
Por eso lo puse como para que tome 2 muestras y envie 1 o mejor dicho me aseguro de tener una muestra antes de enviar.
Tarda alrededor de 5 segundos en conectarse a la red WiFi, luego llega a la función localizoRedesCercanas(); y termina a los 10 segundos, por lo que se lleva dentro de esta función otros 5 segundos. Al finalizar el envío de datos termina con 13 segundos, por lo que el envío se realiza cada 8 segundos (5+3).
Me funciona perfectamente pero realmente estoy olvidando lo que dices de tomar dos muestras, o mejor dicho de asegurarme de que la muestra esté tomada. Para ello, supongo que debería aumentar las unidades dentro del If, pero sigo sin entender lo que haces en estas comparaciones, restas las variables y lo comparas a un UL pero, en que te basas para escoger estos?
Porque uso millis() y no uso delay.
El delay es algo que no existe en mi programación. Solo DETIENE el Arduino y no hace nada productivo asi que lo uso en contadas ocaciones.
millis() devuelve los mseg desde que el arduino se energizó.
Una variable se carga con el evento que la dispara y yo comparo siempre el valor actual de millis() con esa variable.
Asi que imagina esto.
Arranca tu MKR
En algun momento comienzo y tomo un dato envioDatos y vale supongamos 10000 mseg o sea que hace 10 seg se arrancó tu MKR lo hago asi para facilitar cuentas.
cuando millis() - envioDatos se compara por primera vez me da 0
entonces 0 no es mayor a 1000UL que es UL, es la indicación que le dice al compilador que 1000 esta en formato unsigned long igual que millis() y envioDatos.
Solo cuando la diferencia millis() - envioDatos supere a 1000 mseg se hará lo que esta dentro del if
Luego de hacer todo, enviando datos a TB ajusto envioDatos para que dentro de 1000 mseg repita la acción
Ahora si tu sistema demora mas, no tiene sentido que envie cada 1000, debe hacerlo cuando tomar muestras reales.
Asi que esto
Si leo bien el código, la primera vez que se realiza la comparación de millis()-envioDatos no puede ser cero. Ya que envioDatos está definido como unsigned long pero no se define su valor, y no se modifica hasta que entra dentro del propio if donde se compara, por tanto cuando el código llegue por primera vez a ese if, millis() en este caso siempre tendrá un valor mayor que 1000UL. Lo mismo ocurre con el primer if:
En este if, se compara millis() con la variable buscoRedes, también definida en un principio como UL pero no su valor, por tanto siempre se realizará este if, no entiendo el uso de esto.
Entiendo que si fuese todo de manera inmediata, lo mismo el segundo if no se realizaría ya que tardaría menos de un segundo en llegar y por tanto se repetiría el loop. Sin embargo, si esto fuese así, tampoco se realizaría una segunda medida ya que millis()-buscoRedes sería cercano a cero y por tanto menor que 500. No se si es que no te estoy entendiendo, que seguramente sea eso, pero es lo que consigo entender con lo que comentas.
A ver. todos los elementos que se usen con milllis() siempre deben definirse como unsigned long asi que ya no vale la pena mencionarlo. Las cuentas funcionan sin problemas hasta los 49.7 dias y luego simplemente siguen si las haces como las he indicado. En tu caso jamás llegaras a 49.7 dias, asi que es tema para otro sketch.
Cuando defines variables como globales y no le asignas nada estan a 0.
Entonces cuando pasas por el primer ciclo y se encuentra con millis() - buscoRedes lo va a ejecutar porque ya superaste seguramente los 500mseg o 500UL. Y esa es la idea. Si no me crees ponle como global buscoRedes = 0 y veras que nada cambia.
Esta claro que 500 para algo que demora 13000 no tiene sentido. Asi que corrige eso.
Como no su valor? Si la variable se define de un modo todo lo que le asignes será de ese tipo.
Imagina una carrera de atletas de fondo.
Se larga la carrera (arranca el arduino pq se ha energizado y empieza a contar millis()). Se inicializan las variables buscoRedes = 0 y envioDatos = 0;
Tu proceso de conexión a la WIFI asegura que demorará al menos mas de 500 mseg asi que podemos asumir que estamos ahi, pero imaginemos que fue inmediato.
Ahora estas en el loop pero volviendo a la analogía de los atletas, estos dieron una vuelta a la pista y van a pasar por tu puesto de control.
Cuando pasas tu miras el cronometro y tomas un tiempo parcial
Ese tiempo parcial lo comparas en cada caso con la variable y su valor.
En el primer caso si millis()-buscoRedes no es mayor a 500 entonces sigo pero si lo es, ejecuto la rutina y lo mas importante, al terminar el código que esta en el condicional, ajusto buscoRedes con el valor de millis() de ese momento.
buscoRedes = millis();
Por lo tanto no entraré a esta parte del código hasta que millis() - buscoRedes sea mayor a 500UL
Lo mismo ocurre con envioDatos.
Me refería al valor numérico, no a su definición como UL. Estoy acostumbrado a programar microcontroladores en C y esto que comentas de que se declara como valor =0 si no se le indica no siempre es cierto en estos casos, ignoraba que en arduino sí, perdón por mi ignorancia en este caso jajajajaja.
Vale, como dices, al final solo es un ajuste de tiempos jugando con las variables. Gracias.