Yacht Devices Новости: Якорная сигнализация на базе NMEA 2000 Bridge и Alarm Button

17.07.2019

Новое обновление для Bridge позволяет легко рассчитывать расстояния между точками GPS. В этой статье показано, как создать якорный сигнал тревоги, управляемый с экрана MFD или аппаратной кнопки.

Контрольные точки для сигнализации якоря

Рисунок 1. Контрольные точки сигнализации якоря (нажмите, чтобы увеличить или скачать KML)

UPDATE 07/2024: якорь добавлена функция будильника к NMEA 2000 Alarm Button.

Сегодня мы присоединимся к силе NMEA 2000 Bridge и NMEA 2000 Alarm Button для создания якорной сигнализации. Давайте начнем с простой программы (исполняемой Bridge), в которой сигнализация привязки управляется из внешняя кнопка (со встроенным LED) подключен к Alarm Button.

При нажатии кнопки программа сохраняет текущую позицию GPS. LED кнопки начнет мигать, показывая, что сигнал тревоги готов. При каждом обновлении позиции Bridge будет рассчитывать расстояние до сохраненной позиции и включать сирену (включая канал 1 на кнопке), если позиция находится дальше, чем заранее запрограммированное безопасное расстояние. При следующем нажатии кнопки сигнал привязки будет отменен. Также программа включает сирену, если позиция GPS потеряна. При отсутствии фикса GPS программа не позволит установить будильник, и его легко обнаружить: кнопка не будет мигать после нажатия.

Alarm Button необходимо настроить (см. комментарии в шапке программы). Первой и второй командой сбрасываем настройки и переводим Кнопку в «Режим цифрового переключения». Следующая команда отключает звук от канала 7, поэтому активация этого канала будет бесшумной, но будет мигать LED.

И последняя команда связывает кнопку с каналом 7. Когда все каналы выключены (не активны), нажатие кнопки включит канал 7. Когда у Alarm Button есть активные каналы, нажатие кнопки отключает канал с наивысшим приоритетом (наименьшим номером).

# Anchor Alarm (simplified), version 1.0
# See: http://www.yachtd.com/news/anchor_alarm.html
#
# To configure the Alarm Button, send the following sequence of commands:
# YD:RESET
# YD:MODE DS
# YD:LINK 7 SOUND 0
# YD:CHANNEL 7

FW_CAN1_TO_CAN2=OFF
FW_CAN2_TO_CAN1=OFF

SLOT1 = 000EF20D FF 08 00FDFFFFFFFFFFFF # Turn ON the the anchor alarm (Channel 1)
SLOT2 = 000EF20D FF 08 00FCFFFFFFFFFFFF # Turn OFF the the anchor alarm
SLOT3 = 000EF20D FF 08 0003C0FFFFFFFFFF # Turn off all channels, except Channel 1

# We'll run/stop the alarm once in 3 seconds to avoid fast switches
heartbeat(3000)
{
   if (D > 0) { # Alarm is set (D is the safe distance in meters)
      if (R > D) {  # R is distance to D from current GPS position
        load(SLOT1) # Anchor alarm on
        M = 1       # Mark, that alarm was ON by the Bridge
      }
      else {
        load(SLOT2) # Anchor alarm off
        M = 0       # Alarm was OFF by the Bridge
      }
      send(CAN1)
   }
}

# Position, Rapid Update - calculate the distance from current position
match(CAN1,0x1F80100,0x1FFFF00)
{
   if (get(DATA,INT32) < 0x7FFFFFFF) {
       if (get(DATA+4,INT32) < 0x7FFFFFFF) {      
           X = get(DATA,INT32)     # Latitude, 0.0000001 deg
           Y = get(DATA+4,INT32)   # Longitude, 0.0000001 deg
           T = timer()    # Position is valid, save the time of position fix
           R = 0          # Reset the distance from current position
           if (D > 0) {   # Is the alarm already set?
               # Calculate the distance by Haversine Formula
               W = (cast(X - A,FLOAT)/10000000) * M_PI / 180 # delta Lat
               Z = (cast(Y - B,FLOAT)/10000000) * M_PI / 180 # delta Lon
               W = sin(W/2) 
               Z = sin(Z/2) 
               E = cos((cast(A,FLOAT)/10000000) * M_PI / 180)*Z*Z
               U = W*W + cos((cast(X,FLOAT)/10000000) * M_PI / 180)*E
               if (U != 0) {   
                  U = atan2(sqrt(U),sqrt(1-U))
                  R = 12742000*U    # The distance to (A,B) in meters
               }
           }
       }
   }      
}

# Binary Status Report
match(CAN1,0x1F20D00,0x1FFFF00)
{
   if (get(DATA,UINT8) == 0) {     # Is it Bank 0 message?
      S = get(DATA+1,UINT16)       # Status of Channels 1-8 (2 bit each: 1-ON, 0-OFF)
      if ((S & 3) != 1) {          # Is anchor alarm NOT running?                  
         if ((S >> 12) & 3 == 1) { # Is hardware button was pressed (Channel 7 is set)?
            if (timediff(T) < 2000) { # Is GPS position valid?
   
               if (D == 0) {          # Set new alarm
                  A = X
                  B = Y
                  D = 20              # Safe distance in meters
               }
               else {  # The alarm is already set, canceled by user
                  if (M == 1) {
                     load(SLOT3) # Cancel the alarm
                     send(CAN1)
                     M = 0
                     D = 0
                  }
               }
            }
            else {   # We have no actual position (GPS lost?)
               if (D > 0) {      # Was the alarm set?
                  if (M == 1) {  # Was it canceled by user?   
                     load(SLOT3) 
                     send(CAN1)  # Cancel the alarm
                     M = 0
                     D = 0
                  }
                  else {         # It was not canceled by user
                     R = 1000    # Run the Anchor Alarm!
                     M = 0       # GPS position is lost!
                  }
               }
               else  {        # User tries to set new alarm
                  load(SLOT3) # Switch off all buttons, do not allow
                  send(CAN1)  # to set the alarm without valid position
               }
            }
         }
      }
   }
}

# End of program

При включенной сирене (включен канал 1) нажатие кнопки выключает сирену, но не канал 7 (что является признаком готовности якорной сигнализации). Переменная «М» помогает программе понять, был ли сигнал привязки отменен пользователем (канал 1 выключен, канал 7 включен) или еще не был включен в функции heartbeat(), которая вызывается раз в 3 секунды.

Чтобы облегчить расчет расстояния, мы добавили еще один тригонометрическая функция в прошивке 1.31 атан2(). Это не квадрат арктангенсов.

Чтобы протестировать программу, вам понадобится CAN Log Viewer с одним из наших шлюзов. Мы рекомендуем настроить фильтр PGN 0x1F801 так, чтобы он получал только сообщения, отправленные со шлюза, и увеличить таймаут для позиции GPS с 2000 миллисекунд до 20000 миллисекунд (или вам придется нажмите кнопку «Отправить» слишком быстро!).

NAMELATITUDELONGITUDEК CENTER
(METERS)
NMEA 2000 MESSAGE
CENTER54.6911981420.242790580.009F80100 ЭД 36 99 20 02 CE 10 0C
NE_64.2354.6915690820.2435567664.239F80100 6B 45 99 20 F0 EB 10 0C
NE_24.2754.6912840220.2431378224.279F80100 48 3А 99 20 92 ДБ 10 0С
NW_6.8954.6912364720.242706826.879F80100 6D 38 99 20 до н.э. CA 10 0C
SW_9.6854.6911447420.242671599.689F80100 D7 34 99 20 5C C9 10 0C
SE_12.2454.6911614220.2429701712.249F80100 7E 35 99 20 06 D5 10 0C
S_23.9554.6909827920.2427904723.959F80100 84 2E 99 20 01 CE 10 0C
N_20.5954.6913833820.2427916420.609F80100 2A 3E 99 20 0C CE 10 0C

Мы подготовили набор путевых точек (см. рисунок 1 в начале статьи), точные координаты вы можете найдите в файле KML. Вы можете скопировать сообщения NMEA 2000 с координатами из таблицы выше и отправить их с помощью CAN Log Viewer (меню "Инструменты" \ "Отправить сообщения CAN...").

Якорная сигнализация с управлением от MFD

Рисунок 2. Якорная сигнализация с управлением от MFD

Теперь добавим управление от MFD (см. рисунок 2). Мы добавим пять кнопок с разными безопасными расстояниями и кнопку, указывающую состояние тревоги. Для выключения будильника можно нажать любую активную кнопку.

Управление сохраним с аппаратной кнопки; он активирует любимую дистанцию (в нашем примере 20 м). Вам нужно будет загрузите файл конфигурации для вашего MFD здесь (см. пример настроек здесь) и настройте Alarm Button, как показано в первых строках кода ниже.

# Anchor Alarm with MFD, version 1.0
# See details: http://www.yachtd.com/news/anchor_alarm.html
#
# To configure the Alarm Button YDAB-01, send the following sequence of commands:
# YD:RESET
# YD:MODE DS
# YD:LINK 2 SOUND 0
# YD:LINK 3 SOUND 0
# YD:LINK 4 SOUND 0
# YD:LINK 5 SOUND 0
# YD:LINK 6 SOUND 0
# YD:LINK 7 SOUND 0
# YD:CHANNEL 7

FW_CAN1_TO_CAN2=OFF
FW_CAN2_TO_CAN1=OFF

SLOT1 = 000EF20D FF 08 00FDFFFFFFFFFFFF # Turn ON the the anchor alarm (Channel 1)
SLOT2 = 000EF20D FF 08 00FCFFFFFFFFFFFF # Turn OFF the the anchor alarm
SLOT3 = 000EF20D FF 08 0003C0FFFFFFFFFF # Turn off all channels, except Channel 1

# We'll run/stop the alarm once in 3 seconds to avoid fast switches
heartbeat(3000)
{
   if (D > 0) {     # Alarm is set (D is the safe distance in meters)
      if (R > D) {  # R is distance to D from current GPS position
        load(SLOT1) # Anchor alarm on
        M = 1       # Mark, that alarm was ON by the Bridge
      }
      else {
        load(SLOT2) # Anchor alarm off
        M = 0       # Alarm was OFF by the Bridge
      }
      send(CAN1)
   }
}

# Position, Rapid Update - calculate the distance from current position
match(CAN1,0x1F80100,0x1FFFF00)
{
   if (get(DATA,INT32) < 0x7FFFFFFF) {
       if (get(DATA+4,INT32) < 0x7FFFFFFF) {      
           X = get(DATA,INT32)   # Latitude, 0.0000001 deg
           Y = get(DATA+4,INT32)   # Longitude, 0.0000001 deg
           T = timer()   # Position is valid, save the time of position fix
           R = 0           # Reset the distance from current position
           if (D > 0) {   # Is the alarm already set?
               # Calculate the distance by Haversine Formula
               W = (cast(X - A,FLOAT)/10000000) * M_PI / 180 # delta Lat
               Z = (cast(Y - B,FLOAT)/10000000) * M_PI / 180 # delta Lon
               W = sin(W/2) 
               Z = sin(Z/2) 
               E = cos((cast(A,FLOAT)/10000000) * M_PI / 180)*Z*Z
               U = W*W + cos((cast(X,FLOAT)/10000000) * M_PI / 180)*E
               if (U != 0) {   
                  U = atan2(sqrt(U),sqrt(1-U))
                  R = 12742000*U    # The distance to (A,B) in meters
               }
           }
       }
   }      
}

# Binary Status Report
match(CAN1,0x1F20D00,0x1FFFF00)
{
   if (get(DATA,UINT8) == 0) {  # Is it Bank 0 message?
      S = get(DATA+1,UINT16)    # Status of Channels 1-8 (2 bit each: 1-ON, 0-OFF)
      if ((S & 3) == 1) {       # Is anchor alarm running?
         if ((S >> 2) & 0x3FF == 0) { # Are all buttons off?
            D = 0            
            M = 0                 
            load(SLOT3)               # User pressed buttons on MFD
            set(DATA+1,UINT8,0)       # screen to cancel alarm
            send(CAN1)                # Cancel the anchor alarm
         }         
      }
      else {    # Anchor alarm is OFF - read MFD buttons
         K = 0
         if ((S >> 10) & 3 == 1) {            
            K = 5  # Channel 6 is ON
            L = 50 # Set 50m alarm
         }                  
         if ((S >> 8) & 3 == 1) {
            K = 4  # Channel 5 is ON
            L = 30 # Set 30m alarm
         }
         if ((S >> 6) & 3 == 1) {            
            K = 3  # Channel 4 is ON
            L = 20 # Set 20m alarm
         }
         if ((S >> 4) & 3 == 1) {            
            K = 2  # Channel 3 is ON
            L = 10 # Set 10m alarm
         }
         # If two buttons pressed on MFD, the smallest
         # distance have priority
         if ((S >> 2) & 3 == 1) { 
            K = 1 # Channel 2 is ON
            L = 5 # Set 5m alarm
         }

         # Is hardware button was pressed? It have priority over MFD
         if ((S >> 12) & 3 == 1) {
            K = 3  # Favorite distance to turn on
            L = 20 # with hardware button (20 meters)
         }

         if (K == 0) {            
            D = 0 # No buttons pressed, clear alarm settings
         }
         else {   # We have buttons pressed
            if (timediff(T) < 2000) { # Is GPS position valid?
               if (D != L) {
                  # New alarm or modification of alarm
                  A = X
                  B = Y
                  D = L # New safe distance, in meters
               }
               else {
                  # Is user canceled the alarm with hardware
                  # button of or by switching the Channel 1 ?
                  if (M == 1) {
                     load(SLOT3) # Cancel the alarm
                     send(CAN1)
                     K = 0
                     M = 0
                     D = 0
                  }
               }               
            }
            else {   # We have no actual position (GPS lost?)
               if (D > 0) {      # Was the alarm set?
                  if (M == 1) {  # Was it canceled by user?   
                     load(SLOT3) 
                     send(CAN1)  # Cancel the alarm
                     K = 0
                     M = 0
                     D = 0
                  }
                  else {  # It was not canceled by user
                     R = 1000    # Run the Anchor Alarm!
                     M = 0
                  }
               }
               else  {        # User tries to set new alarm
                  load(SLOT3) # Switch off all buttons, do not allow
                  send(CAN1)  # to set the alarm without valid position
                  K = 0       
               }
            }
         }
         if (K > 0) { 
            S = get(DATA+1,UINT16)
            K = (S & 0xFFF) | (1 << (K*2))
            if (S != K) # If multiple buttons are pressed, leave on the actual only
            {
               load(SLOT3)
               set(DATA+1,UINT16, K)
               send(CAN1)
            }
         }
      }
   }
}

# End of program

Вы можете видеть, что код в целом тот же; мы добавили только обработку пяти «виртуальных кнопок» с экрана MFD. Вы также можете добавить Switch Control в систему. Вам не нужно будет его настраивать. Первая кнопка выключит активный сигнал привязки, а ее LED укажет состояние сигнала привязки. Три другие кнопки будут включать/выключать сигналы тревоги на расстоянии 5, 10 и 20 метров.

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

Сообщения с PGN 127501 (двоичный отчет о состоянии, с состоянием каналов) и 127502 (Switch Bank Control, для управления каналами) имеют одинаковый формат. Первый байт содержит номер банка, а следующие 7 байтов (56 бит) содержат 2-битные состояния 28 каналов: 0 — «OFF», 1 — «ВКЛ», 2 — «Ошибка» (для статуса) или «Зарезервировано» (для управления), 3 — «Неизвестно» (для статуса) или «Нет действия» (для управления).

Вы можете скачать код простой программы и код программы с поддержкой MFD. Обновление прошивки 1.31 для Bridge доступен в разделе загрузок .