5 个版本
0.2.3 | 2023年4月12日 |
---|---|
0.2.2 | 2021年9月30日 |
0.2.1 | 2021年9月30日 |
0.2.0 | 2021年9月28日 |
0.1.0 | 2021年9月27日 |
#795 在 算法
每月 45 次下载
19KB
275 行
脏状态机
dirty-fsm
是有限状态机的“快速简单”实现。大部分概念来自我编写的代码,作为 io.github.frc5024.lib5k.libkontrol
的一部分。
示例
在以下示例中,我创建了一个状态机,代表爪子和按钮。当按钮被按下时,爪子将在打开和关闭之间切换。
我们首先设置一个功能标志并加载库。
// This feature is required to use the new `#[default]` macro on enum variants
#![feature(derive_default_enum)]
use dirty_fsm::*;
use thiserror::Error;
接下来,我们定义机器的状态。
/// The possible states of the claw
#[derive(Debug, Default, PartialEq, Eq, Clone, Hash)]
enum ClawState {
/// The claw is closed
#[default]
ClawClosed,
/// The claw is open
ClawOpen
}
除了状态之外,我们还需要定义某种错误类型(尽管如果根本不需要,我们可以简单地使用 ()
)。
/// Defines errors that can occur while running actions
#[derive(Debug, Error)]
enum ClawError {
/// An example error
#[error("Example error")]
ExampleError,
}
接下来,我们定义在第一个状态(ClawClosed
)中实际运行的代码。这是一个普通的 Rust 结构体,实现了 Action
特性。
Action
包含一些在动作的生命周期中在不同点调用的简单函数
on_register
: 当动作通过StateMachine::add_action
注册到状态机时调用一次on_first_run
: 在这个状态开始或切换到之前,在第一次调用execute
之前调用一次。这应该像初始化函数一样处理。通常用于在execute
中执行操作之前保存有关环境的信息。execute
: 在动作的生命周期中多次调用。这是动作代码应该放置的地方。它应该被视为while true
循环的主体,因为它将反复运行,直到返回一个指示动作完成的ActionFlag
。on_finish
: 当这个动作完成后,在最后一次调用execute
之后调用一次。
/// Action that actually handles the claw being closed
#[derive(Debug)]
struct ClawClosedAction;
impl Action<ClawState, ClawError, bool> for ClawClosedAction {
fn on_register(&mut self) -> Result<(), ClawError> {
println!("ClawClosedAction has been registered with the state machine");
Ok(())
}
fn on_first_run(&mut self, context: &bool) -> Result<(), ClawError> {
println!("Button has been pressed, claw is closing");
Ok(())
}
fn execute(
&mut self,
delta: &chrono::Duration,
context: &bool,
) -> Result<crate::action::ActionFlag<ClawState>, ClawError> {
println!("Claw code is running now");
// If the button is pressed, switch to the next claw state
if context {
Ok(ActionFlag::SwitchState(ClawState::ClawOpen))
} else {
Ok(ActionFlag::Continue)
}
}
fn on_finish(&mut self, interrupted: bool) -> Result<(), ClawError> {
println!("ClawClosedAction is done executing");
Ok(())
}
}
由于我们有两个状态,因此需要为另一个状态再次执行此操作。
/// Action that actually handles the claw being opened
#[derive(Debug)]
struct ClawOpenedAction;
impl Action<ClawState, ClawError, bool> for ClawOpenedAction {
fn on_register(&mut self) -> Result<(), ()> {
println!("ClawOpenedAction has been registered with the state machine");
Ok(())
}
fn on_first_run(&mut self, context: &bool) -> Result<(), ClawError> {
println!("Button has been pressed, claw is opening");
Ok(())
}
fn execute(
&mut self,
delta: &chrono::Duration,
context: &bool,
) -> Result<crate::action::ActionFlag<ClawState>, ClawError> {
println!("Claw code is running now");
// If the button is pressed, throw an error as an example
if *context {
Err(ClawError::ExampleError)
} else {
Ok(ActionFlag::Continue)
}
}
fn on_finish(&mut self, interrupted: bool) -> Result<(), ClawError> {
println!("ClawOpenedAction is done executing");
Ok(())
}
}
最后,启动和运行状态机的代码
fn main() {
// Create the state machine
let mut claw_machine = StateMachine::new();
claw_machine.add_action(ClawState::ClawClosed, ClawClosedAction {}).unwrap();
claw_machine.add_action(ClawState::ClawOpen, ClawOpenedAction {}).unwrap();
// State. This example assumes some outside "force" is changing this value
let mut button_pressed = false;
// Run the state machine
loop {
claw_machine.run(&mut button_pressed).unwrap();
}
}
依赖项
~1.5MB
~20K SLoC