Разработка симулятора космического корабля Союз ТМА

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Тренажёр предстартовой подготовки ТПК Союз ТМА. Фото: ЦПК им. Гагарина
Тренажёр предстартовой подготовки ТПК Союз ТМА. Фото: ЦПК им. Гагарина

Привет! Мы - команда симулятора Союз ТМА, программы, имитирующей орбитальный полёт космического аппарата Союз и Международной Космической Станции, сближение и стыковку КА с МКС, а также расстыковку и спуск. Всё это имитируется как в автоматическом (т.е. под управлением моделями бортовой аппаратуры Системы Управления Движением), так и в ручном режимах полёта, которые по своему алгоритмическому и логическому составу идентичны тем, что использовались на борту КА Союз ТМА.

Нами разработано программное обеспечение под названием "Моделирование и Управление" в среде C++ Builder 6. Почему именно в ней, а не в VS - это наш первый проект и ранее никто из нас не имел опыта в программировании, а тем более в тренажёростроении, поэтому для "пробы пера" была выбрана наиболее простая среда, но при этом код разрабатывается так, чтобы его можно было максимально быстро интегрировать в другую среду (Qt, VS).

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

Первой формой была - "Ввод начальных условий". На данной форме вводятся все необходимые параметры для выставления начального состояния КА и МКС, минимальный набор начальных параметров состояния бортовых систем, оскулирующие элементы и др. параметры, необходимые для начала режима. Сам список какие именно параметры необходимы для моделирования столь сложной системы нам были неизвестны, но изучив статьи на данную тему, имеющиеся в интернете, а также пообщавшись с разработчиками тренажёров подготовки космонавтов мы выяснили приблизительный набор параметров, которые использует ЦПК им. Гагарина и НАСА для задания начальных условий режимов полёта.

В этот список входят несколько групп параметров:

  1. Основные характеристики:

    • Массив моментов инерции (Jxx, Jyy, Jzz, Jxy, Jyz, Jzx) - который необходим для математической модели движения. Вводится как для корабля, так и для станции.

    • Масса корабля и станции (в кг).

    • Координаты центра масс корабля и станции.

  2. Параметры орбиты:

    • Параметры орбиты в виде набора Кеплеровых элементов.

    • Параметры орбиты в виде векторов в J2000.

  3. Параметры ориентации:

    • Начальная система координат корабля и станции (инерциальная текущая или орбитальная СК).

    • Углы (тангаж, крен, рыскание).

    • Угловые скорости (Wx, Wy, Wz).

  4. Параметры режима:

    • Признаки занятости стыковочных узлов (наличие пристыкованных кораблей).

    • Начальный режим работы Системы Управления Движением и Навигации.

    • Конфигурация станции.

    • Набор состояния признаков состояния бортовых систем корабля и станции.

    • Дата и время начала режима.

Пользовательский интерфейс данного формата выглядит следующим образом:

Формат "Ввод НУ" - Комплексный
Формат "Ввод НУ" - Комплексный

Пользовательский интерфейс, а также набор и расположение параметров были позаимствованы у тренажёра ДОН Союз-ТМА, как единственные известные нам, по ходу разработки мы от них откажемся и разработаем свой пользовательский интерфейс, основываясь на задачах, поставленных перед симулятором и необходимых параметрах для моделирования.

Из-за обширного количества вводимых значений, в данный формат мы добавили возможность загрузки и сохранения параметров начальных условий в файл. Принцип сохранения и загрузки прост и использует дефолтные компоненты, такие как TSaveDialog и TOpenDialog. Данные сохраняются и загружаются в ini файл (TIniFile), что довольно удобно. Структура файла также разделена на группы в соответствии с логикой набора параметров начальных условий.

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

Квитанция о загрузке начальных условий из файла
Квитанция о загрузке начальных условий из файла

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

// Структура для математических моделей
struct{
//// Д А Т А ////
TDateTime nu_day;                   // 2   Модельное время/дата
//// М К С ////
double vec_j2000_mks[3];                // 8   Массив вектора положения Ц.М. МКС в J2000 (X, Y, Z)
double vel_j2000_mks[3];                // 11  Массив скорости    Ц.М.    МКС    в J2000 (X, Y, Z)
double Q_mks[4];                        // 14  Массив компонентов кватерниона МКС                                             0  1  2
double w_j2000_mks[3];                  // 18  Массив вектора угловой скорости МКС относительно J2000 в проекциях на ССК РС (Wx Wy Wz)
double vec_mks_PC[3];                   // 21  Массив координат   Ц.М.    МКС    в  РС   (X, Y, Z)
double m_mk;                            // 24  Масса МКС
double mi_mks[3][3];                    // 25  Двумерный массив моментов инерции МКС (Jxx, Jxy, Jxz...)
//// Т К ////
double vec_j2000_tk[3];                 // 34  Массив вектора положения Ц.М. ТК в J2000 (X, Y, Z)
double vel_j2000_tk[3];                 // 37  Массив скорости    Ц.М.    ТК    в J2000 (X, Y, Z)                   0   1   2   3
double Q_tk[4];                         // 40  Массив компонентов кватерниона разворота ССК ТК относительно J2000 (Qs, Qx, Qy, Qz)
double w_j2000_tk[3];                   // 44  Массив вектора угловой скорости ТК относительно J2000 в проекциях на ССК ТК (Wx Wy Wz)
double vec_tk_TPK[3];                   // 47  Массив координат   Ц.М.    ТГК/ТПК    в  РС   (X, Y, Z)
double m_tk;                            // 50  Масса ТК
double mi_tk[3][3];                     // 51  Двумерный массив моментов инерции ТК (Jxx, Jxy, Jxz...)
//// M I S C ////
double vec_solar[3];                    // 60  Единичный вектор из центра J2000 на Солнце в проекциях на J2000 (ex, ey, ez)
unsigned long r_st_mks;                 // 63  Режим стабилизации МКС
unsigned long n_su_4_dk;                // 64  Номер стыковочного узла МКС, к которому выполняется причаливание ТК (резерв, не используется)
unsigned long nu_otor_switch_styk_dk;	  // 65  № СУ, к которому пристыкован ТК (для задания состояния состыкованного ТК)
double tk_top_zap;                      // 66  Запас топлива ТК (КДУ О+Г)
double mks_top_zap;                     // 67  Запас топлива МКС (РС ОДУ О+Г)
unsigned long pr_doking;                // 68  Признак состыкованного состояния ТК и МКС по НУ
unsigned long nr_sudn;                  // 69  Начальный режим работы СУДН ТК
} NU_temp;

// Массив признаков УСО
static bool USO_Booled[20][16];         // Матрица УСО (разблюдовка в ТО_УСО п.п. 3.7)

После этого мы изучили некоторые статьи по разработке математических моделей бортовых систем космических аппаратов (Е. А. Микрин - Бортовые комплексы управления космическими аппаратами ISBN 5-7038-2178-9), а также различные технические документы на Союз ТМА (в основном SoyCOM) и составили список основного приборного состава оборудования, которое необходимо реализовать для минимального функционирования системы и отладки основных алгоритмов управления.

В качестве математической модели движения на первом этапе было решено использовать модель SGP4, переработанную под нужды симулятора (вместо входных параметров TLE - массив параметров НУ).

Из приборного состава в первую очередь был реализован Пульт Ручного Ввода Информации (ПРВИ) в UI исполнении, как он был реализован на пульте космонавтов "Нептун" корабля Союз-ТМ

Данный пульт предназначен для информационного обмена оператора с БЦВК "Аргон-16". На кораблях серии ТМА данный пульт был исполнен в программном обеспечении Интегрированного Пульта управления (ИнПУ).

Так как на первом этапе разработки симулятора не предполагалось использовать обмен с моделью ИнПУ, то было решено использовать встроенную модель пульта ПРВИ с сам симулятор.

Логика работы с пультом следующая: оператор последовательно заполняет цифровые Индикаторы Ручного Ввода Информации (ИРВИ) кроме 15-го индикатора (знак + / -), после чего выдает команду на исполнение кнопкой "ИСП" и после обработки введённой информации наблюдает ответ-квитанцию от БЦВК на ИРВИ. Все действия с данным прибором также логируются в журнал. С помощью ПРВИ можно:

  • Произвести чтение/запись уставочной информации (состояние логических признаков управляющих слов 16-разрядной ячейки памяти Аргона).

  • Управлять форматами дисплея (форматы отображения Блока Формирования Изображения).

  • Организовать динамический вывод информации на ИРВИ.

  • Чтение/запись восьмеричных или десятичных чисел в память Аргона.

Исходя из вышеперечисленного можно сказать, что данный формат позволяет производить полный информационный обмен с памятью БЦВК, что на этапе отладки модели БЦВК крайне важно.

Для облегчения восприятия информации и ввода вывода уставочной информации, начиная с кораблей серии Союз ТМА-М работу с ПРВИ упразднили, оставив лишь формат отображения ИнПУ "ПРВИ" (индекс 2Ф46), на который выведены основные управляющие слова (В1-ТА1) для контроля их состояния (при выполнении штатной программы полёта, изменение состояния логических признаков происходит по Командной Радио Линии (КРЛ) с Земли группой ГОГУ). Ниже представлен скриншот формата ПРВИ корабля Союз МС с выведенным на экран состоянием логических признаков управляющего слова А20.

Для удобства работы с кодом и последующей миграции кода из C++ Builder 6 в среду Visual Studio (планируется, что итоговое приложение будет MFC + OpenGL в качестве графического движка для системы визуализации) каждый формат имеет помимо своего файла формы (***_form.cpp) также файл с логикой, где описаны все процедуры и функции для данной системы/прибора. Логика работы прибора ПРВИ в симуляторе следующая:

Вначале пользователь должен включить прибор, нажав клавишу ON, тем самым он выставит логический признак brvi_on = true;

void __fastcall TIrBrForm::brvi_on_btnClick(TObject *Sender)
{
brvi_on=true;           // Признак включения ПРВИ
Panel1->Color=clLime;   // Зажигаем индикатор состояния прибора зеленым цветом
}

Далее используя один из кодов ввода-вывода необходимо ввести последовательно режим, адрес и число, а также, если необходимо, то и знак. Знак можно ввести на любом этапе заполнения цифровых индикаторов. Ниже описаны коды ввода-вывода информации, актуальные для ПрО Союз ТМА №228

Операция

Код

Одиночный ввод десятичных чисел

14

Одиночный ввод восьмеричных чисел

15

Групповой ввод десятичных чисел

17

Групповой ввод восьмеричных чисел

18

Запись "0" в заданный разряд ячейки ОЗУ

30

Запись "1" в заданный разряд ячейки ОЗУ

31

Операция

Код

Одиночный вывод десятичных чисел

24

Одиночный вывод восьмеричных чисел

25

Групповой вывод десятичных чисел

27

Групповой вывод восьмеричных чисел

28

Динамический вывод десятичных чисел

04

Динамический вывод восьмеричных чисел

05

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

void __fastcall TIrBrForm::brvi_btn_1Click(TObject *Sender)
{
if(brvi_on){
USO_BitType[16][3] = 0111;
if(i1->Caption=="")
        i1->Caption="1";
else if(i2->Caption=="")
        i2->Caption="1";
else if(i3->Caption=="")
        i3->Caption="1";
else if(i4->Caption=="")
        i4->Caption="1";
else if(i5->Caption=="")
        i5->Caption="1";
else if(i6->Caption=="")
        i6->Caption="1";
else if(i7->Caption=="")
        i7->Caption="1";
else if(i8->Caption=="")
        i8->Caption="1";
else if(i9->Caption=="")
        i9->Caption="1";
else if(i10->Caption=="")
        i10->Caption="1";
else if(i11->Caption=="")
        i11->Caption="1";
else if(i12->Caption=="")
        i12->Caption="1";
else if(i13->Caption=="")
        i13->Caption="1";
else if(i14->Caption=="")
        i14->Caption="1";
else {}
}
}

Мы не смогли разобраться, как записать это в виде цикла for, поэтому сделали таким образом. По такой же логике работают обработчики и на остальных клавишах. Если необходимо очистить индикаторы, то для этого надо нажать клавишу "СБР", а если убрать последний введенный индикатор, то клавишу "ГАШ".

После окончания заполнения индикаторов необходимо отправить введенные значения на обработку в БЦВК, ниже представлен код обработчика клавиши ИСП:

void __fastcall TIrBrForm::isp_btnClick(TObject *Sender)
{
if(brvi_on) { // Если БРВИ вкл
if(i1->Caption==""&&i2->Caption==""){  // Если первый и второй индикаторы пустые,
i1->Caption=="A";     // Тогда сообщение АА
i2->Caption=="A";
JPS(3,is_irvi,is_operator,"АА","");  // и лог в журнал
} else {              // или (если 1И и 2И не пустые)
AnsiString brvi_msg = i1->Caption+i2->Caption+i3->Caption+i4->Caption+    // Создаем строку текущего состояния И ИРВИ
i5->Caption+i6->Caption+i7->Caption+i8->Caption+i9->Caption+i10->Caption+
i11->Caption+i12->Caption+i13->Caption+i14->Caption+i15->Caption;
JPS(1,is_operator,is_irvi,brvi_msg,"");
Timer1->Enabled=true;  // Включаем таймер задержки индикации
// Обнуляем индикаторы перед индикацией
i1->Caption="";
i2->Caption="";
i3->Caption="";
i4->Caption="";
i5->Caption="";
i6->Caption="";
i7->Caption="";
i8->Caption="";
i9->Caption="";
i10->Caption="";
i11->Caption="";
i12->Caption="";
i13->Caption="";
i14->Caption="";
i15->Caption="";

irvi_string = brvi_msg; // Присваиваем глобальной переменной значение ИРВИ

ChekIrvi(irvi_string); }} else  // Если БРВИ выключен
JPS(3,is_miu,is_operator,cmd_brvi_error,"");   // Ошибка в Журнал
}

Здесь мы собираем из индикаторов строку, которую после присваиваем глобальной AnsiString переменной irvi_string. Процедура ChekIrvi принимает в качестве аргумента сформированную строку и производит с ней следующие операции:

void ChekIrvi (AnsiString irvi_str){
if(irvi_str.IsEmpty())JPS(3,is_miu,is_operator,"Пустой ввод!",""); else {
irvi_type.mode = StrToInt(irvi_str.SubString(1,2)); // Вырезаем первые два символа строки ирви "режим"
switch (irvi_type.mode) {   // Обработчик режима
        case 00: /* Приоритетный или принудительный режим выдачи пр-м 1 - 4 */ break;
        case 04: /* Динамический вывод 10-х чисел */ break;
        case 05: /* Динамический вывод 8-х чисел */ break;
        case 10: /* Ввод уставки РУС */   break;           // Arg addr RUS AUS data?
        case 11: /* Ввод уставки АУС 1-й группы */  break;
        case 12: /* Ввод уставки АУС 2-й группы */  break;
        case 14: /* Одиночный ввод 10-х чисел */                       // Если режим 14, то
                 if((irvi_str.SubString(3,5)).IsEmpty())JPS(3,is_miu,is_operator,"Пустой адрес!",""); else {
                 irvi_type.addr = StrToInt(irvi_str.SubString(3,5));   // Присваиваем значение адреса
                 if(CorrectAddr(irvi_type.addr)) {                     // Проверяем корректность адреса, если корректен, то
                 if((irvi_str.SubString(8,7)).IsEmpty())JPS(3,is_miu,is_operator,"Пустое число!",""); else {
                 irvi_type.value = StrToInt(irvi_str.SubString(8,7));  // Присваиваем значение
                 ArgonMemoryType[irvi_type.addr] = irvi_type.value;    // Записываем его в ячейку памяти Аргона
                 SetItvi(irvi_type.mode,irvi_type.addr,ArgonMemoryType[irvi_type.addr], irvi_type.z );   // Выставляем результат на ИРВИ
                 JPS(4,is_argon,is_irvi,"Запись числа "+               // Логируем результат (от имени Аргона)
                 IntToStr(irvi_type.value)+" по адресу "+IntToStr(irvi_type.addr),"");}}
                 else {                                                 // Если адрес не корректен ,то
                 irvi_err = true;
                 JPS(3,is_argon,is_operator,arg_addr_error,"");     } }  // Логируем превышение допустимого значения памяти А16
                 break;
        case 15: /* Одиночный ввод 8-х чисел */  break;
        case 17: /* Групповой ввод 10-х чисел */ break;
        case 18: /* Групповой ввод 8-х чисел */
                // irvi_type.addr = StrToInt(irvi_str.SubString(3,5));   // Присваиваем значение адреса
                 // if(CorrectAddr(irvi_type.addr)) {                    // Проверяем корректность адреса, если корректен, то
                 //irvi_type.value = StrToInt(irvi_str.SubString(8,7));  // Присваиваем значение
                // ArgonMemoryType[irvi_type.addr] = irvi_type.value;   // Записываем его в ячейку памяти Аргона
                 //SetItvi(irvi_type.mode,(irvi_type.addr)+1,ArgonMemoryType[irvi_type.addr], irvi_type.z );   // Выставляем результат на ИРВИ
                 //mode18act=true;
                 break;
        case 21: /* Вывод уставки АУС 1-й группы */ break;
        case 22: /* Вывод уставки АУС 2-й группы */ break;
        case 24: /* Одиночный вывод 10-х чисел */                      // Если режим 24, то
                 irvi_type.addr = StrToInt(irvi_str.SubString(3,5));   // Присваиваем значение адреса временной переменной
                 if(CorrectAddr(irvi_type.addr)) {                     // Проверяем корректность адреса, если корректен, то
                 SetItvi(irvi_type.mode,irvi_type.addr,ArgonMemoryType[irvi_type.addr], irvi_type.z ); }  // Выставляем результат на ИРВИ
                 else   {                                               // Если адрес не корректен ,то
                 irvi_err = true;
                 JPS(3,is_argon,is_operator,arg_addr_error,"");   }     // Логируем превышение допустимого значения памяти А16
                 break;
        case 25: /* Одиночный вывод 8-х чисел */ break;
        case 27: /* Групповой вывод 10-х чисел */ break;
        case 28: /* Групповой вывод 8-х чисел  */break;
        case 30: /* Изменение состояния признака в слове - запись единицы */
                 irvi_type.addr = StrToInt(irvi_str.SubString(3,5));   // Присваиваем значение адреса временной переменной
                 if(CorrectAddr(irvi_type.addr)) {                     // Проверяем корректность адреса, если корректен, то
                 irvi_type.value = StrToInt(irvi_str.SubString(8,7));  // Присваиваем значение
                 mode_30(irvi_type.addr,irvi_type.value); }             // Выставляем результат на ИРВИ
                 else   {                                              // Если адрес не корректен ,то
                 irvi_err = true;
                 JPS(3,is_argon,is_operator,arg_addr_error,"");   }    // Логируем превышение допустимого значения памяти А16
                 break;
        case 31: /* Изменение состояния признака в слове - запись нуля */
                 irvi_type.addr = StrToInt(irvi_str.SubString(3,5));   // Присваиваем значение адреса временной переменной
                 if(CorrectAddr(irvi_type.addr)) {                     // Проверяем корректность адреса, если корректен, то
                 irvi_type.value = StrToInt(irvi_str.SubString(8,7));  // Присваиваем значение
                 mode_31(irvi_type.addr,irvi_type.value); }             // Выставляем результат на ИРВИ
                 else   {                                              // Если адрес не корректен ,то
                 irvi_err = true;
                 JPS(3,is_argon,is_operator,arg_addr_error,"");   }    // Логируем превышение допустимого значения памяти А16
                 break;
        case 40: /*  */ break;
        case 41: /*  */ break;
        case 42: /*  */ break;
        case 43: /*  */ break;
        case 44: /*  */ break;
        case 45: /*  */ break;
        case 46: /*  */ break;
        case 48: /* Сверка времени */
        break;
        default: irvi_err = true;       // Флаг ошибки (для индикации на ИРВИ)
                 JPS(3,is_argon,is_irvi,"АА","");        // Логируем ошибку о несуществующем режиме
                 JPS(3,is_miu,is_operator,"Несуществующий режим!","");
        irvi_type.addr = StrToInt(irvi_str.SubString(3,5));
        irvi_type.value = StrToInt(irvi_str.SubString(8,7));
        break;
} } }

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

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

Это был первый формат относящийся к модели БЦВК "Аргон-16", но его оказалось недостаточно и в последствии был разработан еще один формат для отладки модели БЦВК "Отладка А16", скриншот которого представлен ниже:

На нём можно наблюдать виртуальные клавиши принудительной выдачи команд в БЦВК (имитации релейных команд для отладки некоторых процедур и алгоритмов), вывести число из ОЗУ без использования ПРВИ (если ПРВИ занят, т.к. с ним могут работать 2 оператора - обмен по UDP), наблюдать текущее значение глобальной переменной ИРВИ, наблюдать статусное окно выбранных каналов БЦВК (т.к. он работает по мажоритарной схеме 2 из 3) и др. Пустые поля по мере разработки будут заполнятся отладочными командами. Все компоненты TLabel выводятся в обработчике таймера, который каждый тик присваивает им состояние переменных.

Этот формат позволит нам отслеживать работу алгоритмов БЦВК (как самых сложных в реализации) и прерывать работу модели при нештатной работе (отклонении от нормы).

Следующими основными форматами, без которых невозможно управление кораблём Союз, являются - КСПл и КСПп. Около половины времени работы космонавта с ПрО пульта "Нептун-МЭ" приходится именно на эти форматы. На них представлены основные команды выдаваемые оператором в бортовые системы корабля - включение и пуск БЦВК, команды управления двигательной установкой, управление ССВП и др. Ниже представлены форматы КСПл и КСПп разработанные для симулятора:

Данные форматы по своему информационному обеспечению идентичны одноименным форматам используемым в ПрО и ИО ИнПУ, что также позволяет работать с ними как с штатными форматами отображения, для сравнения - ниже скриншот штатного формата КСПл корабля Союз ТМА №219 (ПО № 5.19, ИО № 5.1)

Логика работы с данным форматом уникальна и разработана Тяпченко Ю.А. Основным преимуществом данного типа пульта является матричный способ выдачи команд и развернутая форма представления информации. С точки зрения эргономики это довольно удобный способ представления большого количества команд, при малом количестве органов взаимодействия. Логика работы с данным форматом следующая - оператор выбирает вначале строку (букву) и выдает ее, буква загорается и разрешается выбор столбца (цифры), где нечётная цифра включает команду, а чётная ее выключает. К примеру, чтобы выдать команду на включение РУД, необходимо вначале нажать клавишу "В", а потом "7". Таким образом будет подана команда на включение питания ручки управления движением, а в пульт придёт обратная квитанция об успешности исполнения команды, которая "зажжёт" транспарант светло зеленым цветом.

Также можно заметить, что на некоторых транспарантах присутствуют дополнительные символы, обозначение которых описано ниже:

Это обозначает, что если команда без сигнализации - значит обратной квитанции и загорания соответствующего транспаранта не будет, а если команда только прямая, значит при выдаче чётной цифры (выключения) команда не пройдет и транспарант не погаснет. Обычно эти команды выключаются другими командами, к примеру для снятия признака выбора К11 "РРЖ 4С" необходимо выдать Л15 "РРЖ 15С" или Л13 "РРЖ 8С".

В симуляторе логика КСП реализована следующим образом. Объявлен двумерный булевый массив

static bool KSP_Booled[16][9];

который хранит состояние команд, если мы выдаем ту или иную команду КСП, то присваиваем соответствующему элементу значение true, которое снимается обработчиком получившей его системы. К примеру при выдаче команды А7 "СДД ОТКЛ" мы выставляем признак KSP_Booled[0][6]=true; , основной обработчик УСО каждый тик обрабатывает весь массив и при KSP_Booled[0][6]=1 сразу снимает эту команду и посылает команду в КДУ и другие системы соответствующие признаки, в это время в КСП стоит обработчик квитанций УСО, который в свою очередь опрашивает каждый элемент массива УСО и если видит ответную квитанцию об успешном отключении сигнальных датчиков СДД от системы управления, зажигает транспарант "СДД ОТКЛ", ниже представлен код обработки этой команды:

// Модуль КСПл, обработчик нажатия цифры 7
 ...
   if (KSP_Let[0]){ // А                              Если выбранна буква А
   KSP_Booled[0][6]=true;                          // Тогда выставляем признак А7 - правда
   JPS(1,is_operator,is_miu,is_ksp,"А7"); } else   // Логируем выдачу команды
 ... 

// Модуль uso_model.cpp процедура USO_work
 ...
     if(KSP_Booled[0][6]) { // A 7
        KSP_Booled[0][6] = false;
        // 95 Исключение СДД из схемы управления
        USO_Booled[0][3]=true;
        kdu_sdd = false;
     }
 ...
 
// Модуль КСПл - тик таймера индикации
 ...
  if(USO_Booled[0][3]){  // KSP A7
  A7_LABEL->Color=clLime;
  A7_LABEL->Font->Color=clBlack;  } else {
  A7_LABEL->Color=clGreen;
  A7_LABEL->Font->Color=clYellow; }
 ...  

Таким образом мы реализуем штатную логику работы с КСП и УСО, конечно если тут есть люди разбирающиеся в УСО корабля Союз, которые нашли ошибку в нашей интерпретации логики работы с КСП, прошу нас поправить, т.к. у нас не имеется материалов по УСО и данную логику мы построили изучая работу моделей ИнПУ и руководство по работу с системой Нептун-МЭ.

Я думаю это довольно много информации для одного поста, поэтому остальные форматы опишу в следующем посте.

Источник: https://habr.com/ru/post/532726/


Интересные статьи

Интересные статьи

Многие разработчики начинают разработку многопользовательского онлайн сервера на основе библиотеки socket.io. Эта библиотека позволяет очень просто реализовать обмен данными между клиетом...
Всем привет! Не так давно на работе в рамках тестирования нового бизнес-процесса мне понадобилась возможность авторизации под разными пользователями. Переход в соответствующий р...
Это небольшой мануал/история о том, как создать "идеальный" pypi пакет для python, который каждый желающий сможет установить заветной командой: pip install my-perfect-package Ориентирована на н...
Те, кто собираются открывать интернет-магазин, предварительно начитавшись в интернете о важности уникального контента, о фильтрах, накладываемых поисковиками за копирование материалов с других ресурсо...
Всем привет! Несколько месяцев назад мы запустили в продакшн наш новый open-source проект — Grafana-плагин для мониторинга kubernetes, который назвали DevOpsProdigy KubeGraf. Исходный код плагина...