状态机我们大家都知道,有一个专门的设计模式状态机模式,类图大概如下图:不过如果按照下面图来实现的状态机,基本来说非常难用,没有实用性,只能作为教科书的产品。今天我们要实现的是一种通用状态机,可以Send事件,每一个状态可以响应自己注册的事件,同时也可以通过自身或者事件来改变状态机的状态
代码地址
:
https://github.com/9435202/StateAPI
首先Contex类:
CreateState() 接口,用于创建状态机和父状态机关系
Update() 接口,外部驱动状态机函数
SendEvent() 同步发送事件到当前状态,
能发送任意数据到状态中处理
SendAsyncEvent() 异步发送事件到当前状态,能发送任意数据到状态中处理
State类
virtual void start(){} // 状态开始处理 子类实现
virtual void update(){} // update处理 子类实现
virtual void stop(){} // 状态结束处理 子类实现
void set_event_func(); // 设置事件处理回调函数,子类绑定
具体实现如下:
Context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
#include "Event.h"
#include <string>
#include <unordered_map>
#include <thread>
namespace HsmState
class State;
struct NodeState
NodeState& operator = (const NodeState& n)
_state = n._state;
_father_name = n._father_name;
return *this;
State* _state;
std::string _father_name;
class Context
public:
friend class State;
Context();
~Context();
// 开始状态机
bool Start(std::string name);
// 创建一个状态
// [in] state 状态对象,在Context销毁时,内部释放state
// [in] name 状态名称,为空名称为typedname的值
// [in] father_name 父状态的名称
// [out] 返回state
State* CreateState(State* state, std::string name, std::string father_name = "");
// 更新当前状态
void Update();
// 同步事件
// 发送一个事件,提供给root状态和当前状态处理
// 如果当前状态是子状态,则还会给父状态处理
void SendEvent(EventData event_data);
// 异步事件
void SendAsyncEvent(EventData event_data);
// 获取当前状态名称
std::string GetCurStateName();
private:
// 状态切换
void TransForState(std::string name);
// 递归send
void RecursiveSend(NodeState& node_state, EventData& event_data);
std::unordered_map<std::string, NodeState> _states; // 状态列表
NodeState _cur_node_state; // 当前状态名
std::string _cur_name;
std::string _root_name; // 根状态名
#endif // !STATE_H_
contex.cpp
#include "Context.h"
#include "State.h"
namespace HsmState
Context::Context()
Context::~Context()
for (auto iter : _states)
if (iter.second._state)
delete iter.second._state;
iter.second._state = nullptr;
_states.clear();
// 开始状态机
bool Context::Start(std::string name)
std::unordered_map<std::string, NodeState>::iterator iter_map = _states.find(name);
if (iter_map != _states.end())
_cur_node_state = iter_map->second;
_cur_name = iter_map->first;
iter_map->second._state->start();
return false;
// 创建一个状态
// [in] state 状态对象,在Context销毁时,内部释放state
// [in] name 状态名称,为空名称为typedname的值
// [in] father_name 父状态的名称
// [out] 返回state
State* Context::CreateState(State* state, std::string name, std::string father_name)
NodeState node_state;
node_state._state = state;
node_state._state->SetContext(this);
node_state._father_name = father_name;
_states[name] = node_state;
return state;
// 更新当前状态
void Context::Update()
_cur_node_state._state->update();
// 同步事件
// 发送一个事件,提供给root状态和当前状态处理
// 如果当前状态是子状态,则还会给父状态处理
void Context::SendEvent(EventData event_data)
RecursiveSend(_cur_node_state, event_data);
// 异步事件
void Context::SendAsyncEvent(EventData event_data)
// todo 待实现
std::string Context::GetCurStateName()
return _cur_name;
// 递归send
void Context::RecursiveSend(NodeState& node_state, EventData& event_data)
EventDeal event_deal = node_state._state->RunEventFunc(event_data);
if (event_deal == keep_on
&& !node_state._father_name.empty())
std::unordered_map<std::string, NodeState>::iterator iter_map = _states.find(node_state._father_name);
if (iter_map != _states.end())
RecursiveSend(iter_map->second, event_data);
void Context::TransForState(std::string name)
std::string str_name = std::string(name);
std::unordered_map<std::string, NodeState>::iterator iter_map = _states.find(str_name);
if (iter_map != _states.end())
// 停止上一个状态
_cur_node_state._state->stop();
// 初始化下一个状态
_cur_node_state = iter_map->second;
_cur_name = iter_map->first;
_cur_node_state._state->start();
state.h
#ifndef _STATE_H_
#define _STATE_H_
#include "Event.h"
#include<functional>
#include<string>
namespace HsmState
class Context;
class State
public:
// 进入状态时调用,子类重写
virtual void start(){}
// 更新状态,可以由外部周期性调用
virtual void update(){}
// 停止状态是调用,子类重写
virtual void stop(){}
// 设置事件响应回调函数
void set_event_func(std::function<EventDeal(EventData&)> func);
EventDeal RunEventFunc(EventData& event_data);
void SetContext(Context* context);
// 切换状态
// [in] name 状态名称
void TransState(std::string name);
private:
std::function<EventDeal(EventData&)> _event_func;
Context *_context;
#endif // !STATE_H_
std::cout << "WorkState start" << std::endl;
std::function<EventDeal(EventData&)> func = std::bind(&WorkState::DealEvent, this, std::placeholders::_1);;
set_event_func(func);
void stop()
std::cout << "WorkState stop" << std::endl;
EventDeal DealEvent(EventData &event_data)
switch ((EventS)event_data._event_type)
case belazy:
TransState("LoafOnAJob");
break;
default:
break;
return keep_on;
void update()
time++;
if (time == 180)
run = false;
int time = 0;
// 工作摸鱼状态
class LoafOnAJob : public State
public:
void start()
time = 0;
std::cout << "LoafOnAJob start" << std::endl;
void stop()
std::cout << "LoafOnAJob stop" << std::endl;
void update()
time++;
if (time == 10)
TransState("WorkState");
int time = 0;
// 对象工厂
class Factory
public :
static State* CreateState(Context* context, std::string name, std::string parent_name = "")
State* state = nullptr;
if (name == "StartState")
state = new StartState();
else if (name == "HungerState")
state = new HungerState();
else if (name == "Dinner")
state = new Dinner();
else if (name == "DoTheCookingState")
state = new DoTheCookingState();
else if (name == "EatState")
state = new EatState();
else if (name == "SleepState")
state = new SleepState();
else if (name == "WorkState")
state = new WorkState();
else if (name == "LoafOnAJob")
state = new LoafOnAJob();
context->CreateState(state, name, parent_name);
return state;
int main()
Context* context = new Context();
// 创建状态机
Factory::CreateState(context, "StartState");
Factory::CreateState(context, "HungerState");
Factory::CreateState(context, "Dinner");
Factory::CreateState(context, "DoTheCookingState", "Dinner");
Factory::CreateState(context, "EatState", "Dinner");
Factory::CreateState(context, "SleepState");
Factory::CreateState(context, "WorkState");
Factory::CreateState(context, "LoafOnAJob");
// 开始状态机
context->Start("StartState");
int time = 0;
while (run)
time++;
std::this_thread::sleep_for(
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::milliseconds(10)));
context->Update();
// 如果为工作状态,每隔60分钟发出偷懒事件
if (context->GetCurStateName() == "WorkState"
&& time % 60 == 0)
EventData e = EventData((int)belazy);
context->SendEvent(e);
if (context)
delete context;
context = nullptr;
std::cout << "state close" << std::endl;
return 0;
三、运行结果
工作累了就偷偷懒,真是愉快的一天啊!!!
状态机我们大家都知道,有一个专门的设计模式状态机模式,类图大概如下图:不过如果按照下面图来实现的状态机,基本来说非常难用,没有实用性,只能作为教科书的产品。今天我们要实现的是一种通用状态机,可以Send事件,每一个状态可以响应自己注册的事件,同时也可以通过自身或者事件来改变状态机的状态 代码地址:https://github.com/9435202/StateAPI首...
//待完善
有限状态机是一个很常用的技术,在流程控制和游戏AI中都比较实用,因为状态机编程简单又很符合直觉。与有限状态机类似的是设计模式中的状态模式。本文是参考《Programming Game AI by Example》
记得最开始工作时候也接触过有限状态机,当时是一个长长的用switch写成的状态机,理解它的时候真的很困难。
所以现在使用一套内置规则到状态内部去,来控制状态的转换。
现在就来制作一个有限状态机。
作为一个关于使用状态机创建一个智能体的实际案例,我们先模拟这样一个场景。是作为一个简
次态:当条件满足后,即将转移的下一个状态
动作:当满足某个事件时执行的动作;动作执行完毕后可以转移到另一个状态或保持原有状态
条件:转移状态所需的条件,当满足条件时,会触发一个动作或进行状态转移
C++函数指针实现FSM
案例:学生的日常生活。
学生的日常生活包含以下几个状态:起床、上学、吃午饭、做作业、睡觉;
每个状态之间进行转移需要执行相应的事件。
我分为以下几个步骤来实现:
(1)绘制状态转移图
(2)创建状态转移的FSMItem类
枚举:所有
状态机是什么?相信很多人有意无意间都会用到状态机。不过状态机究竟是个什么东西,很多人可能都心里了解,但无法言明。
恰巧今天想到这个问题,便在此记录一下。
状态机:(摘自百度百科)
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:
第一类,若输出只和状态有关而与输入无关,则称为Moore状态机
第二类,输出不仅和状态有关而且和输入
状态控制器库是一个独立于平台的通用C ++框架,该框架允许实现有限状态机及其多动作计划概括。 该库的结构和实现侧重于将有限状态机应用于实时控制回路,但实际上可以合理地适用于几乎所有其他应用,甚至与控制系统完全无关。 重点放在具有非常低的开销上,以便无论在何处使用此库都不会损害整体系统性能,同时仍保持易用性。 代码大小也已保持最小。 除了实现标准的有限状态机和多动作计划状态机之外,该库还可以用于实现分层状态控制器,或者实现这三种状态的任意混合。 请参阅大量文档以获取更多信息。 我欢迎所有反馈,建议和错误报告! 电子邮件:pallgeuer [at] ais.uni-bonn.de
一般来说,“状态机”是一种表达状态转换变换逻辑的方法。曾经有人和我讨论过为什么不直接用ifelse,而要使用“状态机”去实现一些逻辑,认为使用“状态机”是一种炫技的表现。然而对于大型复杂逻辑的变化和跳转,使用ifelse将带来代码难以阅读等弊端。其实ifelse也是一种状态机实现的方式。
之前我们有个业务和操作系统有着强烈的关联,而我们希望比较清晰地描述整个业务中...
YOLOv5是一种目标检测算法,它可以用来识别图像中的对象。YOLOv5的C语言实现可以使用Pytorch框架来进行。
要使用YOLOv5进行目标检测,你需要了解目标检测的基本原理并掌握一些基本的机器学习知识。你需要准备训练数据集和训练好的模型参数。然后你可以使用Pytorch框架来设计和构建你的YOLOv5模型。
在使用YOLOv5的C语言实现时,你可能需要用到一些常见的Pytorch函数和类,如`torch.nn.Module`和`torch.optim`。你还可以使用`torch.utils.data.DataLoader`来加载数据,使用`torch.nn.functional`中的函数来定义损失函数,并使用`torch.nn.Module.train()`和`torch.nn.Module.eval()`方法在训练和测试时切换模型。
最后,你可以使用模型来进行目标检测,并使用工具如`cv2`来绘制检测结果。