Компьютерный тренажер «Управление техническим объектом в реальном времени». Сценарный подход

Постановка задачи

Назначение тренажера — обучение оператора, управляющего некоторым техническим объектом, для которого нужно выполнять строго заданную последовательность действий. Например, это могут быть действия по проверке пилотом бортовых систем контроля перед вылетом или последовательность действий оператора по управлению технологической установкой.
Назовем сценарием обучения требуемую последовательность действий оператора. Управляющие элементы (кнопки, выключатели) могут, для простоты, иметь только два состояния: включено или выключено. Изменение состояния управляющего элемента производится нажатием левой кнопки мыши.
После некоторых действий оператора может задаваться временная задержка реакции системы, в течение которого любые действия оператора будут ошибкой.
Требуется выполнить заданный сценарий без ошибок и за минимально возможное время.

Решение

Для конкретики на форме разместим три управляющих элемента-кнопки: Ключ 1, Ключ 2 и Ключ 3, а также две надписи: первую будем использовать для подсказок и отображения результата тестирования, вторую — для отображения процесса тестирования.
Добавим на форму также невизуальный компонент Timer timer1 (Антон заметил, что это я пропустил, см. комментарий).


Сценарий обучения задается последовательностью нажатия ключей (1,2,3) и пауз (4), в нашем случае, например, это массив  ListEv =new int[] {0,1,3,4,2,4,3,4,1};
Каждому сценарию поставим в соответствие свой метод. Анализ событий, связанных с нажатием кнопок, сосредоточим в методе PrEv(k).

Объявим класс MyEH, содержащий событие Ez и метод его обработки OnEz(k).

class MyEH
{
   public event EventHandler<int> Ez; // событие
   public void OnEz(int k) // метод его обработки 
   {
      if (Ez != null) // игнорирование вызова
         Ez(this, k);
   }
}

А в классе Form1 объявим экземпляр этого класса met:

MyEH met = new MyEH();

Для связи события met.Ez с обработчиком события PrEv( ) достаточно выполнить оператор:

 met.Ez += PrEv;

а для разрыва связи:

met.Ez -= PrEv;

Кроме объекта met добавим следующие поля класса Form1:

int NumbEv = 0; // счетчик действий пользователя
int[] ListEv = new int [0]; // массив - список событий
int N_tim = 0; // номер события (например, задержки)
DateTime dt = new DateTime(); // время старта теста

Обработчик события «Нажатие кнопки» в простейшем случае зададим так:

private void Button1_Click(object sender, EventArgs e)
{
   NumbEv++;
   met.OnEz(1);
}

где в первом операторе увеличивается на 1 счетчик событий NumbEv, а второй оператор предназначен для запуска обработчика события 1 (k=1, кнопка 1) — метода PrEv(k).  Заметим, что это событие (met.Ez) может быть связано или не связано с любым обработчиком событий, в том числе и с PrEv( ), в котором определен сценарий, заданный массивом ListEv.

Если необходим запуск другого сценария обучения, то потребуется лишь задать другой метод обработки вместо PrEv( ), не меняя практически всего остального. В этом и есть преимущество использования механизма событий для неявного установления/разрыва связей с тем или иным обработчиком событий.

Опишем алгоритм формирования временной задержки с отключением обработки событий.

Метод TimerLag( ) вызывается в PrEv( ) и необходим для отключения обработчика событий, задания условного номера события-задержки, наращивания счетчика событий, задания интервала для таймера и его старта.

private void TimeLag(Timer tmr, int t_delay, int n_tim)
{
   met.Ez -= PrEv; // отключение обработки
   N_tim = n_tim; // номер события (4)
   NumbEv++; // счетчик событий
   tmr.Interval = t_delay; // в мс
   tmr.Start(); // запуск таймера
}

Отметим, что имя таймера как объекта также указывается в списке параметров.  После срабатывания таймера он останавливается, восстанавливается обработка событий методом PrEv(k), причем k=N_tim:

private void Timer1_Tick(object sender, EventArgs e)
{
   timer1.Stop();
   met.Ez += PrEv; // восстановление
   met.OnEz(N_tim);
}

Заметим, что для каждого нового сценария потребуется добавлять новый таймер, не меняя содержимого метода TimerLag( ) .

При обучении с подсказками каждый раз номер произошедшего  события сравнивается с заданным в массиве ListEv[ ].  При совпадении появляется новая подсказка, при ошибочном действии — завершение цикла с сообщением «Ошибка. Перезапустить обучение». В режиме контроля обучения подсказки могут быть заблокированы. При отсутствии ошибок вызывается метод StopEv(), сообщающий время, потраченное на обучение.

Полный текст модуля Form1.cs представлен ниже.

using System;
using System.Windows.Forms;
namespace RealTimeModdel
{
   public partial class Form1 : Form
   {
      MyEH met = new MyEH(); // экземпляр "события"
      int NumbEv = 0; // счетчик действий пользователя
      int[] ListEv = new int[0]; // массив - список событий
      int N_tim = 0; // номер события (например, задержки)
      DateTime dt = new DateTime(); // время старта теста
      // конструктор
      public Form1()
      {
         InitializeComponent();
         met.Ez += PrEv; // связывание обработчика с PrEv(k)
         met.OnEz(0); // прямой вызов обработчика с k=0, Старт!
         dt = DateTime.Now; // старт теста
         timer1.Interval = 1000; // задержка 1 с
      }
      // реакция на события - обработка прохождения теста
      public void PrEv(object sender, int k)
      {
         ListEv =new int[] {0,1,3,4,2,4,3,4,1}; // тестовый набор: кнопки 1,2,3 и задержка(4)
         if (NumbEv < ListEv.Length) // все ли позиции пройдены?
         {
            if (ListEv[NumbEv] == k)
               label2.Text = "Действие " + k.ToString() + " - выполнено";
            else // Завершение теста
            {
               label2.Text = "Ошибка. Перезапустить обучение";
               met.Ez -= PrEv;
               return;
            };
            // Тестирование с подсказками
            switch (NumbEv)
            {
               case 0:
                  label1.Text = "Нажми 1";
                  break;
               case 1:
                  label1.Text = "Нажми 3";
                  break;
               case 2:
                  label1.Text = "Задержка 2 с";
                  TimeLag(timer1, 2000, 4);
                  break;
               case 3:
                  label1.Text = "Нажми 2";
                  break;
               case 4: 
                  label1.Text = "Задержка 3 с";
                  TimeLag(timer1, 3000, 4);
                  break;
               case 5:
                  label1.Text = "Нажми 3";
                  break;
               case 6:
                  label1.Text = "Задержка 4 с";
                  TimeLag(timer1,4000, 4);
                  break;
               case 7:
                  label1.Text = "Нажми 1";
                  break;
               default:
                  StopEv();
                  break;
            };
         }
         else
            StopEv(); // Завершение теста
      }
      // Подготовка задержки через таймер
      private void TimeLag(Timer tmr, int t_delay, int n_tim)
      {
         met.Ez -= PrEv; // отключение обработки
         N_tim = n_tim; // номер события (4)
         NumbEv++; // счетчик событий
         tmr.Interval = t_delay; // в мс
         tmr.Start(); // запуск таймера
      }
      // после задержки c передачей номера события N_tim
      private void Timer1_Tick(object sender, EventArgs e)
      {
         timer1.Stop();
         met.Ez += PrEv; // восстановление
         met.OnEz(N_tim);
      }
      // Завершение
      private void StopEv()
      {
         met.Ez -= PrEv; // отключение обработки 
         label1.Text = "Успешное завершение теста";
         TimeSpan timeOfDay = DateTime.Now - dt;
         label2.Text="Общее время тестирования: " + 
            Math.Round(timeOfDay.TotalSeconds) + " c";
      }
      // Событие 1
      private void Button1_Click(object sender, EventArgs e)
      {
         NumbEv++;
         met.OnEz(1);
      }
      // событие 2
      private void Button2_Click(object sender, EventArgs e)
      {
         NumbEv++;
         met.OnEz(2);
      }
      // событие 3
      private void Button3_Click(object sender, EventArgs e)
      {
         NumbEv++;
         met.OnEz(3);
      }
   }

   // класс МОЙ ОБРАБОТЧИК СОБЫТИЯ
   class MyEH
   {
      public event EventHandler<int> Ez; // событие
      public void OnEz(int k) // метод его обработки 
      {
         if (Ez != null) // игнорирование вызова
            Ez(this, k);
      }
   }
}

Изучите работу предложенного примера. Используйте эти решения при разработке собственного тренажера.


NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.


Помощь проекту:

Понравилась статья? Поделиться с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
4 комментариев
Новые
Старые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

Мы же нигде не создаем таймер.

Важно: Вы можете поддержать проект и автора.
Важно: Вы можете поддержать проект и автора.

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

4
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x
()
x