Proyecto Wifi ESP8266 Como Servidor WEB

Hola muy buenas, estoy haciendo mi TFG con un Arduino Wemos D1 mini pro, el cual incluye Wifi, básicamente estoy utilizando eso y un acelerómetro. Consiste en medir la velocidad de una barra para representarlo luego en un servidor. Sin embargo tengo dos problemas que me gustaría saber si alguien tiene alguna idea/ solución:

Problema 1:

La cosa es que para calcular la velocidad (e incluso el recorrido que hace) habría que integrar, pero no hay función que exista para integrarla, así que lo que he hecho es hacer el promedio de las aceleraciones durante el tiempo que se está moviendo, le resto 9.8 (que sería la aceleración de la gravedad) y lo multiplico por el tiempo durante el cual la barra se mueve, lo cual se que no es exacto, pero creo que es incluso menos exacto de lo que esperaba, si alguien tiene idea de cómo podría hacerlo mejor estaría agradecido.

Problema 2:

La idea era hacer un servidor web con la wemos, el cual mi tutor dijo que se podría (aunque sea mi tutor no me aporta mucho a la hora del proyecto, me dice sólamente que busque). Y sí, es cierto que se puede hacer un servidor, pero yo quería conectar mi smartphone o portátil a la placa mediante wifi y que lo único que pueda hacer por estar conectado al wifi es estar en el servidor que incorporaría el wifi del wemos. Sin embargo todo lo que he encontrado ha sido que la placa hace de Access Point (AP) pero conectándose a una Wifi y ahí le asigna una dirección IP al servidor y desde el navegador (que está conectado a la wifi de casa, no conectado mediante wifi a la placa) puedes hacer lo que querías.
Yo quisiera saber si se puede hacer que la placa haga literalmente de AP, que al buscar una wifi con tu teléfono aparezca el del arduino, conectarte, y ya en el navegador conectarte al servidor de la propia placa.

Muchas gracias de antemano.

Agradecería mucho algún link o ejemplo en el que haya algo de código para fijarme.

PD: Siento si esto no va aquí, soy nuevo en el foro.

Saludos!

Puedes describir el movimiento de la barra?
con un gráfico, por favor. Es una una superficie plana o en plano inclinado?

Me extraña que digas que vas a tomar un promedio. Puedes integrar velocidades, tomando las lecturas de aceleración y usando micros() para saber el tiempo transcurrido. Cada muestra a*t te dará una vi que podrás integrar, usando Simpson.

Lo del servidor Web es de facil resolución. Ya lo veremos. Ahora concéntrate en la medición de velocidad.

surbyte:
Puedes describir el movimiento de la barra?
con un gráfico, por favor. Es una una superficie plana o en plano inclinado?

Me extraña que digas que vas a tomar un promedio. Puedes integrar velocidades, tomando las lecturas de aceleración y usando micros() para saber el tiempo transcurrido. Cada muestra a*t te dará una vi que podrás integrar, usando Simpson.

Lo del servidor Web es de facil resolución. Ya lo veremos. Ahora concéntrate en la medición de velocidad.

El movimiento de la barra es el del movimiento de un press de banca del gimnasio por ejemplo, es decir, es un empuje vertical completamente (idealmente perpendicular al suelo, sólo que hay alguna pequeña desviación que yo no tengo en cuenta).

A qué te refieres con lo de micros() y Simpson? Ya te digo que sólo llevo 1 mes trabajando con Arduino, me es mas o menos fácil porque he programado bastante en C y es supera parecido, te escribo un poco el código del calculo de la velocidad que he hecho:

medida=analogRead(A0);
acc= ((medida/1024.0) *vi -ceroG)/sensibilidad;
float acc2= acc*9.8066; 
acc2= abs(acc2);
int iter=0;
suma=0;
Serial.println("Paso1");
if (acc2> (9.8+margen) || acc2<(9.8-margen)){
 inicio=millis();  //Consulta los milisegundos desde que se inició el sketch
     
 while(acc2> (9.8+margen) || acc2<(9.8-margen) ){
   delay(1);
   medida=analogRead(A0);
   acc= ((medida/1024.0) *vi -ceroG)/sensibilidad;
   acc2= acc*9.8066; 
   acc2=abs(acc2);
   suma=acc2+suma;
   iter=iter+1;
   Serial.println(acc2);
   delay(1);
}
  
  fin=millis();  //Consulta los milisegundos desde que se inició el sketch
  transcurrido=(fin-inicio);
  Serial.println("tiempoA:");
  Serial.println(transcurrido);
  transcurrido=transcurrido*0.001;//Calcula el tiempo en segundos desde la última lectura
  Serial.println("tiempoB:");
  Serial.println(transcurrido);
  float vel= ((abs(suma-9.8066))/iter)*transcurrido; 
  float pos= vel*transcurrido;   
  Serial.println("Aceleración:");
  Serial.println(suma/iter);
  Serial.println("Velocidad:");
  Serial.println(vel);
  Serial.println("Posición:");
  Serial.println(pos);

  delay(2000);

samu41:
sólo que hay alguna pequeña desviación que yo no tengo en cuenta

¿En la trayectoria o en capturar el tiempo? Para capturar el tiempo con exactitud, tendría que ser mediante interrupciones...

A qué te refieres con lo de micros() y Simpson?

micros() es la versión que devuelve microseguntos en lugar de millis() para trabajar con mas presición.

Regla de integración de Simpson, es cálculo numeríco. Algo habitual para un programador, es la regla que lleva la integración de un diferencial t al campo discreto usando un Delta t, que es lo que nosotros podemos medir con un microcontrolador.

Yo cuando no veo bien que vamos a medir me cuesta entender que haces en el código.
La barra no puedes poner una imágen? Usa etiquetas.

Puedes poner además todo el código porque hay variables no definidas como ceroG, etc.
Faltan cosas, setup, librerías si las hubiera.

NOTA:
Códigos van con etiquetas.
Enlaces van con etiquetas
Imagenes van con etiquetas.
Con eso te desenvuelves perfectamente en el foro. Todo esta en las normas 1er hilo de cada sección.

Lucario448:
¿En la trayectoria o en capturar el tiempo? Para capturar el tiempo con exactitud, tendría que ser mediante interrupciones...

En la trayectoria, lo que se quiere medir es la velocidad con la que empujas la barra, para que tengáis una imagen más visual en este vídeo se ven los movimientos que quiero medir VIDEO

La idea es que sea lo más recitilíneo posible, pero como la placa wemos d1 mini pro sólo tiene un pin analógico, tomo como referencia el eje Y, lo ideal sería hacer el módulo de XYZ, pero es un error al que estoy dispuesto a asumir. Lo que genera más dificultad es el "integrar" que al no haber función no se cómo hacerlo. También está el tema del servidor que digo

Por favor edita tus post según mis consejos.

Olvida el servidor, primero debes resolver la medición que es la base de tu problema. El servidor y la presentación se resuelve sin problemas.

Que sensor estas usando que lo mides con el AD? me llama la atención!!

Vale, perdón, justo estaba comentando cuando hiciste el post y no lo vi.

Estoy utilizando un acelerómetro de 3 ejes ADXL335. Los valores esos que me comentas sólo son para poder medir bien los valores con el sensor, valores de datasheet (aunque no eran los ideales). Espero que haya quedado claro lo que quiero medir, es la velocidad a la que levanto la barra en la fase concéntrica (en la que se hace fuerza).

Respecto a Simpson, he hablado con un amigo que está haciendo doble grado de física y matemáticas y me ha dicho que esa regla sólo sirve para interpolar 5 valores, es cierto? porque claro, no me serviría, esto mide mucho valores por segundo.

De todas formas os dejo el código completo.

float medida;
float acc;
float vi=3.3;
float ceroG= 1.42;
float sensibilidad= 0.289;
float margen= 0.7; //margen que doy para que no mida nada mas moverlo, si estoy haciendo fuerza la acc!= 9.8, cuando deje de hacer fuerza volverá a ser 9.8
float suma=0; //Iniciamos la suma que luego será el promedio de acc
double transcurrido=0;
unsigned long inicio, fin;  // Mide el tiempo
void setup() {
  // put your setup code here, to run once:
  
  pinMode(A0,INPUT);
  Serial.begin(115200);
  
}

void loop() {
  // put your main code here, to run repeatedly:
  
 medida=analogRead(A0);
 acc= ((medida/1024.0) *vi -ceroG)/sensibilidad; //Aceleración en Gs
 float acc2= acc*9.8066; //Aceleración en m/s^2
 acc2= abs(acc2);
 int iter=0;
 suma=0;
 Serial.println("Paso1");
 if (acc2> (9.8+margen) || acc2<(9.8-margen)){
  inicio=millis();  //Consulta los milisegundos desde que se inició el sketch
      
  while(acc2> (9.8+margen) || acc2<(9.8-margen) ){
    delay(1);
    medida=analogRead(A0);
    acc= ((medida/1024.0) *vi -ceroG)/sensibilidad;
    acc2= acc*9.8066; 
    acc2=abs(acc2);
    suma=acc2+suma;
    iter=iter+1;
    Serial.println(acc2);
    delay(1);
 }
   
   fin=millis();  //Consulta los milisegundos desde que se inició el sketch
   transcurrido=(fin-inicio);
   Serial.println("tiempoA:");
   Serial.println(transcurrido);
   transcurrido=transcurrido*0.001;//Calcula el tiempo en segundos desde la última lectura
   Serial.println("tiempoB:");
   Serial.println(transcurrido);
   float vel= ((abs(suma-9.8066))/iter)*transcurrido; 
   float pos= vel*transcurrido;   
   Serial.println("Aceleración:");
   Serial.println(suma/iter);
   Serial.println("Velocidad:");
   Serial.println(vel);
   Serial.println("Posición:");
   Serial.println(pos);

   delay(2000);
 }
  delay(50); 

}
/* 1g= 9,8066 m/s^2 300mv/g  0G= 1.5V conversor ADC de 10 bits  */

Esto es lo que querés llegar a medir
Análisis biomecánico de la articulación de la rodilla derecha en el levantamiento de pesas

No son movimientos de halterofilia, son de Powerlifting (sentadilla, press de banca y peso muerto). A lo que iba, es cierto que solo se puede usar para 5 datos lo de Simpson?

Ve viendo este documento para comparar algoritmos posibles.

Vale, creo que ya se como hacerlo, lo único que necesito hacer un vector del que no se qué tamaño tiene, ya que depende del numero de muestras que coja, se puede hacer eso?, o en su defecto, cual es el número máximo de posiciones que puede tener un vector en arduino?

Eso debes definirlo en funcion de algunas pruebas.
Toma un par de mediciones min max de cuanto tiempo puede llevar el proceso y entonces podrias definir un tamaño de vector que no complique el funcionamiento del sketch y entonces definir cual será la variación de tiempo para tomar las muestras.
En este punto tal vez convenga usar una librería de tiempo como TimeOne u otra.
Con ella puedes determinar en forma precisa cada toma de Aceleración.

Si modificas la rutina levemente y solo llevas la suma de valores, podrias hasta independizarte de la cantidad tomada y solo llevar la cuenta de cuantas muestras has tomado.

Es decir solo haces esto

suma += analogRead(A0);   // suma del tipo unsigned long o sea 32 bits
contador++;                               // tal vez un unsigned int

El único problema con esta sugerencia es cuando terminas el muestreo?
Viendo el video observo que en el proceso del levantamiento hay al menos 3 etapas en las que la velocidad queda en reposo.
Partiendo de V = 0 levantas desde el piso hasta la extensión de los brazos.
Luego puedes llevarla a la altura de los hombros y otra vez V = 0
Y por ultimo el momento final hasta arriba de la cabeza y otra vez V = 0.

Tal vez yo este viendo una situación que no corresponda con tu caso.
No se como se llama tecnicamente a ese levantamiento de pesos desde el suelo.

Si tomas la diferencia entre dos valores en un intervalo de tiempo, entonces cuando esta diferencia sea casi nula o x debajo de un umbral estarías en V = 0 o sea en alguna de las 3 situaciones descriptas.

Dime si estoy analizando correctamente tu problema o no?

Lo que estás teniendo en la cabeza es otra idea, eso es de halterofilia, los levantamientos que yo digo se recogen en este video que puse antes Sentadilla, press banca y peso muerto RAW total - YouTube

Lo que hago es medir la fase concentrica, es decir, al principio tendré una aceleración de 9.8 (+-un margen), en el momento en que hago la fase excentrica (bajo) la aceleración se modifica, cuando acabo la fase excéntrica empieza la concéntrica (subo, hago fuerza) y el movimiento acabaría cuando dejo de hacer fuerza, es decir, la aceleración volvería a ser otra vez 9.8

Lo que se me ha ocurrido es decir que el vector tiene un valor muy grande, con un float por ejemplo 1000000, empiezo a almacenar valores, y cuando se sale del ciclo cambio el valor, pongo en codigo para ver si se podría hacer.

int i=1000000;
float acc[i];
int j=0;

while (mido aceleración){

acc= analogread(A0);
vector[j]=acc;
j++;
}
if (j<=i){
i=j;
}

De esta forma "reservaría" un montón de posiciones y al final si no las uso las cambio por el número de iteraciones que necesito en verdad. Es algo parecido a reservar memoria con malloc en código C, sólo que en plan chapuza, no se si en arduino existe esa función

Creeis que podría funcionar?

Primero no puedes tener 1000000 valores. No te da la memoria.
Segundo para que guardar en float algo que lees como unsigned int? Eso es como minimo poco eficiente.

Respecto a la prueba ya lo habias puesto bien y no se porque lo he confundido.

Si tomas la diferencia entre dos valores en un intervalo de tiempo, entonces cuando esta diferencia sea casi nula o x debajo de un umbral estarías en V = 0 o sea en alguna de las 3 situaciones descriptas.

Esto esta mal. Porque estaras midiendo aceleración y no es la derivada de V que te indica V = 0 sino la integral de aceleración.

Como minimo tendrás que ir llevando algunas muestras y entre ellas integradas de tirán que has terminado.

Respecto a como proceder te propongo algo?
Porque no haces un loggeo de datos, hagamos un código que funcione, que tome datos los almacene y de algun modo podamos luego recuperarlos.
Con esa gráfica luego podremos tomar conclusiones.
Seria interesante que ademas tuviera un par de switches que ilustren los momentos para luego poder tomar decisiones con lo que se observe.

Esos switches no se si los debería tener quien haga la prueba u otra persona.

Yo lo encararía de ese modo.

Acabo de ver el video una vez mas y tomé estos datos desde el inicio de la prueba:
La bajada 5.55 seg y toda la operación fue de 8.07 seg
Asi que tienes 5.55 hacia abajo y 2.52 hacia arriba.

El segundo ejemplo muestra a alguien que tarda 1.66 hacia abajo y 3.40 en total
Bajada 1.66
Subida 1.74

Buscando la RAM del ESP dice tener 96 KiB of data RAM asi que podras destinar gran parte a tu vector.
Cuanto? supongamos unos conservadores 80k
Un entero son 2 bytes asi que son 40k de datos, mas que bien... diría que demasiados.
Todo depende a que tasa los cargues. Supongamos 1 mseg, eso te daria 40000 mseg o 40 seg para tu prueba.
Asi que podrias mejorar las muestras. ya que un tiempo mas logico podria ser de 20 segundos
Supongamos entonces una muestra cada 500 useg para de nuevo tener 40k de datos con un máximo de 20 segundos.

Esto sería un comienzo del código

#include <TimerOne.h>                       // https://github.com/PaulStoffregen/TimerOne
#default MUESTRAS    20000
volatile unsigned int vector[MUESTRAS] = {0};
volatile unsigned int i = 0;

void setup(void) {
  
  Timer1.initialize(500);         // 500 useg 
  Timer1.attachInterrupt(logger); // tomo datos cada 500 useg
  Serial.begin(9600);
}

void logger(void) {
  vector[i++] = analogread(A0);
}

Falta el loop donde hay que poner algo que lo inicie via un switch, lo detenga (podria ser mismo switch). Algo para levantar los datos y procesarlos en una notebook/PC.

Primero no puedes tener 1000000 valores. No te da la memoria.
Segundo para que guardar en float algo que lees como unsigned int? Eso es como minimo poco eficiente.

Bueno, puse 1000000 pero con un numero muy grande me vale que lo soporte un float, luego reduciría la memoria.
Con lo que dices de segundo, no guardo un int, guardo ya el valor de la aceleración directamente, porque si tuviese que guardar el valor en bruto sería un poco lío, ya que no veo m/s^2 sino un número que a saber a qué valor de aceleración corresponde (Se que se puede calcular, de hecho lo hago, pero es algo transparente para el usuario).

Con lo que respecta del código que me has puesto, no entiendo muy bien con lo que hace, ya que no estoy familiarizado con esas librerías y el logger (al poner en el vector ={0} inicializas todos los valores a 0 no? Esta bien saberlo).

La cosa es que no se cuantas muestras puede hacer en una medición, ya que como has visto varía mucho dependiendo del ejercicio, y no sólo el ejercicio, sino de la persona y el peso que manejes, por eso no puedo decir que muestree cada x, ya que puedo perder algo, yo muestreo todas las veces que me deje el código para que sea mas exacto, es decir, que el unico periodo de tiempo que dejo que pase entre muestreo y muestreo es el tiempo que tarda la placa en ejecutar las instrucciones (que creo que no es poco, ya que hay varios ciclos de por medio).

Saludos, sigo abierto a tus sugerencias, es algo complicado y me gustaría que saliese bien

La cosa es que no se cuantas muestras puede hacer en una medición, ya que como has visto varía mucho dependiendo del ejercicio,

Bueno eso es mas que importante para determinarse. De lo contrario podrias tener un criterio conservador y tomar una muestra cada 5 mseg y entonces extender el tiempo considerablemente.

guardar el valor en bruto y hacerlo convertido es exactamente igual. Porque puedes disponer de el cuando quieras.
No hace falta guardar un float que son 4 bytes cuando alcanza con guardar solo 2 y tener el doble de muestras.

Se comprende?
Si crees que seria mas aconsejable disponer de mas capacidad porque no consideras guardar en una SD?

Mas o menos sí, aunque ahí también estás suponiendo que el vector tiene 5000 espacios de memoria no? No estarías sobredimensionando también? De todas formas, si no se llega a las 5000 muestras en el levantamiento debería saber al menos la última posición

Buenas, os actualizo de como va la cosa, he hablado hoy con mi tutor y me ha dicho en resumidas cuentas que lo que he hecho no vale para nada, entonces lo que tengo intención de hacer es:

-Muestrear continuamente la aceleración, con lo que escribiste surbyte de la interrupción, cada X useg e ir almacenandoles en un vector de 5000 muestras (no se debería llenar) mediante el metodo de buffer circular, si se acabasen los valores empezarían a machacar los del principio.
-Coger dos valores de aceleración y sus instantes, calcular su área (sería la integral), con lo que obtendría un valor de velocidad y lo almacenaría en otro vector igual que el de aceleración de 5000 muestras, así continuamente cogería el ultimo valor cogido y el siguiente, calcularía su área y obtendría un valor de velocidad.
-Solo me quedaría con los valores de velocidad que se corresponderían con dos 0, lo cual indicaría que está parado y entre esos instantes debería haber hecho la fuerza.
-Para hallar la velocidad media calcularia el promedio de todos esos valores de velocidad comprendidos entre los dos nulos.

Ahora mi pregunta es: en el código que pusiste :

#include <TimerOne.h>                       // https://github.com/PaulStoffregen/TimerOne
#default MUESTRAS    20000
volatile unsigned int vector[MUESTRAS] = {0};
volatile unsigned int i = 0;

void setup(void) {
  
  Timer1.initialize(500);         // 500 useg 
  Timer1.attachInterrupt(logger); // tomo datos cada 500 useg
  Serial.begin(9600);
}

void logger(void) {
  vector[i++] = analogread(A0);
}

Yo lo que entiendo ahí es que en el setup al poner eso, en otro thread paralelo el codigo cada 500useg coge una muestra y lo mete en el vector. Mis preguntas:

1º.El setup tiene que tener obligatoriamente el void? o se puede dejar como viene por defecto en arduino?

void setup(){}

2º.Podría usar el vector en la función loop o en otra función tal cual está o debería poner este código?
* *int logger(int vector[i]) {   vector[i++] = analogread(A0); }* *
Es que no estoy familiarizado con las interrupciones en Arduino, en ensamblador di algo pero no tiene nada que ver.
Saludos y muchas gracias, que este proyecto creo que me está quedando un poco grande

  1. Para responderte te pregunto yo también: leiste la librería TimerOne? miraste algun ejemplo? Eso es algo que toda persona de nivel universitario debería hacer. Aprender a responderte a si mismo antes de hacer consultas. Al menos eso hago yo siempre. Pregunto cuando agoté todas las instancias. Es un consejo para siempre.

Toda librería requiere de cierta inicializaición. La inicialización se hace una sola vez. Esa única vez es el setup.
El setup se escribe siempre void setup(), no hay otro modo de hacerlo. Si tienes duda busca un buen libro en Documentación y tutoriales.

  1. no puedes usarlo en el loop porque esa línea tiene sentido en el contexto de la interrupción ocurrida a un intervalo dado de 500 us.

En el loop no ocurrirá de ese modo. Tendrías que activar un flag y cuando el loop pase por ahi actuaría pero quien asegura ese momento?