Эта статья написана по мотивам вот этой. Чтобы повторить успех к имеющейся Baofeng uv-5r была приобретена Quansheng uv-k5, а потом и ещё одна uv-k5, потому что uv-5r очень долго активировал функцию VOX. Кейс очень интересный, но практически использовать его тяжеловато из-за низкой скорости передачи. Ниже описана попытка избавиться от этого недостатка.
Дисклеймер
Туториал описывает как передавать данные через радиоканал, поэтому прежде чем шалить, ознакомьтесь с нормативно-правовой базой государства, на территории которого предполагается шалость.
Автор надеется, что статью прочтут люди, которые разбираются в темах, затронутых в статье, и дадут конструктивную критику.
Введение
Для эксперимента понадобятся два ноутбука, два микроконтроллера и два радиомодуля, например, Ebyte E22. На самом деле подойдут и Raspberry Pi и специальные модули от Waveshare для них. И вообще, необязательно использовать LoRa, можно и привычную FSK на CC1101. В общем, подойдёт всё, что попадётся под руку. На первом этапе, чтобы проверить, как настроен сетевой протокол, микроконтроллеры вообще будут соединены между собой просто проводниками по UART.
Идея в том, чтобы инициализировать сетевой протокол AX.25 через UART, и тогда можно использовать любое устройство с UART на борту для передачи данных. Причём связь будет ограничена лишь радиоканалом. Для Ebyte E22 максимальная скорость передачи 62500 бод. Но на такой скорости информация станет передаваться с потерями. У модулей СС1101 или RF4463F30 скорость передачи можно настроить уже на 500 кбит/сек! Только чудес в дальности передачи ждать не стоит.
Заметка от автора
Автор этой статьи остановился на Ebyte E22 по нескольким причинам. Самая главная из них - это дальность, на которой получилось установить хорошую низкоскоростную связь. При мощности 30 dBm на скорости 4800 бод устойчивая связь была на расстоянии 110 км! С оговорками, конечно же. В эксперименте была обеспечена прямая видимость между антеннами модулей. Без прямой видимости таких результатов ждать не придётся.
Настройка AX.25 в Linux
Установите программы:
sudo apt-get install libax25 ax25-apps ax25-tools
Создайте исполняемый файл kiss.sh следующего содержания:
sudo nano kiss.sh
#!/bin/sh
# start ax25 on ttyS0 using port defined in /etc/ax25/axports
/usr/sbin/kissattach -m 254 /dev/ttyACM0 ax0 10.10.10.1
sleep 1
# listen for various incoming connects like PMS, node, etc.
# (MUST first be configured in /etc/ax25/ax25d.conf)
/usr/sbin/ax25d
sleep 1
# listen for stations heard
/usr/sbin/mheardd
#end of script
Обратите внимание на то, что usb-to-com преобразователь может оказаться на другом порту (не на ttyACM0). Можно вывести список командой ls /dev
и выбрать что-то типа /dev/ttyACM0
.
Скрытый текст
Сделайте файл kiss.sh исполняемым:
sudo chmod a+x kiss.sh
Отредактируйте файл /etc/ax25/axports:
sudo nano /etc/ax25/axports
# /etc/ax25/axports
# The format of this file is:
#
# name callsign speed paclen window description
ax0 ABCDEF 115200 254 1 LoRa<br>
#replace ABCDEF with your 6 letter callsign
Необходимо выполнить те же самые действия для второго компьютера, но указать другой ip адрес и позывной (строка 6 в файле /etc/ax25/axports.
На первом компьютере позывной ABCDEF. Тогда на втором компьютере можно использовать FEDCBA, например).
Промежуточный эксперимент
Чтобы проверить, что всё работает правильно, можно собрать простой экспериментальный стенд. Предлагается использовать два ноутбука, к каждому из которых подключена своя отладочная плата Arduino UNO. Reset каждой из отладочных плат следует соединить с GND, чтобы можно было спокойно пользоваться usb-to-com преобразователем. Отладочные платы следует соединить через последовательные интерфейсы. Обратите внимание на включение RX первой платы в TX второй и TX первой платы в RX второй платы. Платы должны быть соединены по "земле".
/*
UNO 1 UNO 2
---------------------------
0 RX -------------- 1 TX
1 TX -------------- 0 RX
GND -------------- GND
*/
Запустите скрипт kiss.sh с правами суперпользователя:
sudo ./kiss.sh
Теперь можно пинговать компьютеры, подключаться по SSH, передавать файлы с помощью SCP. И многое другое, на что только способно сетевое соединение компьютеров.
Скрытый текст
Заметка от автора
На фото есть подключённые сс1101 на отладочных платах, они в этом эксперименте не участвуют. Если присмотреться, то можно увидеть, что Arduino UNO соединены Reset в GND.
Промежуточные итоги
На этом этапе получилось соединить компьютеры по сети через usb-to-com преобразователи. Есть двусторонний доступ одного компьютера к другому на скорости, позволяющей работать через терминал (а что ещё нужно для счастья?).
Конечно, можно всё оставить и так, только вот длина соединения по последовательному порту оставляет желать лучшего. Тогда напрашивается решение, которое позволит буферизировать данные, поступающие в последовательный порт, и передать их через радиоканал. Дальше немножко сложнее, зато интереснее!
Подготовка радиоканала к передаче данных
В следующем эксперименте будут использованы микроконтроллеры ESP32-S3 на отладочных платах YD-ESP32-23 и два модуля Ebyte E22-400T33D. В качестве IDE используем VS code с PlatformIO (Arduino framework). Для удобства работы с Ebyte E22 можно использовать проверенную автором библиотеку (а можно и не использовать, если скучно).
Заметка от автора
Если поизучать информацию из репозитория, то можно обнаружить, что необязательно ограничивать себя микроконтроллером ESP32. В примерах можно найти реализацию для Arduino UNO и других отладочных плат. А в других репозиториях автора этой замечательной библиотеки есть реализация для других модулей Ebyte, например, E32 или E220. И ещё масса полезной информации!
Программа для микроконтроллера состоит из двух частей: работа с последовательным портом и работа с Ebyte. Для приёма данных из последовательного порта можно использовать исходный код:
while(Serial.available()>0){
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// set a flag so the main loop can do something about it:
stringComplete = true;
}
// when a newline arrives:
if(stringComplete){
// clear a flag:
stringComplete = false;
// print the string:
Serial1.print(inputString);
// clear buffer:
inputString = "";
}
Для промежуточной проверки можно дописать ещё одно условие:
if(Serial1.available()>0){
Serial.write(Serial1.read());
}
Скрытый текст
#include <Arduino.h>
HardwareSerial SerialPort(2);
bool stringComplete = false; // whether the string is complete
String inputString = ""; // a String to hold incoming data
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
SerialPort.begin(115200, SERIAL_8N1, 38, 2);
String str="Ok";
SerialPort.println(str);
}
void loop() {
// put your main code here, to run repeatedly:
while(Serial.available()>0){
char inChar = (char)Serial.read();
inputString += inChar;
stringComplete = true;
}
if(stringComplete){
stringComplete = false;
SerialPort.print(inputString);
inputString = "";
}
if(SerialPort.available()>0){
Serial.write(SerialPort.read());
}
}
Теперь, если запрограммировать пару отладочных плат таким кодом и соединив последовательные порты микроконтроллеров проводами, можно убедиться, что строка записывается и отдаётся в другой компьютер. Снова работает ping и другие прелести терминала.
Скрытый текст
Заметка от автора
На фото выше отладочная плата на ESP32-S3 запрограммирована простым исходным кодом, который позволяет принять из последовательного порта первого компьютера строку и отправить её в последовательный порт второго компьютера.
Автор всегда тестирует функциональные части кода, чтобы отсеивать ошибки на этапе их появления по одной.
Заметка от автора
Следующие абзацы могут показаться непонятными. Чтобы такого не случилось, лучше сначала немного поэкспериментировать с примерами из библиотеки. Всё станет понятнее.
На следующем этапе подключим библиотеку. Сконфигурируем модули в режим FT_FIXED_TRANSMISSION (configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;)
. Мощность можно ограничить до минимально возможной POWER_24 (configuration.OPTION.transmissionPower = POWER_24;)
. В адресе одного модуля можно указать ADDL = 0x2 (configuration.ADDL = 0x2;)
, а в адресе другого ADDL = 0x3 (configuration.ADDL = 0x3;)
.
Скрытый текст
Заметка от автора
Автору для экспериментов были доступны модули Ebyte E22-400T33D мощностью 2 Вт. Чтобы правильно регулировать мощность и выводить отладочную информацию, в файл statesNaming.h был дописан участок с кодом:
#elif defined(E22_33)
enum TRANSMISSION_POWER
{
POWER_33 = 0b00,
POWER_30 = 0b01,
POWER_27 = 0b10,
POWER_24 = 0b11
};
static String getTransmissionPowerDescriptionByParams(byte transmissionPower)
{
switch (transmissionPower)
{
case POWER_33:
return F("33dBm (Default)");
break;
case POWER_30:
return F("30dBm");
break;
case POWER_27:
return F("27dBm");
break;
case POWER_24:
return F("24dBm");
break;
default:
return F("Invalid transmission power param");
}
}
Тогда можно написать
#define E22_33,
и информация о мощности будет выводиться корректно. Если этого не сделать, то на работу системы это не повлияет! Только на вывод отладочной информации.
Скрытый текст
void initEbyteE22_400(){
e22ttl_400.begin();
ResponseStructContainer c;
c = e22ttl_400.getConfiguration();
// It's important get configuration pointer before all other operation
Configuration configuration = *(Configuration*) c.data;
Serial.println(c.status.getResponseDescription());
Serial.println(c.status.code);
printParameters(configuration);
configuration.ADDL = 0x02; // configuration.ADDL = 0x03;
configuration.ADDH = 0x00;
configuration.NETID = 0x00;
configuration.CHAN = 23; // 410.125 + 23 = 433.125 МГц
configuration.SPED.uartBaudRate = UART_BPS_115200;
configuration.SPED.airDataRate = AIR_DATA_RATE_100_96;
configuration.SPED.uartParity = MODE_00_8N1;
configuration.OPTION.subPacketSetting = SPS_240_00;
configuration.OPTION.RSSIAmbientNoise = RSSI_AMBIENT_NOISE_DISABLED;
configuration.OPTION.transmissionPower = POWER_24;
configuration.TRANSMISSION_MODE.enableRSSI = RSSI_DISABLED;
configuration.TRANSMISSION_MODE.fixedTransmission = FT_FIXED_TRANSMISSION;
configuration.TRANSMISSION_MODE.enableRepeater = REPEATER_DISABLED;
configuration.TRANSMISSION_MODE.enableLBT = LBT_DISABLED;
configuration.TRANSMISSION_MODE.WORTransceiverControl = WOR_TRANSMITTER;
configuration.TRANSMISSION_MODE.WORPeriod = WOR_2000_011;
e22ttl_900.setConfiguration(configuration, WRITE_CFG_PWR_DWN_LOSE);
printParameters(configuration);
ResponseStructContainer cMi;
cMi = e22ttl_900.getModuleInformation();
ModuleInformation mi = *(ModuleInformation*)cMi.data;
Serial.println(cMi.status.getResponseDescription());
Serial.println(cMi.status.code);
printModuleInformation(mi);
c.close();
cMi.close();
}
Этим самым устанавливается режим адресной передачи (в библиотеке об этом написано в разделе Normal transmission mode). Мощность регулируется в зависимости от условий эксперимента. Устанавливаются необходимые адреса модулей. Это позволит при обращении из программы (ну или из терминала) на компьютере по определённому ip адресу обратиться к необходимому компьютеру с этим адресом. Модуль Ebyte с каким-то определённым адресом привязывается к компьютеру с каким-то определённым ip.
Transmitter
Теперь заменим в условии if(stringComplete)
15-ю строку для первого модуля Serial1.print(inputString);
на ResponseStatus rs = e22ttl.sendFixedMessage(0, 0x3, 23, inputString);
, а для второго модуля на ResponseStatus rs = e22ttl.sendFixedMessage(0, 0x2, 23, inputString);
С этими изменениями получается, что когда сформирована очередная строка, вместо того, чтобы передать её по проводам, эта строка передаётся модулю Ebyte. Который отправляет её в радиоканал по определённому адресу. Так, при получении строки по последовательному порту из первого компьютера данные отправляются в радиоканал по адресу 0x3 на второй компьютер. А при получении строки по последовательному из второго компьютера данные отправляются в радиоканал по адресу 0x2.
Receiver
Для приёма можно воспользоваться функцией из примеров. Полученные по радиоканалу данные следует отдать через последовательный порт компьютеру:
void somethingAvailableLORA(){
// If something available
if (e22ttl.available()>1) {
// read the String message
#ifdef ENABLE_RSSI
ResponseContainer rc = e22ttl.receiveMessageRSSI();
#else
ResponseContainer rc = e22ttl.receiveMessage();
#endif
// Is something goes wrong print error
if (rc.status.code!=1){
// Serial.println(rc.status.getResponseDescription());
}else{
// Print the data received
// Serial.println(rc.status.getResponseDescription());
Serial.print(rc.data);
#ifdef ENABLE_RSSI
Serial.print(F("RSSI: ")); Serial.println(rc.rssi, DEC);
#endif
}
}
}
Весь исходный код для эксперимента можно найти в репозитории.
Особенности при работе с библиотекой для Ebyte E22
Заметка от автора
Перед опытами для публикации автор хотел оставить скорость работы UART компьютер <-> YD-ESP32-23 и YD-ESP32-23 <-> Ebyte E22 равной 9600 бод. Но при первом же включении оказалось, что даже ping не проходят. Если отправить всего один ping (ping 10.10.10.2 -c 1
), то он пройдёт. А при отправке двух - один пройдёт, а другой потеряется. На самом деле автор имел опыт работы с Ebyte E22 и сразу увеличил скорость UART компьютер <-> YD-ESP32-23 и YD-ESP32-23 <-> Ebyte E22 до 115200 бод. И здесь поджидала сложность.
Внутри модуля Ebyte E22-400T33D есть микроконтроллер, с которым и взаимодействует ESP32. С одной стороны, это упрощает работу, а с другой - уменьшает быстродействие.
При конфигурации Ebyte E22-400T33D (И для Ebyte E22-400T30D, и, наверное, для других подобных модулей тоже. - Прим. авт.) на работу по UART со скоростью 115200, модуль перестаёт корректно выдавать свою конфигурацию и передавать/принимать данные.
Автор столкнулся с этой особенностью какое-то время назад и пока не придумал ничего лучше, чем манипулировать конфигурацией UART в ESP32. Применительно к использованию, описанному в данной статье, будет достаточно после инициализации модуля Ebyte в функции setup()
дописать строки:
Serial1.end();
Serial1.begin(115200, SERIAL_8N1, 18, 17);
Заметка от автора
Это костыль, и он помогает, но не всегда. Автору при работе с этими модулями в одном из применений пришлось отказаться от скорости 115200 бод. А для этого применения и так сойдёт.
После конфигурации UART компьютер <-> YD-ESP32-23 и YD-ESP32-23 <-> Ebyte E22 на 115200 бод ping заработал (~600 ms). Заработал SSH доступ (не получится сказать, что работать приятно, но это ощутимо быстрее, чем на скорости 2400 бод или 4800 бод через Quansheng UV-K5. - Прим. авт.). Получилось передать файл через SCP (на телефоне закончилось место, поэтому на видео не будет видно финала передачи. - Прим. авт.).
После этого эксперимента автор изменил скорость работы по радиоканалу на 19200 бод. Ping стали проходить в основном за ~500 ms. Чуть быстрее стали работать SSH и SCP, но несущественно.
Заметка от автора
Автор бы не стал увеличивать скорость больше 9600 бод из-за потерь. Эксперименты пока не проводились, но, очевидно, потери будут, и это негативно скажется на качестве связи и передаче файлов.
Итоги эксперимента
Теперь, если запрограммировать этим исходным кодом микроконтроллеры, данные станут передаваться через радиоканал. Дальность передач без потерь будет зависеть от скорости связи. Тогда регулируя скорость/дальность, можно решать задачи связи нескольких компьютеров привычным способом и достаточно бюджетно.
Заметка от автора
Есть предположение, что если отказаться от E22-400T33D и воспользоваться E22-400M33S (буква М в маркировке означает отсутствие внутри микроконтроллера), получится увеличить скорость передачи. Из цепочки UART компьютер <-> YD-ESP32-23 и YD-ESP32-23 <-> Ebyte E22 удалится передача по UART YD-ESP32-23 <-> Ebyte E22 и тогда взаимодействие будет идти по SPI напрямую на SX1268.
Используя адресацию, можно соединить и три компьютера и даже больше, но тогда надо будет придумать как бороться с коллизиями. В ходе экспериментов (и в UART терминале, и на спектре радиосигнала) видно, что операционная система отправляет много служебной информации в сеть. При соединении трёх компьютеров это уже может быть критично. Например, если в момент передачи файла с одного компьютера на другой, третий компьютер начнёт сыпать служебные сообщения, по простым правилам приёмник просто примет более сильный сигнал. Это и есть коллизия. Один из способов - это временное разделение. Автор в других экспериментах соединял до 5 устройств между собой на этих модулях, используя временное разделение, но это уже другая история.
Дальше несколько видео. К первому компьютеру подключён RTL-SDR и можно видеть радиоспектр.
Скрытый текст
На видео ping от PC 1 к PC 2. Скорость по радиоканалу 9600 бод
Заметка от автора
Команда ping работает лучше всех. 619 мс на отклик очень похож на правду, потому что в других экспериментах автора с LoRa отклик был ~400 мс. Там было чуть меньше, потому что не было операционной системы, и вся обработка осуществлялась на микроконтроллере.
Скрытый текст
На видео процесс подключения первого компьютера ко второму по SSH
Заметка от автора
Ждать подключения приходится долго, но оно всё-таки срабатывает, и это уже хорошо. Пока непонятно, где это можно применить в реальной жизни, но где-нибудь это да пригодится.
Скрытый текст
На видео работа через SSH с другим компьютером
Заметка от автора
Наверное, это самое интересное видео. Видно как при вводе символов терминал подтормаживает и как при этом работает радиоканал. Необходимо время, чтобы команда дошла до другого компьютера и вернулась обратно. Но даже с такими зависаниями всё ещё работает
Скрытый текст
На видео процесс передачи файла с помощью SCP с одного компьютера на другой через радиоканал
Заметка от автора
А это самое скучное видео, потому что процесс передачи простого и очень маленького файла занимает очень много времени. К тому же на смартфоне закончилось место в самый неподходящий момент. но процесс завершился успешно через несколько секунд после завершения видео.
Скрытый текст
На видео процесс выполнения команды ping после увеличения скорости передачи по радиоканалу до 19200 бод
Заметка от автора
После увеличения скорости передачи по радиоканалу ping стал выполняться на 100 мс быстрее, но некоторые команды иногда выполняются дольше, например, на ~800 мс. Сложно сказать с чем это связано. Эти радиомодули создавались не для высоких скоростей передачи информации, а для больших дальностей передачи с низкими энергозатратами, а тут через них связаны два компьютера на столе.
Скрытый текст
На видео процесс подключения первого компьютера ко второму по SSH при скорости передачи по радиоканалу 19200 бод
Заметка от автора
Увеличение скорости передачи по радиоканалу принесло свой результат. В прошлом подобном видео подключение было закончено примерно на 140 секунде, а теперь спустя 70 секунд уже всё готово.
Скрытый текст
На видео мигание светодиодов, которые подключены к RX TX отладочных плат
Заметка от автора
Процесс обмена между компьютерами происходит постоянно, это можно уведеть даже по светодиодам, которые распаяны на платах.
Скрытый текст
На видео процесс выполнения команды ping на втором компьютере
Заметка от автора
Связь доступна с обоих сторон
Скрытый текст
На видео спектр радиосигнала при выполнении команды ping на втором компьютере
Скрытый текст
На видео процесс передачи файла с помощью SCP через радиоканал на скорости 19200 бод
Заметка от автора
На скорости 19200 бод файл передался быстрее в почти 3 раза, чем при скорости 9600 бод.
Что почитать на эту тему
Спасибо.
С. Н.