В статье «DIY: передаем данные на километры с помощью контроллера Micro::Bit и радиомодуля EBYTE LoRa» (часть 1 и часть 2) мы рассказали, как обеспечить связь на обширных территориях при небольшой излучаемой мощности.

Но что, если нужно передавать данные на расстояния в десятки или даже сотни километров? Например, вдоль таких объектов, как автомобильные дороги, железнодорожные линии или трубопроводы?

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

Пока, однако, мы не будем решать такие грандиозные задачи, ограничившись увеличением дальности с помощью одного ретранслятора на micro::bit с радиомодулем LoRa EBYTE E32.

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

Разместим где-нибудь посередине ретранслятор, который будет получать запросы от центрального узла, сделанного на базе Raspberry Pi, и передавать их в парник на узел micro::bit. Данные измерений в парнике будут передаваться обратно на центральный узел опять же через ретранслятор (рис. 1).

Рис. 1. Архитектура системы сбора данных с ретранслятором
Рис. 1. Архитектура системы сбора данных с ретранслятором

Макет системы сбора данных с ретранслятором показана на рис. 2.

Рис. 2. Макет системы сбора данных с ретранслятором
Рис. 2. Макет системы сбора данных с ретранслятором

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

Центральный узел создан на базе Raspberry Pi, а ретранслятор и узел для парника — на базе micro::bit. 

Конфигурацию радиомодулей E32 мы оставили прежней. Все радиомодули в наших примерах будут работать на канале 15, а их адреса приведены в табл. 1.

Табл. 1. Адреса радиомодулей

Узел

Адрес

Центральный узел

14 (0x0E)

Ретранслятор

13 (0x0D)

Парник

12 (0x0C)

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

Узел ретранслятора

Программу micro::bit для ретранслятора, как и все программы из этой статьи, можно загрузить с сайта GitHub по адресу https://github.com/AlexandreFrolov/loranet.

Файл с программой для ретранслятора называется microbit-pxt-lora-repeater.hex, а файл программы для парника — microbit-lora-net-host2r.hex.

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

После инициализации на светодиодной матрице micro::bit зажигается буква «R», идентифицирующая узел ретранслятора (рис. 3).

Рис. 3. Блок инициализации ретранслятора
Рис. 3. Блок инициализации ретранслятора

Когда центральный узел отправляет в ретранслятор команду «getRData», блок ретранслятора передает по радиоканалу команду «getData» на узел парника с адресом 12 и рисует на мониторе micro::bit стрелку, направленную на сервер. После этого на монитор выводится буква «R» (рис. 4).

Рис. 4. Блок on e32radio received ретранслятора
Рис. 4. Блок on e32radio received ретранслятора

В ответ на команду «getData», отправленную на узел парника, ретранслятор получает от этого узла данные измерений. Они не содержат строку «getRData» и отправляются ретранслятором в неизменном виде на центральный узел с адресом 14.

Как только данные будут отправлены, на мониторе ретранслятора на короткое время появится стрелка, направленная на юг, а затем ее сменит буква «R».

Таким образом, наш ретранслятор передает в одну сторону (в парник) команду «getRData», а затем в другую строну (на центральный узел) данные измерений в парнике.

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

Узел парника

Узел парника практически полностью аналогичен периферийным узлам из упомянутой выше статьи. Изменения касаются только ПО для micro::bit. 

На этапе инициализации выполняются действия, необходимые для работы с радиомодулем и последовательным портом, после чего на монитор выводится буква «B» (рис. 5).

Рис. 5. Блок инициализации узла парника
Рис. 5. Блок инициализации узла парника

Когда от ретранслятора в узел парника поступает команда «getData», соответствующий блок вызывает функцию getWeatherData, возвращающую результаты измерений погоды. Далее полученные от этой функции данные отправляются в узел ретранслятора на 15 канале по адресу 13 (рис. 6).

Рис. 6. Блок on e32radio received парника
Рис. 6. Блок on e32radio received парника

Функция getWeatherData получает данные от погодной станции BME-280, преобразует их в текстовые строки и соединяет через символ точки с запятой (рис. 7).

Рис. 7.  Функция getWeatherData
Рис. 7.  Функция getWeatherData

Центральный узел

В предыдущей статье в центральном узле работала программа, отправляющая в цикле команду «getData» на все периферийные узлы, затем она записывала полученные от них данные измерений в JSON-файл.

Теперь центральный узел обращается к периферийному узлу через ретранслятор. Программа e32-loranet-repeater.py отправляет в узел ретранслятора команду «getRData», а полученные от ретранслятора данные измерений записывает в JSON-файл (листинг 1).

Листинг 1. Файл https://github.com/AlexandreFrolov/loranet/blob/main/py/e32-loranet-repeater.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import RPi.GPIO as GPIO
import serial
import time
import sys
from time import sleep
import json

NODE_ADDR_CHAN = [b'\x00\x0B\x0F',
                  b'\x00\x0C\x0F',
                  b'\x00\x0D\x0F']

def gpio_init ():
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    M0 = 22
    M1 = 27
    GPIO.setup(M0,GPIO.OUT)
    GPIO.setup(M1,GPIO.OUT)
    GPIO.output(M0,GPIO.LOW)
    GPIO.output(M1,GPIO.LOW)
    time.sleep(1)
    ser = serial.Serial("/dev/serial0", 9600, timeout=1)
    ser.flushInput()
    return ser

def send_cmd(node):
    try :
        if ser.isOpen() :
            ser.write(NODE_ADDR_CHAN[node])
            ser.write('getRData \n'.encode())
    except :
        if ser.isOpen() :
            ser.close()
            GPIO.cleanup()

    while ser.inWaiting() == 0:
        sleep(0.03)

    data_left = ser.inWaiting() 
    received_data = ser.readline()
    sleep(0.03)
    received_data += ser.read(data_left)
    rec = received_data.decode("utf-8").strip()
    node_data = rec.split(';')
    return node_data

def format_node_data(node, node_data):
    NODE_1_2_ITEMS = ['Температура',
                  'Давление',
                  'Влажность',
                  'Точка росы']
    NODE_3_ITEMS = ['Температура CPU',
                  'Интенсивность освещения']
    node_dict={}
    i=0
    for val in node_data:
        val = str(val)
        if(node == 0 or node == 1 or node == 2):
            node_dict[NODE_1_2_ITEMS[i]]= val
        else:

            node_dict[NODE_3_ITEMS[i]]= val
        i = i+1
    return node_dict

def get_nodes_data():
    nodes_dict={}
    node = 2
    node_data = send_cmd(node)
    nodes_dict[node] = format_node_data(node, node_data)
    return nodes_dict

def save_nodes_data_to_file(nodes_dict):
    jsonString = json.dumps(nodes_dict, indent=2, ensure_ascii=False)
    print(jsonString)
    with open('hosts_data.json', 'w') as f:
        json.dump(nodes_dict, f, indent=2, ensure_ascii=False)


ser = gpio_init()
nodes_dict = get_nodes_data()
save_nodes_data_to_file(nodes_dict)

По сравнению с ПО центрального узла из предыдущей статьи, основные изменения коснулись функции send_cmd.

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

while ser.inWaiting() == 0:
    sleep(0.03)

Когда в устройстве serial появляются данные, они считываются и декодируются, после чего возвращаются в виде строки со значениями, разделенными символом «точка с запятой»:

data_left = ser.inWaiting() 
received_data = ser.readline()
sleep(0.03)
received_data += ser.read(data_left)
rec = received_data.decode("utf-8").strip()
node_data = rec.split(';')
return node_data

Как и в программе из предыдущей статьи, функция save_nodes_data_to_file записывает данные в файл hosts_data.json, а также выводит на консоль:

$ python e32-loranet-repeater.py
{
  "2": {
    "Давление": "993",
    "Точка росы": "4",
    "Влажность": "24",
    "Температура": "24"
  }
}

Идеи для развития проекта

В каком направлении вы можете развивать свой учебный проект с ретранслятором?

Добавьте больше ретрансляторов

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

Рис. 8. Добавляем второй ретранслятор
Рис. 8. Добавляем второй ретранслятор

Можно сделать так, чтобы первый ретранслятор передавал команду «getRData» на второй узел ретранслятора, установленный в гараже с адресом 12. Второй ретранслятор, в свою очередь, будет передавать эту команду дальше, узлу сбора данных в парнике с адресом 11 (табл. 2).

Табл. 2. Адреса радиомодулей

Узел

Адрес

Центральный узел

14 (0x0E)

Ретранслятор в летнем домике

13 (0x0D)

Ретранслятор в гараже

12 (0x0C)

Парник

11 (0x0B)

При передаче данных в обратную сторону узел из парника должен передавать данные на ретранслятор в гараже по адресу 12.

Передавайте данные измерений с ретрансляторов

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

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

Используйте антенны с большим усилением или направленные антенны

Существенно увеличить дальность при той же мощности можно с помощью антенн, обладающих большим усилением или направленных антенн. 

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

Но подключение двух радиомодулей с интерфейсом UART к одному micro::bit проблематично. Такую задачу можно решить с использованием радиомодулей LoRa с интерфейсами SPI или I2C. 

Второй вариант — использовать в узле ретранслятора два микрокомпьютера micro::bit, к каждому из которых подключен радиомодуль LoRa. При этом данные между микрокомпьютерами можно передавать с помощью встроенного в micro::bit модуля Bluetooth. 

Если у вас появятся еще какие-нибудь идеи по использованию ретрансляторов, расскажите о них в комментариях к этой статье!

Автор: Александр Фролов.


НЛО прилетело и оставило здесь промокод для читателей нашего блога:— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

Комментарии (0)