Иван Иванов   20 декабря в 15:56

Arduino VL53L0X: лазерный дальномер

Датчик Arduino VL53L0X является лазерным дальномером, который измеряет расстояние до целевого объекта в диапазоне до 2 метров.

О датчике VL53L0X

VL53L0X использует измерения дальности инфракрасного излучения для измерения дальности, что позволяет ему получать точные результаты независимо от цвета и поверхности цели.

Датчик VL53LOX от Adafruit (слева) и Pololu (справа)
Датчик VL53L0X от Adafruit (слева) и Pololu (справа)

Измерения расстояния могут быть считаны через цифровой интерфейс I²C. Плата имеет линейный регулятор 2,8 В и встроенные регуляторы уровня, которые позволяют ей работать в диапазоне входного напряжения от 2,6 В до 5,5 В, а расстояние между выводами 0,1″ облегчает использование со стандартными макетами без припоя.

Характеристики

  • Размеры: 0,5″ × 0,7″ × 0,085″ (13 мм × 18 мм × 2 мм)
  • Вес: 0,5 г (0,02 унции)
  • Рабочее напряжение: от 2,6 В до 5,5 В
  • Ток питания: 10 мА (типичное среднее значение во время активного измерения). Зависит от конфигурации, цели и среды. Пиковый ток может достигать 40 мА.
  • Выход (I²C): считывание 16-битного расстояния (в миллиметрах)
  • Диапазон измерения расстояния: до 2 метров (6,6 фута).

График таблицы характеристик VL53L0X типичной производительности измерения дальности (в режиме по умолчанию):

Эффективный диапазон зависит от конфигурации, цели и среды. В техническом описании не указан минимальный диапазон, но эффективный предел составляет около 3 см.

Распиновка

Для использования платы VL53L0X необходимо как минимум четыре соединения (см. схему ниже):

  • VIN,
  • GND,
  • SCL,
  • SDA.

Вывод VIN должен быть подключен к источнику от 2,6 до 5,5 В, а заземление должно быть подключено к 0 вольт. Встроенный линейный регулятор напряжения преобразует VIN в источник питания 2,8 В для интегральной схемы VL53L0X.

Контакты I²C, SCL и SDA подключены к встроенным переключателям уровня, что делает их безопасными для использования при напряжениях свыше 2,8 В; они должны быть подключены к шине I²C, работающей на том же логическом уровне, что и VIN.

Вывод XSHUT является входом, а вывод GPIO1 - выходом с открытым стоком; оба контакта вытянуты платой до 2,8 В. Они не подключены к переключателям уровня на плате и не допускают 5 В, но их можно использовать как есть со многими микроконтроллерами 3,3 В и 5 В: микроконтроллер может считывать выходной сигнал GPIO1, пока его логический верхний порог ниже 2,8 В, и микроконтроллер может чередовать свой собственный выход между состояниями низкого и высокого импеданса, чтобы управлять выводом XSHUT. В качестве альтернативы, 4-канальный двунаправленный логический переключатель уровня может использоваться снаружи с этими выводами.

PIN (пин, вывод) Описание
VDD Регулируемый выход 2,8 В. Почти 150 мА доступно для питания внешних компонентов. Если вы хотите обойти внутренний регулятор, вместо этого вы можете использовать этот вывод в качестве входа 2,8 В с отключенным VIN.
VIN Это основной источник питания от 2,6 до 5,5 В. Переключатели уровня SCL и SDA поднимают линии I²C высоко до этого уровня.
GND Заземление (0 В) для подключения вашего источника питания.
SDA Сдвинутая по уровню линия данных I²C: ВЫСОКИЙ (HIGH) это VIN, НИЗКИЙ (LOW) - это 0 В
SCL Линия синхронизации I²C со сдвигом уровня: ВЫСОКИЙ (HIGH) это VIN, НИЗКИЙ (LOW) - это 0 В
XSHUT Этот вывод является активным-низким входом отключения; плата тянет его до VDD, чтобы включить датчик по умолчанию. Низкий уровень этого вывода переводит датчик в аппаратный режим ожидания. Этот вход не смещен по уровню.
GPIO1 Программируемый выход прерывания (логический уровень VDD). Этот вывод не сдвинут по уровню.

Принципиальная схема датчика

Схема подключения датчика

Мы подключаем датчик VL53L0X к Ардуино согласно следующей схеме:

В случае платы Arduino на 5 В включая Arduino Uno, Leonardo, Mega или Pololu A-Star 32U4:

Arduino -> VL53L0X
5V <-> VIN
GND <-> GND
SDA <-> SDA
SCL <-> SCL

В случае плат Arduino 3.3 В включая Arduino Due:

Arduino -> VL53L0X
3V3 <-> VIN
GND <-> GND
SDA <-> SDA
SCL <-> SCL

На схеме выше я обозначил выводы SDA и SCL.

Библиотека VL53L0X

По ссылке выше вы можете скачать библиотеку для этого датчика. Данная библиотека предназначена для работы с Arduino IDE версии 1.6.x или выше. Не знаю, работает ли она с более ранними версиями. В целом, эта библиотека должна поддерживать любую Arduino-совместимую плату, включая контроллеры Pololu A-Star 32U4.

Установка библиотеки

Если вы используете версию Arduino IDE 1.6.2 или более позднюю, то данная библиотека уже есть в "Менеджере библиотек" (англ. - Library Manager), что позволяет нам установить её через IDE.

В нашей среде разработки Ардуино мы выбираем:

Скетч -> Подключить библиотеку -> Управлять библиотеками

Далее мы попадаем в Менеджер библиотек, где начинаем вводить название библиотеки VL532L0X после чего нам нужно прокрутить окно вниз до VL53L0X by Polulu и нажать Установить:

Если у вас английская версия IDE, то вам нужно следовать такому пути:

Sketch -> Include Library -> Manage Libraries

Далее также ищем VL53l0X и жмем Install.

Если это не работает, вы можете вручную установить библиотеку. Для этого нам нужно скачать архив последней версии с GitHub и распаковать его. Потом переименовать vl53l0x-arduino-master в VL53L0X.

После чего перемещаем или копируем папку VL53L0X в папку libraries внутри директории где установлена Arduino IDE.

Вы можете просмотреть местоположение своего эскиза, открыв меню «Файл» (англ. - File) и выбрав «Найстроки» (Preferences) в Arduino IDE. Если в этом месте еще нет папки с библиотеками, создайте ее самостоятельно. После установки библиотеки перезапустите Arduino IDE.

Примеры скетчей

После установки библиотеки датчика VL53L0X становится доступно пару примеров скетчей, которые показывают, как использовать библиотеку.

Вы можете получить к ним доступ из IDE Arduino, открыв меню:

Файл -> Примеры -> VL53L0X

Я приведу код примеров ниже. Если вы не можете найти эти примеры, библиотека, вероятно, была установлена неправильно, и вам следует повторить приведенные выше инструкции по установке.

Пример №1

Первый пример показывает как использовать непрерывный режим для измерения дальности с помощью VL53L0X. Он основан на vl53l0x_ContinuousRanging_Example.c из API VL53L0X.

Показания диапазона приведены в миллиметрах.

Если вы просто скопируете код ниже, то не забудьте, что вам нужно установить две библиотеки для корректной работы - Wire.h и VL53LOX.h.

#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("Не удалось обнаружить и инициализировать датчик!");
    while (1) {}
  }

  // Запустите непрерывный режим (снимайте показания 
  // как можно быстрее). Чтобы вместо этого использовать непрерывный синхронизированный режим,
  // укажите желаемый период между измерениями в мс 
  // (например, sensor.startContinuous(100)).
}

void loop()
{
  Serial.print(sensor.readRangeContinuousMillimeters());
  if (sensor.timeoutOccurred()) { Serial.print(" ТАЙМАУТ"); }

  Serial.println();
}

Пример № 2

Во втором примере показано, как получить одиночное измерение дальности с помощью VL53L0X. При желании датчик можно настроить с различными профилями измерения дальности. Подробнее можно посмотреть в руководстве пользователя API VL53L0X, чтобы повысить производительность для определенного проекта. Код основан на четырех примерах "SingleRanging" из API VL53L0X.

Показания диапазона приведены в миллиметрах.

#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

// Раскомментируйте строку ниже, чтобы использовать дальний режим. 
// Это увеличивает чувствительность датчика и расширяет его потенциальный диапазон, 
// но увеличивает вероятность получения неточных показаний 
// из-за отражений от объектов, отличных от намеченной цели. 
// Лучше всего работает в темноте.

//#define LONG_RANGE

// Раскомментируйте одну из двух строк ниже, чтобы получить:
// - более высокую скорость за счет меньшей точности ИЛИ
// - более высокую точность за счет меньшей скорости

//#define HIGH_SPEED
//#define HIGH_ACCURACY

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("Не удалось обнаружить и инициализировать датчик!");
    while (1) {}
  }

#if defined LONG_RANGE
  // понижает предел скорости обратного сигнала (по умолчанию 0,25 MCPS (мчип/с))
  sensor.setSignalRateLimit(0.1);
  // увеличить периоды лазерного импульса (по умолчанию 14 и 10 PCLK)
  // * - PCLK — это частота периферии
  sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
  sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
#endif

#if defined HIGH_SPEED
  // уменьшить тайминг до 20 мс (по умолчанию около 33 мс)
  sensor.setMeasurementTimingBudget(20000);
#elif defined HIGH_ACCURACY
  // увеличить тайминг 200 мс
  sensor.setMeasurementTimingBudget(200000);
#endif
}

void loop()
{
  Serial.print(sensor.readRangeSingleMillimeters());
  if (sensor.timeoutOccurred()) { Serial.print(" ТАЙМАУТ"); }

  Serial.println();
}

API VL53L0X

Большая часть функциональности этой библиотеки основана на API VL53L0X, предоставленной компанией производителем. Отдельные комментарии в коде цитируются или перефразированы из исходного кода API, руководства пользователя API (UM2039) и Технического описание VL53L0X.

Для получения дополнительной информации о коде библиотеки и о том, как он был получен из API, см. комментарии в файле VL53L0X.cpp на GitHub.

Эта библиотека предназначена для того, чтобы обеспечить более быстрый и простой способ начать использование VL53L0X с Arduino-совместимым контроллером, в отличие от настройки и компиляции API-интерфейса ST для Arduino.

Библиотека имеет более упрощенный интерфейс, а также меньший объем памяти. Однако она не реализует некоторые из более продвинутых функциональных возможностей, доступных в API (например, калибровка датчика для правильной работы под стеклом), и имеет менее надежную проверку ошибок.

Для продвинутых приложений, особенно когда хранение и память менее важны, рассмотрите возможность использования API VL53L0X напрямую (скачать документацию API можно выше).

Справочник по библиотеке

uint8_t last_status

Статус последней передачи записи I²C. Обратитесь к документации Wire.endTransmission() для получения возвращаемых значений.

VL53L0X(void)

Конструктор

void setAddress(uint8_t new_addr)

Изменяет адрес ведомого устройства I²C VL53L0X на заданное значение (7-разрядное, 7 бит).

uint8_t getAddress(void)

Возвращает текущий адрес I²C.

bool init(bool io_2v8 = true)

Инициализирует и настраивает датчик. Если необязательный аргумент io_2v8 равен true (по умолчанию, если не указан), датчик настроен на режим 2V8 (вход / выход 2,8 В); если false, датчик остается в режиме 1V8. Возвращаемое значение является логическим значением, указывающим, успешно ли завершена инициализация.

void writeReg(uint8_t reg, uint8_t value)

Записывает 8-битный регистр датчика с заданным значением.

Константы адреса регистра определяются типом перечисления regAddr в VL53L0X.h.

Пример использования: sensor.writeReg(VL53L0X::SYSRANGE_START, 0x01);

void writeReg16Bit(uint8_t reg, uint16_t value)

Записывает 16-битный регистр датчика с заданным значением.

void writeReg32Bit(uint8_t reg, uint32_t value)

Записывает 32-битный регистр датчика с заданным значением.

uint8_t readReg(uint8_t reg)

Считывает 8-битный регистр датчика и возвращает прочитанное значение.

uint16_t readReg16Bit(uint8_t reg)

Считывает 16-битный регистр датчика и возвращает прочитанное значение.

uint32_t readReg32Bit(uint8_t reg)

Считывает 32-битный регистр датчика и возвращает прочитанное значение.

void writeMulti(uint8_t reg, uint8_t const * src, uint8_t count)

Записывает произвольное количество байтов из заданного массива в датчик, начиная с заданного регистра.

void readMulti(uint8_t reg, uint8_t * dst, uint8_t count)

Считывает произвольное количество байтов с датчика, начиная с данного регистра, в данный массив.

bool setSignalRateLimit(float limit_Mcps)

Устанавливает ограничение скорости обратного сигнала до данного значения в единицах MCPS (мегачип в секунду). Это минимальная амплитуда сигнала, отраженного от цели и полученного датчиком, необходимого для того, чтобы он мог сообщить правильное значение. Установка нижнего предела увеличивает потенциальный диапазон датчика, но также увеличивает вероятность получения неточного показания из-за отражений от объектов, отличных от намеченной цели. Этот лимит по умолчанию инициализируется до 0,25 MCPS. Возвращаемое значение является логическим значением, указывающим, был ли запрошенный предел действительным.

float getSignalRateLimit(void)

Возвращает текущий предел скорости обратного сигнала в MCPS.

bool setMeasurementTimingBudget(uint32_t budget_us)

Устанавливает временной интервал измерения для данного значения в микросекундах. Это время, разрешенное для одного измерения диапазона; более длительный тайминг позволяет проводить более точные измерения. По умолчанию составляет около 33000 микросекунд или 33 мс; минимум 20 мс. Возвращаемое значение является логическим значением, указывающим, было ли запрошенное значение действительным.

uint32_t getMeasurementTimingBudget(void)

Возвращает текущий тайминг измерения в микросекундах.

bool setVcselPulsePeriod(vcselPeriodType type, uint8_t period_pclks)

Устанавливает период импульса VCSEL (лазер с поверхностным излучением с вертикальной полостью) для данного типа периода (VL53L0X::cselPeriodPreRange или VL53L0X::VcselPeriodFinalRange) равным данному значению (в PCLK). Более длительные периоды увеличивают потенциальный диапазон датчика. Допустимые значения (только четные числа):

- Предварительно: от 12 до 18 (по умолчанию инициализируется до 14)
- Итоговое: от 8 до 14 (по умолчанию инициализируется до 10)

Возвращаемое значение является логическим значением, указывающим, был ли запрошенный период действительным.

uint8_t getVcselPulsePeriod(vcselPeriodType type)

Возвращает текущий период импульса VCSEL для данного типа периода.

void startContinuous(uint32_t period_ms = 0)

Начинает непрерывное измерение дальности. Если необязательный аргумент period_ms равен 0 (по умолчанию, если не указан), используется непрерывный режим (датчик проводит измерения как можно чаще); если он не нулевой, используется непрерывный синхронизированный режим с указанным периодом между измерениями в миллисекундах, определяющим, как часто датчик выполняет измерение.

void stopContinuous(void)

Останавливает непрерывный режим.

uint16_t readRangeContinuousMillimeters(void)

Возвращает показание диапазона в миллиметрах, когда активен непрерывный режим.

uint16_t readRangeSingleMillimeters(void)

Выполняет одиночное измерение дальности и возвращает показания в миллиметрах.

void setTimeout(uint16_t timeout)

Устанавливает период ожидания в миллисекундах, после которого операции чтения будут прерваны, если датчик не готов. Значение 0 отключает тайм-аут.

uint16_t getTimeout(void)

Возвращает текущую настройку периода ожидания.

bool timeoutOccurred(void)

Указывает, произошел ли тайм-аут чтения с момента последнего вызова timeoutOccurred().