Wiki
有限狀態機(Finite State Machine)
約 2 分鐘閱讀
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
1.有限狀態機(Finite State Machine)
FSM就是:把任務分成幾個狀態,並規定遇到什麼事件時切換狀態。

重點理解四件事:
- 狀態: 當前任務在做什麼,例如“前往目標”。
- 事件/條件: 發生了什麼,例如導航返回成功。
- 轉移: 從“前往目標”切到“到點等待”。
- 進入/退出動作: 進入導航狀態時傳送一次目標;中途退出時取消尚未完成的目標。 狀態機通常圍繞“當前處於哪個狀態,什麼時候切換”組織邏輯;BT圍繞條件檢查和動作組合組織邏輯。兩者都能做任務決策。
1.1.例子
1.1.1.例子1
做一個小例子:
首先定義四個狀態:
| 狀態 | 表示什麼 |
|---|---|
| 待機 | 還沒有任務 |
| 導航中 | 已傳送目標,正在等待結果 |
| 已完成 | 導航成功 |
| 異常 | 導航失敗 |
再定義事件:开始任务、导航成功、导航失败、重置。
狀態是“現在處於什麼階段”,事件是“剛剛發生了什麼”。
狀態機根據這兩項決定下一步。
// 定义任务可能处于的状态
enum class State {
IDLE, // 待机:还没有开始任务
NAVIGATING, // 导航中:已经发送目标,正在等待结果
COMPLETED, // 已完成:导航成功
ERROR // 异常:导航失败
};
// 定义可能收到的事件
enum class Event {
START, // 收到“开始任务”指令
NAV_SUCCEEDED, // 导航模块报告成功
NAV_FAILED, // 导航模块报告失败
RESET // 收到“重置任务”指令
};
// 保存当前状态,初始状态为待机
State current_state = State::IDLE;
// 函数声明:暂时代表发送A点目标,具体实现以后再写
void sendGoalA();
// 每次发生事件时,调用这个函数
void handleEvent(Event event)
{
// 先判断任务当前处于哪个状态
switch (current_state)
{
case State::IDLE:
// 待机状态下,收到开始指令才启动导航
if (event == Event::START)
{
current_state = State::NAVIGATING;
sendGoalA(); // 发送一次导航目标
}
break; // 跳出switch,本次事件处理结束
case State::NAVIGATING:
// 导航中,根据导航结果切换状态
if (event == Event::NAV_SUCCEEDED)
{
current_state = State::COMPLETED;
} else if (event == Event::NAV_FAILED)
{
current_state = State::ERROR;
}
// 如果收到START等其他事件,保持当前状态
break;
// 已完成和异常状态,共用下面的重置逻辑
case State::COMPLETED:
case State::ERROR:
if (event == Event::RESET)
{
current_state = State::IDLE;
}
break;
}
}
下面模擬事件依次發生:
void demo()
{
// 当前为待机,操作员点击开始指令:进入导航中,发送目标
handleEvent(Event::START);
// 当前已在导航中,再收到开始指令:忽略,不重复发送目标
handleEvent(Event::START);
// NAV2导航报告成功:进入已完成状态
handleEvent(Event::NAV_SUCCEEDED);
// 收到重置指令:回到待机状态
handleEvent(Event::RESET);
}
核心就是:先看當前狀態,再看收到的事件,決定是否切換狀態以及執行什麼動作。
1.1.2.例子2
增加“到點後等待2秒”的功能:
#include <chrono>
using Clock = std::chrono::steady_clock;
// 任务状态
enum class State {
IDLE, // 待机
NAVIGATING, // 导航中
WAITING, // 到点后等待
COMPLETED, // 任务完成
ERROR // 任务异常
};
// 任务事件
enum class Event {
START, // 开始任务
NAV_SUCCEEDED, // 导航成功
NAV_FAILED, // 导航失败
WAIT_FINISHED, // 等待结束
RESET // 重置任务
};
State current_state = State::IDLE;
// 保存等待的结束时刻
Clock::time_point wait_deadline;
// 暂时代表发送导航目标,具体实现以后再写
void sendGoalA();
// 处理事件
void handleEvent(Event event)
{
switch (current_state) {
case State::IDLE:
if (event == Event::START)
{
current_state = State::NAVIGATING;
sendGoalA(); // 只发送一次目标
}
break;
case State::NAVIGATING:
if (event == Event::NAV_SUCCEEDED)
{
// 导航成功时,设置一次等待结束时刻
wait_deadline =
Clock::now() + std::chrono::seconds(2);
current_state = State::WAITING;
}
else if (event == Event::NAV_FAILED)
{
current_state = State::ERROR;
}
break;
case State::WAITING:
if (event == Event::WAIT_FINISHED)
{
current_state = State::COMPLETED;
}
break;
case State::COMPLETED:
case State::ERROR:
if (event == Event::RESET)
{
current_state = State::IDLE;
}
break;
}
}
// 主循环或定时器周期性调用这个函数
void tick()
{
// 只有处于等待状态,才检查时间
if (current_state == State::WAITING)
{
if (Clock::now() >= wait_deadline)
{
handleEvent(Event::WAIT_FINISHED);
}
}
}
模擬呼叫過程:
handleEvent(Event::START); // 待机 → 导航中
handleEvent(Event::NAV_SUCCEEDED); // 导航中 → 等待,启动一次计时
// 接下来,主循环周期性调用tick()
tick(); // 未到结束时刻:保持WAITING
tick(); // 未到结束时刻:保持WAITING
// 2秒到期后的下一次检查
tick(); // 触发WAIT_FINISHED,进入COMPLETED