Skip to Content

Sensor de distancia VL53L1X/TOF400C con Arduino

Sensor de distancia VL53L1X/TOF400C con Arduino

En este tutorial aprenderás a usar el sensor de distancia láser VL53L1X (también llamado TOF400C) con un Arduino o cualquier otro microcontrolador común (ESP32/ESP8266) para medir distancias.

El VL53L1X es un sensor de distancia Time-of-Flight (ToF) muy pequeño que utiliza luz láser infrarroja para medir la proximidad de un objeto. Midiendo el tiempo que tarda la luz en reflejarse en un objeto, puede calcular distancias con alta precisión.

Partes necesarias

Necesitarás un sensor de distancia VL53L1X. Para el microcontrolador, usé un Arduino Uno para este proyecto, pero cualquier otro Arduino o un ESP32/ESP8266 también funcionará. Además, usaremos un OLED para mostrar las distancias medidas por el VL53L1X en una pantalla.

Sensor de distancia VL53L1X

Arduino

Arduino Uno

USB Data Sync cable Arduino

Cable USB para Arduino UNO

Dupont wire set

Juego de cables Dupont

Half_breadboard56a

Protoboard

OLED display

Pantalla OLED

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Características del VL53L1X

El VL53L1X es un chip diminuto (4.4 x 2.5 x 1.56 mm) con dos orificios en la parte superior. Uno para el emisor de luz láser y otro para el detector de luz. El VL53L1X funciona enviando un pulso de luz láser desde el emisor, recibiendo la luz reflejada de un objeto en el detector, y basándose en el tiempo que tardó (tiempo de vuelo) calcula la distancia al objeto. La imagen a continuación muestra los conos del emisor y del detector.

Principio de funcionamiento del VL53L1X (source)

Aquí están las principales especificaciones del VL53L1X:

  • Emisor VCSEL de 940 nm (luz IR, invisible al ojo)
  • Tiempo de medición de 20 ms hasta 1000 ms
  • Tamaño programable de la región de interés (ROI)
  • Posición programable de la ROI en la matriz receptora
  • Tres modos de distancia: corto, medio y largo
  • Distancia entre 4 cm y 400 cm
  • Resolución: 1 mm
  • Voltaje: 2.6 a 3.5 V
  • Interfaz de comunicación I2C (hasta 400 kHz)

Las regiones de interés programables (ROI) del VL53L1X permiten reducir o dividir el campo de visión completo en múltiples zonas. Puedes usar esto para implementar reconocimiento de gestos, como deslizamientos, por ejemplo. Para más detalles, consulta la hoja de datos del sensor VL53L1X:

VL53L1X como parte de un sistema LiDAR

Existen muchas aplicaciones para sensores de distancia láser, como advertencia de proximidad en estacionamientos, detección de intrusos, evitación de obstáculos en robótica y más. Lo más importante es que los sensores de distancia láser se usan comúnmente en LiDAR sistemas, que significa Luz Detección y Rango, y se utilizan para crear mapas y modelos 3D altamente precisos.

Además del sensor de distancia láser, un sistema LiDAR típicamente incluye una unidad GPS y una unidad de medición inercial (IMU). El escáner es un mecanismo que mueve el haz láser a través de un área amplia, permitiendo al sistema capturar datos desde diferentes ángulos y posiciones. La unidad GPS proporciona datos de ubicación precisos. Finalmente, la IMU rastrea la orientación y el movimiento del sistema LiDAR, lo cual es crucial para mantener la precisión durante el escaneo.

Mientras se emiten y reflejan los pulsos láser, el sistema registra continuamente las mediciones de distancia junto con sus ángulos y posiciones correspondientes. Estos datos se usan para crear una nube de puntos que representa la distribución espacial de los objetos en el área escaneada.

Puedes construir un LiDAR simple tú mismo montando el sensor de distancia láser en un servo y usar el servo para escanear el entorno, mientras el sensor mide distancias. Sin embargo, en este tutorial solo usaremos el sensor de distancia láser, sin un dispositivo de escaneo.

Esquema de aplicación del VL53L1X

El siguiente esquema de aplicación muestra el cableado externo necesario para usar el chip VL53L1X. Puedes ver las resistencias pull-up para la interfaz I2C que conecta el VL53L1X a un microcontrolador (host), y dos condensadores que estabilizan la fuente de alimentación.

Application Schematic of VL53L1X
Esquema de aplicación del VL53L1X (source)

SDA y SCL son los pines para la interfaz I2C. XSHUT es el pin de apagado, que permite apagar el sensor cuando se conecta a tierra. Esto es útil si quieres conectar varios sensores VL53L1X a la misma línea I2C. GPIO1 es un pin de interrupción que puede señalar al microcontrolador que los datos están listos.

Sin embargo, en lugar de usar el pequeño chip VL53L1X directamente, es mejor obtener una placa breakout que ya tenga la electrónica integrada y sea mucho más fácil de conectar.

Placa breakout para VL53L1X

La siguiente imagen muestra el reverso y el frente de una placa breakout típica para el VL53L1X. El chip sensor real está ubicado detrás de la cubierta protectora ovalada. La cubierta reduce el impacto de la luz ambiental en la precisión del sensor.

Placa breakout para VL53L1X (source)

El pinout tiene los mismos pines mencionados antes. SDA, SCL para I2C, GPIO1 como señal de interrupción, XSHUT para selección del chip, y VIN y GND para la alimentación.

Conectando el VL53L1X

Gracias a la interfaz I2C del VL53L1X, conectarlo a un Arduino es fácil. Primero, conecta los pines SCL y SDA de la placa breakout VL53L1X a los pines correspondientes del Arduino como se muestra abajo. Luego, conecta tierra a GND y 3.3V a VIN del VL53L1X.

Connecting VL53L1X with Arduino
Conectando VL53L1X con Arduino

La placa breakout VL53L1X funciona con 5V o 3.3V y puedes usar cualquiera para VIN. Aquí, uso 3.3V para VIN. Ahora, escribamos algo de código para probar el funcionamiento del sensor VL53L1X.

Código para medir distancia con VL53L1X

Antes de poder medir distancias con el sensor VL53L1X, tendrás que instalar una librería. Las más comunes son la Adafruit VL53L1X Library y la VL53L1X Library by Pololu. Sin embargo, tuve problemas con las librerías de Adafruit al escribir el tutorial para el VL53L0X Distance Sensor, por lo que usaré la VL53L1X Library by Pololu. También ofrece más opciones de configuración para el VL53L1X.

Instalando la librería VL53L1X de Pololu

Para instalar la VL53L1X Library by Pololu, abre el Library Manager, busca VL53L1X, encuentra la de Pololu e instala. La imagen a continuación muestra cómo se ve una vez instalada la librería:

Installing VL53L1X Library by Pololu via Library Manager
Instalando la librería VL53L1X de Pololu vía Library Manager

Con la librería instalada, probemos el sensor. El siguiente código lee las distancias medidas por el VL53L1X y las imprime en el monitor serial.

#include "VL53L1X.h"

VL53L1X sensor;

void sensor_init(VL53L1X::DistanceMode range_mode, bool high_speed) {
  Wire.begin();
  sensor.setTimeout(500);
  sensor.init();
  sensor.setDistanceMode(range_mode);  
  int budget = high_speed ? 33000 : 140000;
  sensor.setMeasurementTimingBudget(budget);
}

void setup() {
  Serial.begin(9600);
  // range_mode: VL53L1X::Short, VL53L1X::Medium, or VL53L1X::Long
  sensor_init(VL53L1X::Medium, false);   
}

void loop() {
  int dist = sensor.readRangeSingleMillimeters();
  Serial.println(dist);
  delay(1000);
}

Vamos a desglosar el código en sus componentes para entenderlo mejor.

Inclusión de la librería

El código comienza incluyendo la librería necesaria para el sensor VL53L1X. Esta librería proporciona las funciones necesarias para comunicarse con el sensor.

#include "VL53L1X.h"

Creación de un objeto sensor

Luego, creamos una instancia de la clase VL53L1X, que nos permite interactuar con el sensor.

VL53L1X sensor;

Función de inicialización del sensor

La función sensor_init() es responsable de inicializar el sensor. Toma dos parámetros: range_mode que especifica el modo de medición de distancia, y high_speed que determina el presupuesto de tiempo de medición.

void sensor_init(VL53L1X::DistanceMode range_mode, bool high_speed) {
  Wire.begin();
  sensor.setTimeout(500);
  sensor.init();
  sensor.setDistanceMode(range_mode);  
  int budget = high_speed ? 33000 : 140000;
  sensor.setMeasurementTimingBudget(budget);
}

Dentro de esta función:

  • Wire.begin(); inicializa la comunicación I2C.
  • sensor.setTimeout(500); establece un tiempo de espera para las operaciones del sensor.
  • sensor.init(); inicializa el sensor.
  • sensor.setDistanceMode(range_mode); configura el modo de distancia según el parámetro de entrada.
  • El presupuesto de tiempo de medición se establece según si se solicita alta velocidad.

Según el datasheet, el presupuesto de tiempo del VL53L1X debe configurarse así.

  • 20 ms es el presupuesto mínimo y solo puede usarse en modo de distancia corta.
  • 33 ms es el presupuesto mínimo que funciona para todos los modos de distancia.
  • 140 ms es el presupuesto que permite alcanzar la distancia máxima de 4 m (en oscuridad sobre una carta blanca) en modo de distancia larga.

En el código, uso 33 ms para el modo rápido, ya que funciona con todos los rangos, y 140 ms para el modo lento, que permite la distancia máxima.

Para el rango, puedes usar las constantes predefinidas VL53L1X::Short, VL53L1X::Medium o VL53L1X::Long. El rango que el sensor puede medir depende del modo elegido y de la luz ambiental. La siguiente tabla del datasheet del VL53L1X muestra estas dependencias:

Maximum distance vs. distance mode under ambient light for VL53L1X
Distancia máxima vs. modo de distancia bajo luz ambiental para VL53L1X

El modo de distancia larga permite alcanzar la distancia máxima de hasta 4 m bajo condiciones ideales (oscuridad). Generalmente, la distancia medida se ve afectada por la luz ambiental. El modo de distancia corta es más inmune a la luz ambiental, pero su distancia máxima suele estar limitada a 1.3 m.

Función setup

En la función setup(), iniciamos la comunicación Serial e inicializamos el sensor con un modo de distancia específico.

void setup() {
  Serial.begin(9600);
  // range_mode: VL53L1X::Short, VL53L1X::Medium, or VL53L1X::Long
  sensor_init(VL53L1X::Medium, false);   
}

Aquí, Serial.begin(9600); configura el Monitor Serial a una velocidad de 9600 baudios. La función sensor_init() se llama con VL53L1X::Medium como modo de rango y false para alta velocidad, lo que significa que el sensor operará en rango medio con un presupuesto de tiempo más largo.

Función loop

Finalmente, en la función loop(), leemos continuamente la distancia del sensor y la imprimimos en el Monitor Serial.

void loop() {
  int dist = sensor.readRangeSingleMillimeters();
  Serial.println(dist);
  delay(1000);
}

Si subes y ejecutas el código, deberías ver las distancias medidas impresas en el Monitor Serial.

Distances measured with VL53L1X printed on Serial Monitor
Distancias medidas con VL53L1X impresas en el Monitor Serial

En la siguiente sección vamos a añadir un OLED a nuestro circuito y mostrar las distancias en él, en lugar de imprimirlas en el Monitor Serial.

Añadiendo un OLED para mostrar datos del VL53L1X

Como el OLED también es un dispositivo I2C, conectarlo es sencillo. Simplemente conectamos SDA y SCL a los mismos pines a los que está conectado el sensor VL53L1X. Y como el OLED funciona a 3.3V, también podemos compartir las líneas de alimentación.

Connecting OLED and VL53L1X with Arduino
Conectando OLED y VL53L1X con Arduino

Código para mostrar distancias medidas por VL53L1X en OLED

El siguiente código lee las mediciones de distancia del sensor VL53L1X y las muestra en el OLED. Echa un vistazo rápido al código completo primero, luego discutiremos sus detalles.

#include "Wire.h"
#include "VL53L1X.h"
#include "Adafruit_SSD1306.h"

Adafruit_SSD1306 oled(128, 64, &Wire, -1);
VL53L1X sensor;

void sensor_init(VL53L1X::DistanceMode range_mode, bool high_speed) {
  Wire.begin();
  sensor.setTimeout(500);
  sensor.init();
  sensor.setDistanceMode(range_mode); 
  int budget = high_speed ? 33000 : 140000;
  sensor.setMeasurementTimingBudget(budget);
}

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

void display() {
  static char text[30];
  int dist = sensor.readRangeSingleMillimeters();
  sprintf(text, "%4d mm", dist);

  oled.clearDisplay();
  oled.setCursor(20, 25);
  oled.print(text);

  oled.display();
}

void setup() {
  oled_init();
  sensor_init(VL53L1X::Medium, false); 
}

void loop() {
  display();
}

Vamos a desglosar el código en sus partes para entenderlo mejor.

Inclusión de librerías

Al inicio del código, incluimos las librerías necesarias para nuestro proyecto. La librería Wire.h se usa para la comunicación I2C, VL53L1X.h para la interfaz con el sensor de distancia VL53L1X, y Adafruit_SSD1306.h para controlar la pantalla OLED.

#include "Wire.h"
#include "VL53L1X.h"
#include "Adafruit_SSD1306.h"

Si aún no has instalado la Adafruit_SSD1306 Library, tendrás que hacerlo. Solo instálala vía Library Manager como de costumbre:

Adafruit_SSD1306 library installed in Library Manager
Librería Adafruit_SSD1306 instalada en Library Manager

Ten en cuenta que la dirección I2C para la pantalla OLED está configurada en 0x3C en oled.begin(). La mayoría de estos pequeños OLED usan esta dirección (or 0x27) pero la tuya podría ser diferente. Si no ves nada en el OLED, probablemente tenga una dirección I2C distinta y tendrás que cambiarla.

Si no sabes la dirección I2C, consulta el tutorial How to Interface the SSD1306 I2C OLED Graphic Display With Arduino para encontrarla. También el tutorial Use SSD1306 I2C OLED Display With Arduino te enseñará más sobre cómo usar un OLED.

Inicialización de objetos

Luego, creamos instancias de la pantalla OLED y del sensor de distancia. La pantalla OLED se inicializa con un ancho de 128 píxeles y una altura de 64 píxeles. El parámetro &Wire indica que usamos la librería Wire para comunicación I2C, y -1 indica que no usamos un pin de reset.

Adafruit_SSD1306 oled(128, 64, &Wire, -1);
VL53L1X sensor;

Función de inicialización del sensor

La función sensor_init() inicializa el sensor VL53L1X. Toma dos parámetros: range_mode para configurar el modo de medición de distancia y high_speed para determinar el presupuesto de tiempo de medición. Dentro de la función, iniciamos la comunicación I2C, establecemos un tiempo de espera para el sensor, lo inicializamos y configuramos el modo de distancia. El presupuesto de tiempo se ajusta según si la alta velocidad está activada o no.

void sensor_init(VL53L1X::DistanceMode range_mode, bool high_speed) {
  Wire.begin();
  sensor.setTimeout(500);
  sensor.init();
  sensor.setDistanceMode(range_mode); 
  int budget = high_speed ? 33000 : 140000;
  sensor.setMeasurementTimingBudget(budget);
}

Función de inicialización del OLED

La función oled_init() inicializa la pantalla OLED. Comienza encendiendo la pantalla usando el parámetro SSD1306_SWITCHCAPVCC y configurando la dirección I2C a 0x3C. También configuramos el tamaño del texto a 2 y el color del texto a blanco.

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

Función de visualización

La función display() es responsable de leer la distancia del sensor y mostrarla en la pantalla OLED. Primero declara un array estático de caracteres text para contener la cadena de distancia. La distancia se lee en milímetros usando sensor.readRangeSingleMillimeters(), y el resultado se formatea en el array text usando sprintf(). Luego se limpia la pantalla OLED, se posiciona el cursor en un lugar específico y se imprime la distancia. Finalmente, se actualiza la pantalla para mostrar el nuevo contenido.

void display() {
  static char text[30];
  int dist = sensor.readRangeSingleMillimeters();
  sprintf(text, "%4d mm", dist);

  oled.clearDisplay();
  oled.setCursor(20, 25);
  oled.print(text);

  oled.display();
}

Función setup

En la función setup(), llamamos a las funciones de inicialización tanto de la pantalla OLED como del sensor de distancia. El sensor se inicializa en modo rango medio y con alta velocidad desactivada.

void setup() {
  oled_init();
  sensor_init(VL53L1X::Medium, false); 
}

Función loop

Finalmente, la función loop() llama continuamente a la función display(), que actualiza la pantalla OLED con la última medición de distancia del sensor. Este bucle se ejecuta indefinidamente, proporcionando lecturas de distancia en tiempo real.

void loop() {
  display();
}

Conclusiones

En este tutorial aprendiste a usar el sensor de distancia VL53L1X con un Arduino para medir distancias y mostrarlas en un OLED.

El sensor VL53L1X es un sensor muy pequeño, rápido y de alta precisión que usa luz láser infrarroja para medir distancias. El VL53L1X es casi idéntico al VL53L0X pero tiene un rango mayor. El primero puede medir distancias de hasta 400 cm, mientras que el segundo está limitado a 200 cm. Si necesitas un sensor para un rango mucho mayor, echa un vistazo al TF Luna que puede medir distancias de hasta 8 metros.

Otro sensor de distancia láser similar que usa el método Time-of-Flight es el sensor TOF10120. Sin embargo, el VL53L1X tiene más opciones de configuración (largo alcance, alta velocidad) y un rango mayor (hasta 400 cm frente a 180 cm).

Otros sensores comunes de distancia infrarroja como el GP2Y0A710K0F o el GP2Y0A21YK0F usan triangulación para determinar la distancia basándose en el ángulo de la luz IR reflejada y tienen menor alcance y precisión.

Si tienes alguna pregunta, no dudes en dejarla en la sección de comentarios.

¡Feliz bricolaje ; )