Tratamiento datos y comunicación arduino-ordenador

Hola,

estoy con un proyecto al que le he dado varias vueltas ya. os cuento un poco.

Tengo dos arduinos, los cuales realizan varios calculos y crean una variable que se actualiza cada 0,1s. Estas variables (una por Arduino), será utilizadas en el navegador de un ordenador que tiene un programa que suele necesiar esta variable cada 0,5s.

En un primer paso conecté los arduinos con una Ethernet Shield, pero el problema que tiene es que cada cierto tiempo la Ethernet Shield no responde, se queda unos segundos (hasta algun minuto) que no responde. Pasa de forma aleatoria. Y ha sido descartada para este proyecto.

He estado mirando posibilidades. La idea que más lógica me parece es conectar por USB los dos Arduinos al ordenador y tratar de guardar los datos en dos archivos o base de datos. Realmente solo me hace falta el dato actual en algun sitio que puedan consultarlo en tiempo real a demanda del programa, por lo que lo de la base de datos lo veo enorme (y tendría que entenderlo, he leido bastante, pero no lo tengo claro). Así mismo, abrir un archivo, guardar el dato y cerrar el archivo cada menos de medio segundo y que lo puedan consultar al mismo tiempo lo veo también poco eficiente.

¿Alguien me puede orientar un poco sobre que forma tendría de guardar solo el ultimo valor y que se pueda consultar en tiempo real? No me vale verlo en la ventana Serial, tienen que tratar el dato y meterlo en su programa (en el primer prototipo lo hice con la Ethernet shield y funciona, mientras esta no falle).

Edito: el ordenador donde conectar los arduinos tiene Windows.

Seguro que podeis ayudarme a elegir la opción corecta. Después buscaré la forma de ejecutarla.

Gracias de antemano!

Diec.

El problema es que estas con el sistema operativo equivocado :slight_smile: , windows esta en la otra esquinas de un RTO. No hay motivo (si el programa del arduino es correcto) para que falle la comunicación por Ethernet, es mas probable que la falla este del lado windows. Tendrías que explicar un poco mejor para que necesitas la medición cada 0.1 segundos, tal vez pueda delegar algo en el Arduino y no en la PC.

Gracias por tu respuesta!

Que sea Windows no puedo evitarlo, es lo que utilizan en el ordenador... y el fallo de comunicación con la Ethernet Shield solo lo he puesto para evitar que me recomendarais ese camino, ya que no lo quieren asi, aunque probablemente el fallo esté en el lado de win2, como bien has dicho.

No necesito el dato cada 0,1s, lo necesitan cada 0,5s. En el Arduino lo actualizo cada 0,1s para tener el dato más reciente cuando hicieran la llamada a la IP de la ethernet shield. Pero en el ordenador lo necesitan cada poder consultarlo cada 0,5s.

Mi idea era que el arduino enviara por puerto serie a una BD o a un archivo del ordenador, donde a su vez, su programa pueda leer ese dato cuando lo necesite. Pero no se si es buena idea o hay otro camino más sencillo/seguro.

Explico un poco mejor el funcionamiento:
Su programa, en cuanto se pone en marcha, necesita los datos en tiempo real que consigue el Arduino. El programa pide el dato actual cada 0,5s durante 60s aprox. No necesitan guardar los datos, solo el valor más actual.

Espero que haya quedado más claro. :slight_smile:

Gracias!

Es difícil aconsejarte, sin saber donde realmente esta el problema. Por lo visto van utilizar otro programa para levantar el dato ¿cual? El problema de windows es que no es multiusuario real, te obliga a cerrar el archivo antes que otro programa lo lea. Tal vez sea lo mejor, como propusiste, utilizar una base de datos que permite abrir varias instancias de un archivo, pero eso depende de lo complicado que pueda ser leer el dato desde la aplicación que utilizara el dato.

Diec:
Tengo dos arduinos, los cuales realizan varios calculos y crean una variable que se actualiza cada 0,1s. Estas variables (una por Arduino), será utilizadas en el navegador de un ordenador que tiene un programa que suele necesiar esta variable cada 0,5s.

Lo otro seria entender porque planteas usar 2 Arduinos ?

Hola de nuevo,

PeterKantTropus:
Es difícil aconsejarte, sin saber donde realmente esta el problema. Por lo visto van utilizar otro programa para levantar el dato ¿cual? El problema de windows es que no es multiusuario real, te obliga a cerrar el archivo antes que otro programa lo lea. Tal vez sea lo mejor, como propusiste, utilizar una base de datos que permite abrir varias instancias de un archivo, pero eso depende de lo complicado que pueda ser leer el dato desde la aplicación que utilizara el dato.

Utilizan un navegador web como interfaz, donde gestionan diferentes cosas y donde se visualiza entre otras cosas, los datos de los sensores. Desde una base de datos seguro que lo pueden leer. Otro tema es que yo consiga poner el dato enviado por serie en la base de datos. Pensaba que habría alguna forma sencilla de ller lo que sale en la consola serial.

Kike_GL:
Lo otro seria entender porque planteas usar 2 Arduinos ?

La idea de dos Arduinos es porque en un principio estaban en dos maquinas distintas. Ahora estarán cerca del ordenador y los sensores tendrán cable hasta ellas. Tengo que comprobar que sea posible conectar todo a uno solo. Trabajo con interrupciones para medir velocidades y estas pueden producirse cada 30 mS, más cálculos, etc. No tengo claras las posibilidades de que se acumulen las interrupciones. No he estudiado los ciclos que necesitan las instrucciones y las interrupciones en Arduino.

Con esta información, tenéis alguna otra idea de como hacerlo, alguna pista o algo? Necesitáis mas información?

Gracias por vuestra ayuda!

Diec.

Porque no explicas NO como lo quieres hacer sino que tienes que hacer.

Tienes sensores, qué sensores de qué tipo, cuantos.
Sabemos que necesitas datos cada 500 mseg y por eso los lees antes cada 100mseg para asegurarte tener sus datos, puedes leerlos incluso mas rapido, asi que por ahi viene mi pregunta.

Pero da indicios de cantidades porque no veo donde esta el cuello de botella asi como lo explicas.
En un foro público no puedes ocultar datos porque si no, no podemos entender el contexto y se complica sugerirte soluciones.

Asi que se mas especifico y permite que la experiencia de quienes te han respondido te de miradas distintas a tu problema.

Hola Surbyte,

la parte del Arduino no la habia explicado porqué es la que tengo "más clara" (aunque estoy abierto a cualquier idea), pero allá voy.

En un principio son dos contadores de velocidad.

2 sensores proximidad mecanicos (como un interuptor) para contar vueltas. Las vueltas tienen, por limitación mecánica, un rango de funcionamiento de mínimo 1 vuelta/segundo y máximo 35 vueltas/segundo.

2 interruptores para modificar el valor fijo de distancia por vuelta.

En un principio las maquinas estaban separadas entre sí y cada una llevaba un arduino. Ahora esto podría cambiarse.

La solución para medir la velocidad ha sido sacar la media de los ultimos 3 segundos (para que sea estable), pero actualizandola cada 500mS.

La señal del sensor activa una interrupción y aumenta una serie de contadores.

Después cada 500mS se activa una función que realiza los calculos y los traspasos entre contadores.

if (millis()> proximaMedida )
  {
    contador = contador30;
    velocidad = contador * distancia * hora;
    proximaMedida = millis()+intervaloMedida;
    contador30 = contador25;
    contador25 = contador20;
    contador20 = contador15;
    contador15 = contador10;
    contador10 = contador5;
    contador5 = 0;
  }

void interrupcionSensor ()
{
   if (millis()> rebote)
  {
    contador5++;
    contador10++;
    contador15++;
    contador20++;
    contador25++;
    contador30++;
    rebote = millis() + retardoRebote;
  }
}

Ahora las condiciones son conectar un arduino con dos sensores y doblar cálculos, o dos Arduinos con un sensor cada uno. Mediante USB a un ordenador. La mejor solución sería pasar el dato más actual a una dirección localhost para que el programa actual solo tuviera que cambiar la URL donde antes cogia los datos a la nueva. Pero como he dicho antes, estoy abierto a propuestas.

Yo sigo investigando y he encontrado como hacer parte con Python, pero no tengo una solución completa.

Gracias!

Lo que muestras no luce como algo que use interrupciones, supongo que solo muestras la parte de cálculos
Cuando se usan interrupciones se deben detener las mimas en el momento de la lectura y no veo eso en tu rutina.

surbyte:
Lo que muestras no luce como algo que use interrupciones, supongo que solo muestras la parte de cálculos
Cuando se usan interrupciones se deben detener las mimas en el momento de la lectura y no veo eso en tu rutina.

En los ejemplos de Arduino no veo que utilicen detener interrupción mientras están en la interrupción. Habría que detenerla al empezar y volverla a activar al salir? No alargaria mucho la interrupción?

El código, no está completo, porque estoy modificando cosas. La interrupción es la función interrupciónSensor().

unsigned long proximaMedida =                           0;

unsigned long rebote =                                  0;
unsigned long retardoRebote =                         30;

float velocidad =                                       0;

const float distancia =                          0.000530;  // Distancia recorrida entre inputs en Km (valor fijo marcado por distancia por vuelta)
const float hora =                                   1200;  // Una hora en bloques de 3s como contador30

const int pinInterrupcion =                             2;  // Entrada interrupción en pin 2 (int 0)

float contador =                                        0;

volatile int contador30 =                               0;
volatile int contador25 =                               0;
volatile int contador20 =                               0;
volatile int contador15 =                               0;
volatile int contador10 =                               0;
volatile int contador5 =                                0;


void setup()
{

  Serial.begin(9600);
  

 
  pinMode (pinInterrupcion, INPUT_PULLUP);
  attachInterrupt (digitalPinToInterrupt (pinInterrupcion), interrupcionSensor, RISING);

}
 
void loop()
{

  if (millis()> proximaMedida )
  {
    contador = contador30;
    velocidad = contador * distancia * hora;
    proximaMedida = millis()+intervaloMedida;
    contador30 = contador25;
    contador25 = contador20;
    contador20 = contador15;
    contador15 = contador10;
    contador10 = contador5;
    contador5 = 0;
  }


void interrupcionSensor ()
{
   if (millis()> rebote)
  {
    contador5++;
    contador10++;
    contador15++;
    contador20++;
    contador25++;
    contador30++;
    rebote = millis() + retardoRebote;
  }
}

Alguna idea para realizar mejor esa interrupción? Y sí podría poner dos sensores con un arduino con estas condiciones?

Alguna idea de como pasar los datos al ordenador?

Gracias Surbyte!

Cuando mides RPM tu tomas una ventana de tiempo y en esa ventana de tiempo acumulas lectura de pulsos minetras las interrupciones estan ON y luego detienes interrupciones superada dicha ventana y presentas los datos o calculas.
Esa es la manera correcta de leer.

Asi por ejemplo puedes usar una ventana de cualquier ancho y mientras el error sea aceptable medir mas o menos rápido. 35 1/seg = 2100 RPM.
Para mi 35Hz es algo que mediría a la inversa. tomaría el tiempo que esa frecuencia tiene usandola como ventana para que un timer me introduzca la mayor cantidad de pulsos a contar y hacerlo de modo preciso.
35 hz => 28.6 mseg o sea que cada menos tiempo que 50 mseg tienes una lectura, mucho mejor que los 500 mseg no?

Utilizan un navegador web como interfaz, donde gestionan diferentes cosas y donde se visualiza entre otras cosas, los datos de los sensores. Desde una base de datos seguro que lo pueden leer. Otro tema es que yo consiga poner el dato enviado por serie en la base de datos. Pensaba que habría alguna forma sencilla de ller lo que sale en la consola serial.

Es sencillo hacerlo poniendo al Arduino como esclavo y un pequeño programa en la Pc que haga de conector, por ejemplo hice hace algún tiempo esto .

surbyte:
Cuando mides RPM tu tomas una ventana de tiempo y en esa ventana de tiempo acumulas lectura de pulsos minetras las interrupciones estan ON y luego detienes interrupciones superada dicha ventana y presentas los datos o calculas.
Esa es la manera correcta de leer.

Asi por ejemplo puedes usar una ventana de cualquier ancho y mientras el error sea aceptable medir mas o menos rápido. 35 1/seg = 2100 RPM.
Para mi 35Hz es algo que mediría a la inversa. tomaría el tiempo que esa frecuencia tiene usandola como ventana para que un timer me introduzca la mayor cantidad de pulsos a contar y hacerlo de modo preciso.
35 hz => 28.6 mseg o sea que cada menos tiempo que 50 mseg tienes una lectura, mucho mejor que los 500 mseg no?

Gracias Surbyte,

esa fue la primera opción que hice. Pero para este proyecto no le vi ventajas. La velocidad era muy inestable (es muy real) y como en los velocimetros de los coches hay que sacar una media de los ultimos segundos para que la aguja no vaya dando botes. Y al final, el programa toma la medida cada 500mS. Es casi más importante la estabilidad, que tener un dato muy actual.
Ademas, con ese sistema, hay que poner un temporizador para asegurar el cero. Sí fuera a, por ejemplo, 500rpm y parara de repente. No le llega ninguna señal para medir el tiempo y se queda esperando a hacer el próximo cálculo.
Creo que la solución que he adoptado es la que más se adapta a las necesidades. Lo que todavia no tengo claro es lo de parar la interrupción. La idea la veo lógica, preo en este caso, no le veo problema a que entre una interrupción en cualquier momento. La máxima perdida que veo es que me incremente unos contadores y otros, no. Lo cual no modificaría en exceso el resultado.

Habría que implementar detachiterrupt() cuando haga el cálculo y volver a activarla cuando lo acabe? Que pasaría si en ese momento entra un pulso del sensor? Lo perdería, supongo.

PeterKantTropus:
Es sencillo hacerlo poniendo al Arduino como esclavo y un pequeño programa en la Pc que haga de conector, por ejemplo hice hace algún tiempo esto .

Hola PeterKantTropus,

gracias! Estoy probando con tu idea, aunque veo que con windows es todo más díficil (tambiém debo ser yo que no estoy acostrumbrado). Al primer paso de recibir los datos en el ordenador llegué ayer, pero en vez de con MODBUS, con Python (que por cierto parece un lenguaje interesante). Ahora voy a intentar tu solución y tal vez, transformar la segunda parte para que funcione con Python. A ver que consigo.

Gracias!

Habría que implementar detachiterrupt() cuando haga el cálculo y volver a activarla cuando lo acabe? Que pasaría si en ese momento entra un pulso del sensor? Lo perdería, supongo.

Si son correctas todas tus afirmaciones.
Detienes interrupciones, calculas, pierdes lo que ocurra pero cual es el problema si la ventana se cerró? No pierdes nada, lees correctamente.

No estoy de acuerdo con el otro tema que planteas. Pero bueno cada cual toma sus decisiones.
Si algo mide cada 50 mseg tengo 10 lecturas para promediar incluso puedo usar promedio movil donde se descarta siempre la mas vieja y se suma la mas nueva.. y vas llevando la cosa con mayor ponderación si quieres.

Lo hablo con mucha liviandad pero todo requiere trabajo y ambos sabemos que asi son las cosas.

El promedio movil de Luis Llamas te resuelve el problema desde la programación, y tendras algo robusto y estable. Por eso te lo sugiero.
Si decides por ejemplo que quieres 20 o 50 muestras el sistema inicia y va ponderando con lo que tiene y mejora la media hasta llegar al valor que elegiste y de ahi agrega y quita como ya te he dicho.

Tal vez te he desviado de tu problema. Pero lo que tienes que hacer no requiere gran trabajo por eso es bueno enfocarse en como se miden las cosas y luego como presentarlarlas o enviarlas.
Si Solo se trata de 2 o mas variables via puerto serie... eso no puede darte problemas usando tasas como las permitidas en Arduino. Solo enviaras 2 o 4 datos. Corrígeme si estoy equivocado cada 500 mseg.