Как мы строили авиатренажер A320: история в картинках (ч.1)

в 11:24, , рубрики: diy или сделай сам, авиасимулятор, работа над ошибками, своими руками, метки: , ,

Привет всем!

В прошлом посте я написал о бесценном опыте, полученном при строительстве авиатренажера Boeing B737NBG.

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

Я разобью пост на два — один будет в основном про ИТ, а второй — в основном про этапы строительства, со слайдами.

Поехали.

Вводная

В августе 2012 года я влился в только начавшийся проект строительства нового авиатренажера. На тот момент дела обстояли так:

  • К нам ехали заказанные и изготовленные подвижная платформа и кабина
  • Обшивка находилась в производстве
  • Заканчивалось проектирование силового каркаса
  • Были закуплены и уже стояли на складе проекторы

Первым делом, как это ни странно, я взялся рисовать ИТ-инфраструктуру.

ИТ-инфраструктура

В голове все было просто: в качестве симулятора у нас X-Plane 10 с его возможностями искривлять изображение под цилиндрическую проекцию.

Нужно масштабирование — значит будет пять серверов: один обсчитывает динамику, три — формируют изображение для трёх проекторов, четвертый — генерит картинку для системы видеозаписи роликов для клиентов.

Компоненты Project Magenta занимаются почти всем остальным.

ProjectMagenta

  1. Рисование картинок на экранах кабины — Airbus Glass Cockpit, ABGC
    Как мы строили авиатренажер A320: история в картинках (ч.1)
  2. Обсчет работы самолётных систем — pmSystems
    Как мы строили авиатренажер A320: история в картинках (ч.1)
  3. Реализация работы Flight management and guidance system — MCDU
    Как мы строили авиатренажер A320: история в картинках (ч.1)
  4. Автопилот. Реализован в модуле Flight control unit, FCU
    Как мы строили авиатренажер A320: история в картинках (ч.1)
  5. Электро-дистанционная система управления самолётом, по-нашему, Fly-By-Wire. Она-же обеспечивает интерфейс с органами управления — сайдстиками, педалями, ручками управления двигателями и т.п. Кроме этого, именно в этом модуле заложены «законы», препятствующие слишком большим кренам, опасным тангажам и прочему — Flight Control Laws — pmFBW
    Как мы строили авиатренажер A320: история в картинках (ч.1)
  6. Звуки — куда уж без них. pmSounds

Вроде ничего не забыл.

Система сдержек и противовесов

Проектирование инфраструктуры получалось из совокупности ограничений и опыта Боинга.

Одна из проблем из опыта с Боингом — сервера в стойке страшно пылятся, потом начинают перегреваться. Значит наиболее нагруженные компьютеры — а это X-Plane — должны стоять в серверной.

Тянуть USB из кабины — увольте, значит должны быть бортовые компьютеры.

Если они на борту подвижной платформы, значит они либо с SSD, либо бездисковые. SSD на моей памяти два раза перегрелся, поэтому будем познавать бездисковую загрузку. Весь «бортовой» софт у нас под виндой, значит это будет iSCSI.

Загрузить 6 компьютеров по сети — нужна пропускная способность, значит свичи у нас должны быть с поддержкой транков. Выбор пал на D-Link DGS-1210-16.

X-Plane будет несколько, и сценарии на них должны совпадать, плюс еще и iSCSI, бэкапы и т.д., значит должен быть файлсервер, а точнее — NAS. По соотношению «цена-качество» подошел Synology RS-812+ с апгрейдом памяти до 3Гб. Заодно он поддерживает транки.

Серверная должна быть чистой, то есть дверь в нее должна быть закрыта, значит максимально реализуем удаленный доступ, значит должен быть IP KVM (в реальности он пригодился один раз, в основном пользуемся VNC).

Кроме этого, совсем не улыбается залезать в закабинное пространство где находятся бортовые компьютеры, поэтому нужно по крайней мере уметь их включить и выключить. Значит нужно железобетонно работающее устройство, позволяющее нажать кнопку «Power». Оно было заказано знакомому электронщику, после ряда итераций получилось устройство с Eth, которое может «нажать» кнопку питания.
Выглядит оно так:
Как мы строили авиатренажер A320: история в картинках (ч.1)

Верхняя плата — «мастер», к ней по RS-485 подключаются «ведомые». На каждом «ведомом» — 8 каналов, в каждом из каналов — два дискретных входа (для подключения светодиодов питания и HDD) и один выход — для кнопки Power.

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

В общем, в результате пары недель проектирования получилась вот такая схема:
Как мы строили авиатренажер A320: история в картинках (ч.1)

Бортовые компьютеры у нас на Celeron G540 2.5ГГц с 4 Гб памяти и видеокартой Low profile на чипе Radeon HD 6450, с гигабайтом памяти.

Графические сервера для X-Plane — Core i5-3470 c 8Гб RAM и двумя 500Гб дисками в зеркале. Для рисования картинки стоят GeForce GTX 670 c 2048Мб. В качестве операционки у нас Ubuntu 12.04 LTS 86_64, теперь и X-Plane стоит 64-битный.

Сервер что обсчитывает динамику — под Win7_32 на Core i7-3770, используется встроенная видеокарта. X-Plane тут 32-битный, и сервер под виндой потому, что плагин для интерфейса с подвижной платформой есть только под 32-бита и под винду.

Кабели и провода

Сверхцелью было построить тренажер так, чтобы в кабину входили только витые пары и силовые кабели. Так и получилось в конечном итоге.
В кабину снаружи идет силовой кабель 220В, две витые пары для соединения свичей (транк), три витые пары для удлинителей HDMI и еще одна витая пара для пульта управления трапом и платформой.

Удлинители я использовал Hama HDMI, со своей задачей они справляются.

Витая пара везде — CAT6 FTP.

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

Электричество

В Боинге мы столкнулись с проблемой неправильной электрической сети, поэтому в этот раз я сел рисовать однолинейную схему (не могу ее найти).
Идея была в том, что мы защищаем автоматами все линии, плюс мы защищаем от поражения током людей.

Расчеты нагрузки показали, что на всю кабину (проекторы, компьютеры, контроллеры ввода-вывода, бортовая вентиляция, свич) достаточно 3000ВА.
На 5 серверов, NAS, свич и KVM тоже нужно примерно столько-же.

На наружние вентиляторы кабины, инструкторскую станцию и привод трапа нужно меньше 1500ВА, поэтому пригодились старенькие 1500 SmartUPS
Итого UPSов стоит четыре — два Ippon Smart Winner 3000 VA с дополнительным блоком батарей, и два 1500VA SmartUPS, оставшиеся от одной из итераций улучшения Боинга.
На одном трёхкиловаттнике висит серверная, на другом — вся кабина. На одном 1500 висит вентиляция кабины и инструкторская станция, ну и еще один — в запасе.

Учитывая наличие автономных источников энергии (UPSы), УЗО для защиты людей стоят после ИБП, т.е. бесперебойники у нас «привязаны» к щиту.

Как мы строили авиатренажер A320: история в картинках (ч.1)

Вентиляция и кондиционирование

Серверная у нас совсем небольшая, около 5 квадратных метров, и туда выделяется 2кВт тепла от стойки и еще, наверное, 1кВт от шкафа управления платформой. Значит будем вешать кондей.

Кондей был выбран Samsung AQ12TSBN, у него производительность по холоду около 3.5кВт. Монтаж я сделал сам, благо инструменты и оборудования было закуплено до этого и использовалось для монтажа кондеев на даче.
Лето показало правильность выбора, температура в серверной колебалась около установленных 19 градусов.

Дурацкой ошибкой было повесить внутренний блок над электрическим щитом, поэтому пришлось уделить особое внимание дренажу. Тьфу-тьфу, эксцессов не было, но к следующему лету я установлю дренажный насос, чтобы уж точно.

В кабине с вентиляцией дело обстоит не так просто.
У нас есть два объема — собственно кокпит, в котором сидят люди, и закабинное пространство, в котором стоят утюги-проекторы и компьютеры.
С самого начала мы решили, что кондиционирования делать не будем — слишком много проблем с конденсатом.

В закабинном пространстве сделаны приток и вытяжка малошумными вентиляторами с производительностью в районе 250 кубов в час. Приток сделан в место установки компьютеров
Как мы строили авиатренажер A320: история в картинках (ч.1)

Вытяжка — около проекторов, в верхней точке (пардон за качество фотки)
Как мы строили авиатренажер A320: история в картинках (ч.1)

На самом деле, не мешало бы еще воткнуть вентилятор в отверстие в «крыше», но температурные замеры не показывают такой необходимости.

Чтобы воздух циркулировал в кабине, снаружи стоит большой 2000-кубовый нагнетательный вентилятор, ну а вытяжка делается двумя последовательно стоящими сайлентами из под ног:
Как мы строили авиатренажер A320: история в картинках (ч.1)

Изначально по расчетам я ошибся с выбором вентиляторов, 2000-кубовый нагнетатель появился позднее, вначале стояли 250-кубовые сайленты.
Даже с 2000 вентилятором в кабине бывает жарко, поэтому мы подумываем, как можно еще улучшить систему.

Костыли, костылики и костылищи

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

Проблем для окостыливания было несколько:

  1. Синхрнизация общих данных X-Plane
  2. Автоматизация включения-выключения проекторов
  3. Перезапуск сбойнувших компонентов Project Magenta
X-Plane: синхронизация и запуск

Для синхронизации данных X-Plane в итоге выбран rsync с NASа.
Я пробовал запускать прямо с NFS-шары, но учитывая что у нас и Винда и Линукс, а еще структура каталогов X-Plane, по-моему, в пьяном бреду придумана, я решил что конфигурация у каждого — своя, а сценарии и общие данные синхронизируются по сети каждый раз когда запускается или перезапускается X-Plane.

Кстати, по мере проработки идеи с запуском X-Plane прямо с шары, я дошел до того, что редактировал бинарник, чтобы все файлы, открываемые для записи, находились в одной директории. Все было успешно закончено, и через два дня вышел апдейт. После этого я решил делать rsync.

Скрипт для запуска получился вот таким:

#!/bin/bash

LOGFILE="/var/log/xplane-starter.log"

log_msg () {
    DATE=`/bin/date`
    /bin/echo "$DATE: $@" >> $LOGFILE
}

log_msg "Starting xplane-startup.sh"

while [ 1 ]; do 
 log_msg "Rsyncing"
 /root/bin/rsync_64.get >> $LOGFILE
 /bin/sed -i".bak" '/UNSAFE/d' "/xplane.64/Output/preferences/X-Plane Screen Res.prf"
  /usr/bin/pactl set-card-profile 'alsa_card.pci-0000_01_00.1' 'output:hdmi-stereo-extra1'
 /usr/bin/xinit  /root/bin/xinitrc.64 >> $LOGFILE 2>&1 &
 XINIT_PID=$!
 log_msg "xinit pid = $XINIT_PID"
 while [ 1 ]; do
  sleep 1
  # Check that the process is still alive
  if [ -e /proc/${XINIT_PID} -a /proc/${XINIT_PID}/exe ]; then
   sleep 1
  else
   log_msg "Process dead, restarting" 
   break
  fi  
 done
done

Поскольку X-Plane'у совершенно не нужен оконный менеджер, то собственно запуск делается через xinit:

/usr/bin/xsetroot -cursor_name top_left_arrow
DISPLAY=:0.0 /usr/bin/X11/xset s 0
DISPLAY=:0.0 /usr/bin/X11/xset s noblank
/root/bin/shm_wipe.sh
/usr/bin/x11vnc -display :0 -ncache 10 -many &
umask 0000
/xplane.64/X-Plane-x86_64 --no_crash_reporter
/usr/bin/killall -9 x11vnc

shm_wipe.sh — моя лень. Периодически x11vnc перестает запускаться из-за исчерпания shared memory, поэтому в инетах найден рецепт поиска и «отвязывания» неиспользуемых сегментов.

Дополнительно через cron делается перезагрузка X-Plane ранним утром, бо есть в нем утечки памяти. Кроме этого, ночью на всякий случай дается команда на выключение проекторов.

На Винде не все так кошерно, rsync-синхронизацию я делаю периодически руками…

Мониторинг бортового компьютера

Чтобы бороться с подвисающими компонентами ProjectMagenta, на бортовом компьютере написан целый скрипт на PowerShell, да еще и с элементами .NET.

Начался скрипт с детектирования сбойнувший USB-устройств, а дальше оброс уже всем остальным.

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

Отдельной строкой расскажу про EHID.
EHID — это интерфейс между железом кабины (контроллерами ввода-вывода) и программными компонентами. Распространяется под NDA, я его подписал и теперь являюсь счастливым обладателем спецификации. Применил пока для окостыливания бага с тиллером в X-Plane, о котором расскажу ниже.
Суть в том, что есть компонент A320_EHID.exe (и соответственно B737_EHID.exe для Боинга), который держит в себе «дерево» всех всех компонентов кабины — и аналоговых осей, и светодиодов, и тумблеров и всего вообще.
У каждого элемента есть собственное имя и 32-разрядный ID.

Приложения обращаются не напрямую к железу, а к EHID. Общение — поверх TCP, Event-driven. Поллинг весь реализован в EHID, так что такой концепт сильно облегчает жизнь.

Спецификация затрагивает два уровня — между железом и EHID, и между EHID и приложениями.
Нижний уровень представлен в том числе и описанием протокола поверх USB HID, и реализуется в том числе в прошивках контроллеров.

Беда в том, что «последняя ошибка» обнаружилась на стыке драйверов Винды и реализации EHID в прошивках: при одновременном поступлении данных от большого количества устройств, что-то такое волшебное происходит внутри EHID, что приводит к DoS. Обнаруживается, слава богу, легко: EHID перестает отвечать на запросы приложений. На этом и основан мониторинг.

Говнокод — тот еще, не пинайте.

Import-Module c:scriptsReleaseDeviceManagement.psd1 

[int] $Port = 21843
$IP = "192.168.X.X"
$Address = [system.net.IPAddress]::Parse($IP) 

$LogDirs = @("C:EHID","C:MCDU","C:RMCDU","C:FBW","C:pmSystems","C:FCU","C:xpuipc")

Write-Host "Starting the supervisor script..."

# Check if we just started
$p = Get-Process -Name xpwideclient -ErrorAction silentlycontinue
if (!($p))
 {
  Write-Host "Just started"
  # Find and remove logfiles
  foreach($logdir in $LogDirs)
   {
    del $logdir*.log -ErrorAction SilentlyContinue
   }
  del R:*.tmp  -ErrorAction SilentlyContinue
  
  # Set the routing for the goddamn windows shitty default gw to iSCSI target
  route delete 0.0.0.0
  route add 0.0.0.0 mask 0.0.0.0 192.168.X.X
  # Start XPUIPC
  Start-Process C:xpuipcxpwideclient.exe  -WorkingDirectory "C:xpuipc" -WindowStyle Minimized
  Start-Process C:EHIDA320_EHID.exe -ArgumentList "-run" -WorkingDirectory "C:EHID" -WindowStyle Minimized
  Start-Sleep -Seconds 3
 }
else
 {
  Write-Host "Already working"
  $startFlag=0
 }

# Cycle forever
while ( 2 -ge 1)
{
 # Clear the flag
 $failFlag = 0
 
 # Get the list of the failed devices 
 $FailedDevices = Get-WmiObject Win32_USBControllerDevice |%{[wmi]($_.Dependent)} | Where-Object {$_.Status -ne "OK"}
 foreach($fDevice in $FailedDevices)
  {
   # Set the flag to restart the processes
   $failFlag = 1
   # Disable and then enable device
   $dDev = Get-Device | Where-Object {$_.InstanceID -eq $fDevice.DeviceID}
   Write-Warning "Failed device found:" $fDevice.DeviceID
   Disable-Device -TargetDevice $dDev -Verbose
   Enable-Device -TargetDevice $dDev -Verbose  
  }
 
 # Detect hang of A320_EHID 
 # Create IP Endpoint 
 $End = New-Object System.Net.IPEndPoint $address, $port 

 # Create Socket 
 $Saddrf = [System.Net.Sockets.AddressFamily]::InterNetwork 
 $Stype = [System.Net.Sockets.SocketType]::Stream 
 $Ptype = [System.Net.Sockets.ProtocolType]::TCP 

 # Create byte array  
 [Byte[]] $Message = 0x02,0x03,0x00,0x04
 
 $buffer = new-object System.Byte[] 8192    

 Try 
  {
   $Sock = New-Object System.Net.Sockets.Socket $saddrf, $stype, $ptype
   $Sock.TTL = 26 
   $Sock.ReceiveBufferSize = 8192;
   $Sock.ReceiveTimeout = 500;
   $Sock.Blocking = 1;
   # Connect to socket 
   $Sock.Connect($end)
   $Sent = $Sock.Send($Message)    
   Start-Sleep -m 30  
   $Received = $Sock.Receive($buffer)  
   $Sock.Close()
  } 
 Catch [Exception]
  {
   Write-Host "Error checking EHID"  $_.Exception.Message;
   $failFlag=1;
  }
 
 # Detect restart file-flag
 $FileExists = (Test-Path "R:restart.txt" -PathType Leaf)
 if ($FileExists)
  {
   Write-Host "Restart file exists!"
   del R:restart.txt
   $failFlag = 1
  }
  
 # Restart the processes
 if ($failFlag -eq 1) 
  {
   Write-Warning "Restarting processes"
   Write-Warning "Freezing..."
   Start-Process C:scriptssim_pause.exe -WorkingDirectory "C:scripts" -WindowStyle Minimized
   
   Stop-Process -Name A320_EHID -force -ErrorAction silentlycontinue
   Stop-Process -Name pmFBW -force -ErrorAction SilentlyContinue
   Stop-Process -Name pmSystems -force -ErrorAction SilentlyContinue
   Stop-Process -Name MCDU -force -ErrorAction SilentlyContinue
   Stop-Process -Name RMCDU -force -ErrorAction SilentlyContinue
   Stop-Process -Name FCU -force -ErrorAction SilentlyContinue

   # Set start flag
   $startFlag=1
  }
  
 if ($startFlag -eq 1)
  { 
   Start-Process C:EHIDA320_EHID.exe -ArgumentList "-run" -WorkingDirectory "C:EHID" -WindowStyle Minimized
   Start-Sleep -Seconds 3
  }

  # FIXME Workaround for the falling PM processes
 $p = Get-Process -Name RMCDU -ErrorAction silentlycontinue 
 if (!($p))
  {
   Write-Host "RMCDU dead, restarting."
   Start-Process C:RMCDURMCDU.exe -WorkingDirectory "C:RMCDU" -WindowStyle Minimized
  }
  
 $p = Get-Process -Name FCU -ErrorAction silentlycontinue 
 if (!($p))
  {
   Write-Host "FCU dead, restarting."
   Start-Process C:FCUFCU.exe -WorkingDirectory "C:FCU"
  }    

 $p = Get-Process -Name MCDU -ErrorAction silentlycontinue 
 if (!($p))
  {
   Write-Host "MCDU dead, restarting."
   Start-Process C:MCDUMCDU.exe -WorkingDirectory "C:MCDU"
  }
    
 $p = Get-Process -Name pmFBW -ErrorAction silentlycontinue
 if (!($p))
  {
   Write-Host "pmFBW dead, restarting."
   Start-Process C:FBWpmFBW.exe -WorkingDirectory "C:FBW"
  }
  
 $p = Get-Process -Name pmSystems -ErrorAction silentlycontinue
 if (!($p))
  {
   Write-Host "pmSystems dead, restarting."
   Start-Process C:pmSystemspmsystems.exe -WorkingDirectory "C:pmSystems"
  }  
 
 if ($startFlag -eq 1)
  { 
   # Clear the flag and start the processes
   $startFlag = 0   
   Start-Sleep -Seconds 45	
   Write-Warning "Un-Freezing..."
   Start-Process C:scriptssim_unpause.exe -WorkingDirectory "C:scripts" -WindowStyle Minimized
  }
 Start-Sleep -Seconds 5	
}
X-Plane, Tiller и костыль

Тиллер — это рукоятка управления разворотом передней стойки. Нужен для руления на земле.
Рулить можно двумя способами — тиллером и педалями. По достижению определенной скорости, тиллер перестает действовать, остаются только педали.

Проблема в том, что в X-Plane (по признанию его автора) «потеряли» датареф, т.е. внутреннюю переменную, куда можно было бы записать положения тиллера.
Кроме этого, если к X-Plane не подключено джойстика, то он считает, что мы — убогие нищие симмеры, которые летают на клавиатуре, и поэтому нужно делать разворот передней стойки по командам от штурвала-сайдстика.

У меня была весьма бурная переписка на эту тему с автором X-Plane Остином Мейером (в ходе которой он показал себя истеричным козлом, пардон муа), который пообещал исправить этот косяк в одном из релизов. Ждем.

Пока мы ждем, я написал костылик, который с одной стороны цепляется к виртуальному джойстику (VJoy), а с другой — через сеть и EHID забирает значение положения рукоятки тиллера.
В X-Plane я назначил единственную ось — этот самый тиллер, и, в глазах X-Plane, мы перестали быть нищебродами, в связи с чем функционал разворота колёс сайдстиком отключился.
Ничего сложного или необычного в этом костыле нету, поэтому не вижу смысла приводить исходники. Написано за час на .NET по-моему.

Заключение

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

Спасибо, что дочитали!

Автор: Kitsok

Источник

Поделиться

* - обязательные к заполнению поля