【问题标题】:periodic state machine with boost statechart具有升压状态图的周期性状态机
【发布时间】:2013-06-06 20:54:33
【问题描述】:

我想实现一个状态机,它会定期监控一些状态数据(我系统的状态)并对其做出反应。

这对于状态机来说似乎是非常基本的事情(我以前曾多次遇到过这个问题),但我找不到一个好的方法来解决它。这是一些伪代码来解释我想要实现的目标:

// some data that is updated from IOs for example
MyData data;

int state = 0;

while( true ) {
    update( & data ); //read a packet from serial port 
                      //and update the data structure
    switch( state ) {
    case 0:
        if( data.field1==0 ) state = 1;
        else doSomething();
        break;
    case 1:
        if( data.field2>0 ) state = 2;
        else doSomethingElse();
        break;

    // etc.

    }
    usleep(100000); //100ms
}

当然,最重要的是,我希望能够在进入和退出状态时执行一些操作,可能在状态的每次迭代中执行一些操作,拥有子状态、历史记录等。这就是为什么这种简单化方法的原因很快变得不切实际,因此提升状态图。

我已经考虑了一些解决方案,希望得到一些反馈。

1) 我可以列出我的所有转换条件并为每个条件创建一个事件。然后我会有一个循环来监控每个布尔切换的时间。例如我的第一个条件可能是:

if( old_data.field1!=0 && new_data.field1==0 )
    // post an event of type Event 1

但似乎很快就会变得困难

2) 有一个所有状态都响应的事件。只要有一些新的状态数据可用,就会发布此事件。因此,当前状态将检查数据并决定是否启动到另一个状态的转换

3) 让所有状态都继承自定义 do_work(const MyData & data) 方法的接口,该方法将在循环中从外部调用,检查数据并决定是否启动到另一个状态的转换

另外,我愿意使用其他框架(即 Macho 或 boost MSM)

【问题讨论】:

  • 也许您可以在 state-machine.com 上查看带有分层状态机的 QP 活动对象框架。你不写你想在哪个操作系统/环境上运行它,但从 usleep() 调用来看,它看起来像 POSIX,QP 多年来一直支持它。
  • 全面披露 Miro(上面评论过的)是 QP 的作者,所以他正在开发自己的产品;)我强烈推荐他的书。

标签: state state-machine fsm boost-statechart boost-msm


【解决方案1】:

在与 boost MSM、状态图和 QP 合作后,我认为您在状态图方面走在了正确的轨道上。 MSM 更快,但如果您对状态机或元编程没有太多经验,那么如果您做错了什么,来自 MSM 的错误消息将很难理解。 boost.statecharts 是最简洁、最容易理解的。至于 QP,它以嵌入式风格编写(大量预处理器的东西,较弱的静态检查),尽管它也适用于 PC 环境。我也相信它更慢。它确实具有在许多小型 ARM 和类似处理器上工作的优势。与提升解决方案相比,它不是免费用于商业用途的。

为每种类型的状态更改创建事件不会扩展。我会制作一种类型的事件EvStateChanged 给它一个数据成员,其中包含对数据集的副本或引用(如果需要,可能还有一个旧数据)。然后,您可以使用服装反应来处理您在任何状态上下文中需要的任何内容。尽管默认转换在烤面包机环境中运行良好(通常用于演示 SM 功能),但我见过的大多数现实世界的 SM 都有许多自定义反应,不要害羞地使用它们。

我不太了解您的问题,无法提供代码示例,但大致如下:

while( true ) {
    update( & data ); //read a packet from serial port 
                      //and update the data structure
    if(data != oldData){
          sm.process_event(EvDataChanged(data,oldData));
    }
    else{
        timeout++;
        if(timeout>MAX_TIMEOUT)
            sm.process_event(EvTimeout());
    }
    usleep(100000); //100ms
}

然后根据这些方面的状态处理客户反应中的数据更改:

SomeState::~SomeState(){
    DoSomethingWhenLeaving();
}
sc::result SomeState::react( const EvDataChanged & e){
    if(e.oldData.Field1 != e.newData.Field1){
        DoSomething();
        return transit<OtherState>();
    }
    if(e.oldData.Field2 != e.newData.Field2){
        return transit<ErrorState>();   //is not allowed to change in this state
    }
    if(e.oldData.Field3 == 4){
        return forward_event();  //superstate should handle this
    }
    return discard_event(); //don't care about anything else in this context
}

【讨论】:

    猜你喜欢
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    相关资源
    最近更新 更多