Un sensor PIR común solo ve movimiento: si te quedas quieto leyendo en la cama, para él dejaste de existir y la luz se apaga. Un radar de ondas milimétricas no tiene ese problema, porque detecta incluso el leve movimiento del pecho al respirar. Con esa misma capacidad puede estimar tu frecuencia respiratoria y cardíaca, y saber si estás dormido, sin cables ni pulseras.
En esta guía vas a armar un sistema de monitoreo sin contacto con el radar DFRobot C1001 de 60 GHz, un ESP32 y una pantalla OLED SSD1306, con una cámara térmica AMG8833 opcional. Con el mismo hardware se cargan tres programas distintos: seguimiento de posición en vivo, registro del sueño y medición de pulso y respiración. Los datos viajan por WiFi a un computador, que los muestra en una página web. Al final te proponemos usarlo para lo que más rinde en una casa: un detector de presencia de verdad para domótica en el dormitorio.

Es un proyecto educativo. El pulso, la respiración y las etapas de sueño que muestra son estimaciones del módulo y no sirven para diagnóstico ni para un estudio clínico del sueño.
Cómo "ve" un radar de 60 GHz
El radar emite una señal que sube de frecuencia de forma continua (un chirp) y escucha el eco. Como el eco vuelve con un pequeño retardo, la diferencia de frecuencia entre lo emitido y lo recibido indica la distancia al objeto. Para el movimiento fino se usa la fase del eco: a 60 GHz la longitud de onda es de unos 5 mm, así que un desplazamiento de apenas un milímetro del pecho cambia la fase de forma medible. La respiración mueve el tórax varios milímetros; el latido, décimas de milímetro. Separando esas dos oscilaciones por su frecuencia, el radar estima ambas tasas.
Todo ese procesamiento ocurre dentro del módulo C1001. El ESP32 no toca la señal de radio: recibe informes ya calculados (presencia, movimiento, distancia, posición, respiración, pulso, estado del sueño) por UART.
Datos del C1001 (SEN0623)
- Radar de 60 GHz para detección de personas.
- Alimentación de 5 V en VIN, lógica UART de 3,3 V.
- UART a 115200 baudios, 8 bits, sin paridad, 1 bit de parada.
- Dos modos de trabajo: detección de caídas (pensado para montaje en el techo) y sueño (al lado o sobre la cama).
- Informes de presencia, movimiento, distancia, posición, pulso, respiración, estado en cama, etapas del sueño y estadísticas.

El proyecto original se probó con un módulo con firmware G60SM1SYv010109. Algunas respuestas a comandos dependen de esa versión, así que otro firmware puede comportarse distinto.
Para qué está la cámara térmica
El radar actualiza la posición más o menos cada dos segundos, lo que hace que el marcador en pantalla avance a saltos. La AMG8833 es una matriz de 8 × 8 sensores infrarrojos (64 temperaturas, unos 60° de campo de visión, 10 cuadros por segundo) que encuentra la zona más caliente de la imagen y calcula hacia qué lado está. El programa combina la distancia del radar con el ángulo de la cámara térmica para mover el marcador diez veces por segundo. La cámara no mide distancia, y otro objeto caliente (una estufa, un perro) puede confundir el ángulo.
Arquitectura

Hay tres partes: los sensores, el ESP32 y la interfaz. El radar habla por UART; la cámara térmica y la OLED comparten el bus I2C. El ESP32 lee, actualiza la OLED y manda paquetes UDP por WiFi a un programa en Python que corre en el computador. Ese programa sirve la página web, que puedes abrir también desde el celular si está en la misma red.
Conexiones

Radar C1001 al ESP32:
| Pin del C1001 | ESP32 |
|---|---|
| VIN | 5 V |
| GND | GND |
| TX | GPIO16 (RX del ESP32) |
| RX | GPIO17 (TX del ESP32) |
Las líneas UART van cruzadas: lo que transmite el sensor lo recibe el ESP32. No alimentes el radar desde la salida de 3,3 V del ESP32: necesita 5 V en VIN y comparte la tierra con el ESP32.
OLED y AMG8833 al ESP32 (ambos a 3,3 V, en el mismo bus):
| Pin | ESP32 |
|---|---|
| VCC | 3,3 V |
| GND | GND |
| SDA | GPIO21 |
| SCL | GPIO22 |
La OLED responde en la dirección 0x3C y la AMG8833 en 0x69, así que conviven sin conflicto en el mismo bus.
El original monta todo en una PCB con zócalos hembra, y conecta el radar y la cámara térmica con cuatro cables cada uno para poder orientarlos sin mover la placa. En una protoboard funciona igual.


Dónde poner el radar
La ubicación decide más que el código.
Para seguir la posición, el radar y la cámara térmica miran hacia la zona observada y tienen que quedar fijos uno respecto del otro. Al configurarlo, camina de un lado al otro: si te mueves a la izquierda, el marcador tiene que ir a la izquierda.

Para el sueño, el pulso y la respiración, el radar va al lado de la cama o un poco por encima del pecho, apuntando al tórax. El original usa cerca de un metro de distancia y una inclinación hacia abajo de 30° a 45°. La ventana útil para medir el pecho es de unos 0,4 a 1,5 m, pero es una guía, no una garantía.

Un radar en el centro de un techo alto detecta presencia, pero rara vez entrega pulso o respiración. Si la pantalla dice "presencia" y las tasas no aparecen, revisa la dirección y la distancia al pecho antes de tocar el programa.
El software
Lo que necesitas
- Arduino IDE con el paquete de placas de Espressif, eligiendo ESP32 Dev Module.
- Las librerías Adafruit GFX, Adafruit SSD1306 y Adafruit BusIO.
- Python 3 en el computador. Los servidores usan solo la librería estándar: no hay que instalar nada con pip.
Los programas leen el radar directamente por UART y la cámara térmica por Wire, sin librerías de DFRobot ni de la AMG8833. Hay una buena razón: el autor descubrió que la función track() de la librería de DFRobot lee un registro equivocado (el 0x83/0x8E, que según el manual del fabricante del radar es la consulta de proporción de altura, no la posición).
Tres aplicaciones, nueve archivos
Cada aplicación tiene un programa para el ESP32 y dos archivos para el computador (server.py e index.html). Se guardan dentro de una carpeta C1001_Monitor:
| Aplicación | Programa del ESP32 | Archivos del computador | Puerto UDP | Dirección en el navegador |
|---|---|---|---|---|
| Seguimiento en vivo | HeatGate/HeatGate.ino |
radar/server.py, radar/index.html |
4210 | http://127.0.0.1:8080 |
| Monitor de sueño | SleepWatch/SleepWatch.ino |
sleep/server.py, sleep/index.html |
4211 | http://127.0.0.1:8081 |
| Pulso y respiración | WaveWatch/WaveWatch.ino |
wave/server.py, wave/index.html |
4212 | http://127.0.0.1:8082 |
Solo un programa corre a la vez en el ESP32; el cableado no cambia, y la cámara térmica solo la usa el seguimiento. No mezcles los tres programas en un mismo proyecto de Arduino.
Configurar la red
El ESP32 se conecta a una red WiFi de 2,4 GHz y el computador tiene que estar en la misma red local. Evita las redes de invitados, que suelen aislar a los clientes entre sí. Cambia estas tres líneas al principio del programa que elijas:
static const char *WIFI_SSID = "YOUR_SSID";
static const char *WIFI_PASS = "YOUR_PASSWORD";
static const IPAddress HOST_HINT(192, 168, 1, 100); // Your laptop's IPv4 address.
192.168.1.100 es solo un ejemplo: pon la IPv4 de tu computador (en Windows, ipconfig) como cuatro números separados por comas. Permite en el firewall el tráfico UDP entrante de Python y, si vas a mirar desde el celular, el puerto TCP de la página.
Cargar y abrir
- Abre el
.inoelegido, selecciona ESP32 Dev Module y el puerto, y súbelo. - Abre el monitor serie a 115200 baudios para ver la conexión WiFi y el arranque de los sensores.
- Desde la carpeta
C1001_Monitor, ejecuta por ejemplopython radar/server.py. - Abre la dirección de la tabla en el navegador. No abras
index.htmlcon doble clic: la página necesita al servidor. Desde el celular, cambia127.0.0.1por la IP del computador.
El seguimiento en vivo por dentro
HeatGate.ino pone el radar en modo sueño, que entrega la posición en el plano (x lateral, y hacia adelante, z en centímetros) y la distancia. Manda un paquete UDP de 53 bytes unas diez veces por segundo; ojo, esa es la frecuencia de la red, no diez mediciones nuevas del radar por segundo.
Un detalle curioso: las coordenadas del radar vienen en formato signo y magnitud (el bit 15 indica el signo y los 15 bits bajos son centímetros), no en complemento a dos como casi todo lo demás. Por eso el programa las convierte con su propia función.
Así lee el programa la cámara térmica, registro por registro y sin librería:
// AMG8833 8x8 thermal camera, 60 deg field of view, 10 frames per second.
// The radar gives range every 2 s; the camera gives the left/right angle
// ten times a second. The blip is placed at radar range, thermal bearing.
static const uint8_t AMG_ADDR = 0x69;
static const float AMG_FOV_DEG = 60.0f;
// Which image axis runs left/right in front of the radar, and its sign
// relative to the radar's +x. Set from a capture with the person moving.
static const bool THERM_USE_ROWS = false;
static const float THERM_SIGN = 1.0f;
static const float DEG2RAD = 0.0174533f;
static bool amgOk = false;
static float thermPix[64];
static bool thermValid = false;
static float thermBearDeg = 0;
static float thermCol = 0, thermRow = 0, thermMax = 0, thermMed = 0;
static int thermN = 0;
static uint32_t thermMs = 0;
static uint32_t thermGoodMs = 0;
static int16_t outX = 0, outY = 0;
static bool outTherm = false;
static void amgWrite(uint8_t reg, uint8_t v) {
Wire.beginTransmission(AMG_ADDR);
Wire.write(reg);
Wire.write(v);
Wire.endTransmission();
}
static bool amgBegin() {
Wire.beginTransmission(AMG_ADDR);
if (Wire.endTransmission() != 0) return false;
amgWrite(0x00, 0x00); // normal mode
amgWrite(0x01, 0x3f); // initial reset
delay(10);
amgWrite(0x02, 0x00); // 10 fps
return true;
}
// Pixels 0x80..0xFF: 12-bit two's complement, 0.25 C per LSB, row-major.
static bool amgRead() {
for (int chunk = 0; chunk < 4; chunk++) {
Wire.beginTransmission(AMG_ADDR);
Wire.write(0x80 + chunk * 32);
if (Wire.endTransmission(false) != 0) return false;
if (Wire.requestFrom(static_cast<int>(AMG_ADDR), 32) != 32) return false;
for (int i = 0; i < 16; i++) {
uint8_t lo = Wire.read();
uint8_t hi = Wire.read();
int raw = ((hi << 8) | lo) & 0x0fff;
if (raw & 0x0800) raw -= 4096;
thermPix[chunk * 16 + i] = raw * 0.25f;
}
}
return true;
}
Cada píxel es un número de 12 bits en complemento a dos con resolución de 0,25 °C. Luego el programa calcula la mediana de los 64 valores, se queda con los píxeles claramente más calientes y saca su centro de gravedad. Si el movimiento sale invertido, cambia THERM_SIGN; si la cámara quedó girada, THERM_USE_ROWS elige el otro eje.
Detector de presencia para domótica en el dormitorio
El uso más práctico de este radar en una casa no es medir el pulso, sino resolver el problema del PIR: saber si hay alguien en la pieza aunque esté inmóvil. Algunas ideas para llevarlo ahí:
- Luces que no se apagan contigo adentro. Usa el informe de presencia (y no el de movimiento) para mantener encendida la luz del dormitorio y apágala solo tras unos minutos sin presencia.
- Rutina de noche automática. El estado "en cama" del modo sueño puede bajar la calefacción, cerrar cortinas o silenciar notificaciones cuando te acuestas.
- Integración con Home Assistant. En vez de mandar los datos a un servidor en Python, publica presencia y estado en cama por MQTT; Home Assistant los toma como sensores y los usa en sus automatizaciones.
Una nota de privacidad: el radar no graba imágenes, lo que lo hace más aceptable que una cámara en un dormitorio. Aun así, los datos de sueño son personales; mantén el servidor dentro de tu red local, como recomienda el original.
Errores comunes
- No llega nada del radar. Revisa que TX y RX estén cruzados y que el radar tenga 5 V en VIN, no 3,3 V.
- La página no muestra datos. El computador y el ESP32 tienen que estar en la misma red, y el firewall tiene que dejar pasar el UDP de Python.
- Hay presencia pero no pulso ni respiración. El radar no está apuntando al pecho o está fuera de la ventana de 0,4 a 1,5 m.
- El marcador se va hacia un rincón. Probablemente la cámara térmica está viendo una fuente de calor. Sácala del campo de visión o desactiva el aporte térmico.
Variantes y mejoras
- Una versión más barata solo de presencia. Si lo que quieres es domótica y no signos vitales, un sensor de presencia estática de 24 GHz es más simple y suficiente para mantener una luz encendida mientras estás quieto.
- Pantalla en el velador. Cambia la OLED por una pantalla más grande y muestra un resumen de la noche anterior al despertar.
- Alerta de caída para adultos mayores. El modo de detección de caídas del C1001, con el radar en el techo del baño, puede mandar un aviso al celular de un familiar.
Personalización para Chile
En Chile consigues buena parte del montaje en MechatronicStore:
- ESP32 con Wifi y Bluetooth ESP 32 ESP WROOM-32 ESP32S Tipo C (SKU X2-10V2): el ESP32 clásico que pide el proyecto (ESP32 Dev Module).
- Pantalla Oled 128x64 I2C 0.96" SSD1315 (SKU D-111): la misma resolución, tamaño y bus I2C que la SSD1306 del original. El SSD1315 es compatible con la librería Adafruit SSD1306 en el uso habitual.
- Breadboard / Protoboard 830 puntos MB102 (SKU C-302) y Cables macho hembra 40 piezas 20cm (SKU C-412): para armarlo sin PCB y orientar los sensores con libertad.
El radar C1001 de 60 GHz y la cámara térmica AMG8833 no están en el catálogo.
Recursos
- Tutorial original (inglés): Human Tracking & Vital Signs Monitor: ESP32, C1001 & AMG8833, en el que se basa esta guía, con el código completo de los nueve archivos.
- Esquemático en PDF: descarga
- Archivos Gerber de la PCB: descarga
- Librería de la pantalla: Adafruit SSD1306
Versión chilena con componentes en stock local en MechatronicStore.








