uWave и Arduino: подключаем гидроакустический модем к микроконтроллеру

Как подключить гидроакустический модем uWave к Arduino по UART.
Лаборатория подводной связи и навигации
Главная / Статьи / Технологии / uWave и Arduino: подключаем гидроакустический модем к микроконтроллеру

Модем uWave имеет габариты 41 на 45 мм и массу 0,16 кг, а с управляющей системой общается по обычному UART. Поэтому подключить его к Arduino и другим микроконтроллерам несложно: нужны четыре-пять проводов и библиотека, которая разбирает текстовый протокол модема. В статье разберём, что для этого понадобится, как соединить модем с платой, как получить библиотеку uWAVE_ALib и какие задачи она решает.

Что понадобится

  • Модем uWave или uWave Max. Модемы семейства uWave используют один и тот же интерфейс сопряжения: UART 9600 бит/с и протокол NMEA 0183 PUWV. Другие устройства для передачи данных — в категории «Передача данных».
  • Плата, совместимая с Arduino Uno или Nano: именно такая плата указана в списке оборудования примеров библиотеки.
  • Питание модема 5–12 В.
  • Второй модем, если нужно запрашивать данные у удалённого абонента или передавать пакеты.

Как модем общается с контроллером

Физический интерфейс — UART с напряжением линий данных 3,3 В. Настройки по умолчанию: 9600 бит/с, 8 бит данных, 1 стоп-бит, без контроля чётности и аппаратного управления потоком. Обмен идёт текстовыми предложениями NMEA 0183 вида $PUWV0,1,0*hh с контрольной суммой. Без повторителей и преобразователей интерфейса корректная работа гарантируется на кабеле не длиннее 2 м.

У модема два режима, и разница между ними важна:

  • Прозрачный канал доступен сразу после включения: всё, что вы записали в UART, без анализа уходит в гидроакустический канал и в неизменном виде выдаётся принимающим модемом. Достаточно подключить модем к последовательному порту.
  • Командный режим: модем разбирает входные данные как команды. Он нужен для настройки, кодовых запросов удалённым модемам (глубина, температура, напряжение питания) с измерением времени распространения сигнала и для пакетного режима с гарантированной доставкой. Включается уровнем на жиле Service/CMD; в примерах библиотеки эту жилу ведёт вывод Arduino.

Две оговорки из документации. Жилу Service/CMD можно подтягивать только к уровню 3–5 В или к земле: более высокое напряжение приведёт к неустранимой негарантийной поломке. А перед включением питания эта жила должна быть притянута к земле, иначе модем войдёт в режим обновления программного обеспечения.

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

У кабеля uWave две версии, отличающиеся цветами жил: свою версию определите по схеме подключения в документации. Функции жил одинаковы. Вот как их соединяют с платой Arduino Nano в примерах библиотеки:

Функция Кабель версии 1 Кабель версии 2 Вывод Arduino Nano
Питание +5…+12 В зелёная красная VIN
UART Tx модема чёрная зелёная D2
UART Rx модема белая или прозрачная белая или прозрачная D3
Service / CMD коричневая жёлтая D4
GND экран экран GND

Tx модема идёт на приёмный вывод программного порта (D2), Rx модема — на передающий (D3). Связь с модемом ведётся через SoftwareSerial, а аппаратный Serial остаётся для монитора порта. У uWave Max интерфейс сопряжения такой же (UART 9600 бит/с, NMEA 0183 PUWV, питание 5–12 В), но цвета жил для своей модели сверьте с документацией.

Про питание и уровни. В примерах Arduino и модем питаются от USB-порта компьютера. Учтите, что в режиме передачи uWave потребляет 6 Вт (uWave Max — 15 Вт) против 0,33 Вт на приёме, а максимальная выходная мощность у uWave Max достигается только при напряжении 12 В. Кроме того, линии данных модема работают на уровне 3,3 В, а плата Nano — на 5 В. В примерах согласование уровней не описано, поэтому для постоянной установки предусмотрите его сами: плата на 3,3 В или преобразователь уровней.

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

Библиотека uWAVE_ALib имеет открытый исходный код, лицензия GPL-3.0. Исходный код лежит на GitHub, есть зеркало на GitVerse. В репозитории нет релизов и файла library.properties, а в индексе менеджера библиотек Arduino IDE её нет, поэтому установка ручная:

  1. Скачайте репозиторий (Code → Download ZIP) или клонируйте его.
  2. Создайте новый скетч и скопируйте в его папку два файла из каталога src: uWAVE_ALib.h и uWAVE_ALib.cpp.
  3. Подключите в скетче SoftwareSerial.h и "uWAVE_ALib.h".

В каталоге examples лежат два готовых скетча. Перед запуском кода полезно убедиться, что модем отвечает: подключите его к компьютеру через преобразователь UART-USB, включите командный режим и отправьте запрос информации об устройстве $PUWV?,0*27, добавив в конец символы CR LF. Этот пример приведён в спецификации протокола.

Пример: запрос к удалённому модему

Первый пример из репозитория («всё в одном») показывает почти все приёмы работы с модемом и выводит запросы и результаты в монитор порта. Ниже фрагмент, сокращённый и упрощённый по мотивам этого примера: убраны комментарии, начальная настройка и разбор остальных событий. Источник: examples/uWAVE_ALib_example_1.ino, github.com/ucnl/uWAVE_ALib, лицензия GPL-3.0.

#include <SoftwareSerial.h>
#include "uWAVE_ALib.h"

#define SPEED_OF_SOUND (1500)

#define REMOTE_MODEM_TX_ID (0)
#define REMOTE_MODEM_RX_ID (0)
#define REMOTE_REQUEST_PERIOD_MS (5000)

#define uWAVE_RX_PIN  (3)
#define uWAVE_TX_PIN  (2)
#define uWAVE_CMD_PIN (4)

long rem_req_ts = 0;

SoftwareSerial uWavePort(uWAVE_TX_PIN, uWAVE_RX_PIN);

uWAVE uWrapper(&uWavePort, uWAVE_CMD_PIN);
uWAVE_EVENT_Enum result;

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

  uWrapper.enable();
}

void loop()
{
  result = uWrapper.process();

  if (result != uWAVE_NONE)
  {
    if (result & uWAVE_REMOTE_RESPONSE_RECEIVED)
    {
      Serial.print(F("propagation time, s="));
      Serial.println(uWrapper.getRem_propTime_s());
      Serial.print(F("Slant range, m="));
      Serial.println(uWrapper.getRem_propTime_s() * SPEED_OF_SOUND);
      Serial.print(F("value="));
      Serial.println(uWrapper.getRem_value());
    }
  }
  else if (!uWrapper.isWaitingLocal() && !uWrapper.isWaitingRemote() &&
           (millis() - rem_req_ts >= REMOTE_REQUEST_PERIOD_MS))
  {
    if (uWrapper.queryRemoteModem(REMOTE_MODEM_TX_ID, REMOTE_MODEM_RX_ID, RC_DPT_GET))
      rem_req_ts = millis();
  }
}

Как это работает:

  • enable() поднимает уровень на жиле CMD, то есть включает командный режим.
  • process() нужно вызывать как можно чаще. Функция читает данные из порта и возвращает набор флагов событий: подтверждение команды, ответ удалённого модема, тайм-аут, доставка пакета и другие.
  • queryRemoteModem() отправляет кодовый запрос удалённому модему, а не возвращает данные сразу. Ответ придёт событием uWAVE_REMOTE_RESPONSE_RECEIVED со временем распространения сигнала и запрошенным значением. Для RC_DPT_GET это глубина удалённого модема. Одновременно выполняется один запрос: поэтому в условии проверяются isWaitingLocal() и isWaitingRemote().
  • Наклонная дальность — время распространения, умноженное на скорость звука. Пример берёт 1500 м/с. Разрешение по времени 0,0001 с даёт при такой скорости 0,15 м по дальности, но реальная скорость звука зависит от температуры, солёности и глубины. Для расчёта скорости звука есть онлайн-калькулятор: там же собраны и другие утилиты, например калькулятор контрольной суммы NMEA 0183, удобный при ручной отладке.

Типовые задачи

Телеметрия и дальность. Запросы RC_DPT_GET, RC_TMP_GET, RC_BAT_V_GET возвращают глубину, температуру и напряжение питания удалённого модема, а по времени ответа считается расстояние до него. Свои показатели модем с датчиком давления и температуры выдаёт после настройки функцией queryForAmbientDataConfig(): глубина, давление, температура воды и напряжение питания, однократно или с периодом от 0,5 до 60 с.

Удалённое управление. У модема девять пользовательских кодовых команд, RC_USR_CMD_000 … RC_USR_CMD_008. Второй пример из репозитория связывает их с девятью выводами Arduino (D5–D13): при получении команды на соответствующем выводе на 500 мс появляется высокий уровень. К выводам можно подключить светодиоды через резистор 200–300 Ом или реле. Так можно управлять автономным подводным устройством без кабеля.

Пакетная передача данных. В пакетном режиме модем передаёт до 64 байт с гарантированной доставкой (ALO, at-least-once) и уведомлением о получении. Адресация — от 0 до 254, адрес 255 используется для широковещательных сообщений без подтверждения. В библиотеке отправку выполняет queryForPktSend(), а исход приходит событиями uWAVE_PKT_DELIVERED с числом попыток, uWAVE_PKT_SEND_FAILED и uWAVE_PKT_RECEIVED с адресом отправителя. Для работы в этом режиме модемы переводят в командный режим, подробности — в спецификации протокола.

Прозрачный канал. Если нужно просто передавать байты, библиотека не нужна: данные, записанные в UART, уходят в гидроакустический канал как есть. Так можно связать два микроконтроллера.

Ссылки

Нужна помощь с интеграцией модема в ваше устройство? Напишите нам.

Приобрести
продукцию UCNL

Узнайте подробнее о системах цифровой беспроводной передачи данных под водой
Приобрести продукцию UCNL