Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. State machine - transition a child state before exiting parent
Forum Updated to NodeBB v4.3 + New Features

State machine - transition a child state before exiting parent

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 2 Posters 293 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    rdowell
    wrote on last edited by rdowell
    #1

    I'm trying to implement a state machine in a machine control application. The machine has 3 basic runtime states, Idle, Standby, and Running, which I put into a single parent state called Normal.

    The basic transitions are as follows:

    Idle --> Running on 'Start'
    Running-->Standby on 'Stop'
    Running --> Idle on 'Finished'
    Standby --> Running on 'Start'
    Standby --> Idle on 'Reset'

    In addition to these normal transitions however there is also an 'Emergency Stop' function which I want to handle separately, because it's possible for this button to be engaged at any time, so I want that state to be outside of 'Normal' and instead use a History state to return to Normal when the button is disengaged. This way an E-Stop from Idle or Standby will return to those states, however, if the button is hit while Running, I want the following to happen:

    Running --> Standby (so that the History state of Normal will return to Standby instead of back to Running)
    Normal --> Emergency Stop

    To that end I made the following state definitions and transitions:

    // Basic states
    QState* NormalState = new QState(stateMachine);
    QState* EStopState = new QState(stateMachine);
    
    // Normal states
    QState* IdleState = new QState(NormalState);
    QState* StandbyState = new QState(NormalState);
    QState* RunningState = new QState(NormalState);
    
    // Normal transitions
    IdleState->addTransition(machineManager, &Manager::OnStart, RunningState);
    RunningState->addTransition(machineManager, &Manager::OnStop, StandbyState);
    RunningState->addTransition(machineManager, &Manager::OnFinish, IdleState);
    StandbyState->addTransition(machineManager, &Manager::OnStart, RunningState);
    StandbyState->addTransition(machineManager, &Manager::OnReset, IdleState);
    
    // EStop transitions
    QHistoryState *normalReturnState = new QHistoryState(NormalState);
    RunningState->addTransition(machineManager, &Manager::OnEStop, StandbyState);
    NormalState->addTransition(machineManager, &Manager::OnEStop, EStopState);
    EStopState->addTransition(machineManager, &Manager::OnEStopReleased, normalReturnState);
    

    This works fine when E-Stop is engaged in Idle or Standby, but if I engage E-Stop while Running, only the Running --> Standby transition occurs and the second one is ignored.

    I know I could potentially solve this issue by making parallel states, i.e. Idle/Standby/Running in one parallel group and Normal/EStop in the other, but I'm concerned that would add much more complication to my display logic

    For example, if I were to do:

    StandbyState->assignProperty(widget, "enabled", true);
    EStopState->assignProperty(widget, "enabled", false);
    

    This would work if EStop and Standby are not parallel. If they were parallel then it would depend on which one the state machine enters first. The same problem would happen if I put any processing on the entered() or exited() events, but if the states were not parallel, and EStop were able to first transition Running --> Standby, then I expect I would receive a predictable sequence of events like this:

    On EStopDown:
    RunningState::exited()
    StandbyState::entered()
    StandbyState::exited()
    NormalState::exited()
    EStopState::entered()
    On EStopUp:
    EStopState::exited()
    NormalState::entered()
    StandbyState::entered()

    SGaistS 1 Reply Last reply
    0
    • R rdowell

      I'm trying to implement a state machine in a machine control application. The machine has 3 basic runtime states, Idle, Standby, and Running, which I put into a single parent state called Normal.

      The basic transitions are as follows:

      Idle --> Running on 'Start'
      Running-->Standby on 'Stop'
      Running --> Idle on 'Finished'
      Standby --> Running on 'Start'
      Standby --> Idle on 'Reset'

      In addition to these normal transitions however there is also an 'Emergency Stop' function which I want to handle separately, because it's possible for this button to be engaged at any time, so I want that state to be outside of 'Normal' and instead use a History state to return to Normal when the button is disengaged. This way an E-Stop from Idle or Standby will return to those states, however, if the button is hit while Running, I want the following to happen:

      Running --> Standby (so that the History state of Normal will return to Standby instead of back to Running)
      Normal --> Emergency Stop

      To that end I made the following state definitions and transitions:

      // Basic states
      QState* NormalState = new QState(stateMachine);
      QState* EStopState = new QState(stateMachine);
      
      // Normal states
      QState* IdleState = new QState(NormalState);
      QState* StandbyState = new QState(NormalState);
      QState* RunningState = new QState(NormalState);
      
      // Normal transitions
      IdleState->addTransition(machineManager, &Manager::OnStart, RunningState);
      RunningState->addTransition(machineManager, &Manager::OnStop, StandbyState);
      RunningState->addTransition(machineManager, &Manager::OnFinish, IdleState);
      StandbyState->addTransition(machineManager, &Manager::OnStart, RunningState);
      StandbyState->addTransition(machineManager, &Manager::OnReset, IdleState);
      
      // EStop transitions
      QHistoryState *normalReturnState = new QHistoryState(NormalState);
      RunningState->addTransition(machineManager, &Manager::OnEStop, StandbyState);
      NormalState->addTransition(machineManager, &Manager::OnEStop, EStopState);
      EStopState->addTransition(machineManager, &Manager::OnEStopReleased, normalReturnState);
      

      This works fine when E-Stop is engaged in Idle or Standby, but if I engage E-Stop while Running, only the Running --> Standby transition occurs and the second one is ignored.

      I know I could potentially solve this issue by making parallel states, i.e. Idle/Standby/Running in one parallel group and Normal/EStop in the other, but I'm concerned that would add much more complication to my display logic

      For example, if I were to do:

      StandbyState->assignProperty(widget, "enabled", true);
      EStopState->assignProperty(widget, "enabled", false);
      

      This would work if EStop and Standby are not parallel. If they were parallel then it would depend on which one the state machine enters first. The same problem would happen if I put any processing on the entered() or exited() events, but if the states were not parallel, and EStop were able to first transition Running --> Standby, then I expect I would receive a predictable sequence of events like this:

      On EStopDown:
      RunningState::exited()
      StandbyState::entered()
      StandbyState::exited()
      NormalState::exited()
      EStopState::entered()
      On EStopUp:
      EStopState::exited()
      NormalState::entered()
      StandbyState::entered()

      SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      I might be wrong but I don't think it can be easily achieved with QHistoryState but that said, you could have an additional emergency stopped state for the Running case and simply go back from that state to Idle.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      R 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi,

        I might be wrong but I don't think it can be easily achieved with QHistoryState but that said, you could have an additional emergency stopped state for the Running case and simply go back from that state to Idle.

        R Offline
        R Offline
        rdowell
        wrote on last edited by
        #3

        @SGaist That occurred to me as a possibility but there is another complicating factor which is that there are other runtime error conditions that should essentially do the same thing as the E-Stop (drop from Running to Standby then go to an Error state) so it would require duplicating those as well.

        I did have a thought about a way to handle it though, which is to essentially have an 'Interrupt' signal that is fired by the Manager object before the E-Stop/Error signals. The interrupt signal would trigger the Running --> Standby transition while the regular OnEStop signal would come second, and trigger the Normal --> EStop transition

        SGaistS 1 Reply Last reply
        0
        • R rdowell

          @SGaist That occurred to me as a possibility but there is another complicating factor which is that there are other runtime error conditions that should essentially do the same thing as the E-Stop (drop from Running to Standby then go to an Error state) so it would require duplicating those as well.

          I did have a thought about a way to handle it though, which is to essentially have an 'Interrupt' signal that is fired by the Manager object before the E-Stop/Error signals. The interrupt signal would trigger the Running --> Standby transition while the regular OnEStop signal would come second, and trigger the Normal --> EStop transition

          SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Then it might be simpler to implement your own history state that can handle that special case.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved