2

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

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

问题是,虽然我可以轻松地将机器人置于“EmergencyStopped”状态,但我无法退出并让机器人从之前的状态进入“空闲”状态。例如,如果机器人这样做:

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

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

所以我的问题是:

  • 我可以而且应该在这个工作流程中使用正交状态吗?如果是,当我退出正交状态“EmergencyStopped”时,如何强制状态“空闲”?
  • 或者我应该使“紧急停止”非正交并声明从所有状态到它的过渡?
  • 还是有其他解决方案?
4

1 回答 1

5

还有另一种解决方案。在您的情况下,复合状态是更好的选择。见图表。

状态机图

如何避免将许多转换写入“紧急停止”。

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

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

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

typedef mpl::vector<Idle> initial_state;

如果转换目标是状态“正常”,那么转换目标状态是“空闲”状态,因为它被标记为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

于 2019-05-23T06:22:18.970 回答