Пиу-пиу

Лазер как способ передавать текстовые сообщения

Телефон из бумажных стаканчиков из-под мороженого вполне можно считать одним из важнейших изобретений человечества. Это простое устройство, которое может собрать даже ребенок, позволяет вести разговор на относительно большом расстоянии. Не межгород, конечно, но на расстоянии пары десятков метров работает. Помните детский восторг, когда, прислонив ухо к стаканчику или спичечному коробку, вы слышали голос своего приятеля?

Время прошло. Технологии шагнули далеко вперед, но частичка детства все еще остается с нами. Случившаяся самоизоляция значительно усложнила покупку устройств для самоделок, но дала достаточно времени на испытание не очень распространенных способов обмена сообщениями. Совместно с инженерами «Авито» (кстати, недавно они выложили отличный Playbook) редактор N + 1 Василий Сычёв создал компактные кодировщики-декодировщики Морзе, способные передавать сообщения с помощью лазерного луча.

Свет как способ связи

Человечество изобрело множество способов обмениваться информацией на расстоянии. Для этого оно использовало дым от костров, трубы, барабаны, электромагнитные волны и, конечно же, свет. Сегодня без оптических сетей сложно представить высокоскоростной доступ в интернет — по меньшей мере в ваш подъезд сделан ввод международной сети с помощью оптического волокна. Но началось все, пожалуй, в 1880 году.

Тогда канадский изобретатель шотландского происхождения Александер Белл и его помощница Сара Орр запатентовали устройство, позволявшее вести разговор на расстоянии с помощью света. Это устройство получило название «фотофон». Оно состояло из передатчика — тонкого способного вибрировать зеркала — и приемника — параболического зеркала с селеновыми ячейками в точке фокусировки. Передатчик фотофона отражал свет в сторону приемника.

Принцип работы устройства был довольно прост. Человек, говоривший в передатчик, вызывал колебания отражающего зеркала. Это приводило к неравномерному отражению солнечного света и, как следствие, неравномерному же освещению приемника. Такая вот модуляция. Селеновые же ячейки в параболическом зеркале приемника под воздействием неравномерного освещения изменяли свое электрическое сопротивление от нескольких сотен до нескольких десятков Ом.

Таким образом осуществлялась модуляция электрического тока в цепи приемника. Изменения тока вызывали колебания пластин в наушниках, благодаря чему и воспроизводился принятый фотофоном голос.

Первый эксперимент с фотофоном был поставлен Беллом в 1880 году в Вашингтоне. Во время испытаний голосовое сообщение было передано на расстояние 213 метров с использованием только лишь солнечного света. Впрочем, последующие эксперименты показали, что качество передачи голоса напрямую зависит от облачности и качества воздуха. Например, облака или туман существенно ухудшали слышимость или вовсе делали передачу голоса невозможной. Тем не менее, Белл получил четыре патента на фотофон, усовершенствованные аналоги которого стали широко использоваться лишь век спустя.

Современные волоконно-оптические линии и так называемые линии оптики свободного пространства (FSO, free space optics) являются потомками того самого фотофона. В них оптические модемы — устройства, модулирующие световое излучение, — передают данные на большие расстояния посредством тончайших стеклянных проволочек или мощных лазерных излучателей.

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

Доморощенная оптика свободного пространства

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

Приемо-передатчики FSO представляют собой устройства с оптическими приемниками и лазерными инфракрасными передатчиками. При этом передача модулированного лазерного сигнала производится через атмосферу без дополнительных приспособлений. В таких устройствах обычно используются лазеры с длиной волны от 700 до 950 нанометров или 1550 нанометров. В идеальных условиях технология FSO позволяет обмениваться данными на скорости до 30 гигабит в секунду на расстоянии до трех километров.

Устройства, которые мы собрали совместно с инженерами «Авито», можно сказать, используют технологию FSO. В самом примитивном ее виде. Устройства довольно просты. Всего мы собрали два устройства, с помощью которых два самоизолированных москвича на расстоянии сотни метров могут обмениваться простыми текстовыми сообщениями.

Каждое устройство выполнено на базе микроконтроллера Arduino Nano, миниатюризованный аналог платы Arduino Uno. На основе такой мы уже собирали флопотрон. Кроме того, в конструкцию устройства входит жидкокристаллический символьный дисплей на две строки по 16 символов в каждой. Передача символов на дисплей и управление им производятся с помощью платы-преобразователя шины I2C (обмен данными со множеством устройств всего по двум проводам), линии данных которой подключены к аналоговым пинам A4 и A5.

Наконец, устройство оснащено лазерным излучателем для передачи данных, фоторезистором для регистрации излучения и тактовой кнопкой. Включать лазерный излучатель можно как нажатием кнопки, так и программно, подавая на него питание с помощью управляемого пина на плате Arduino Nano. Фоторезистор сделан частью делителя напряжения и подключен к цифровому пину D2.

Сам фоторезистор пришлось спрятать внутри гильзы для обжима многожильной проводки. Дело в том, что днем уровень освещенности достаточно высок, чтобы на цифровом пине D2 определялась постоянная логическая единица. Гильза служит своего рода блендой, препятствующей попаданию на фоторезистор паразитной засветки. Кроме того, внутри металлическая гильза имеет зеркальную поверхность, что несколько упрощает прицеливание лазерным лучом.

Анод лазера подключен к цифровому пину D3. При нажатии кнопки пять вольт подаются непосредственно на лазер, а при программном управлении — на цифровом пине D3 появляется логическая единица, то есть напряжение около пяти вольт. В обоих случаях лазер включается. При отпускании кнопки или переводе D3 в логический ноль, лазер выключается.

Для передачи информации можно использовать самые разнообразные системы. Например, таблицу ASCII. В ней распространенным символам соответствуют уникальные цифровые коды. Именно эти коды и можно передавать с помощью лазерного луча. При этом, если разработчик обладает усидчивостью, можно даже реализовать алгоритм контрольной суммы для обнаружения и в некоторых случаях коррекции ошибок в передаче данных.

Передавать символы ASCII можно восьмибитными пакетами, состоящими из последовательности восьми нулей и единиц. При использовании микроконтроллеров и автоматизации передачи сообщений, возможно создать алгоритм синхронизации, при котором передать единицу можно включением лазера на строго определенный промежуток времени и выключением его опять же на строго определенный промежуток времени.

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

Именно такая бинарность кода Морзе делает его удобным для передачи на расстояние с помощью лазера. Для того, чтобы избежать необходимости писать алгоритм синхронизации передачи и приема сообщений, мы решили отказаться от передачи точки, которую приняли за условный ноль, выключением лазера. Вместо этого передача производится именно по принципу морзянки: короткое включение лазера — точка, длинное — тире.

Программная часть

Мы написали два варианта скетча (так называется программа для Arduino). Первый вариант состоит из 92 строк кода. Он описывает работу микроконтроллера только в качестве приемника и декодировщика кода Морзе. В этом случае отправка сообщений производится, можно сказать, по-старинке: нажатием кнопки вручную. Посмотреть весь код можно на GitHub; он подробно прокомментирован. Здесь мы приведем лишь небольшую часть кода, исполняемую в цикле loop.

void loop() {
  press = millis();
  while (digitalRead(LIGHT)) {
    signal = millis() - press;
  }
  if (signal > 100) {
    morze += morzeCode();
    signal = 0;
  }
  lcd.setCursor(0,0);
  lcd.print("Код: ");
  lcd.print(morze);
  release = millis();
  while (!digitalRead(LIGHT)) {
    waitTimer = millis() - release;
    if (waitTimer >= 2000 &&
        morze.length() >= 1 &&
        morze.length() <= 6) {
      if (lcdSymbol < 16) {
        lcd.setCursor(lcdSymbol,1);
      } else if (lcdSymbol == 16) {
        lcd.setCursor(0,1);
        lcdSymbol = 0;
      }
      morze2letter();
      nullFirstRow();
      morze = "";
    }
  }
}

В этом коде определение тире или точки производится с помощью чтения состояния пина D2 и продолжительности этого состояния. Для этого используется функция millis() возвращающая время от начала исполнения цикла loop в миллисекундах.

Сначала необходимо определить, облучается ли фоторезистор лазером. Для этого в переменную press записывается время от начала цикла loop. Затем, если фоторезистор облучается и на пине D2 возникает логическая единица, начинает работать цикл while, записанный по принципу while true. То есть он повторяется до тех пор, пока на D2 присутствует логическая единица, то есть условие цикла является истинным.

На протяжении всего цикла производится постоянное вычисление продолжительности сигнала на фоторезисторе. Это простая формула: из текущего времени от начала цикла loop, возвращаемого функцией millis(), отнимается время, прежде записанное в переменную press. Вычисленная разница записывается в переменную signal.

Как только фоторезистор перестает облучаться и на D2 появляется логический ноль, цикл while прерывается, и код в теле loop продолжает исполнятся. Отдельно написанная функция morzeCode() позволяет по величине в переменной signal определить, пришла точка или тире. Опытным путем было установлено, что при ручном нажатии кнопки величина signal не превышает 200 миллисекунд в случае точки, и превышает их в случае тире.

Результат работы функции morzeCoder() — символ точки или тире — сохраняется в строковую переменную morze с помощью конкатенации. Следует отметить, что это не лучшее решение, поскольку работа со строковыми переменными в Arduino реализована криво и иногда может давать неожиданный результат. В нашем случае все работает замечательно, но все равно следует быть осторожным.

Для того, чтобы конкатенация работала, в программе реализован оператор ветвления if с условием, что значение переменной signal больше 100. И он же служит своего рода защитой от регистрации возможных случайных вспышек или паразитной засветки фоторезистора.

Наконец, введен дополнительный цикл while, срабатывающий в том случае, если на D2 появляется логический ноль. Цикл срабатывает, если функция digitalRead() возвращает 0. В этом цикле измеряется время, в течение которого не регистрируется лазерное излучение. Это необходимо для разделения передачи символов морзянкой. Благодаря этому последовательность точек и тире считается завершенной, если новых вспышек лазера не регистрируется больше двух секунд (в случае автоматической отправки сообщений продолжительность импульсов точек и тире, а также интервалы между последовательностями точек и тире можно существенно уменьшить).

Второй скетч представляет собой доработанный вариант первого. Он состоит из 125 строк кода. В этом варианте добавлена возможность обмениваться информацией с компьютером через последовательный порт (он эмулируется Arduino и определяется в системе как один из номерных портов COM). Отправлять на Arduino Nano сообщения и принимать сообщения от микроконтроллера можно с помощью встроенного в среду разработки Arduino IDE «Монитора порта». Для разбора принимаемых Arduino Nano с компьютера сообщений, кодирования их в морзянку и отправку на другое устройство с помощью лазера была дописана небольшая функция. Вот она:

void getMessage() {
  message = Serial.readString();
  Serial.println(message);
  for (int i = 0; i < message.length(); i++) {
    for (int j = 0; j < 55; j++) {
      if (symbols[j] == message[i]) {
        for (int ij = 0; ij < strlen(dotsAndDashes[j]); ij++) {
          if (dotsAndDashes[j][ij] == '.') {
            digitalWrite(LASER, HIGH);
            delay(100);
            digitalWrite(LASER, LOW);
            delay(100);
          } else if (dotsAndDashes[j][ij] == '-') {
            digitalWrite(LASER, HIGH);
            delay(250);
            digitalWrite(LASER, LOW);
            delay(100);
          }
        }
      }
    }
    delay(800);
  }
}

В ней текст, переданный Arduino Nano с помощью «Монитора порта», записывается в строковую переменную message с помощью метода readString() объекта Serial. Этот объект описывает работу с последовательным портом. Затем принятое сообщение передается обратно в «Монитор порта» для контроля — чтобы оператор (будем так называть человека, посылающего сообщение) мог увидеть, действительно ли текст принят Arduino Nano.

Дальнейшая задача отправки кода Морзе с помощью лазера решается тремя, вложенными один в другой циклами for. Первый цикл итерирует по каждой букве полученного через «Монитор порта» текста. Второй — повторяется 55 раз (по числу хранящихся в массивах последовательностей кодов Морзе и соответствующих им букв алфавита). Он необходим для того, чтобы сопоставлять каждую букву сообщения (определяется первым циклом) с каждой переменной в массиве букв алфавита (определяется вторым циклом).

В случае, если найдено совпадение между буквой в сообщении и буквой в массиве, запускается третий цикл. Он итерирует по каждому символу в последовательности точек и тире, соответствующей определенной ранее букве. В случае, если в последовательности встречается точка, лазер включается на 100 миллисекунд, а если тире — то на 250. Продолжительность включения можно уменьшить. Тогда повысится скорость передачи сообщения.

Наконец, после того, как отработают два цикла, вложенных в первый, выполнение программы приостанавливается на 800 миллисекунд. Это необходимо для того, чтобы сработал таймер задержки, то есть программа определила, что последовательность точек и тире передана и дальнейших вспышек лазера не последует. Только после этого на экран выводится декодированный символ и все повторяется сначала до тех пор, пока не закончатся буквы в принятом от «Монитора порта» тексте.

К слову, если в первом варианте скетча код Морзе кодировал буквы русского алфавита, то во втором он кодирует буквы латинского алфавита. Таким образом пришлось обойти одно из ограничений Arduino. Дело в том, что «Монитор порта» Arduino IDE, передает русский текст в кодировке Windows 1251, родной кодировке для операционных систем Windows. В этой же кодировке Arduino IDE возвращает принятый текст «Монитору порта».

Однако внутри себя Arduino Nano, как и другие Arduino, работает с принятым текстом в кодировке UTF. В случае с латинским алфавитом, это не вызывает никаких проблем, — для всех кодировок латинские буквы имеют одинаковое расположение в таблицах этих самых кодировок. Русские же буквы в таблицах кодировок Windows 1251 и UTF имеют разное положение. В результате буквы, принятые в кодировке Windows, при прямом отображении в UTF без конвертации выводятся в виде «крякозябр». Вы, наверное, встречали такое на некоторых сайтах, особенно старых, не поддерживающих или поддерживающих неправильно кодировку UTF-8.

В целом же оба скетча выводят информацию на дисплей на двух строках. На первой строке дисплея отображается принимаемый код Морзе. На второй — декодированное сообщение. Причем если символы во второй строке заканчиваются, а принятое сообщение еще закончилось, оно продолжает отображаться на этой же строке слева направо, постепенно стирая ранее выведенную на дисплей информацию — своеобразная бегущая строка.

Подводя итог, можно сказать одно: Arduino — одна из замечательных платформ, позволяющих интерактивно и увлекательно изучать языки программирования. В данном случае — основы C и C++. Написал простой код — помигал светодиодом, написал код посложнее — передал текст с помощью лазера.

Василий Сычёв

Нашли опечатку? Выделите фрагмент и нажмите Ctrl+Enter.
Назвался груздем

Тест, который научит вас разбираться в грибах