Para transmitir datos entre los dispositivos se usa una trama de 96 bits.
uint8_t frame[12]
El frame se interpreta de esta manera:
x | x x x x | x x x x | x x x [Ctrl] | [pA1] [pA2] [pA3] [pA4] | [pB1] [pB2] [pB3] [pB4] | [pC1] [pC2] [pC3]
Si bien el payload es genérico, según el byte de control los payload pA; pB y pC adquieren distintas funciones.
En cada dispositivo hay un switch case que procesa este byte y dependiendo del contenido, decide cómo procesar la carga de la trama.
Esta trama proviene del gateway, hay que probar a qué dispositivo iba dirigida. Para esto solamente es necesario comparar los 32 bits del payload B (pB) con el identificador único (devID) del dispositivo receptor.
0000 | x x x x | id0 id1 id2 id3 | x x x [Ctrl]|[pA1][pA2][pA3][pA4]|[pB1][pB2][pB3][pB4]|[pC1][pC2][pC3]
A station just sent a packet to the server. We should ignore it.
Another station is broadcasting its 32 bit ID string, attempting to register itself in a gateway with its ID.
Reforzar las líneas de GND, tanto del STM como de las Orange. Sin la masa extra se desconecta aleatoriamente.
La señal de entrada es la salida del mezclador de RF, después de acondicionar la amplitud a Vmax < 5v, la señal recibida tiene la particularidad que cuando no hay objetos en movimiento, el mezclador devuelve la portadora modulada de forma aleatoria (o al menos no es consistente como cuando hay un objetivo).
Por lo tanto se implementó por código un filtro, para únicamente tomar como válidas las lecturas de objetos en movimiento y de alguna forma descartar el ruido del radar en “reposo”.
La lógica es la siguiente, tipo autocorrelador de medias-longitudes de onda:
for de n repeticioneswhile se detectan los pulsos de la señal de entradaEl código:
while (1){ /* * ############################################## * CHECK FOR TIME CONSISTENCY * ############################################## * NO SÉ QUÉ MIERRRRDA HICEEEEEEEEEEEEEEEEE 😅😅😅😅😅😅 * podría tener dos variables auxiliares * auxA y auxB * espero al nivel alto/bajo * incremento auxA mientras dure el nivel * espero los 20ms y espero que termine el nivel donde caí * cuento de vuelta incrementando auxB con el ancho del puso * comparo A - B las veces que haga falta, mientras no me pase del 1000ms * también puedo usar un acumulador y la otra variable que sume un semiciclo y reste al siguiente * si están dentro de cierto límite, los pulsos son parecidos y puedo estimar que es una lectura válida * lo que estaría bueno, sería ponerle nombres un poco más descriptivos a las variables * por ej que una variable auxiliar o temporal se llame aux o temp * el minimo se llame min, el mázimo max, etc. No a, b, c, c_0, a_2, _aux0, etc * lo que hace es correr nsteps veces un bucle y guarda el ancho del pulso * en un array de nsteps elementos, después compara todos y guarda el más grande * contra el más chico, de esa forma sabe si es tolerable la variación */ while(!HAL_GPIO_ReadPin(GPIOB, RADAR_Pin)); // espera un nivel alto, para saber el contexto inicial for(i=0; i < nsteps; i++){ //_delayUsec(50); // qué poronga hace este delay??... chau //AFUERA /* * HIGH LEVEL ...‾‾‾‾‾‾‾‾... */ while(HAL_GPIO_ReadPin(GPIOB, RADAR_Pin)){ // aumenta un contador int de 16 bits inicializado en 0 mientras dure el pulso alto // mentira, solamente espera que el valor deje de ser 1 } // acá si salió del while significa que llegó el final del pulso // acá espera la friolera de 20 ms (a 1 kHz son 20 pulsos) // tampoco sé para qué hace esto 😅 // aaaacá está la papa, auxA tiene el ancho del pulso alto en algún momento // si lo guardo y comparo con el ancho de un pulso 20 ms después, // me debería mostrar la consistencia entre anchos de 2 pulsos aleatorios del tren de pulsos // si este delay lo pongo al principio no tengo que resincronizarme con los pulsos HAL_Delay(20); /* * FALLING EDGE ‾‾‾‾|_____ * qué pasa si cae en un nivel alto después del delay de 20ms?? gg * bueno, espero un par de pulsos más, así lo agarro completo */ while(HAL_GPIO_ReadPin(GPIOB, RADAR_Pin)); while(!HAL_GPIO_ReadPin(GPIOB, RADAR_Pin)); while(HAL_GPIO_ReadPin(GPIOB, RADAR_Pin)){ // acá una vez que empieza un nivel alto aleatorio, aumenta el valor de un entero de 16 bits // en el array de contener intentos _A_n[i]++; } /* * FALLING EDGE ‾‾‾|___ * en este punto ya tengo dos variables (A y B) con el largo de pulsos separados 20 ms uno del otro * mentira, tengo el ancho del pulso del enésimo bucle for */ // necesito guardar el más grande (A) y el más chico (B) y sacar la diferencia (0) if(i == 0){ /* para la primera vuelta, el máximo y el mínimo son lo mismo * */ auxA = _A_n[0]; auxB = _A_n[0]; } if(_A_n[i] > auxA){ // ahora, si esta vuelta es más grande que auxA, guardo en auxA auxA = _A_n[i]; } if(_A_n[i] < auxB){ // pero si esta vuelta es más chica que auxB, guardo en auxB auxB = _A_n[i]; } } // end FOR /* * me interesa saber la diferencia entre el más grande y el más chico * ya que esa diferencia es el fucking jitter, calculado de forma directa! * */ aux0 = auxA - auxB; /* * otra cosa que me interesa es el valor medio de aux0 en el tiempo * dice cuánto se incrementa el jitter * puedo hacer mean = (aux0(n) + mean)/2 */ meanJitter = (aux0 + meanJitter)/2; //ToDo: hacer configurable maxjitter y nsteps // hacer que desde alguna parte pueda poner los valores y un "send" para establecerlos // revisar los docs if(aux0 < maxJITTER){ // y si el resultado está dentro de lo permitido... // puedo tomar el tiempo T que demoran n pulsos // GetTick() se configura automáticamente con hal init // https://stackoverflow.com/questions/42747128/does-hal-gettick-return-ticks-or-milliseconds-and-how-to-measure-in-microsec timerTick_0 = HAL_GetTick(); for(i=0; i<(100*nsteps); i++){ while(HAL_GPIO_ReadPin(GPIOB, RADAR_Pin)); while(!HAL_GPIO_ReadPin(GPIOB, RADAR_Pin)); } // T_00ms contiene los ms x100 de cada pulso // o sea T_00ms == 100 significa que cada periodo fue de 1 ms // después se implementa la matemática para pasar de T a velocidad // la frecuencia mucho no me sirve, pero sería (100/T_00ms)x10³ T_00ms = (HAL_GetTick() - timerTick_0)/nsteps; } else{ T_00ms = 0; } } /* ################################################## * * USER CODE END WHILE * * ################################################## * */ /* USER CODE BEGIN 3 */ /* USER CODE END 3 */ }
Palabras clave Dedicatoria y agradecimientos Resumen Abstract Índice de Figuras Índice de Tablas 1. Introducción 1.1 Contexto temático 1.2 Definición del problema 1.3 Motivación 1.4 Objetivos 1.4.1 Objetivo general 1.4.2 Objetivos específicos 1.5 Contribución esperada y alcance 1.6 Metodología 2. Marco teórico 2.1 Internet de las cosas (IoT) 2.1.1 ¿Qué es IoT o ‘Internet de las cosas’? 2.1.2 IoT Industrial 2.2 Bases de Datos 2.2.1 Redis 2.2.2 InfluxDB 2.3 STM32 2.3.1 STM32F103 2.4 Arquitectura ARM 2.4.1 H3 Quad-core Cortex-A7 2.4.2 Linux sobre Plataformas ARM 2.5 Lenguajes de programación 2.5.1 Lenguaje C 2.5.2 Python en Sistemas Embebidos 2.6 Radar Doppler Microondas 2.6.1 Generalidades 2.6.1.1 Introducción, Principios Básicos y Características Generales 2.6.1.2 Radar Doppler 2.6.1.3 Bandas de Radiofrecuencia y Aplicaciones 2.6.1.4 Bandas I/J (Radares de Banda X y Ku) 2.6.1.5 Implementación del radar Doppler 2.6.2 Uso en metrología legal 2.6.3 Filtrado Analógico 2.6.4 Filtrado Digital 2.6.4.1 Filtrado por Autocorrelación 3. Diseño 3.1 Diseño del Sistema 3.1.1 Diagrama General del Sistema Propuesto 3.1.2 Selección de Dispositivos de Cómputo (MCUs y CPUs) 3.1.2.1 Selección de los microcontroladores 3.1.2.2 Selección de los CPU para los gateways 3.1.3 Selección de Sensores y Periféricos 3.1.4 Selección de Software 3.1.5 Diseño del Endpoint 3.1.6 Diseño del Gateway 3.1.7 Diseño de la Aplicación Web 4. Implementación 4.1 Enfoque y metodología 4.2 Implementación del Endpoint 4.2.1 Implementación del contador de frecuencia y filtrado 4.2.1.1 Contador de frecuencia 4.2.1.2 Filtrado 4.2.2 Implementación de las comunicaciones 4.2.3 Display 4.2.4 Acondicionamiento de la entrada de señal del radar 4.3 Implementación del Gateway 4.4 Implementación de la aplicación web 5. Pruebas 5.1 Optimización del filtro autocorrelador 5.1.1 Mediciones en reposo / solo ruido de fondo 5.1.2 Mediciones de la señal de calibración 5.1.3 Costo computacional de leer el GPIO 5.2 Pruebas de interferencia 5.3 Simulación con un generador de señales 5.4 Pruebas sobre vehículos 6. Análisis de Resultados Experimentales y Discusión 7. Conclusiones 7.1 Recomendaciones para versiones futuras Bibliografía Anexo A: Bucle infinito del endpoint Anexo B: Callbacks del MCU B.1 Interrupción del temporizador B.2 Interrupción DMA (Buffer UART Rx) Anexo C: Bucle infinito del gateway