状态机框架 FFSM2 的使用

  1. 1. 一些基本概念
  2. 2. FFSM2
    1. 2.1. Example
    2. 2.2. 状态的定义
    3. 2.3. 一些常用函数

FFSM2

什么是状态机?让我们先来看看 维基百科 中的定义:

有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机(英语:finite-state automaton,缩写:FSA),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型。

总的来说,它是现实事物运行规则 抽象 而成的一个数学模型。它在例如 TCP,游戏开发等程序开发中得到了广泛应用。

一些基本概念

  • 状态(State):当前系统的状态,决定了当前系统的输入与输出
  • 事件(Event):相当于系统的输入,系统接收到事件后会触发(trigger)某个动作或进行状态转移
  • 转移(Transition):表明系统状态改变,一个转移由 当前状态具体事件(输入)共同决定
  • 进入动作(Entry):在进入状态时执行
  • 退出动作(Exit):在退出状态时执行

image-20220228171621675

FFSM2

andrew-gresyk/FFSM2 是一个高性能的扁平式 有限状态机 框架。使用 C++11 编写,仅有一个头文件。利用模板实现了编译期对结构体进行静态构建,因此不需要动态内存分配。

Example

include ffsm2/machine.hpp 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// FFSM2 (flat state machine for games and interactive applications)
// Created by Andrew Gresyk
//
// Traffic light example:
// Cycle between R-Y-G-Y-B three times, then turn off

// State structure:
//
// Root
// ├ On
// │ ├ Red
// │ ├ YellowDownwards
// │ ├ YellowUpwards
// │ └ Green
// └ Off

// Output:
//
// On
// Red
// Yellow v
// Green
// Yellow ^
// Red
// Yellow v
// Green
// Yellow ^
// Red
// Yellow v
// Green
// Yellow ^
// Red
// Off

// optional: enable FSM structure report in debugger
#define FFSM2_ENABLE_STRUCTURE_REPORT
#include <ffsm2/machine.hpp>

#include <iostream>

//------------------------------------------------------------------------------

// 构造状态机原型(prototype),此处为状态机中保存的上下文信息
struct Context {
unsigned cycleCount = 0;
};
using M = ffsm2::MachineT<ffsm2::Config::ContextT<Context>>;

// 利用宏简化状态的定义
#define S(s) struct s

// state machine structure
using FSM = M::Root<S(On),
S(Red),
S(YellowDownwards),
S(YellowUpwards),
S(Green),
S(Off)
>;

#undef S

//------------------------------------------------------------------------------
// 静态检查各个状态的 ID
static_assert(FSM::stateId<Red>() == 0, "");
static_assert(FSM::stateId<YellowDownwards>() == 1, "");
static_assert(FSM::stateId<YellowUpwards>() == 2, "");
static_assert(FSM::stateId<Green>() == 3, "");
static_assert(FSM::stateId<Off>() == 4, "");

////////////////////////////////////////////////////////////////////////////////

// top-level region in the hierarchy
struct On
: FSM::State // necessary boilerplate!
{
// called on state entry
void enter(Control& control) {
control.context().cycleCount = 0;
std::cout << "On" << std::endl;
}
};

//------------------------------------------------------------------------------

// sub-states
struct Red
: FSM::State
{
void enter(Control& control) {
++control.context().cycleCount;
std::cout << " Red" << std::endl;
}

// state can initiate transitions to _any_ other state
void update(FullControl& control) {
// multiple transitions can be initiated, can be useful in a hierarchy
if (control.context().cycleCount > 3)
control.changeTo<Off>();
else
control.changeTo<YellowDownwards>();
}
};

struct YellowDownwards
: FSM::State
{
void enter(Control&) {
std::cout << " Yellow v" << std::endl;
}

void update(FullControl& control) {
control.changeTo<Green>();
}
};

struct YellowUpwards
: FSM::State
{
void enter(Control&) {
std::cout << " Yellow ^" << std::endl;
}

void update(FullControl& control) {
control.changeTo<Red>();
}
};

struct Green
: FSM::State
{
void enter(Control&) {
std::cout << " Green" << std::endl;
}

void update(FullControl& control) {
control.changeTo<YellowUpwards>();
}
};

// another top-level state
struct Off
: FSM::State
{
void enter(Control&) {
std::cout << "Off" << std::endl;
}
};

int main() {
// shared data storage instance
Context context;

FSM::Instance machine{context};

while (machine.isActive<Off>() == false)
machine.update();

return 0;
}

M::Root 用于构造有 根状态(Root state)的状态机,当状态机更新(update)时,无论其子状态是什么,都会 先执行根状态update 函数,再执行子状态的 update 函数,如果需要先执行子状态的函数,可使用 reverseUpdate 函数,同样的,根状态也需要重载 reverseUpdate 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using M = ffsm2::Machine;

#define S(s) struct s

using FSM = M::Root<S(Root),
S(Off),
S(On)>;

#undef S

struct Root : FSM::State {
void enter(Control &control) {
std::cout << "Root: enter" << std::endl;
}

void reverseUpdate(FullControl &) {
std::cout << "Root: update" << std::endl;
}
};

struct Off : FSM::State {
void enter(Control &) {
std::cout << "Off: enter" << std::endl;
}

void reverseUpdate(FullControl &) {
std::cout << "off: update" << std::endl;
}
};

struct On : FSM::State {
void enter(Control &) {
std::cout << "On: enter" << std::endl;
}

void reverseUpdate(FullControl &) {
std::cout << "on: update" << std::endl;
}
};

//------------------------------------------------------------------------------

int main() {
FSM::Instance machine;

machine.reverseUpdate();
machine.reverseUpdate();

return 0;
}

输出:

1
2
3
4
5
6
Root: enter
Off: enter
off: update
Root: update
off: update
Root: update

如果状态机比较简单,不需要根状态,则可以使用 M::PeerRoot,除了没有根状态外,用法与 M::Root 一致。

状态的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
struct State : FSM::State {
// 进入状态时执行
void enter(PlanControl &control) {

}
// 进入状态前进行判断,可通过 GuardControl 取消当前转换
void entryGuard(GuardControl &control) {

}
// 重复进入状态时执行
void reenter(PlanControl &control) {

}
// 退出状态时执行
void exit(PlanControl &control) {

}
// 退出前进行判断
void exitGuard(GuardControl &control) {

}
// 更新状态机
void update(FullControl &control) {

}
// 逆序更新状态机
void reverseUpdate(FullControl &control) {

}
// 具体事件的动作
// 注意:如果有多个事件,那么每个事件都要有对应的 react 函数,否则可能会编译错误
void react(BaseEvent &event, FullControl &control) { ... }
void react( ... &event, FullControl &control) { ... }
void react( ... &event, FullControl &control) { ... }
};

一些常用函数

  1. FSM::Instance

    • changeTo<TState>():转换到 TState
    • update():更新状态机(从根状态到子状态)
    • reverseUpdate():逆向更新状态机(从子状态到根状态)
    • react<TEvent>():向状态机发送 TEvent 事件
    • activeStateId():获取当前状态的 ID
  2. Control

    • context():返回状态机上下文(Context)的 引用

    • request():获取当前 转换请求 的引用 Transition &,可获取起始状态和目标状态

  3. FullControl

    • changeTo<TState>:同上
  4. GuardControl

    • currentTransitions() :获取当前转换的引用 Transition &,可获取起始状态和目标状态
    • cancelPendingTransition():取消当前转换(注意:只有当前状态的 exitGuard 和目标状态的 entryGuard 均满足条件才能进行转换)
本网站所有文章除特别声明外,均采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。