sml icon indicating copy to clipboard operation
sml copied to clipboard

Issue transition from an innerstate to other states

Open Tal-seven opened this issue 4 years ago • 1 comments

Hi, I have pasted the code below for a motor control statemachine.

auto conditionalSwitchToControl = [](const auto& evt,auto& sm,auto& deps,auto& subs)
{
	if(sml::aux::get<controllerInterface*,sml::aux::remove_reference_t<decltype(deps)>>(deps)->emergencyStatus())
	{
		sml::aux::get<smlTimer_Impl&,decltype(deps)>(deps).reload();
	}
	else
	{
		if(sml::aux::get<dispatchInterface*,sml::aux::remove_reference_t<decltype(deps)>>(deps)
			->hasdeferredEventArrived())
		{
			sml::aux::get<dispatchInterface*,sml::aux::remove_reference_t<decltype(deps)>>(deps)->setDeferredEvent(false);
			auto temp = sml::aux::get<dispatchInterface*,sml::aux::remove_reference_t<decltype(deps)>>(deps)
			 ->getdeferredEvent();
			if(std::is_same_v<sml::aux::remove_reference_t<decltype(temp)>,_event::enableControl>)
			{
				sm.process_event(_event::enableControl{},deps,subs);
			}
			else if(std::is_same_v<sml::aux::remove_reference_t<decltype(temp)>,_event::start>)
			{
				sm.process_event(_event::start{},deps,subs);
			}
		}
		else
		{
			sm.process_event(_event::reInit{},deps,subs);
		}
	}
};


namespace guard {

auto emergencyON = [](const auto& evt,auto& sm,auto& deps,auto& subs)-> bool 
{
	return sml::aux::get<controllerInterface*,sml::aux::remove_reference_t<decltype(deps)>>(deps)->emergencyStatus();
};

auto paramsReceived = [](const auto& evt,auto& sm,auto& deps,auto& subs) -> bool
{
	return sml::aux::get<controllerInterface*,sml::aux::remove_reference_t<decltype(deps)>>(deps)->paramsInited();
};
}

struct _state::Halt {
auto operator()(){
	using namespace sml;
	return make_transition_table(
	*"halted"_s + on_entry<_>/[](dispatchInterface* dis,smlTimer_Impl& timer)
		{
			dis->setHalt(true);
			dis->updateState(STATE::HALT);
			timer.init(1000);
		},
		
		"halted"_s + event<_event::timeout>/conditionalSwitchToControl, 

		"halted"_s + on_exit<_>/[](dispatchInterface* dis) {dis->setHalt(false);}   
				
	);
}
};

struct _state::openLoopControl {
auto operator()() {
	using namespace sml;
	return make_transition_table(
	*"init2"_s + on_entry<_>/[](controllerInterface* iface,dispatchInterface* dis){iface->initialise();dis->updateState(STATE::OPENLOOPCONTROL);},
	 "init2"_s + event<_event::cmd>[!guard::emergencyON] = "drive"_s, 
	
	 "drive"_s + event<_event::cmd>[!guard::emergencyON]/[](controllerInterface* iface) {iface->setpointUpdate();iface->drive();},
		
	 "drive"_s + on_entry<_>/[](controllerInterface* iface,smlTimer_Impl& timer){iface->setpointUpdate();iface->drive();timer.init(5);},
	 "drive"_s + event<_event::timeout>/[](smlTimer_Impl& timer,controllerInterface* iface){iface->feedback();timer.reload();},
	 "drive"_s + event<_event::brake>/[](controllerInterface* iface) {iface->setPointZero();},
	 
	 "drive"_s + event<_event::emergency>/[](controllerInterface* iface,dispatchInterface* dis)
	 {iface->stop();dis->updateState(STATE::HALT);} = state<_state::Halt> 
	 
	);
}
};

struct _state::control {
auto operator()()	{
	using namespace sml;
	return make_transition_table(
	*"init"_s + on_entry<_>/[](controllerInterface* iface,dispatchInterface* dis)	{iface->initialise(); dis->updateState(STATE::CONTROL);},
	 "init"_s + event<_event::cmd>[!guard::emergencyON] = "controlActive"_s,
	 
	 "controlActive"_s + on_entry<_>/[](smlTimer_Impl& timer,dispatchInterface* dispatch){timer.init(2);dispatch->updateState(STATE::CONTROLACTIVE);},
	 "controlActive"_s + event<_event::timeout>/[](controllerInterface* iface,smlTimer_Impl& timer){iface->update();timer.reload();},
		"controlActive"_s + event<_event::brake>/[](controllerInterface* iface) {iface->setPointZero()},

	 "controlActive"_s + event<_event::emergency>/[](controllerInterface* iface,dispatchInterface* dis)
	 {iface->stop();dis->updateState(STATE::HALT);} = state<_state::Halt> 	 
	);
}

};


struct _state::idle {
auto operator()() {
	using namespace sml;
	return make_transition_table(

		*"S1"_s	+ on_entry<_>/[](dispatchInterface* dis,controllerInterface* iface)
		{
			dis->updateState(STATE::IDLE);
			if(!iface->paramsInited())
				dis->dispatchParamsRequest();
		},
		"S1"_s + event<_event::enableControl>[guard::paramsReceived] = state<_state::control>,
		"S1"_s + event<_event::enableControl>[!guard::paramsReceived]/[](dispatchInterface* dis){dis->dispatchParamsRequest();},
		"S1"_s + event<_event::start>[!guard::paramsReceived]/[](dispatchInterface* dis){dis->dispatchParamsRequest();},
		"S1"_s + event<_event::start>[guard::paramsReceived]	= state<_state::openLoopControl>,	
		"S1"_s + event<_event::emergency> = state<_state::Halt>,		

		state<_state::openLoopControl> + event<_event::enableControl>[!guard::emergencyON]/[](smlTimer_Impl& timer){timer.reset();}
		= state<_state::control>,
	 state<_state::control> + event<_event::start>[!guard::emergencyON]/[](smlTimer_Impl& timer){timer.reset();}
 		= state<_state::openLoopControl>,
		
		
		state<_state::Halt> + event<_event::enableControl>[!guard::emergencyON] = state<_state::control>,
		
		state<_state::Halt> + event<_event::start>[!guard::emergencyON] = state<_state::openLoopControl>, 
		state<_state::Halt> + event<_event::reInit>[!guard::emergencyON] = "S1"_s 		
 );
}


};

The statemachine works as intended and the behaviour is correct when testing on x86 but when i run the same on an stm32 microcontroller (arm-none-eabi-gcc 7.3.1). The behaviour changes a little i.e. upon processing of the event<reInit> or event<start> or event<enableControl> an external transition from _state::halt to the relevant state is expected but doesnt happen. The transition happens on x86. I hope i have properly followed the UML semantics for statemachine transitions and that there are no illegal transitions. I faced a similar issue when going from state<openLoopControl> or state<control> to state<Halt>. The event _event::emergency would not trigger a state transition to _state::Halt. This was because the definition of sub_sm _state::Halt was after the definiton of state<openLoopControl> and state<control>. Moving the definition above fixed the issue. However i havent faced similiar issues on x86 tests.

Tal-seven avatar Apr 03 '20 01:04 Tal-seven

Encountered the same erroneous behaviour on an armv7 processor.

On x86 do you also compile using gcc with the same version ? It might be due to some compiler shenanigans for ARM platform or some gcc errors

GuiCodron avatar Jul 29 '20 15:07 GuiCodron