Mi hijo hace atletismo, la idea es medir el tiempo de reacción entre el disparo y la salida de tacos, tengo que ver cómo lo hace un dispositivo profesional, (con que sensores)
El funcionamiento pienso, es que el sensor de los tacos de salida, empieza a leer después del disparo, y a contar el tiempo, hasta que el acelerómetro muestre un cambio(una mínima vibración) que será cuando su pie empuje hacia atrás.
Pido ayuda/consejos para poder iniciar el proyecto
El displayado de datos en principio será en un display, en la fase 2, será por trasmisión Bluetooth a un app móvil que generará tanto la orden del disparo simulado, como los resultados.
Mi idea, es utilizar cualquier Arduino, con soporte Bluetooth (estoy muy oxidado, me podéis echar un cable aquí también ya que no tengo idea que hay por el mercado ahora mismo) + Acelerometro 3 ejes ADXL335
Edito para poner que por casa tengo sin abrir una placa de desarrollo basada en el [ESP8266] que incluye Bluetooth y wifi creo
Un saludo y gracias de Antemano
Adjunto foto del borrador a grandes rasgos que acabo de hacer ahora mismo.
Veo varios errores posibles en la idea que te voy a presentar.
En los equipos profesionales debe haber una señal que indica el comienzo via el disparo que pone a 0 el error que describiré a continuación, si en cambio, tenemos que esperar el tiempo que le lleva a la onda de sonido que viaja a 342.3 m/seg, solamente con estar a 10 mts hablamos de 29.2 mseg.
Continúo con la idea: Supongamos que dices voy a colocar un micrófono y cuando se reciba una señal que alcance determinado umbral será el momento del disparo. Obviamente eso ocurrirá a un intante T tal que la señal llegue y sea alcance un umbral determinado x un circuito Schmitt Trigger.
La segunda parte es la reacción en el arranque. Dices y concuerdo de poner un acelerómetro, de nuevo esto tiene su velocidad de reacción asi que otro error involucrado.
Otra opción sería disponer de algun sensor de presión en los tacos de salida y al dejar de tener presión o al desbalancearse entre ambos tacos, considerarlo como el arranque. No se bien que consideras como fin de dicho momento? Si es cuando se desprende un zapato o cuando ambos lo hacen.
Muchas gracias por tu comentario,
el altavoz de disparo estará situado en el mismo sitio que uno profesional la distancia que recorre el sonido sería la misma, pienso.
Y si es cierto habrá que hacer pruebas de campo, para calibraciones de tiempos, añadiendo o quitando, incluyendo el tiempo de demora de las propias sentencias del programa.
iré colocando un link en GitHub
según avance el proyecto, y así me podeis ir orientado, en todos y cada uno de los errores.
Respecto a los sensores, efectivamente acabo de revisar un poco Internet y los sensores de presión (actuaban con 25kg) fueron sustituidos en los actualidad por acelerómetros.
Eso no quita que existe algo EXTRA que detecte el momento en que se dispara sin incurrir en el error de propagación de la onda. Estoy hilando fino pero asi debe ser. Quieres medir algo en uSeg de modo que no se puede permitir errores de ninguna naturaleza.
Bien, si los sensores de presión no van, entonces será el acelerómetro.
Obviamente descartemos un enlace inalámbrico para transmitir el arranque, asi que ya tienes para trabajar.
Detección de un disparo, aconsejo usar electrónica simple, mic + preamplificador + Schmitt Trigger que te dará el inicio de la cuenta
Luego el acelerómetro detectará el final.
Creo que no me expliqué bien, tengo las ideas en la cabeza pero no salen bien
Es un dispositivo para entrenamientos.
Al pulsar un botón en la app en el móvil, este enlazará con ESP8266 y daremos la orden de correr el programa y ya todo el proceso se correrá en nuestro ESP8266, solo interactuaremos con la app de nuestro móvil para iniciar de nuevo el programa, es decir:
Pulsa nos un botón en la pantalla de nuestro móvil (disparo) y envía la orden de iniciar el programa en el ESP8266:
1° Inicializamos el Acelerometro
2° Activaremos un buzzer (disparo de salida)
3° empezará a contar el timer
4° Nuestro dispositivo se quedará leyendo el acelerómetro y en el instante que nos de señal iremos a leer el timer, guardamos ese registro.
5° Enviamos de vuelta a la app del móvil los datos obtenidos
Es decir no usaremos un microfono para recoger el sonido del disparo, este se generará en el propio programa
En principio antes de postear tenía dudas de los módulos que podría o no utilizar, y esa era la pregunta básicamente, pero según he ido recopilando electrónica que tenía en el trastero, fui sacando una placa de desarrollo NodeMCU ESP8266 y un módulo Acelerómetro ADXL345, pienso que nos podemos apoyar de momento con esto, qué opinas?
Las dudas empezarán más adelante estoy leyendo a cerca del ESP2866 y las interacciones con su librerías del IDE de Arduino que es con el que voy a trabajar
Con el ADXL345 y sus librerías ya trabajé en alguna ocasión con él.
Si claro.
Yo creo que deberías empezar tal vez haciendo que el ESP8266 actue como AP, tu te conectas a ese ESP8266 y su AP por ejemplo en 192.168.4.1 como se suele hacer para lo cual hay muchos ejemplos y la pagina simple que creas puede tener un boton de START y tmb recibir los datos del ESP266 cuando comience la cuenta.
Para hacer eso te recomiendo este sitio ESP8266 NodeMCU Access Point (AP) for Web Server | Random Nerd Tutorials
Pero tengo algún problema con tres botones de configuración de sensibilidad (con el método indexOf) que añadí, no logro que me funcionen correctamente, alguna idea donde puede estar el fallo?
En principio el resto me funciona bien,
Pero al clickear en sens Baja no va se me va a sens alta e igual con la Media....
/*
Este programa pretende medir los tiempos de reacción y cuantificar las mejorías en los entrenamientos de un atleta.
Para ello utilizaremos una Placa de desarrollo NodeMCU ESP8266 y Módulo Acelerómetro CJMCU ADXL345
Un Buzzer que hará las veces de pistoletazo de salida
y todo controlado a través de un enlace WIFI y a unservidor Web
*/
#include <SparkFun_ADXL345.h> // Esta biblioteca le permite comunicar con el acelerómetro ADXL345
#include <ESP8266WebServer.h> // Biblioteca se utiliza para simplificar la creación de un servidor web.
ADXL345 adxl = ADXL345();
unsigned long timer1 = 0;
unsigned long timer2 = 0;
unsigned long tiempo_desde_disparo = 0;
int sensibilidad = 50;
unsigned long resultado = 0;
String sensibilidadSTR = " MEDIA";
int PinBUZZER = 2; //Definimos el pin de salida - GPIO2 / D4
const char ssid[] = "Club-Atletismo-Leganes"; //Definimos la SSDI de nuestro servidor WiFi -nombre de red-
const char password[] = "complejoeuropa"; //Definimos la contraseña de nuestro servidor
WiFiServer server(80); //TCPservidor en el puerto 80
// -------------------------------------------------------------------------------------------------------------
void setup() {
Serial.begin(115200);
Serial.println("Iniciar");
Serial.println();
adxl.powerOn(); // Power on the ADXL345
adxl.setRangeSetting(2); // Definir el rango del Acelerómetro, valor en 2g
pinMode(PinBUZZER, OUTPUT); // Inicializamos el GPIO2 como salida (Buzzer)
digitalWrite(PinBUZZER, LOW); // Dejamos inicialmente el GPIO2 apagado
server.begin(); // Inicializamos el servidor
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password); // Red con clave, en el canal 1 y visible
Serial.println();
Serial.print("Direccion IP Access Point - por defecto: "); //Imprime la dirección IP
Serial.println(WiFi.softAPIP());
Serial.print("Direccion MAC Access Point: "); //Imprime la dirección MAC
Serial.println(WiFi.softAPmacAddress());
}
int medX() { // Función que devuelve una muestra pònderada de 10 medidas del eje X
int x, y, z;
int mX = 0;
for (int i = 0; i < 10; i++) {
adxl.readAccel(&x, &y, &z);
mX = mX + x;
}
mX = mX / 10;
return mX;
}
// -------------------------------------------------------------------------------------------------------------
void loop()
{
WiFiClient client = server.available(); // Comprueba si el cliente ha conectado
if (!client) {
return;
}
Serial.println("nuevo cliente"); // Espera hasta que el cliente envía alguna petición
while (!client.available()) {
delay(1);
}
Serial.printf("Clientes conectados al Access Point: %dn", WiFi.softAPgetStationNum()); // Imprime el número de clientes conectados
String peticion = client.readStringUntil('r'); // Lee la petición
Serial.println(peticion);
client.flush();
int x, y, z, x1;
String salida = "<h2>**************</h2>";
if (peticion.indexOf('/START=L') != -1) { // Comprueba la petición de sensibilidad
sensibilidad = 90;
sensibilidadSTR = "<h2>Sensibilidad: BAJA</h2>";
}
if (peticion.indexOf('/START=M') != -1) {
sensibilidad = 50;
sensibilidadSTR = "<h2>Sensibilidad: MEDIA</h2>";
}
if (peticion.indexOf('/START=H') != -1) {
sensibilidad = 20;
sensibilidadSTR = "<h2>Sensibilidad: ALTA</h2>";
}
if (peticion.indexOf('/START=O') != -1) { // Comprueba la petición de DISPARO
digitalWrite(PinBUZZER, HIGH); // Activamos el BUZZER ( DISPARO !!! )
timer1 = millis();
x = medX();
// x=x-Xcal;
while (true) //Realizar este bucle mientras NO tengamos(una mínima) Accelearación en el EJE de las X
{
x1 = medX();
if ((x1 - x) > sensibilidad || (x1 - x) < -sensibilidad) { // Accelearación +-50(Sensibilidad Media) en el EJE de las X ******
x1 = medX();
timer2 = millis();
resultado = timer2 - timer1;
if (resultado < 100) { //Por debajo de 100ms en Atletismo se considera SALIDA NULA ************
salida = "<h2 style='color:red'>** SALIDA NULA **</h2>";
}
else {
salida = "<h2 style='color:green'>* SALIDA CORRECTA *</h2>";
}
break;
}
else
{
tiempo_desde_disparo = millis();
if ((tiempo_desde_disparo - timer1) > 3000) { // ********** Apagamos el buzzer 3 segundos después del disparo y colocamos el mensaje "SIN SALIDA"
digitalWrite(PinBUZZER, LOW);
salida = "<h2 style='color:orange'>- NO HUBO SALIDA -</h2>";
break;
}
}
}
}
if (peticion.indexOf('START=F') != -1) { // RESET valores
x = 0;
x1 = 0;
resultado = 0;
timer1 = 0;
timer2 = 0;
String salida = "<h2>*******-******</h2>";
}
// ******************************************************* Envía la página HTML de respuesta al cliente
client.println("HTTP/1.1 200 OK");
client.println(""); // No olvidar esta línea de separación
client.println("<!DOCTYPE HTML>");
client.println("<meta charset='UTF-8'>");
client.println("<meta name='MobileOptimized' content='width' />");
client.println("<html>");
client.println("<body style='background-color:black;'>"); // Web Page Heading
client.println("<font color='grey'>");
client.println("<center><h1 style='color:orange'>CLUB ATLETISMO</h1>");
client.println("<center><h1 style='color:orange'>LEGANES</h1>");
client.println("<h2>Tiempos de Reacción</h2>");
client.println("<p>- Salida de Tacos -</p>");
client.println("<p><100ms: SALIDA NULA</p>");
//client.println(x);
client.println("<br><br>");
client.println("<h1 style='color:yellow'>");
client.print(resultado); // Mostramos el resultado, es decir el TR (Tiempo de reacción)
client.println(" ms</h1>");
client.println("<br><br>");
client.println(salida); // Mostramos Salida NULA o CORRECTA
client.println("<br><br>");
//Se crean botones con estilos
client.println("<button type='button' onClick=location.href='START=O' style='margin:auto; background-color:green; color:#A9F5A9; padding:5px; border:2px solid black; width:200;'><h2> -- GO --</h2> </button>");
client.println("<button type='button' onClick=location.href='START=F' style='margin:auto; background-color:red; color:#F6D8CE; padding:5px; border:2px solid black; width:200;'><h2> RESET</h2> </button><br><br>");
client.println(sensibilidadSTR); //Mostramos la sensibilidad del Acelerómetro
//Se crean 3 botones para modificar la sensibilidad del Acelerómetro
client.println("<button type='button' onClick=location.href='/START=L'> Sens BAJA </button>");
client.println("<button type='button' onClick=location.href='/START=M'> Sens MEDIA </button>");
client.println("<button type='button' onClick=location.href='/START=H'> Sens ALTA </button><br><br>");
client.println("</center></font></body></html>");
delay(1);
Serial.println("Petición finalizada"); // Se finaliza la petición al cliente. Se inicaliza la espera de una nueva petición.
}
ahora le daré una vuelta a las GPIO que son unt yanto especialitas en el arranque.
he podido ver que me hace cosas extrañas en GPIO2 donde tengo conectado el transistor, y mirando los datos técnicos he podido ver que al arrancar / reiniciar / activar, GPIO2 DEBE estar ALTO.
Como es la GPIO2 con la que voy a trabajar voy a ver como soluciono que no se me tire a masa por el transistor esa salida, ya que no arrancará, porque tiene que estar a nivel alto...
Colocando un PNP en lugar de NPN, el transistor estará abierto al arrancar dejando esa GPIO2 a nivel Alto, y cuando quiera activar el buzzer dejo esa salida a nivel Bajo... Voy a probar. . . .
Edito: cambiando al GPIO15 funciona correctamente ya que esta tiene que tener una configuración a nivel BAJO al arrancar
Hay ciertas reservas con los pines a usar en el ESP8266.
Revisa esto
Label
GPIO
Input
Output
Notes
D0
GPIO16
no interrupt
no PWM or I2C support
HIGH at boot
used to wake up from deep sleep
D1
GPIO5
OK
OK
often used as SCL (I2C)
D2
GPIO4
OK
OK
often used as SDA (I2C)
D3
GPIO0
pulled up
OK
connected to FLASH button, boot fails if pulled LOW
D4
GPIO2
pulled up
OK
HIGH at boot
connected to on-board LED, boot fails if pulled LOW
D5
GPIO14
OK
OK
SPI (SCLK)
D6
GPIO12
OK
OK
SPI (MISO)
D7
GPIO13
OK
OK
SPI (MOSI)
D8
GPIO15
pulled to GND
OK
SPI (CS)
Boot fails if pulled HIGH
RX
GPIO3
OK
RX pin
HIGH at boot
TX
GPIO1
TX pin
OK
HIGH at boot
debug output at boot, boot fails if pulled LOW
A0
ADC0
Analog Input
X
Ahi veras que GPIO2 o sea D4 esta pulled up, o sea tiene un resistor a 3.3V y esta HIGH en el arranque.
Tienes otros pines sin observaciones, usa alguno que diga OK
Olvidé explicar porque puse 11.
11 es la posicón que devuelve esta consulta
Como tengo que afinar tiempos
Y el tiempo de medida un bucle de 25 medidas y despues me saca una media ponderada u alguna instrucción mas...
Queria restar a la salida esos tiempos,
Veo que el modulo trabaja a 80-160Mhz
No se si esa frecuencia de reloj es la de cada instrucción,
es decir 1/160.000.000= 625 picoSegundos? Voy bien encaminado o el tiempo de cada instrucción no es equiparable a la frecuencia de reloj a la que trabaja.
Aunque yo creo que seria despreciable del orden de 2 o 3microSegundos
O mirandolo bien el cuello se botella seria el acelerómetro, no se, miraré cuanto tarda en recolectar una muestra, porque si es 1ms en este caso si seria sustancial, no mucho pero si sustancial
Tienes para medir micros() en microsegundos y millis() en milisegundos.
Las instrucciones puede ocupar 1,2, o mas ciclos reloj asi que la cuenta no es la de 1 ciclo.
Tienes que hacer un estudio pormenorizado de las instrucciones que el compilador ha usado para saber el tiempo involucrado.
Un promedio mas o menos efectivo sería usar micros y ver el tiempo que te indica. Con eso podrias ir acotando errores.