¿Alguna vez te fijaste en ese clip que la enfermera te pone en el dedo y muestra dos números al tiro? Ese aparato es un pulsioxímetro, y el corazón de un equipo así cabe en un módulo de dos centímetros que puedes conectar a un ESP32 con cuatro cables. Al final de esta guía vas a tener tres mediciones funcionando. frecuencia cardíaca en BPM, saturación de oxígeno (SpO2) y temperatura. y, más importante, vas a entender por qué el sensor entrega lo que entrega y en qué momento deja de ser confiable.

Este proyecto sirve como base para wearables, monitores de ejercicio, proyectos de bioinstrumentación para la universidad o simplemente para entender cómo funciona la fotopletismografía sin leer un paper.

Advertencia médica, en serio. El MAX30102 es un componente de prototipado, no un dispositivo médico. No está certificado, no está calibrado contra un estándar clínico y sus lecturas de SpO2 pueden desviarse varios puntos porcentuales. No lo uses para tomar decisiones de salud, diagnosticar nada ni reemplazar un oxímetro certificado. Si te preocupa tu saturación o tu pulso, anda a un centro de salud. Acá lo usamos para aprender electrónica.

Qué hace realmente el MAX30102

El módulo integra el circuito MAX30102, un sensor óptico que mide la saturación de oxígeno en sangre y la frecuencia cardíaca de forma no invasiva. Incluye además un sensor de temperatura que el propio chip usa para compensar y calibrar sus lecturas ópticas.

Módulo sensor MAX30102 de pulsioximetría y frecuencia cardíaca visto de cerca

Adentro hay tres piezas: un LED rojo, un LED infrarrojo y un fotodetector. Los LED emiten luz hacia la piel y el fotodetector mide cuánta vuelve reflejada. Como el volumen de sangre en el dedo cambia con cada latido, la cantidad de luz reflejada también cambia. y de esa variación sale todo lo demás.

Módulo MAX30102 mostrando el LED rojo y el LED infrarrojo

La física, en tres pasos

Diagrama de funcionamiento del MAX30102 para medir SpO2 y frecuencia cardíaca

  1. Emisión: el LED rojo y el infrarrojo iluminan el tejido, cada uno en una longitud de onda distinta.
  2. Detección: parte de esa luz atraviesa el tejido y parte se refleja. Cuánta se refleja depende del volumen de sangre y de su nivel de oxigenación. El fotodetector mide esa luz de vuelta.
  3. Comparación: la hemoglobina oxigenada absorbe más luz infrarroja; la desoxigenada absorbe más luz roja. Comparando la intensidad reflejada en ambas longitudes de onda, el chip calcula la SpO2. Y midiendo el tiempo entre los máximos de esa onda, calcula los BPM.

Por qué tus lecturas van a ser más ruidosas que las del hospital

Acá hay un detalle que casi ningún tutorial menciona y que explica el 90% de las frustraciones con este sensor: el MAX30102 trabaja por reflectancia, no por transmitancia. El oxímetro de la clínica es una pinza que pone el LED a un lado del dedo y el fotodetector al otro: la luz atraviesa el dedo completo y la señal es limpia. El MAX30102 tiene LED y fotodetector en la misma cara, así que solo ve la luz que rebota en los primeros milímetros de tejido. Eso significa tres cosas concretas:

  • La señal es del orden de decenas de veces más débil, así que el ruido pesa mucho más.
  • Cualquier movimiento del dedo desplaza la zona iluminada y arruina la medición.
  • La luz ambiente que se cuela por los costados entra directo al fotodetector como señal falsa.

Por eso la recomendación de apoyar el dedo quieto y con presión constante no es un detalle de cortesía: es la diferencia entre medir y no medir.

MAX30102 vs MAX30100 vs MAX30105

Los tres se ven casi iguales en las fotos de las tiendas y se confunden seguido:

Chip LED Uso típico Nota
MAX30100 Rojo + IR Versión antigua Tiene erratas conocidas de I2C y peor relación señal/ruido. Evítalo si puedes elegir.
MAX30102 Rojo + IR Pulso y SpO2 El punto dulce precio/rendimiento. Es el de esta guía.
MAX30105 Rojo + IR + Verde Pulso, SpO2, presencia y detección de partículas El LED verde extra sirve para detección de humo/partículas y para pulso con movimiento. Más caro.

Un detalle que confunde a todo el mundo: la librería se llama MAX30105 pero funciona perfecto con el MAX30102. SparkFun escribió un solo driver para toda la familia MAX3010x y lo nombró por el chip tope de línea. Si ves MAX30105 sensor; en el código y tu módulo dice MAX30102, está correcto. no te compraste el sensor equivocado.

Conexión al ESP32

El sensor habla por I2C, así que se conecta a los pines I2C por defecto de tu placa:

Placa SDA SCL
ESP32 (DevKit clásico) GPIO 21 GPIO 22
ESP32-S3 GPIO 8 GPIO 9

El módulo se alimenta por el pin VIN, y acepta tanto 5V como 3V3 porque trae un regulador propio a bordo. En total son cuatro cables: VIN, GND, SDA y SCL.

Diagrama de conexión entre el sensor MAX30102 y la placa ESP32

Dos cosas que te van a ahorrar tiempo:

  • No necesitas resistencias pull up externas. El módulo (la placa morada o azul que compras, no el chip pelado) ya trae las pull up de I2C soldadas. Si además pones las tuyas, bajas demasiado la resistencia equivalente del bus y puedes hacerlo fallar.
  • La dirección I2C es 0x57 y es fija. No hay jumper para cambiarla. Si necesitas dos MAX30102 en el mismo proyecto, vas a tener que usar un segundo bus I2C del ESP32 o un multiplexor tipo TCA9548A.

Si tu placa no es ninguna de las dos de la tabla, revisa el pinout específico de tu modelo antes de conectar.

Preparar el Arduino IDE

Necesitas dos cosas instaladas: el soporte para placas ESP32 en el Arduino IDE (si nunca lo instalaste, hazlo primero desde el gestor de placas), y la librería del sensor.

Para la librería, abre el Gestor de Librerías del Arduino IDE, busca SparkFun MAX3010x e instala la de SparkFun.

Gestor de librerías del Arduino IDE con la librería SparkFun MAX3010x

Existen varias librerías para este sensor, pero la de SparkFun es la que mejor anda y la más directa de usar.

1) Frecuencia cardíaca (BPM)

Este primer sketch lee el pulso y muestra el promedio en el Monitor Serial.

C++
/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-max30102-oximeter-heart-rate-sensor/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"

MAX30105 sensor;

// Settings
const byte RATE_SIZE = 5;   // How many beats we average
byte rates[RATE_SIZE];      // Store last few valid BPM values
byte rateSpot = 0;
byte validBeats = 0;
long lastBeat = 0;
float currentBPM = 0;
int averageBPM = 0;

unsigned long lastPrint = 0;

// Only accept realistic heart rates (adjust for your case)
const float MIN_BPM = 45;
const float MAX_BPM = 180;

void setup() {
  Serial.begin(115200);
  Serial.println("MAX30102 Heart Rate Sensor");
  Serial.println();
  Serial.println("Place your finger on the sensor...");
  Serial.println();

  // Initialize the sensor
  if (!sensor.begin(Wire, I2C_SPEED_FAST)) {
    Serial.println("Error initializing the sensor...");
    while (1);
  }

  sensor.setup();                    // Use default settings
  sensor.setPulseAmplitudeRed(0);    // Turn off red LED
}

void loop() {
  long irValue = sensor.getIR();      // Read infrared value

  // Check if a heartbeat was detected
  if (checkForBeat(irValue)) {
    long timeBetweenBeats = millis() - lastBeat;
    lastBeat = millis();

    currentBPM = 60.0 / (timeBetweenBeats / 1000.0);

    // Only keep realistic values
    if (currentBPM >= MIN_BPM && currentBPM <= MAX_BPM) {
      rates[rateSpot] = (byte)currentBPM;
      rateSpot++;
      if (rateSpot >= RATE_SIZE){
        rateSpot = 0;
      }
      // Count valid beats (until buffer is full)
      if (validBeats < RATE_SIZE) {
        validBeats++;
      }
      
      // Only calculate average when buffer is full
      if (validBeats >= RATE_SIZE) {
        // Calculate the average
        averageBPM = 0;
        for (byte i = 0; i < RATE_SIZE; i++) {
          averageBPM += rates[i];
        }
        averageBPM /= RATE_SIZE;
      }
    }
  }

  // Print once every second
  if (millis() - lastPrint >= 1000) {
    lastPrint = millis();

    if (irValue < 50000) {
      // No finger on the sensor
      Serial.println("Waiting for finger...");
    }
    else if (averageBPM == 0) {
      // Finger is present but not enough valid beats yet
      Serial.println("Measuring... keep your finger still");
    }
    else {
      // We have a valid average
      Serial.print("Heart Rate: ");
      Serial.print(averageBPM);
      Serial.println(" BPM");
    }
  }
}

Cómo funciona el código

El truco está en el LED infrarrojo. Cuando el corazón late, entra más sangre a los vasos del dedo, se absorbe más luz infrarroja y llega menos luz al fotodetector. Entre latido y latido pasa lo contrario. Esa subida y bajada forma una onda, y midiendo el tiempo entre sus peaks sale la frecuencia.

Como el algoritmo de pulso solo usa el infrarrojo, el código apaga el LED rojo para que no moleste:

C++
sensor.setup();                    // Use default settings
sensor.setPulseAmplitudeRed(0);    // Turn off red LED

En el loop(), la función checkForBeat() decide si acaba de ocurrir un latido a partir de la señal infrarroja. Si lo hubo, se calcula el tiempo transcurrido desde el latido anterior y de ahí salen los BPM.

Las variables globales son las que sostienen ese promedio:

C++
const byte RATE_SIZE = 5;  
byte rates[RATE_SIZE]; 
byte rateSpot = 0;
byte validBeats = 0;
long lastBeat = 0;
float currentBPM = 0;
int averageBPM = 0;

unsigned long lastPrint = 0;

RATE_SIZE define cuántas lecturas entran en el promedio. rates es el arreglo circular donde se guardan, y rateSpot marca en qué posición se va a escribir la próxima. cuando llega al final vuelve a cero y empieza a pisar las más viejas. validBeats cuenta cuántos latidos válidos llevas acumulados y crece hasta llegar a RATE_SIZE, momento en que el promedio recién se considera confiable. lastBeat guarda el instante del último latido válido, que es justamente lo que permite calcular el intervalo entre latidos. Y lastPrint no tiene nada que ver con la medición: existe solo para imprimir una vez por segundo en vez de inundar el Monitor Serial con miles de líneas.

Ahora, el promedio móvil merece una explicación, porque es lo que hace la diferencia entre un número que baila y uno legible. El código guarda las últimas 5 lecturas válidas en el arreglo rates y recién muestra un valor cuando el buffer se llenó. Además descarta cualquier lectura fuera del rango de 45 a 180 BPM:

C++
const float MIN_BPM = 45;
const float MAX_BPM = 180;

Ese filtro existe porque un dedo mal apoyado genera falsos latidos que dan valores absurdos. Si eres deportista y tu pulso en reposo baja de 45, ajusta MIN_BPM. Si quieres un número más estable a costa de que tarde más en aparecer, sube RATE_SIZE a 8 o 10.

El umbral irValue < 50000 es el detector de "no hay dedo". No es un valor sagrado: depende de tu módulo, de la presión del dedo y hasta del tono de piel. Si el sensor dice "Waiting for finger..." con el dedo puesto, imprime irValue crudo en el Monitor Serial y ajusta el umbral a la mitad de lo que veas con el dedo apoyado.

El bloque de impresión distingue tres situaciones, y conviene reconocerlas en pantalla para saber qué está pasando: si irValue está bajo el umbral no hay dedo y verás Waiting for finger...; si hay dedo pero el promedio todavía vale 0, significa que el buffer aún no se llena y verás Measuring... keep your finger still; y recién cuando hay cinco latidos válidos acumulados aparece el número en BPM. Si te quedas pegado indefinidamente en el segundo mensaje, no es que el código esté malo. son latidos que están cayendo fuera del rango válido por movimiento.

Dedo apoyado sobre el sensor MAX30102 conectado al ESP32 durante la medición

Sube el código, abre el Monitor Serial a 115200 baudios y apoya el dedo. Mantenlo quieto y con presión pareja. un elástico o una banda de goma para sujetar el sensor al dedo funciona mucho mejor que el pulso.

Monitor serial del Arduino IDE mostrando las lecturas de frecuencia cardíaca en BPM

2) Saturación de oxígeno (SpO2)

La SpO2 no se calcula latido a latido: el algoritmo necesita una ventana completa de muestras para comparar las dos longitudes de onda. Por eso este sketch junta 100 lecturas antes de entregar un resultado.

C++
/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-max30102-oximeter-heart-rate-sensor/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"

MAX30105 sensor;

// Buffers needed by the algorithm
#define BUFFER_SIZE 100
uint32_t irBuffer[BUFFER_SIZE];
uint32_t redBuffer[BUFFER_SIZE];

int32_t spo2;          // Oxygen saturation value
int8_t  validSPO2;     // 1 = valid reading, 0 = not valid yet
int32_t heartRate;     // Not used, but required by the function
int8_t  validHeartRate;

void setup() {
  Serial.begin(115200);
  Serial.println("MAX30102 Oxygen Saturation");
  Serial.println();
  Serial.println("Place your finger on the sensor...");
  Serial.println();

  // Initialize the sensor
  if (!sensor.begin(Wire, I2C_SPEED_FAST)) {
    Serial.println("Error initializing the sensor...");
    while (1);
  }

  byte ledBrightness = 60;  // 0=Off to 255=50mA
  byte sampleAverage = 4;   // 1, 2, 4, 8, 16, 32
  byte ledMode = 2;         // 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  byte sampleRate = 100;    // 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411;     // 69, 118, 215, 411
  int adcRange = 4096;      // 2048, 4096, 8192, 16384

  // Configure sensor with these settings
  sensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);
}

void loop() {
  // Collect 100 samples (takes a few seconds)
  for (byte i = 0; i < BUFFER_SIZE; i++) {
    while (sensor.available() == false) {
      sensor.check();
    }

    redBuffer[i] = sensor.getRed();
    irBuffer[i]  = sensor.getIR();
    sensor.nextSample();
  }

  // Calculate SpO2
  maxim_heart_rate_and_oxygen_saturation(irBuffer, BUFFER_SIZE, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

  // Display oxygen saturation
  if (validSPO2) {
    Serial.print("Oxygen Saturation: ");
    Serial.print(spo2);
    Serial.println(" %");
  } else {
    Serial.println("Measuring... keep your finger still");
  }

  Serial.println();
}

Cómo funciona el código

Acá el LED rojo sí se usa: la SpO2 sale justamente de la razón entre la luz roja y la infrarroja reflejadas. El algoritmo necesita dos buffers paralelos, uno por cada longitud de onda, más las variables donde deja el resultado:

C++
// Buffers needed by the algorithm
#define BUFFER_SIZE 100
uint32_t irBuffer[BUFFER_SIZE];
uint32_t redBuffer[BUFFER_SIZE];

int32_t spo2;             // Oxygen saturation value
int8_t  validSPO2;     // 1 = valid reading, 0 = not valid yet
int32_t heartRate;     // Not used, but required by the function
int8_t  validHeartRate;

Los uint32_t no son capricho: las lecturas crudas del ADC del MAX30102 llegan como enteros de 18 bits sin signo, así que no caben en un int de 16 bits. Con 100 muestras de cada color, los dos arreglos ocupan 800 bytes de RAM. irrelevante en un ESP32, pero es lo primero que tendrías que recortar si alguna vez portas este código a un microcontrolador de 2 KB. Y fíjate en heartRate y validHeartRate: están declaradas solo porque la firma de la función las exige, no porque este sketch las use.

El sensor se configura con parámetros específicos para esta medición:

C++
byte ledBrightness = 60;
byte sampleAverage = 4;
byte ledMode = 2;
byte sampleRate = 100;
int pulseWidth = 411;
int adcRange = 4096;

sensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);

Qué significa cada uno:

Parámetro Valor Qué controla Opciones
ledBrightness 60 Brillo de los LED 0 a 255
sampleAverage 4 Muestras que promedia el sensor 1, 2, 4, 8, 16, 32
ledMode 2 Qué LED se activan 1 = solo rojo, 2 = rojo + IR, 3 = rojo + IR + verde
sampleRate 100 Muestras por segundo 50, 100, 200, 400, 800, 1000, 1600, 3200
pulseWidth 411 Ancho de pulso del LED 69, 118, 215, 411
adcRange 4096 Rango del ADC (sensibilidad) 2048, 4096, 8192, 16384

Con sampleRate = 100 y un buffer de 100 muestras, cada resultado toma aproximadamente un segundo de captura. Si subes el buffer para tener más estabilidad, ese tiempo sube en la misma proporción. y el dedo tiene que quedarse quieto todo ese rato.

La función que hace el trabajo pesado es:

C++
maxim_heart_rate_and_oxygen_saturation(irBuffer, BUFFER_SIZE, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

Deja la saturación en spo2 y levanta la bandera validSPO2 cuando la lectura es confiable. Fíjate que la función también devuelve frecuencia cardíaca, pero en este sketch no se usa: el algoritmo de pulso del primer ejemplo responde mejor.

Monitor serial mostrando los valores de saturación de oxígeno medidos con el MAX30102

Espera unos segundos con el dedo apoyado hasta que aparezcan valores válidos. Si ves lecturas que saltan entre 80 y 99, no es que te estés asfixiando: es movimiento.

3) Temperatura

El sensor de temperatura que el chip usa internamente para calibrarse también se puede leer directamente.

C++
/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-max30102-oximeter-heart-rate-sensor/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Wire.h>
#include "MAX30105.h"

MAX30105 sensor;

void setup() {
  Serial.begin(115200);
  Serial.println("MAX30102 Temperature Sensor");
  Serial.println();

  // Initialize the sensor
  if (!sensor.begin(Wire, I2C_SPEED_FAST)) {
    Serial.println("Error initializing the sensor...");
    while (1);
  }
  
  // Turn off the LEDs so they don't heat the sensor
  sensor.setup(0);            // 0 = LEDs off
  sensor.enableDIETEMPRDY();  // Enable temperature ready signal
}

void loop() {
  // Read temperature in Celsius
  float tempC = sensor.readTemperature();

  // Convert to Fahrenheit
  float tempF = tempC * 1.8 + 32.0;

  // Print the temperature readings
  Serial.print("Temperature: ");
  Serial.print(tempC, 2);
  Serial.print(" °C   |   ");
  Serial.print(tempF, 2);
  Serial.println(" °F");

  delay(1000);
}

Acá el orden importa: se apagan los LED con sensor.setup(0) para que no calienten el encapsulado y falseen la medición, y se habilita la señal de temperatura lista con sensor.enableDIETEMPRDY(). Después, readTemperature() devuelve grados Celsius y el resto es aritmética para pasar a Fahrenheit.

Monitor serial mostrando las lecturas de temperatura del MAX30102

Una advertencia importante que el sensor no te va a dar: esto es la temperatura del die, o sea del silicio del chip, no tu temperatura corporal. Está pensada para compensación interna, tiene una precisión del orden de ±1 °C y lo que mide es la temperatura de la yema del dedo en contacto con el encapsulado, que es varios grados más baja que la temperatura central del cuerpo y varía con la temperatura ambiente. Sirve perfecto para ver tendencias o para el proyecto; no sirve para saber si alguien tiene fiebre.

Errores comunes y cómo salir de ellos

  • "Error initializing the sensor..." y se queda pegado. Es el while(1) del setup. Revisa el cableado y confirma que el sensor aparece en el bus: sube un sketch de I2C scanner y busca la dirección 0x57. Si no aparece ninguna dirección, el problema es de conexión o de alimentación. Si aparece otra, no es un MAX30102.
  • Compila pero nunca detecta el dedo. Baja el umbral irValue < 50000 según lo que midas realmente (ver arriba).
  • Los BPM demoran mucho en aparecer. Es el buffer: necesita 5 latidos válidos consecutivos. Con el pulso en reposo eso son unos 5 segundos, más lo que tardes en estabilizar el dedo.
  • Valores erráticos en SpO2. Casi siempre es movimiento o luz ambiente. Tapa el sensor con el dedo completo y aléjate de luz directa.
  • El sensor se calienta. Si dejaste ledBrightness alto y el sensor corriendo mucho rato, es normal. Baja el brillo: para un dedo apoyado con presión, valores entre 30 y 60 sobran.

Variantes y mejoras

Estas tres ideas extienden el proyecto más allá del Monitor Serial:

  • Unificar los tres sketches en un solo oxímetro con pantalla. Es el paso natural: en lugar de tener tres programas separados, puedes alternar entre los modos de medición y mostrar BPM, SpO2 y temperatura en una pantalla OLED de 0.96" por I2C. Lo bueno es que la OLED comparte el mismo bus que el sensor. los mismos GPIO 21 y 22. así que no necesitas cables adicionales, solo cuidar que las direcciones I2C no choquen (la OLED suele estar en 0x3C y el sensor en 0x57, así que conviven sin problema). Si armas esto, deja el disclaimer médico visible en la pantalla de inicio.
  • Registrar en el tiempo en vez de mirar números. Un pulso aislado dice poco; una curva dice bastante. Guarda las lecturas con marca de tiempo en una microSD por SPI, o mándalas por WiFi a un servidor web del propio ESP32 para graficarlas en el navegador. El ESP32 tiene WiFi integrado, así que esta variante no cuesta hardware extra.
  • Convertirlo en un dispositivo a batería. Con una batería LiPo y el deep sleep del ESP32 puedes hacer un medidor portátil que despierte solo cuando lo necesitas. La clave está en apagar los LED del sensor con sensor.setup(0) antes de dormir: son, por lejos, lo que más consume del circuito.

Personalización para Chile

Todo lo que necesitas para este proyecto se consigue en MechatronicStore:

  • Placa ESP32 DevKit. el cerebro del proyecto. Cualquier variante DevKit de 30 o 38 pines sirve; solo confirma en qué GPIO quedan SDA y SCL en tu modelo.
  • Módulo sensor MAX30102. el protagonista. Búscalo también como "GY MAX30102"; es el mismo módulo.
  • Protoboard 400 puntos y jumpers macho hembra. el sensor viene con header de pines, así que macho hembra es la combinación que necesitas para llegar de la protoboard al módulo.
  • Cable USB para programar y alimentar el ESP32 (micro USB o USB-C según tu placa).

Equivalencias, para que no te compliques leyendo el tutorial original: si en un tutorial en inglés ves un "SparkFun ESP32 Thing" o un "Adafruit HUZZAH32", el ESP32 DevKit del catálogo local cumple exactamente la misma función a una fracción del precio. cambian los GPIO expuestos, no el chip. Y donde digan "MAX30102 breakout board", cualquier módulo MAX30102 del mercado local es equivalente: todos usan el mismo chip de Maxim y la misma librería.

Lo único de la lista de materiales que no vas a encontrar en una tienda de electrónica es el elástico para sujetar el sensor al dedo, y ese lo tienes en la casa.

Presupuesto aproximado: el proyecto completo sale del orden de CLP $20.000 a $25.000 si partes de cero, y bastante menos si ya tienes el ESP32 y la protoboard. Confirma precios y stock en el catálogo antes de comprar.

Recursos

Versión chilena con componentes en stock local en MechatronicStore. Guía inspirada en el tutorial de Random Nerd Tutorials, reescrita con contexto adicional sobre las limitaciones del sensor, comparación con la familia MAX3010x y sección de troubleshooting.