处理 Boost MSM 中每个状态的错误

Hug*_*l31 2 c++ boost-msm

我正在使用 Boost MSM 来模拟机器人的行为。有多种状态,如“手动移动”、“自动移动”、“工作”、“空闲”等......但是我需要能够从任何状态强行停止机器人,将其置于无法移动的状态无法接收新命令,因此我创建了“EmergencyStopped”状态。 当机器人被要求重新武装自己时,机器人应该返回到“空闲”状态。

然而,Boost 不建议创建从所有状态到单个状态的转换,而更喜欢使用正交状态。因此,我可以执行“AllOk”和interrupt_state“EmergencyStopped”正交状态。

问题是,虽然我可以轻松地将机器人置于“紧急停止”状态,但我无法退出它并将机器人从之前的状态置于“空闲”状态。例如,如果机器人执行以下操作:

  • [工作,一切正常] -> 停止
  • [工作,紧急停止] -> 恢复

机器人将处于 [Work, AllOk] 状态,而我希望它处于 [Idle, AllOk] 状态。

所以我的问题是:

  • 我可以并且应该在此工作流程中使用正交状态吗?如果是,当我进入正交状态“EmergencyStopped”时,如何强制状态为“空闲”?
  • 或者我应该使“EmergencyStopped”成为非正交并声明从所有状态到它的过渡?
  • 或者还有其他解决方案吗?

Tak*_*ndo 5

还有另一种解决方案。就您而言,复合状态是更好的选择。看图。

状态机图

如何避免编写许多到“EmergencyStopped”的转换。

Em-将发生“停止”事件时需要转换为“EmergencyStopped”的所有状态转换为“正常”状态。并将从“正常”过渡到“紧急停止”。它的触发事件是“停止”。这种方法可以避免编写许多到“EmergencyStopped”的转换。即使您要添加“正常”的其他状态,也不需要为添加的状态添加转换。这是复合状态方法的好处之一。

如果发生“恢复”事件,如何转换到“空闲”状态。

将“空闲”状态设置为initial_state。它反映到UML状态机图中的初始伪状态。

typedef mpl::vector<Idle> initial_state;
Run Code Online (Sandbox Code Playgroud)

如果转换目标是状态“正常”,则转换目标状态是“空闲”状态,因为它被标记为initial_state

这两种技术解决了你的问题。

这是完整的代码:

#include <iostream>
#include <boost/msm/back/state_machine.hpp>

#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/static_assert.hpp>

namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;

// ----- Events
struct ev1 {};
struct ev2 {};
struct ev3 {};
struct stop {};
struct recover {};

// ----- State machine
struct YourSystem_:msmf::state_machine_def<YourSystem_>
{
    struct Normal_:msmf::state_machine_def<Normal_>
    {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            std::cout << "Normal::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            std::cout << "Normal::on_exit()" << std::endl;
        }

        struct Idle:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "Idle::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                std::cout << "Idle::on_exit()" << std::endl;
            }
        };

        struct Work:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "Work::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                std::cout << "Work::on_exit()" << std::endl;
            }
        };

        struct AllOk:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                std::cout << "AllOk::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                std::cout << "AllOk::on_exit()" << std::endl;
            }
        };

        // Set initial state
        typedef mpl::vector<Idle> initial_state;
        // Transition table
        struct transition_table:mpl::vector<
            //          Start      Event   Next       Action      Guard
            msmf::Row < Idle,      ev1,    Work,      msmf::none, msmf::none >,
            msmf::Row < Work,      ev2,    AllOk,     msmf::none, msmf::none >,
            msmf::Row < AllOk,     ev3,    Idle,      msmf::none, msmf::none >
            > {};
    };
    struct EmergencyStopped:msmf::state<>
    {
        template <class Event,class Fsm>
        void on_entry(Event const&, Fsm&) const {
            std::cout << "EmergencyStopped::on_entry()" << std::endl;
        }
        template <class Event,class Fsm>
        void on_exit(Event const&, Fsm&) const {
            std::cout << "EmergencyStopped::on_exit()" << std::endl;
        }
    };

    typedef msm::back::state_machine<Normal_> Normal;

    // Set initial state
    typedef Normal initial_state;
    // Transition table
    struct transition_table:mpl::vector<
        //          Start             Event     Next               Action      Guard
        msmf::Row < Normal,           stop,     EmergencyStopped,  msmf::none, msmf::none >,
        msmf::Row < EmergencyStopped, recover,  Normal,            msmf::none, msmf::none >
    > {};
};

// Pick a back-end
typedef msm::back::state_machine<YourSystem_> Ys;

int main()
{
    Ys ys;
    ys.start();

    std::cout << "> Send ev1()" << std::endl;
    ys.process_event(ev1());
    std::cout << "> Send ev2()" << std::endl;
    ys.process_event(ev2());

    std::cout << "> Send stop()" << std::endl;
    ys.process_event(stop());
    std::cout << "> Send recover()" << std::endl;
    ys.process_event(recover());
}
Run Code Online (Sandbox Code Playgroud)

并运行演示https://wandbox.org/permlink/uBm6jTvG0YL3gSgl