代码之家  ›  专栏  ›  技术社区  ›  Stewart

boost msm接通电流状态

  •  0
  • Stewart  · 技术社区  · 6 年前

    我有一个实时循环,我需要根据我所处的状态来完成每次迭代。

    我使用boosts元状态机库来实现我的状态机。根据我所处的状态调用函数的最佳方法是什么?

    假设我有一个超级简单的状态机:

    //Events
    struct run {};
    struct stop {}; 
    
    struct MyStateMachine : public boost::msm::front::state_machine_def<MyStateMachine>
    {
        // FSM states
        struct Idle : public boost::msm::front::state<> {};
        struct Running : public boost::msm::front::state<> {};
    
        typedef Idle initial_state;
    
        // transition actions
        void do_start(run const&)  { std::cout << "Starting\n"; }
        void do_stop(stop const&)  { std::cout << "Stopping\n"; }
    
        struct transition_table : boost::mpl::vector<
            //    Start     Event     Next     Action               
          a_row < Idle     , run    , Running, &MyStateMachine::do_start   >,
          a_row < Running  , stop   , Idle   , &MyStateMachine::do_stop    >
        > {};
    };
    

    根据我们所处的状态,我可以看到一些工作方法:

    1)接通当前状态

    class MyModule : RealTimeModule
    {
        void Init() override  { // Called before realtime
            fsm_.start();
        }
    
        void Step() override {  // Called once each iteration during realtime
    
            switch(fsm_.current_state()[0])
            {
            case 0:      do_idle();     break;
            case 1:      do_run();      break;
            default:     assert();
            }
        }
    
        void DoEvent(Event e) override { // Called once per received event
    
            fsm_.process_event(e);
        }
    
    private: 
        boost::msm::back::state_machine<MyStateMachine> fsm_;
    };
    

    这看起来不太好,因为没有直观的方法知道 case 0 闲置 或者那个 case 1 跑步 .

    2)添加转换和事件来表示每个迭代

    //Events
    struct run {}; 
    struct stop {};
    struct step {}; // !!!NEW EVENT!!!
    
    struct MyStateMachine : public boost::msm::front::state_machine_def<MyStateMachine>
    {
        ...
        // transition actions
        void do_start(run const&)  { std::cout << "Starting\n"; }
        void do_stop(stop const&)  { std::cout << "Stopping\n"; }
        void do_idle(step const&)  { std::cout << "Idling  \n";  } //!!!NEW ACTION!!!
        void do_run (step const&)  { std::cout << "Running \n";  } //!!!NEW ACTION!!!
    
        struct transition_table : boost::mpl::vector<
            //    Start     Event     Next     Action               
          a_row < Idle     , run    , Running, &MyStateMachine::do_start   >,
          a_row < Running  , stop   , Idle   , &MyStateMachine::do_stop    >,
          a_row < Idle     , step   , Idle   , &MyStateMachine::do_idle    >, //!!!NEW TRANSITION!!!
          a_row < Running  , step   , Running, &MyStateMachine::do_step    > //!!!NEW TRANSITION!!!
        > {};
    };
    
    class MyModule : RealTimeModule
    {
        ...
        void Step() override {
            fsm_.process_event(step); //!!!SIMPLIFIED STEP!!!
        }
        ...
    };
    

    这看起来好多了,但我的问题是如果我想实现 boost::msm::front::state<>::on_entry() on_exit ,则这些函数将在每次迭代时调用,而不是在转换到该状态时调用。


    我发现可以使用函子前端调用带有事件的操作,而不使用转换 here 是的。转换表中的行如下所示:

    msm::front::Row < Idle, step, msm::front::none, step_idle, msm::front::none >
    

    但是,为了使用它,我需要使我的操作看起来像这样:

    struct do_step {
        template <class Event, class Fsm, class SourceState, class TargetState>
        void operator()(Event const&, Fsm&, SourceState&, TargetState&) const {
            std::cout << "Idling" << std::endl;
        }
    };
    

    也许这是一个风格的东西,但这似乎太冗长,不是一个好的解决方案。有没有办法加上 msm::front::none 用简单的前端代替函子前端?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Stewart    6 年前

    好的,我找到了答案。让我恼火的是,我真的需要阅读未注释的boost头文件,而不是文档或引用来找出该做什么。

    我需要使用 a_irow 结构不涉及转换,而只是调用操作:

    struct transition_table : boost::mpl::vector<
        //    Start     Event     Next     Action               
      a_row < Idle     , run    , Running, &MyStateMachine::do_start   >,
      a_row < Running  , stop   , Idle   , &MyStateMachine::do_stop    >,
     a_irow < Idle     , step   ,          &MyStateMachine::do_idle    >,
     a_irow < Running  , step   ,          &MyStateMachine::do_step    >
    > {};
    

    总而言之,这些是可以添加的行类型:

     a_row<Source, Event, Target, Action       >
      _row<Source, Event, Target               >
       row<Source, Event, Target, Action, Guard>
     g_row<Source, Event, Target,         Guard>
    a_irow<Source, Event,       , Action       >
      irow<Source, Event,         Action, Guard>
    g_irow<Source, Event,                 Guard>
     _irow<Source, Event,                      >  // Forces events to be ignored
    

    使用:

    typename Source;
    class    Event;
    typename Target;
    typedef void (Derived::*action)(Event const&) Action;
    typedef bool (Derived::*guard)(Event const&)  Guard;
    

    参考: boost/msm/front/state_machine_def.hpp