crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V  < 1 2  
Ответить в данную темуНачать новую тему
> Конечный автомат на Qt, (Qt State Machine Framework)
Antrix
  опции профиля:
сообщение 1.2.2009, 17:33
Сообщение #11


Студент
*

Группа: Новичок
Сообщений: 18
Регистрация: 25.9.2008
Пользователь №: 300

Спасибо сказали: 4 раз(а)




Репутация:   0  


Возможно пример неудачен, ну я старался объснить как мог :rolleyes: . А с переменными bool я думал будет легче понять.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 1.2.2009, 18:04
Сообщение #12


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


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

Пожарный шлейф сигнализации (ШС) обладает такими свойствами:
1) снят с ошраны
2) на охране
3) сигнал (состояние) "Внимание"
4) сигнал (состояние) "Пожар"
5) постановка в движении

Обычно пожарные ШС - круглосуточные, т.е. их нельзя снять с охраны (человек нажимает кнопку "Снять с охраны"). вместо снятия с охраны для любых круглосуточных (как пожарных так и охранных ШС) осуществляют "перепостановку". При перепостановке снимается питание с ШС и с линий питаний датчиков, чтобы сброить их состояние. Затем подается питание, с этого момента состояние ШС = №5 (постановка в движении), нужно для установления рабочих режимов датчиков.
т.е.
6) перепостановка (переход в сост. №1 и последующий автоматический переход в состояние №5)

И работа КА выглядит так:
Подаем питание прибора, в КА поступает входной сигнал "Поставить на охрану"
тогда КА переходит в состояние №5, по истечении некоторого времени КА переходит в одно из состояний №2 или №3 или №4

Из состояния №2 может перейти в №6 или №3 или №4
Из состояния №3 может перейти в №6 или №4
Из состояния №4 может перейти в №6

Т.е. состояния непоследовательные
---
Написал наспех может чего пропустил
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kwisp
  опции профиля:
сообщение 1.2.2009, 18:11
Сообщение #13


астарожна ынтжинэр
*****

Группа: Участник
Сообщений: 1404
Регистрация: 26.11.2008
Из: ТаганрогРодинаЧехова
Пользователь №: 435

Спасибо сказали: 113 раз(а)




Репутация:   23  


Litkevich Yuriy,
Цитата
вообще любой пример не удачен, если все состояния в нем изменяются последовательно.

в любом наборе.
а пример с кнопкой в Qt State Machine Framework как раз такой. нужно попробовать реализовать "простой" пример, состояний 5 хотя бы с запрещенными переходами непоследовательный может быть не с одним уровнем истории состояний своим (у каждого наверное свой) методом и способом который предлагает Qt State Machine Framework
тогда станет все наглядно ясно.

Сообщение отредактировал kwisp - 1.2.2009, 18:12
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 1.2.2009, 18:18
Сообщение #14


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(kwisp @ 1.2.2009, 21:11) *
а пример с кнопкой в Qt State Machine Framework как раз такой
а там как раз во 2 коментарии сказано о не удачности примера

мне собственно стало интересно как они реализовали работу с КА:
QStateMachine machine;

QState *s1 = new QState(machine.rootState());
s1->setPropertyOnEntry(&button, ”text”, ”In s1?);

QState *s2 = new QState(machine.rootState());
s2->setPropertyOnEntry(&button, ”text”, ”In s2?);

QState *s3 = new QState(machine.rootState());
s3->setPropertyOnEntry(&button, ”text”, ”In s3?);

s1->addTransition(&button, SIGNAL(clicked()), s2);
s2->addTransition(&button, SIGNAL(clicked()), s3);
s3->addTransition(&button, SIGNAL(clicked()), s1);


machine.setInitialState(s1);
machine.start();
Т.е. реализовано добавление переходов (addTransition) и используются сигналы, такое мне в голову не приходило.
Эту штуку можно использовать в программах опрашивающих разные устройства, например, на шине ModBas
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Tonal
  опции профиля:
сообщение 2.2.2009, 15:25
Сообщение #15


Активный участник
***

Группа: Участник
Сообщений: 452
Регистрация: 6.12.2007
Из: Новосибирск
Пользователь №: 34

Спасибо сказали: 69 раз(а)




Репутация:   17  


Цитата(SABROG @ 1.2.2009, 3:04) *
Почитал в инете примеры со строками на эту тему тут, тут и тут, а так и не понял какое преимущество он дает.
Ну, а чем тогда конечный автомат лучше для QCheckBox по сравнению с этим кодом?
    Qt::CheckState state = checkBox1->checkState();
    if (checkBox1->isTristate())
    {
        checkBox1->setCheckState((state+1)%3); //чеким по-кругу 0,1,2,0,1,2...n
    }
    else
    {
        checkBox1->setCheckState(state^Qt::Checked); //xor'им 0 или 2 с 2 (Qt::Checked).
    }

Возможно и не работает, но идея должна быть понятна

Этот код - тот же конечный автомат только запрограммированный через if-ы.
Конечный автомат - это способ (математический формализм) для описаия поведения некоторой системы через состояния и переходы между ними.
Конечным автоматом можно описать поведения GUI программы, работу с устройством, сетевым протоколом, разбор текстового файла...
Те же регулярные выражения реализуются через конечные автоматы - строка регэкспа разбирается, по ней строится КА (конечный автомат), после чего через него пропускается поток символов - каждый символ - событие, переводящее КА в какое-то состояние. :)

Так что вопрос "что лучше" тут бессмысленен.
Если научится работать с КА и находить их в задачах, то будет проще работать. :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 2.2.2009, 15:45
Сообщение #16


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Видимо if'ы обеспечивают как раз тот механизм "непоследовательности" автомата, в то время как операция взяти по модулю - последовательное выполнение.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 2.2.2009, 15:58
Сообщение #17


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


вообще чаще используют переключатель:
примерно так
void HModBus (void)
{
  static byte fase=0;
  volatile UINT clcCRC;
  volatile UINT pakCRC;

  //фазы состояний движка ModBus
  enum fase
    {
        FASE_START_RX,    /* запускаем прием */
        FASE_END_RX,    /* ждем завершения приема */
        FASE_NODE_CHK,    /* проверяем номер узла в сети */
        FASE_CRC16_CHK,    /* проверяем CRC16 */
        FASE_FUNK_CHK,    /* проверяем номер номер функции */
        //FASE_FUNK_WRK,    /*  */
        FASE_START_TX,    /* передаем обратно */
        FASE_END_TX        /* ждем завершения передачи */
    };
    
    switch (fase)
    {
        //====== ЗАПУСК ПРИЕМА ======
        case FASE_START_RX:    
        {
            MbusRxRun();
            fase=FASE_END_RX;
            break;
        };
        //====== ЖДЕМ ЗАВЕРШЕНИЯ ПРИЕМА ======
        case FASE_END_RX:
        {
            if (mbus_f_rxend)
            {
                fase=FASE_NODE_CHK;
            }
            break;
        };
        //====== ПРОВЕРЯЕМ ПРИНЯТОЕ - НОМЕР УЗЛА ======
        case FASE_NODE_CHK:
        {
            BYTE temp;
            
            temp=*(mbus_buff.buff+MBUS_FIELD_NODE);
            if ((temp!=mbus_cfg.node)&&(temp!=MMBUS_ALL_NODE)&&(temp!=MMBUS_PRG_NODE))
            {
                fase=FASE_START_RX;    // Пакет не нам, в любом случае
            }
            else
            {
                fase=FASE_CRC16_CHK;
            }
            break;
        };    
        //====== ПРОВЕРЯЕМ ПРИНЯТОЕ - CRC16 ======
        case FASE_CRC16_CHK:
        {
            BYTE *pbuff=mbus_buff.buff;
            
            // вызвать функцию проверки CRC16
            clcCRC=CalcCRC16(pbuff, rxcnt-2);
            
            pakCRC=pbuff[rxcnt-2];    // младший байт
            pakCRC|=((UINT)pbuff[rxcnt-1])<<8;    // старший байт 03 04 83 00
            
            if (clcCRC!=pakCRC)
            {
                fase=FASE_START_RX;
            }
            else /**/
            {
                fase=FASE_FUNK_CHK;
            }
            break;
        };
        //====== ПРОВЕРЯЕМ/ИСПОЛНЯЕМ ПРИНЯТУЮ ФУНКЦИЮ =====
        case FASE_FUNK_CHK:
        {
            /* если определена функция проверки/исполнения
                ModBus'овских функций, то исполняем ее */
            if(modbusFunc)
            {
                if (modbusFunc()) fase=FASE_START_RX;    //функция вернула не нуль->передавать не надо
                else fase=FASE_START_TX;    // иначе передаем ответ
            }
            else
            {
                #ifdef DBG_MBUS_ON
                    fase=FASE_START_TX;
                #else  // !DBG_MBUS_ON
                    fase=FASE_START_RX;
                #endif // DBG_MBUS_ON            
            }
            break;
        };            
        //====== ПЕРЕДАЕМ ОТВЕТ ======
        case FASE_START_TX:
        {
            MbusTxRun();
            fase=FASE_END_TX;
            break;
        };
        //====== ЖДЕМ ЗАВЕРШЕНИЯ ПЕРЕДАЧИ ======
        case FASE_END_TX:
        {
            if (mbus_f_txend)
            {
                fase=FASE_START_RX;
            }
            break;
        };
    }

} // END OF HModBus()
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kuzulis
  опции профиля:
сообщение 20.4.2010, 19:56
Сообщение #18


Активный участник
***

Группа: Участник
Сообщений: 393
Регистрация: 29.6.2009
Пользователь №: 862

Спасибо сказали: 36 раз(а)




Репутация:   7  


ООО!!! Хоть тема и старая, но подниму... Наткнулся на нее и свои 5 копеек добавлю.

Цитата
вообще чаще используют переключатель:


Дадада.. Именно! Есть такая штука - как SWITCH технология программирования в которой и используется такой подход. Чаще всего оно применяется в автоматике, АСУТП, при программировании ПЛК и т.п.

В инете оч много литературы по этому поводу (кратко ознакомится на википедии можно).

Этот подход очень удобен, но необычен для основного контингента программистов, которые привыкли думать "классически". :)
Этот подход в сложных алгоритмах со множеством состояний избавляет нас от большого кол-ва ошибок, позволяя делить алгоритм на несколько КА по вложенности и т.п.

Как я к примеру делаю:
1. Делю алгоритм на различные КА, выполняющие определенные функции
2. Для каждого КА рисую граф переходов
3. По графу пишу программу

При этом каждый КА имеет у меня набор свойств:
1. Набор состояний
2. Набор входных воздействий

И в зависимости от текущего воздействия на автомат и его состояния выполняется некий алгоритм, который переводит КА в другие состояния и т.п. В общем, все оч просто и удобно. :)

Я сам нечто похожее делаю для ПЛК (правда к Qt4 это никоим образом не относится)... Результаты - впечатляют! Ошибок по сравнению с "классикой" гораздо меньше и код гораздо понятнее и читабельней!

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Анна
  опции профиля:
сообщение 18.12.2017, 17:31
Сообщение #19


Активный участник
***

Группа: Участник
Сообщений: 276
Регистрация: 22.5.2008
Из: Зеленоград
Пользователь №: 181

Спасибо сказали: 30 раз(а)




Репутация:   4  


Вот сейчас читаю про паттерн "Состояние".
В принципе, это то, что мне надо. При срабатывании QAction программа переходила бы в то или иное состояние, в которых по-разному реагировала бы на срабатывания других QAction (например, некоторые действия должны игнорироваться при одном состоянии и выполняться при другом).
Но вот как увязать описанный в книге паттерн с классами QState и QStateMachine представить не могу.

Может, кто подскажет?
Книжные примеры брала у Э.Фримен и Э.Фримен "Паттерны проектирования" и Гамма, Хельм, Джонсон и Влиссидес "Приёмы объектно-ориентированного проектирования"
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 10.1.2018, 22:33
Сообщение #20


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Анна @ 18.12.2017, 19:31) *
Но вот как увязать описанный в книге паттерн с классами QState и QStateMachine представить не могу.
Я про этот патерн не читал.

Один из вариантов использования QStateMachine выглядит примерно так:
Сначала описываем сам автомат (без описания полезной работы)
void MyClass::createMachine()
{

_meassureMachine = new QStateMachine(this);

// Список состояний и связь их со слотами полезной работы
QState *meassurePrepareState = new QState();
meassurePrepareState->setObjectName("_meassure_meassurePrepareState");
connect(meassurePrepareState, SIGNAL(entered()), this, SLOT(meassurePrepareStateSlot()));
_meassureMachine->addState(meassurePrepareState);

_meassureMachine->setInitialState(meassurePrepareState);

QState *measureState = new QState();
measureState->setObjectName("_meassure_measureState");
connect(measureState, SIGNAL(entered()), this, SLOT(measureRunStateSlot()));
_meassureMachine->addState(measureState);


QState *repeatState = new QState();
repeatState->setObjectName("_meassure_repeatState");
connect(repeatState, SIGNAL(entered()), this, SLOT(meassureRepeatStateSlot()));
_meassureMachine->addState(repeatState);

QState *twuErrorState = new QState();
twuErrorState->setObjectName("_meassure_twuErrorState");
connect(twuErrorState, SIGNAL(entered()), this, SLOT(meassureTwuErrorStateSlot()));
_meassureMachine->addState(twuErrorState);


// переходы между состояниями
meassurePrepareState->addTransition(_timerNext, SIGNAL(timeout()), measureState);

measureState->addTransition(measureState, SIGNAL(finished()), repeatState);
measureState->addTransition(this, SIGNAL(twuFailed()), twuErrorState);

}



Далее/ранее по коду создаём слоты которые выполняются при входе в соответствующее состояние
void MyClass::meassurePrepareStateSlot()
{
...
}


void MyClass::measureRunStateSlot()
{
...
}


void MyClass::meassureRepeatStateSlot()
{
...
}

void MyClass::meassureTwuErrorStateSlot()
{
...
}


Ну а QAction умеет посылать сигналы.

П.С.
Выдрано как попало из реального кода

Сообщение отредактировал Litkevich Yuriy - 10.1.2018, 22:39
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V  < 1 2
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 28.3.2024, 18:09