Yacht Devices Новости: Датчик аварийного сигнала на базе Python Gateway

21.09.2026

Вход RX устройства Python Gateway можно использовать для приёма дискретного сигнала включения/выключения и передачи произвольных данных устройствам NMEA 2000 различными способами.

CommandBOSS Comb PR

KTI Systems (Keenan Filters) — семейная компания из США, выпускающая системы фильтрации дизельного топлива и управления топливной системой для прогулочных и коммерческих судов по всему миру. В её системе CommandBOSS есть дополнительное реле AUX, которое срабатывает при засорении топливного фильтра. Обычно к нему подключают внешний звуковой сигнализатор, но по заказу система может поставляться с выходом «сухой контакт» вместо стандартного подключения сигнализатора.

По просьбе клиента мы разработали программу для нашего YDPG-01 Python Gateway , которая при срабатывании реле AUX передаёт на многофункциональные дисплеи Raymarine Axiom сигнал NMEA 2000 «Низкое давление топлива».

Хотя вход RX устройства YDPG-01 представляет собой полноценный приёмник UART RS-422 с дифференциальным входом, он имеет внутреннюю слабую подтяжку к 3,3 В через резистор 10 кОм. Это позволяет использовать его как компаратор, подающий логический сигнал на вход GPIO основного процессора. Если оба входа, RX+ (жёлтый провод) и RX− (синий провод), свободны, то есть ни к чему не подключены, machine.Pin.IN.value() возвращает логическую 1. Если оставить RX+ свободным, а RX− (синий провод) соединить с GND (неизолированный провод экрана), вызов value() вернёт 0.

Сначала переведём UART RX в режим цифрового входа:


    # we do not need NMEA 0183 library
    n0183.deinit()
    # we do not need UART
    uart_rx.deinit()

    # configure "RX-" (blue) as GPIO input
    # returns 0 if "RX-" is connected to GND
    # returns 1 if "RX-" floats
    pin = machine.Pin("rx", machine.Pin.IN)

Затем добавим обработчик прерывания IRQ, который будет вызываться при каждом изменении состояния входа:


    # track when pin was triggered
    pin_triggered_timestamp_ms = utime.ticks_ms() 
    # and into which state, default = 1, no alarm
    pin_triggered_value = 1

    # process pin state change
    def pin_callback(pin_):

        global pin_triggered_timestamp_ms, pin_triggered_value
        
        print ( "pin state change:", pin_.value() )
        
        pin_triggered_timestamp_ms = utime.ticks_ms()
        pin_triggered_value = pin_.value()

    # set up pin IRQ handler
    pin.irq(handler=pin_callback)

Код обработчика прерывания ISR должен быть как можно проще и быстрее (см. рекомендации MicroPython по реализации ISR). Здесь мы лишь сохраняем состояние входа и время его изменения. Обработчик вызывается при каждом изменении состояния, а логика срабатывания сигнализации выполняется асинхронно в основном цикле таймера:


    # Timer thread, called each 10 ms 
    def main_timer_callback(timer):
        # software debounce:
        # if pin held low for more than 100 ms, trigger alarm
        # if pin goes high, cancel alarm immediately
        now_ms = utime.ticks_ms()
        if utime.ticks_diff( now_ms, pin_triggered_timestamp_ms ) > 100:
            if pin_triggered_value == 0:
                alarm_state = True
            else: 
                alarm_state = False
        else:
            alarm_state = False

    # set up main timer, calling "main_timer_callback" each 10 ms
    main_timer = machine.Timer(period = 10, callback = main_timer_callback)

Теперь мы можем считывать состояние внешнего оборудования. Разберёмся, как передать сигнал тревоги на Axiom. На данный момент (2025 год) Axiom не полностью поддерживает PGN общих аварийных сигналов. Поэтому используем стандартный PGN 127489 «Engine Parameters, Dynamic» и передадим сигнал «Низкое давление топлива», установив соответствующий двоичный флаг в поле «Engine Discrete Status 1».

Однако есть сложность: если в сети уже имеется источник данных двигателя NMEA 2000, например наш Engine Gateway YDEG-04 или YDES-04, появятся два источника PGN 127489, что может вызвать конфликт данных. К счастью, Axiom не привязывает источник данных двигателя к конкретному устройству NMEA 2000, а определяет двигатель по полю «Engine Instance». Это означает, что Axiom будет обрабатывать PGN 127489 как от шлюза двигателя, так и от Python Gateway.

Кроме того, сигнализация должна работать и при включённом шлюзе двигателя (двигатель запущен, шлюз передаёт PGN 127489 с действительными данными), и при выключенном, когда PGN 127489 передаёт только YDPG-01. Поэтому мы реализовали два режима работы.

Если YDPG-01 обнаружит PGN 127489 от двигателя, он перейдёт в режим сопровождения: при получении каждого такого сообщения устройство сразу передаст его копию с установленным флагом тревоги. Ожидается, что Axiom отреагирует на это однократным срабатыванием сигнализации двигателя.

Если в течение 4500 мс YDPG-01 не получит PGN 127489 от двигателя, он перейдёт в автономный режим и начнёт передавать собственные сообщения PGN 127489. Во всех полях, кроме «Engine Instance» и флагов тревоги, будет указано, что данные недоступны.

Разумеется, при отсутствии тревоги YDPG-01 не передаёт PGN 127489, чтобы не создавать лишний трафик на шине.

Нужно также учитывать поведение функции n2k.sendpgn() , которая отправляет подготовленные данные PGN в шину CAN. Ошибка передачи приведёт к остановке программы YDPG-01, поэтому следует использовать обработчик исключений, позволяющий продолжить выполнение программы.


    try:
        n2k.sendpgn(data_array, 127489, src = YDPG_ADDRESS)		
    except:
        pass

Полная программа доступна здесь. Для установки подключите YDPG-01 к USB-порту компьютера: устройство определится как внешний USB-диск. Замените стандартный файл main.py на этом диске новым файлом main.py. Перезагрузите устройство, чтобы запустить программу.

Для проверки программы подключите YDEG-01 к шине NMEA 2000, соедините RX− с GND и убедитесь, что на Axiom появился сигнал «Низкое давление топлива». После разъединения проводов сигнал должен исчезнуть.

Мы много говорили об Axiom, но будет ли это работать с другими многофункциональными дисплеями NMEA 2000?

Да, но только с теми, где можно явно выбрать конкретное устройство NMEA 2000 как источник данных двигателя, например Simrad GO XSR или Garmin Echomap 62cv. Для этого YDPG-01 должен пересылать копии всех PGN с данными двигателя левого борта (PORT). Тогда его можно будет выбрать на дисплее в качестве источника данных этого двигателя.

Измените программу, включив настройку


    MFD_MODE = MFD_NAVICO

Затем включите зажигание двигателя левого борта и убедитесь, что YDPG-01 передаёт копию каждого PGN с данными двигателя. Выберите YDPG-01 на дисплее в качестве источника данных двигателя левого борта и проверьте правильность данных и срабатывание сигнализации.

На некоторых многофункциональных и других дисплеях NMEA 2000 нельзя выбрать устройство — источник данных двигателя, поэтому описанный способ не подойдёт. Для таких дисплеев потребуется наш YDNB-07 Bridge , который объединит сообщения PGN 127489 от двигателя и YDPG-01 в один поток PGN 127489.

А ещё лучше было бы, если бы все производители многофункциональных дисплеев, а не только Garmin, добавили поддержку стандартных PGN NMEA 2000 «Alert» и «Alert Text». Тогда YDPG-01 смог бы передавать произвольный текст тревоги, не ограничиваясь уже предусмотренными сигналами, например сигналами двигателя.

Например, наш новый Garmin GPSMAP 743xsv поддерживает эти PGN, и отправка произвольного сигнала тревоги для него реализована гораздо более аккуратно, никаких «хаков», не требуется настройка MFD, YDPG-01 просто отправляет любой текст, который вы хотите, и да, поддерживаются строки в формате Unicode:

Garmin generic NMEA2000 alert