Contenido detallado
🗣️ Cómo «habla» un sensor con la placa
Antes de conectar cualquier sensor, averigua en qué «idioma» entrega el dato. Hay cuatro: digital (sí o no, como «hay un obstáculo»), analógica (un voltaje que varía, como la reflectancia del suelo), ancho de pulso (el dato está en la duración de un pulso, como en el HC-SR04) y bus (el sensor envía números ya preparados mediante un protocolo, como I2C). El idioma determina el pin, la función de lectura y las precauciones eléctricas.
🌱 ¿Eres nuevo aquí?
Un módulo sensor es el sensor ya montado en una plaquita con resistencias y, a veces, un comparador que transforma la señal analógica en digital. La hoja de datos (datasheet) es el documento del fabricante que indica el voltaje de trabajo, los pines y los tiempos. Un bus es un par de cables compartido por varios dispositivos, cada uno con su dirección.
Cómo leer: cada cuadro es un idioma, con la función de Arduino que lo entiende en una esquina. Arriba (verde), el valor está en el nivel del voltaje. Abajo (cian), el valor está en el TIEMPO: en la duración del pulso o en la secuencia de bits. Los de abajo requieren que el programa espere o se comunique, por eso aparecen de nuevo en el tema 6.
| Sensor del kit | Idioma | Alimentación | Precaución |
|---|---|---|---|
| HC-SR04 | ancho de pulso | 5 V | ECHO regresa en 5 V: divisor |
| IR de obstáculos | digital | 3,3 V | ajustar el trimpot |
| TCRT5000 (línea) | analógico (AO) o digital (DO) | 3,3 V | usar un pin del ADC1 |
| VL53L0X, MPU-6050 | I2C | 3,3 V (módulo) | direcciones diferentes |
Por qué aprender
Cuando conoces el idioma, cualquier sensor nuevo se convierte en una pregunta rápida: qué pin, qué función, qué voltaje. Dejas de depender de un tutorial para cada pieza y empiezas a leer la hoja de datos.
Conceptos clave
🦇 HC-SR04: distancia por eco
O HC-SR04 funciona como un murciélago. Envías un pulso corto al pin TRIG; emite un chillido ultrasónico (40 kHz, que no puedes oír) y mantiene el pin ECHO en nivel alto hasta que regresa el eco. La duración de ese pulso es el tiempo de ida y vuelta. Como el sonido viaja a unos 343 m/s (0,0343 cm por microsegundo), la distancia es duración × 0,0343 ÷ 2, dividido entre 2 porque el sonido fue y volvió.
Cómo leer: arriba, el recorrido del sonido hasta el obstáculo y de vuelta. En el medio, las dos señales a lo largo del tiempo: el pulso corto de TRIG y el pulso largo de ECHO, cuyo ancho es lo que mides. A la derecha, la protección: ECHO sale en 5 V y pasa por el divisor 1 kΩ/2 kΩ, que entrega unos 3,3 V al GPIO 18. TRIG puede conectarse directamente: 3,3 V del ESP32 bastan para activarlo.
Montaje en tres pasos
Alimentación
VCC a 5 V (pin VIN/5V del DevKit alimentado por USB) y GND al GND común. La versión HC-SR04P acepta 3,3 V y no necesita el divisor; comprueba cuál tienes.
TRIG directo
TRIG al GPIO 5, con un jumper simple.
ECHO por el divisor
ECHO → 1 kΩ → punto medio → GPIO 18; desde el punto medio, 2 kΩ hasta GND. Cálculo del módulo 1.2: 5 × 2 ÷ 3 ≈ 3,3 V. En Wokwi no hace falta el divisor, pero móntalo para practicar.
Objetivo: medir la distancia cinco veces por segundo y mostrarla en centímetros, avisando cuando no haya eco. En Wokwi, agrega «HC-SR04» y haz clic en él durante la simulación para cambiar la distancia.
// HC-SR04: distancia por eco (ESP32, paquete esp32 3.x)
const int PINO_TRIG = 5;
const int PINO_ECHO = 18; // mediante el divisor 1k/2k en el hardware real
const unsigned long TIMEOUT_US = 30000; // ~5 m: sin eco después de eso
float medirCm() {
digitalWrite(PINO_TRIG, LOW); delayMicroseconds(2);
digitalWrite(PINO_TRIG, HIGH); delayMicroseconds(10); // pulso de activación
digitalWrite(PINO_TRIG, LOW);
unsigned long dur = pulseIn(PINO_ECHO, HIGH, TIMEOUT_US);
if (dur == 0) return -1; // ningún eco
return dur * 0.0343 / 2.0; // cm (ida y vuelta)
}
void setup() {
Serial.begin(115200);
pinMode(PINO_TRIG, OUTPUT);
pinMode(PINO_ECHO, INPUT);
Serial.println("HC-SR04 pronto");
}
void loop() {
float cm = medirCm();
if (cm < 0) Serial.println("sin eco (demasiado lejos o superficie blanda)");
else { Serial.print("distancia: "); Serial.print(cm, 1); Serial.println(" cm"); }
delay(200);
}
Cómo verificar
- ✓Con la mano a unos 20 cm del sensor: el Monitor muestra cerca de «distancia: 20.0 cm»; compruébalo con una regla (un error de 1 a 2 cm es normal).
- ✓En Wokwi, el valor sigue el control deslizante del sensor.
- ✗¿Siempre aparece «sin eco»? Comprueba que haya 5 V en VCC y que TRIG y ECHO no estén intercambiados.
✓ El HC-SR04 detecta bien
- ✓Una pared, una caja o la pata de una silla de frente.
- ✓Entre unos 2 cm y 2 a 3 m, en interiores.
- ✓Superficies duras y lisas.
✗ El HC-SR04 se confunde
- ✗Cortina, sofá, cojín: absorben el sonido.
- ✗Una pared muy inclinada: el eco se desvía hacia un lado.
- ✗Dos HC-SR04 activados al mismo tiempo: uno escucha el eco del otro.
Por qué aprender
Es el «ojo» del rover que esquiva obstáculos en el módulo 1.6. Conocer sus límites (superficies blandas, ángulos) explica por qué el robot a veces choca con una cortina y no con una pared.
Conceptos clave
🔦 Infrarrojo: línea y obstáculos
Los sensores infrarrojos (IR) de reflexión tienen un LED que emite luz invisible y un receptor al lado. Una superficie clara refleja mucho; una superficie negra absorbe. En el sensor de línea (TCRT5000), apuntado al suelo a pocos milímetros, esto permite distinguir la cinta negra del piso. En el sensor de obstáculos, apuntado hacia adelante, un objeto cercano devuelve luz y el módulo avisa. Muchos módulos incluyen un comparador con trimpot (tornillito azul) que transforma la señal analógica en digital.
🌱 ¿Eres nuevo aquí?
O umbral (threshold) es el valor que separa «línea» de «suelo»: por encima es una cosa, por debajo es otra. Calibrar consiste en medir el valor en la zona clara y en la oscura de la superficie real y poner el umbral a la mitad. En muchos módulos, la salida digital DO queda en LOW cuando detecta; comprueba el LED indicador de la plaquita.
Cómo leer: las flechas rojas representan la luz infrarroja. A la izquierda vuelve toda; en el centro, casi nada vuelve. En los módulos TCRT5000 comunes, menos luz en el receptor = un número MAYOR en el ADC (los valores 300 y 3500 son ejemplos; los tuyos serán distintos). A la derecha, la regla: el umbral queda a mitad de camino entre la lectura del claro y la del negro, medidas en el piso que usarás.
Objetivo: calibrar el sensor de línea (AO en GPIO 35) durante los primeros 5 segundos, pasándolo sobre el claro y el negro, y después indicar «LINHA» o «chao»; leer al mismo tiempo un sensor de obstáculos (DO en GPIO 27). En Wokwi, usa un potenciómetro en lugar del AO y un botón en lugar del DO.
// IR de línea (analógico) con calibración + IR de obstáculos (digital)
const int PINO_LINHA = 35; // AO del TCRT5000, ADC1
const int PINO_OBST = 27; // DO del módulo de obstáculos
int minimo = 4095, maximo = 0, limiar = 2048;
void setup() {
Serial.begin(115200);
pinMode(PINO_OBST, INPUT_PULLUP); // mantiene el nivel si el módulo está desconectado
Serial.println("Calibrando por 5 s: pasa el sensor por el claro y el negro");
unsigned long inicio = millis();
while (millis() - inicio < 5000) {
int v = analogRead(PINO_LINHA);
if (v < minimo) minimo = v;
if (v > maximo) maximo = v;
delay(5);
}
limiar = (minimo + maximo) / 2;
Serial.print("min="); Serial.print(minimo);
Serial.print(" max="); Serial.print(maximo);
Serial.print(" limiar="); Serial.println(limiar);
}
void loop() {
int v = analogRead(PINO_LINHA);
bool naLinha = (v > limiar); // negro = valor alto
bool obstaculo = (digitalRead(PINO_OBST) == LOW); // muchos módulos: LOW = detectó
Serial.print("linha="); Serial.print(v);
Serial.print(naLinha ? " LINHA" : " chao");
Serial.println(obstaculo ? " | OBSTACULO" : " | livre");
delay(100);
}
Cómo verificar
- ✓Después de la calibración, «max» debe ser mucho mayor que «min» (una diferencia de cientos o más).
- ✓Sobre la cinta aparece «LINHA»; fuera de ella, «chao». Pon la mano a pocos cm del sensor de obstáculos: «OBSTACULO».
- ✗¿min y max casi iguales? El sensor está demasiado alto (lo ideal es dejarlo entre unos 3 y 10 mm del piso) o no lo pasaste sobre el negro.
Por qué aprender
Son los sensores más baratos del kit y la base del seguidor de línea de la Trilha 2, donde cinco de ellos, uno al lado del otro, forman una barra. La calibración automática que acabas de escribir es la misma que usa el proyecto 2.6.
Conceptos clave
📉 Ruido y filtro de promedio
Ningún sensor da el mismo número dos veces. La lectura «salta» por ruido eléctrico, vibración, eco perdido. A veces aparece un valor absurdo (0 cm, 900 cm) que, si el robot lo toma en serio, hace que frene de repente. Dos herramientas sencillas resuelven casi todo: descartar lo que esté fuera del rango posible y calcular el promedio móvil de las últimas N lecturas válidas.
🌱 ¿Eres nuevo aquí?
A promedio móvil guarda las últimas N lecturas en una lista circular y devuelve su promedio; con cada lectura nueva, sale la más antigua. La mediana ordena los valores y toma el del medio; es excelente contra los picos aislados. El costo del filtro es el retraso: con N grande, la curva queda lisa, pero tarda en reaccionar.
Cómo leer: la línea cian es lo que entrega el sensor; la verde es lo que debe usar el robot. Los círculos rojos son lecturas imposibles, descartadas antes de calcular el promedio. Observa que, cuando el objeto se acerca, la línea verde baja un poco después que la cian: ese es el retraso del filtro, pequeño con 5 muestras.
Objetivo: aplicar descarte + promedio móvil de 5 lecturas al HC-SR04 del tema 2 y ver ambas curvas juntas en el Serial Plotter.
// Descarte + promedio móvil en el HC-SR04 (ESP32, paquete esp32 3.x)
const int PINO_TRIG = 5, PINO_ECHO = 18;
const int N = 5; // tamaño de la ventana
float janela[N];
int pos = 0, cheias = 0;
float medirCm() {
digitalWrite(PINO_TRIG, LOW); delayMicroseconds(2);
digitalWrite(PINO_TRIG, HIGH); delayMicroseconds(10);
digitalWrite(PINO_TRIG, LOW);
unsigned long dur = pulseIn(PINO_ECHO, HIGH, 30000);
return (dur == 0) ? -1 : dur * 0.0343 / 2.0;
}
float filtrar(float novo) {
janela[pos] = novo; pos = (pos + 1) % N; // lista circular
if (cheias < N) cheias++;
float soma = 0;
for (int i = 0; i < cheias; i++) soma += janela[i];
return soma / cheias;
}
void setup() {
Serial.begin(115200);
pinMode(PINO_TRIG, OUTPUT); pinMode(PINO_ECHO, INPUT);
}
void loop() {
float cru = medirCm();
static float filtrado = 0;
if (cru >= 2 && cru <= 400) filtrado = filtrar(cru); // descarta lo imposible
Serial.print("cru:"); Serial.print(cru);
Serial.print(",filtrado:"); Serial.println(filtrado);
delay(60); // HC-SR04 pide unos 60 ms entre mediciones
}
Cómo verificar: en el Serial Plotter, «cru» tiene dientes y picos (incluido -1 cuando falta el eco) y «filtrado» es una línea lisa que sigue tu mano con un pequeño retraso. Cambia N a 15 y observa cómo aumenta el retraso.
✓ Filtrar la medición
- ✓Primero descarta; después calcula el promedio.
- ✓Ventana pequeña (3 a 7) para decidir rápido.
- ✓Usa la mediana cuando los picos son poco frecuentes y enormes.
✗ Un filtro que estorba
- ✗Promedio de 50 lecturas: el robot detecta la pared demasiado tarde.
- ✗Incluir el -1 de «sin eco» en el promedio.
- ✗Filtrar en el código un ruido causado por un cable suelto.
Por qué aprender
Un robot que reacciona al ruido frena, gira y duda sin motivo. Con el filtro, la decisión del módulo 1.6 es confiable. En la Trilha 2, la misma idea aparece como filtro complementario de la IMU y filtro en la derivada del PID.
Conceptos clave
🔗 Sensores I2C: dos cables, varios sensores
O I2C es un bus de dos cables, SDA (datos) y SCL (reloj), compartido por varios dispositivos. Cada uno tiene una dirección de 7 bits, escrita en hexadecimal: el sensor láser de distancia VL53L0X suele responder en 0x29, la IMU MPU-6050 en 0x68 y la pequeña pantalla OLED en 0x3C. En el ESP32 clásico, los pines predeterminados son SDA = GPIO 21 e SCL = GPIO 22, y la biblioteca es la Wire, que ya viene en el paquete.
Cómo leer: las dos líneas horizontales representan todo el bus. Cada módulo cian se conecta a ellas con dos cables (puntos blancos) y solo responde cuando el ESP32 llama a su dirección. Las resistencias ámbar mantienen las líneas en 3,3 V cuando nadie se comunica; la mayoría de los módulos ya trae estos pull-ups en la placa. Además de SDA y SCL, cada módulo necesita 3,3 V y GND.
Del inicio al primer número
Conecta cuatro cables
VCC → 3,3 V, GND → GND, SDA → GPIO 21, SCL → GPIO 22.
Ejecuta el escáner
Pregunta quién responde en cada una de las 127 direcciones. Si aparece tu sensor, el cableado está correcto.
Instala la biblioteca del sensor
Herramientas → Administrar bibliotecas. Para el VL53L0X, busca «VL53L0X» e instala la de Pololu. Abre uno de sus ejemplos en Archivo → Ejemplos para comprobar la versión.
Objetivo: listar todos los dispositivos I2C conectados en el Monitor Serial. En Wokwi, agrega un "MPU6050" conectado a 21/22 y el escáner debería encontrar 0x68.
// Escáner I2C: ¿quién está en el bus? (ESP32, paquete esp32 3.x)
#include <Wire.h>
void setup() {
Serial.begin(115200);
Wire.begin(); // SDA 21, SCL 22 en el ESP32 clásico
delay(300);
Serial.println("Buscando dispositivos I2C...");
int achados = 0;
for (byte endereco = 1; endereco < 127; endereco++) {
Wire.beginTransmission(endereco);
if (Wire.endTransmission() == 0) { // 0 = alguien respondió
Serial.print(" encontrado en 0x");
if (endereco < 16) Serial.print("0");
Serial.println(endereco, HEX);
achados++;
}
}
Serial.print(achados); Serial.println(" dispositivo(s).");
}
void loop() {}
Cómo verificar: con un VL53L0X, aparece "encontrado en 0x29" y "1 dispositivo(s)."; con el MPU-6050 de Wokwi, 0x68. Cero dispositivos = SDA y SCL intercambiados, falta GND o el módulo no tiene alimentación.
Objetivo: leer la distancia en milímetros del VL53L0X (placa real; Wokwi no tiene esta pieza), con la biblioteca VL53L0X de Pololu.
// Distancia por láser VL53L0X mediante I2C (biblioteca VL53L0X de Pololu)
#include <Wire.h>
#include <VL53L0X.h>
VL53L0X sensor;
void setup() {
Serial.begin(115200);
Wire.begin();
sensor.setTimeout(500);
if (!sensor.init()) {
Serial.println("VL53L0X no encontrado: revisa los cables y la dirección");
while (true) delay(1000);
}
sensor.startContinuous(); // mide sin parar
}
void loop() {
int mm = sensor.readRangeContinuousMillimeters();
if (sensor.timeoutOccurred()) Serial.println("timeout");
else { Serial.print("distancia: "); Serial.print(mm); Serial.println(" mm"); }
delay(100);
}
Cómo verificar: con la mano a 10 cm, aparece algo cercano a "distancia: 100 mm"; sin nada enfrente (a más de unos 1,2 m), valores cercanos a 8190 indican "fuera de alcance".
Por qué aprender
Las IMU, las pantallas y los sensores de color, presión y distancia por láser usan I2C. Con dos pines conectas varios, algo que te hará falta en la Trilha 2, cuando el robot tenga IMU y encoders y empiecen a escasear los pines.
Conceptos clave
⏱️ Leer varios sensores sin bloquear
Un delay(500) parece inofensivo, pero durante ese medio segundo el ESP32 no hace nada más: no lee el IR, no ve la pared, no detiene el motor. La solución es cambiar la espera por una pregunta: "¿ya pasó suficiente tiempo desde la última vez?", usando millis(). Cada sensor tiene su propio reloj y el loop() gira miles de veces por segundo, atendiendo a quien le toque.
🌱 ¿Eres nuevo aquí?
Código bloqueante es lo que detiene todo mientras espera (como delay). No bloqueante revisa el reloj y sigue adelante. Una tarea periódica es un fragmento de código que se ejecuta cada X milisegundos. La cuenta millis() - ultimo >= intervalo, con unsigned long, sigue siendo correcta incluso cuando el contador da la vuelta, después de unos 49 días encendido.
Cómo leer: arriba, cada bloque rojo representa medio segundo en que el programa está sordo y ciego; el obstáculo (línea ámbar) solo se detecta en la siguiente lectura. Abajo, tres tareas con ritmos propios: IR cada 10 ms, distancia cada 60 ms, mensaje cada 250 ms. Ninguna espera a las otras, y el obstáculo se detecta en la próxima lectura de distancia.
Objetivo: combinar HC-SR04, IR de línea y un LED de alerta en un solo programa sin ningún delay en el loop. El LED del GPIO 2 se enciende cuando hay un obstáculo a menos de 20 cm. Es la estructura básica de la parte de "sentir" del rover del módulo 1.6.
// Varios sensores sin bloquear: millis() en lugar de delay (ESP32, 3.x)
const int PINO_TRIG = 5, PINO_ECHO = 18, PINO_LINHA = 35, PINO_LED = 2;
const float PERTO_CM = 20.0;
unsigned long tIR = 0, tDist = 0, tPrint = 0;
float distanciaCm = -1;
int linha = 0;
float medirCm() {
digitalWrite(PINO_TRIG, LOW); delayMicroseconds(2);
digitalWrite(PINO_TRIG, HIGH); delayMicroseconds(10);
digitalWrite(PINO_TRIG, LOW);
unsigned long dur = pulseIn(PINO_ECHO, HIGH, 25000); // espera como máximo 25 ms
return (dur == 0) ? -1 : dur * 0.0343 / 2.0;
}
void setup() {
Serial.begin(115200);
pinMode(PINO_TRIG, OUTPUT); pinMode(PINO_ECHO, INPUT); pinMode(PINO_LED, OUTPUT);
Serial.println("Sensores funcionando sin delay");
}
void loop() {
unsigned long agora = millis();
if (agora - tIR >= 10) { // IR: 100 veces por segundo
tIR = agora;
linha = analogRead(PINO_LINHA);
}
if (agora - tDist >= 60) { // distancia: ~16 veces por segundo
tDist = agora;
float cm = medirCm();
if (cm > 0) distanciaCm = cm;
digitalWrite(PINO_LED, (distanciaCm > 0 && distanciaCm < PERTO_CM) ? HIGH : LOW);
}
if (agora - tPrint >= 250) { // informe: 4 veces por segundo
tPrint = agora;
Serial.print("dist="); Serial.print(distanciaCm, 1);
Serial.print(" cm | linha="); Serial.print(linha);
Serial.println(distanciaCm > 0 && distanciaCm < PERTO_CM ? " | PERTO" : "");
}
}
Cómo verificar
- ✓El Monitor muestra 4 líneas por segundo con "dist=" y "linha="; acerca la mano a menos de 20 cm y aparece "PERTO" y el LED se enciende al instante.
- ✓Al pasar el sensor de línea sobre el negro, "linha=" cambia de inmediato, incluso mientras se mide la distancia.
- ✗¿Todo lento? ¿Quedó algún delay() en el loop o en una función llamada desde allí.
💡 pulseIn también espera
O pulseIn se bloquea hasta que vuelve el eco, por eso el timeout de 25 ms: en el peor caso, el loop pierde 25 ms, nunca medio segundo. En la Trilha 2 separarás esto definitivamente con tareas de FreeRTOS e interrupciones.
Por qué aprender
Un delay largo deja al robot ciego y hace que choque antes de darse cuenta. Con tareas periódicas, el rover del módulo 1.6 mide, decide y se mueve al mismo tiempo, y puedes agregar sensores sin reescribir el resto.
Conceptos clave
✅ Resumen del módulo
Para profundizar
- I2C en Arduino-ESP32 (Espressif) — Wire, pines y velocidad
- Biblioteca VL53L0X de Pololu — ejemplos y modos de medición
- HC-SR04 en Wokwi — simular el sensor de distancia
- Blink Without Delay (Arduino) — explicación del patrón de millis()
- ADC en Arduino-ESP32 — lectura analógica de los sensores IR
Siguiente módulo
1.5 · Motores y energía. Motor DC, servo o paso a paso; puente H TB6612FNG o DRV8833; velocidad con PWM; servo con ESP32Servo; baterías y GND común.