andrew-gresyk / hfsm2 Goto Github PK
View Code? Open in Web Editor NEWHigh-Performance Hierarchical Finite State Machine Framework
Home Page: https://hfsm.dev
License: MIT License
High-Performance Hierarchical Finite State Machine Framework
Home Page: https://hfsm.dev
License: MIT License
The minimal example and extended tutorial links on the webpage are broken
Hi Andrew
Next quest for you. My state machine has become so large that it complains about (line 1013)
static_assert(UNIT+(WIDTH+7)/(sizeof(Unit)*8)<=CAPACITY,"");
How do I change the CAPACITY limit?
I noticed that bool isActive(StateID)
API, but not found API that get machine current state id.
This might be a dumb question, but when a state function is called (enter(), update(), etc), is it an instance, with viable member data, or must I call Instance::access() to get access to the current state?
I thought at first that it is an instance, but reading through the source of machine.hpp, it calls Head::enter(), where Head is a type, so I don't see any instance being passed through.
By the way, I love this library. I looked at the Boost state machine documentation, and couldn't make heads or tails of it reading over for an hour, while I was able to go from zero to skeleton with HFSM2 in less than that time.
For others, I'm using this in an embedded system (RPi Pico, hierarchical states) and it compiles down to a nice size. I've thus far just tested it in a simulated environment with FreeRTOS (POSIX target), while I work out the rest of the development, but always also compile for my target system as well.
Hi Andrew
Is there an structural difference between
M::Root<THead, TStates>
and
M::PeerRoot<M::Composite<THead, TStates>>
and
M::PeerRoot<THead,M::CompositePeers<TStates>>
Does all 3 implementation give the same?
Which is better?
I'm interested in the planner part of it for use in Godot Engine.
https://github.com/panda-planner-dev/ipc2020-domains has some example problems.
The satellite and minecraft ones are interesting. https://github.com/panda-planner-dev/ipc2020-domains/tree/master/total-order/Satellite-GTOHP if you need pre-buillt ai ones though.
Adding more than one headless root / region causes a build error.
Hi!
Maybe this is a stupid question, but I stumbled across this during debugging for an ARM cortex-M target:
This library is meant to be fully static with no dynamic allocations, but the keyword "new" is used at several locations:
template <typename T, Long NC_>
template <typename... TArgs>
HFSM2_CONSTEXPR(14)
typename DynamicArrayT<T, NC_>::Index
DynamicArrayT<T, NC_>::emplace(const TArgs&... args) noexcept {
HFSM2_ASSERT(_count < CAPACITY);
new (&_items[_count]) Item{args...};
return _count++;
}
Isn't that dynamic allocation? It seems like on my target there is actual heap allocation at these points. What am I missing?
I discovered today that there appears to be a conflict between HFSM2 and the Linux libc sys/ioctl.h header that causes a bizarre cascade of template errors and syntax errors.
The conflict occurs when including sys/ioctl.h before hfsm2/machine.hpp, due to HFSM2's use of the symbol NCC
in various template arguments in machine.hpp:
https://github.com/andrew-gresyk/HFSM2/blob/master/include/hfsm2/machine.hpp#L3562
NCC
is defined as an integer literal in <bits/ioctl-types.h> which gets included by <sys/ioctl.h>:
https://github.com/raspberrypi/tools/blob/master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/usr/include/arm-linux-gnueabihf/bits/ioctl-types.h#L36
After renaming NCC
to _NCC
in HFSM2, I can confirm that the errors are resolved.
It's a bit unfortunate that the ioctl.h header causes this macro pollution. I'm not sure if there is any better fix than renaming the template argument in HFSM2 or maybe #undef'ing the symbol...
Hi, I have issue with state machine below. It's stuck in last update
method, program never stops. If I uncomment call to update
before Disable
event, everything works as expected. I'm not sure if I'm using the library incorrectly or if it's a bug.
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#define HFSM2_ENABLE_PLANS
#include <hfsm2/machine.hpp>
using M = hfsm2::Machine;
using FSM = M::PeerRoot<struct Disabled,
M::Composite<struct Enabled,
M::Composite<struct Active,
struct A,
struct B,
struct C,
struct D
>,
struct Idle
>
>;
// Events
struct Enable {};
struct Disable {};
struct Disabled : FSM::State
{
void update(FullControl& control) noexcept
{
control.changeTo<Enabled>();
}
void react(const Enable&, FullControl& control) noexcept
{
control.changeTo<Enabled>();
}
using FSM::State::react;
};
struct Enabled : FSM::State
{
void react(const Disable&, FullControl& control) noexcept
{
control.changeTo<Disabled>();
}
using FSM::State::react;
};
struct Active : FSM::State
{
void planSucceeded(FullControl& control)
{
control.changeTo<Idle>();
}
};
struct Idle : FSM::State
{
void update(FullControl& control) noexcept
{
control.changeTo<Active>();
}
};
struct A : FSM::State
{
void enter(PlanControl& control) noexcept
{
auto plan = control.plan();
plan.change<A, B>();
plan.change<B, C>();
plan.change<C, D>();
}
void update(FullControl& control) noexcept { control.succeed(); }
};
struct B : FSM::State
{
void update(FullControl& control) noexcept { control.succeed(); }
};
struct C : FSM::State
{
void update(FullControl& control) noexcept { control.succeed(); }
};
struct D : FSM::State
{
void update(FullControl& control) noexcept { control.succeed(); }
};
TEST_CASE("test")
{
FSM::Instance fsm;
REQUIRE(fsm.isActive<Disabled>());
fsm.update();
REQUIRE(fsm.isActive<Enabled>());
REQUIRE(fsm.isActive<Active>());
REQUIRE(fsm.isActive<A>());
fsm.update();
REQUIRE(fsm.isActive<B>());
fsm.update();
REQUIRE(fsm.isActive<C>());
fsm.update();
REQUIRE(fsm.isActive<D>());
fsm.update();
REQUIRE(fsm.isActive<Idle>());
fsm.update();
REQUIRE(fsm.isActive<A>());
fsm.update();
REQUIRE(fsm.isActive<B>());
// uncomment to make test pass
// fsm.update();
// REQUIRE(fsm.isActive<C>());
fsm.react(Disable{});
REQUIRE(fsm.isActive<Disabled>());
fsm.react(Enable{});
REQUIRE(fsm.isActive<Enabled>());
REQUIRE(fsm.isActive<Active>());
REQUIRE(fsm.isActive<A>());
fsm.update();
REQUIRE(fsm.isActive<B>());
}
I'd like use HFSM2 in firmware for stm32, compiler is GNU ARM Embedded Toolchain (gcc 10.2 or 9.3.1). The problem is that both RTOSes and bare metal usually don't support stdlib and POSIX. Can I use the library as it is or some efforts to port are needed?
Hi!
I'm looking to leverage payloads for "messaging" on state switch - both documentation and tests exist for payloads but they don't describe how to actually fetch them.
This was my attempt:
void StateActivating::enter(PlanControl& aControl)
{
auto currentRequest = aControl.requests().begin();
if (currentRequest != aControl.requests().end() && currentRequest->payloadSet)
{
const auto& stateChangePayload = currentRequest->payload();
// intended entry processing
}
else
{
// failsafe entry processing
}
}
However currentRequest != aControl.requests().end()
always evaluates to false, curiously enough payloadSet
is true
.
Test code that invokes entry looks like this:
fsmInstance.immediateChangeWith<StateActivating>(entryPayload);
Perhaps immediateChangeWith
immediately clears the request? If so, how to retrieve the payload then?
Is there any way to fetch the last state in a state's enter()
function?
When i try to compile the next code (https://doc.hfsm.dev/quick-tutorial):
#include <HFSM2/include/hfsm2/machine.hpp>
struct Context {
bool powerOn;
};
using M = hfsm2::MachineT<Context>;
//using M = hfsm2::MachineT<hfsm2::Config::ContextT<Context>>;
#define S(s) struct s
using FSM = M::PeerRoot<
S(Off), // initial top-level state
M::Composite<S(On), // sub-machine region with a head state (On) and and 3 sub-states
S(Red), // initial sub-state of the region
S(Yellow),
S(Green)
>,
S(Done)
>;
#undef S
struct Event {};
struct Off
: FSM::State
{
void entryGuard(FullControl& control) { // called before state activation, use to re-route transitions
if (control.context().powerOn) // access shared data
control.changeTo<On>(); // initiate a transition into 'On' region
}
};
struct On
: FSM::State
{
void enter(PlanControl& control) { // called on state activation
auto plan = control.plan(); // access the plan for the region
plan.append<Red, Yellow>(); // sequence plan steps, executed when the previous state succeeds
plan.append<Yellow, Green>();
plan.append<Green, Yellow>();
plan.append<Yellow, Red>();
}
void exit(PlanControl& /*control*/) {} // called on state deactivation
void planSucceeded(FullControl& control) { // called on the successful completion of all plan steps
control.changeTo<Done>();
}
void planFailed(FullControl& /*control*/) {} // called if any of the plan steps fails
};
struct Red
: FSM::State
{
void update(FullControl& control) { // called on periodic state machine updates
control.succeed(); // notify successful completion of the plan step
} // plan will advance to the 'Yellow' state
};
struct Yellow
: FSM::State
{
void update(FullControl& control) {
control.succeed(); // plan will advance to the 'Green' state on the first entry
// and 'Red' state on the second one
}
};
struct Green
: FSM::State
{
void react(const Event&, FullControl& control) { // called on external events
control.succeed(); // advance to the next plan step
}
};
struct Done
: FSM::State
{};
int main() {
Context context;
context.powerOn = true;
FSM fsm{ context };
assert(fsm.isActive<On>()); // activated by Off::entryGuard()
assert(fsm.isActive<Red>()); // On's initial sub-state
fsm.update();
assert(fsm.isActive<Yellow>()); // 1st setp of On's plan
fsm.update();
assert(fsm.isActive<Green>()); // 2nd setp of On's plan
fsm.react(Event{});
assert(fsm.isActive<Yellow>()); // 3rd setp of On's plan
fsm.update();
assert(fsm.isActive<Red>()); // 4th setp of On's plan
fsm.update();
assert(fsm.isActive<Done>()); // activated by On::planSucceeded()
return 0;
}
I get:
1>------ Build started: Project: prueba_hfsm2_msvc2019, Configuration: Debug x64 ------
1>main.cpp
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11821,16): error C2027: use of undefined type 'hfsm2::detail::M_<Context>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11248): message : see declaration of 'hfsm2::detail::M_<Context>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11821,1): error C2061: syntax error: identifier 'PeerRoot'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11823,8): error C2027: use of undefined type 'hfsm2::detail::M_<Context>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11248): message : see declaration of 'hfsm2::detail::M_<Context>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11827,5): error C2059: syntax error: '>'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11837,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11837,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11838,32): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11839,13): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11840,13): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11840,30): error C2065: 'On': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11840,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11846,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11846,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11847,27): error C2061: syntax error: identifier 'PlanControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11856,26): error C2061: syntax error: identifier 'PlanControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11858,35): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11862,32): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11848,21): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11850,1): error C3536: 'plan': cannot be used before it is initialized
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11850,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11851,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11852,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11853,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11859,9): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11859,1): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11867,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11867,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11868,28): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11869,9): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11875,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11875,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11876,28): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11877,9): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11884,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11884,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11885,41): error C2061: syntax error: identifier 'FullControl'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11886,9): error C2065: 'control': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11892,1): error C2653: 'FSM': is not a class or namespace name
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11892,1): error C2504: 'State': base class undefined
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11900,5): error C2065: 'FSM': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11900,9): error C2146: syntax error: missing ';' before identifier 'fsm'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11900,9): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11901,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11901,29): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11902,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11902,30): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11905,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11906,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11906,33): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11908,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11909,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11909,32): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11911,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11912,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11912,33): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11914,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11915,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11915,30): error C2059: syntax error: ')'
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11917,5): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11918,12): error C2065: 'fsm': undeclared identifier
1>P:\Mis-Proyectos\Profesional\Miniferias\prueba_hfsm2\inc\HFSM2\include\hfsm2\machine.hpp(11918,31): error C2059: syntax error: ')'
1>Done building project "prueba_hfsm2_msvc2019.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
DJuego
Thank you for this promising contribution, @andrew-gresyk! I like very much little header-only gems like this library! :-D
I am a absolute newbie in Hierarchical Finite State Machines. :-) My interests are robotics and games too.
However i am interested in knowing more about it. I would like to familiarize myself with some kind of (graphical?) representation of HFSM. Any suggestion? Any recommended reading?
I miss a series of examples that serve to show/explain the library and, incidentally, to test it. :-)
Cheers!
DJuego
I have tried to get a variable from the current Context to modify the Utility function. this doesn't seem to work for me. leaving the Control signature const results in the following error in intellisense:
C++ the object has type qualifiers that are not compatible with the member function object type is: const hfsm2::detail::ControlT<hfsm2::detail::ArgsT<Context, hfsm2::detail::G_<(hfsm2::FeatureTag)'\001', Context, int8_t, float, hfsm2::RandomT<float>, (hfsm2::Long)4U, void>, hfsm2::detail::Merge<hfsm2::detail::ITL_<void>, hfsm2::detail::Merge<hfsm2::detail::Merge<hfsm2::detail::ITL_<Red>, hfsm2::detail::Merge<hfsm2::detail::ITL_<Yellow>, hfsm2::detail::ITL_<Green>>>, hfsm2::detail::ITL_<Off>>>, hfsm2::detail::Merge<hfsm2::detail::ITL_<void>, hfsm2::detail::Merge<hfsm2::detail::ITL_<Red>, hfsm2::detail::Merge<hfsm2::detail::ITL_<>, hfsm2::detail::ITL_<>>>>, (hfsm2::Long)2U, (hfsm2::Long)0U, (hfsm2::Long)0U, (hfsm2::Long)6U, (hfsm2::Long)4U, void>>
Removing the cosnt gets rid of the error, but causes compilation to fail.
I made a minimal example to test the error, and it still seems to happen.
#define HFSM2_ENABLE_UTILITY_THEORY
#include <hfsm2/machine.hpp>
#include <iostream>
struct Context {
uint8_t cycleCount = 0;
};
using M = hfsm2::MachineT<hfsm2::Config::ContextT<Context>>;
#define S(s) struct s
using FSM = M::PeerRoot<
M::Utilitarian<S(Red),
S(Yellow),
S(Green)
>,
S(Off)
>;
#undef S
struct On
: FSM::State {
void enter(Control& control) {
control.context().cycleCount = 0;
std::cout << "On" << std::endl;
}};
struct Red
: FSM::State {
void enter(Control& control) {
++control.context().cycleCount;
std::cout << " Red" << std::endl;
}
void update(FullControl& control) {
if (control.context().cycleCount > 3)
control.changeTo<Off>();
else
control.changeTo<Green>();
}};
struct Yellow
: FSM::State {
void enter(Control&) { std::cout << " Yellow ^" << std::endl; }
void update(FullControl& control) { control.changeTo<Red>(); }
///
Utility utility(const Control& control) { return 0.5f + control.context().cycleCount; }
///
};
struct Green
: FSM::State {
void enter(Control&) { std::cout << " Green" << std::endl; }
void update(FullControl& control) { control.changeTo<Yellow>(); }
};
struct Off
: FSM::State {
void enter(Control&) { std::cout << "Off" << std::endl; }
};
int main() {
Context context;
FSM::Instance machine{ context };
while (machine.isActive<Off>() == false)
machine.update();
return 0;
}
Hi Andrew
Since I have changed to c++17 I get a warning: extra ';' [-Wpedantic], on several line in the machine.hpp code:
Example:
line 215: HFSM_IF_DEBUG(struct None{});
^
line 1097: HFSM_IF_ASERT(void verifyStructure(const Index occupied = INVALID) const);
^
I simply declare
_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wpedantic\"")
#include <hfsm2/machine.hpp>
_Pragma("GCC diagnostic pop")
to remove the warnings
Hi Andrew
I'm having some problems with creating orthogonal regions with composite parts.
I have something like this:
struct SomeEvent{};
HFSM=Machine::Root<A,
B,
Machine::Orthogonal<C,
Machine::Composite<D,
E,F,G,Machine::Composite<H,I,J>
>,
Machine::Composite<K,
L,
Machine::Composite<M,N,O>,
Machine::Composite<P,Q,R>,
Machine::Composite<S,T,U>,
V
>
>,
W
>;
The structure compiles fine, but when I add changeTo to state E, then it complains
state E : HFSM::State
{
void react(const SomeEvent&, FullControl& control)
{
control.changeTo<F>();
}
using HFSM::State::react;
}
Thank you very much for the library, it is one of the most robust libraries I found in Github. I am thinking of employing it within entt ecs framework. Do you have any recommendations or experience? Do I store FSM::Instance (FSM is M::Root or M::PeerRoot) as a component in the ecs system? Is the size of the FSM::Instance always constant regardless of the state selected if the plan did not change (ie it has the size of the largest state?)
Thanks
Hi Andrew
Thanks for your help last time.
Here comes my next question.
Is it possible to give a hfsm as an parameter in a function?
Could be as a pointer, a reference (or something else, if that is the way to go).
Best regards
Kjeld
Hi, I want to create state machine with looped plan. I took Wiki.Plans.Traffic Light test as a starting point and added
fsm.update();
REQUIRE(fsm.isActive<Yellow>());
at the end. After update
state machine is still in Red
state. Is this a bug or I have to somehow "restart" the plan?
The following, in clang
MyState : FSM::State
{
void update(FullControl& control)
{
hfsm2::StateID OtherStateID = stateId<MyOtherState>();
// do some stuff
}
}
Gives this error (in machine.hpp~4395):
error : template name refers to non-type template 'index'
1> static constexpr StateID stateId() { return typename TFirst::StateList ::template index<T>(); }
I believe the compiler is treating the typename
keyword as though it applies to the whole function call expression (TFirst::StateList:: template index<T>()
) instead of just TFirst::StateList
.
I tried to disambiguate this inline by finding the right incantation of typename/template keywords, but it proved beyond my capabilities.
This fixed the error:
using StateList = typename TFirst::StateList;
template <typename T>
static constexpr StateID stateId() { return StateList ::template index<T>(); }
Hi, I have a scenario where I am transitioning into a state (FHaveTarget
) because of a parent state's react()
function. In FHaveTarget::entryGuard()
, I want to set the initial substate of FHaveTarget
based on the parameters from that event.
Is there a way for the parent to pass those parameters into the entryGuard()
of the state? Here follows the simplest version of this I've got.
The two ways I can think around this are to add parameters to a shared context object, or to flatten the hierarchy, neither of which are satisfactory.
How should I do this in HFSM2?
using M = hfsm2::Machine
using FSM =
M::Root
<
struct FRoot,
struct FNoTarget,
M::Composite
<
struct FHaveTarget,
struct FTargetInRange,
struct FTargetOutOfRange
>
>;
struct FUpdateTargetEvent
{
AActor* Target;
bool bTargetOutOfRange;
};
struct FRoot : FSM::State
{
void react(FUpdateTargetEvent const& Event, FullControl& Control)
{
if (Event.Target)
{
Control.changeTo<FHaveTarget>();
}
else
{
Control.changeTo<FNoTarget>();
}
}
};
struct FNoTarget : FSM::State
{
};
struct FHaveTarget : FSM::State
{
void entryGuard(FullControl& control)
{
// HERE is where I don't have the data I want: Event
if (Event.bTargetOutOfRange)
{
Control.changeTo<FTargetOutOfRange>();
}
else
{
Control.changeTo<FTargetInRange>();
}
}
void enter(Control& control) { /* set FireTarget (somehow) and set some state on it */ }
void exit(Control& control) { /* unset that state */ }
private:
AActor* FireTarget = nullptr;
};
struct FTargetInRange : FSM::State
{
void enter(Control& control) { /* set some additional state on target */ }
void exit(Control& control) { /* unset that state */ }
};
struct FTargetOutOfRange : FSM::State
{
};
Thank you for your brilliant work.
Your "react" pattern works by calling every active state from the outside and in.
Could you also add a "retract" pattern, that would be call the way back?
I had some issue, where I had to have the inner react have higher priority than some further out,
So therefor I ask for the update.
Hi Andrew
Do you have some examples on how to make mulitple copies of the same HFSM2 machine?
Creating an object containing an HFSM2, and the creating multiple instances of that obejct
Best regards
Kjeld
Is it thread-safe? What can be done to be thread safe?
Hi Andrew
I found a conflict between your hfsm2.hpp file and ioctl-types.h file
The ioctl-types.h file defines a value for NCC to be 8, and this course your file to make compile errors.
Could you rename your NCC template variable?
#define NCC 8
struct termio
{
unsigned short int c_iflag; /* input mode flags */
unsigned short int c_oflag; /* output mode flags */
unsigned short int c_cflag; /* control mode flags */
unsigned short int c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
The following snippet is missing CONSTRUCT
and DESTRUCT
. In which case it returns nullptr. Yet, these functions seem to be called when we implement enter and exit functions.
HFSM2/include/hfsm2/detail/debug/shared.hpp
Lines 73 to 92 in d1674df
This causes the proposed "recordMethod" logger to be stuck:
void recordMethod(Context& /*context*/, const StateID origin, const Method method) override {
std::cout << stateName(origin) << "::" << hfsm2::methodName(method) << "()" << std::endl;
}
Adding the two fixes the freeze and we have the following output:
Idle -> DoAction
DoAction::contruct()
DoAction::enter()
HeadState::update()
HeadState -> Idle
DoAction::update()
DoAction -> Idle
DoAction::exit()
DoAction::destruct()
HeadState::update()
This function should not return nullptr but instead '\0'
or unknownMethod
to prevent unsafe operations.
I currently have a very large state system, all written in one file that appears very large and bulky. Can I write different states in different. h files to reduce maintenance costs?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.