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

Handle an error from every state in Boost MSM

我正在使用 Boost MSM 来模拟机器人的行为。有多种状态,如"ManualMove"、"AutoMove"、"Work"、"Idle"等... 但是我需要能够从任何状态强制停止机器人,将其置于无法移动且无法接收新命令的状态,因此我创建了一个 "EmergencyStopped" 状态。 当机器人被要求重新武装时,机器人应该回到"Idle"状态。

但是,Boost 不建议创建从所有状态到单个状态的转换,而更喜欢使用正交状态。 例如,我可以做 "AllOk" 和 interrupt_state "EmergencyStopped" 正交状态。

问题是,虽然我可以轻松地将机器人置于 "EmergencyStopped",但我无法退出它并使机器人从之前的状态进入 "Idle" 状态。例如,如果机器人执行:

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

所以我的问题是:

还有一个解决办法。在您的情况下,复合状态是更好的选择。见图。

如何避免将许多转换写入 "EmergencyStopped"。

Em-place 所有需要转换到 "EmergencyStopped" 的状态,如果 "stop" 事件发生到 "Normal" 状态。并放置从 "Normal" 到 "EmergencyStopped" 的过渡。它的触发事件是"stop"。这种方法可以避免将许多转换写入 "EmergencyStopped"。即使您要添加 "Normal" 的其他 child 状态,也不需要为添加的状态添加转换。这是复合状态方法的好处之一。

如果 "recover" 事件发生,如何转换到 "Idle" 状态。

将 "Idle" 状态设置为 initial_state。它反映了 UML state-machine 图中的初始伪状态。

typedef mpl::vector<Idle> initial_state;

如果转换目标是状态"Normal",那么转换目标状态是"Idle"状态,因为它被标记为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());
}

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