【问题标题】:Handle an error from every state in Boost MSM处理 Boost MSM 中每个状态的错误
【发布时间】:2019-10-06 14:40:06
【问题描述】:

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

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

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

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

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

所以我的问题是:

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

【问题讨论】:

  • 让我澄清一下您的示例中的元素,“Work”、“AllOk”和“EmergencyStopped”是状态? “停止”和“恢复”是事件吗? “空闲”状态在哪里?
  • 我认为“Idle”、“Work”和“AllOk”是状态。并且所有这些州都会收到“停止”事件。然后转换到“EmergencyStopped”状态。在“EmergencyStopped”状态下,如果接收到“recover”事件,则转换到“Idle”状态。我理解正确吗?
  • 没错。我将用图表编辑问题,以便当天晚些时候更清楚。

标签: c++ boost-msm


【解决方案1】:

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

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

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

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

将“空闲”状态设置为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

【讨论】:

  • 这正是我所需要的。谢谢!
  • 一个出色且非常详细的答案。我只希望他们都是这样 :-)
猜你喜欢
  • 2013-05-22
  • 1970-01-01
  • 1970-01-01
  • 2017-01-06
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多