XBotInterface  2.4.1
XBotInterface provides a generic API to model and control a robot.
StateMachine.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 IIT-ADVR
3  * Author: Arturo Laurenzi, Luca Muratore
4  * email: arturo.laurenzi@iit.it, luca.muratore@iit.it
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>
18 */
19 
20 
21 #ifndef __XBOT_FINITE_STATE_MACHINE_H__
22 #define __XBOT_FINITE_STATE_MACHINE_H__
23 
24 #include <memory>
25 #include <string>
26 #include <iostream>
27 #include <unordered_map>
28 #include <tuple>
30 #include <XBotInterface/Logger.hpp>
31 
32 namespace XBot {
33 
34 namespace FSM {
35 
41  struct Message {
42  std::string message;
43  };
44 
49  struct Event : Message {
50  std::string name;
51  };
52 
53  // Forward declaration for State class
54  template <typename StateType, typename SharedDataType> class State;
55 
60  struct SharedDataBase {};
61 
62 #ifdef XBOT_MULTIPLE_FSM_MODE
63  template <typename EventType>
64  bool broadcast_event(const EventType& e);
65 #endif
66 
73  template <typename StateType, typename SharedDataType = SharedDataBase>
74  class StateMachine {
75 
76  public:
77 
78  friend class State<StateType, SharedDataType>;
79 
81  fsm_ptr(this),
82  _is_fsm_init(false),
83  _data(std::make_shared<SharedDataType>()),
84  _console_logger("fsm")
85  {}
86 
87  bool init( const std::string& initial_state_name ){
88  return init(initial_state_name, Message());
89  }
90 
91  template <typename MessageType>
92  bool init( const std::string& initial_state_name, const MessageType& msg )
93  {
94  auto it = _registered_states.find(initial_state_name);
95 
96  if( it == _registered_states.end() )
97  {
98  std::cerr << "ERROR in " << __PRETTY_FUNCTION__ << "! Initial state " <<
99  initial_state_name <<
100  " was not registered with this state machine! Call register_state()!" << std::endl;
101 
102  abort();
103  return false;
104  }
105 
106  _current_state = _previous_state = it->second;
107  _current_state->entry(msg);
108 
109  _is_fsm_init = true;
110 
111  return true;
112  }
113 
114  bool register_state( std::shared_ptr<StateType> state )
115  {
116  if( _registered_states.count(state->get_name()) ){
117  std::cerr << "ERROR in " << __PRETTY_FUNCTION__ << "! State " <<
118  state->get_name() <<
119  " has already beed registered with this state machine!" << std::endl;
120 
121  return false;
122  }
123 
124  state->_parent_fsm = fsm_ptr;
125  state->_data = _data;
126  _registered_states[state->get_name()] = state;
127 
128  return true;
129 
130  }
131 
132  template <typename EventType>
133  bool send_event(const EventType& event)
134  {
135  if(!_is_fsm_init){
136  std::cerr << "ERROR in " << __PRETTY_FUNCTION__ << "! State machine " <<
137  " has not been initialized! Call init()!" << std::endl;
138 
139  return false;
140  }
141 
142  _current_state->react(event);
143  return true;
144  }
145 
146  bool run(double time, double period){
147 
148  if(!_is_fsm_init){
149  std::cerr << "ERROR in " << __PRETTY_FUNCTION__ << "! State machine " <<
150  " has not been initialized! Call init()!" << std::endl;
151 
152  return false;
153  }
154 
155  _current_state->run(time, period);
156  return true;
157  }
158 
159  std::shared_ptr<const StateType> get_current_state() const
160  {
161  return _current_state;
162  }
163 
164  SharedDataType& shared_data()
165  {
166  return *_data;
167  }
168 
169  protected:
170 
171  private:
172 
173 
174  template <typename MessageType>
175  bool transit( const std::string& next_state_name, const MessageType& msg )
176  {
177  auto it = _registered_states.find(next_state_name);
178 
179  if( it == _registered_states.end() )
180  {
181  std::cerr << "ERROR in " << __PRETTY_FUNCTION__ << "! State " <<
182  next_state_name <<
183  " was not registered with this state machine! Call register_state()!" << std::endl;
184  abort();
185  return false;
186  }
187 
188  _current_state->exit();
189  _previous_state = _current_state;
190  _current_state = it->second;
191  _current_state->entry(msg);
192 
193  return true;
194  }
195 
196  std::shared_ptr<StateType> _current_state, _previous_state;
197 
198  StateMachine<StateType, SharedDataType> * fsm_ptr;
199 
200  std::unordered_map<std::string, std::shared_ptr<StateType>> _registered_states;
201 
202  bool _is_fsm_init;
203 
204  std::shared_ptr<SharedDataType> _data;
205  XBot::LoggerClass _console_logger;
206 
207 
208  };
209 
210 
211 
212 
220  template <typename StateType, typename SharedDataType = SharedDataBase>
221  class State {
222 
223  public:
224 
225  friend class StateMachine<StateType, SharedDataType>;
226 
227  virtual std::string get_name() const = 0;
228 
229  virtual void run(double time, double period) {}
230  virtual void exit() {}
231 
232  void react(const Event& e) {}
233 
234 
235  protected:
236 
237  SharedDataType& shared_data()
238  {
239  return *_data;
240  }
241 
243  {
244  return *_parent_fsm->_console_logger;
245  }
246 
247  template <typename MessageType>
248  bool transit( const std::string& next_state_name, const MessageType& msg )
249  {
250  return _parent_fsm->transit(next_state_name, msg);
251  }
252 
253  bool transit( const std::string& next_state_name )
254  {
255  return _parent_fsm->transit(next_state_name, Message());
256  }
257 
258  std::string get_previous_state_name() const
259  {
260  _parent_fsm->_previous_state->get_name();
261  }
262 
263  template <typename EventType>
264  void send_event(const EventType& e)
265  {
266 #ifdef XBOT_MULTIPLE_FSM_MODE
267  broadcast_event(e);
268 #else
269  _parent_fsm->send_event(e);
270 #endif
271  }
272 
273 
274 
275  private:
276 
277  std::shared_ptr<SharedDataType> _data;
278 
280 
281  };
282 
283 }
284 
285 }
286 
287 #endif
XBot::FSM::State::transit
bool transit(const std::string &next_state_name)
Definition: StateMachine.h:253
XBot::FSM::StateMachine::init
bool init(const std::string &initial_state_name)
Definition: StateMachine.h:87
XBot::FSM::StateMachine::get_current_state
std::shared_ptr< const StateType > get_current_state() const
Definition: StateMachine.h:159
XBot::FSM::Message::message
std::string message
Definition: StateMachine.h:42
XBot::FSM::StateMachine::register_state
bool register_state(std::shared_ptr< StateType > state)
Definition: StateMachine.h:114
XBot::FSM::State::send_event
void send_event(const EventType &e)
Definition: StateMachine.h:264
XBot::FSM::State::shared_data
SharedDataType & shared_data()
Definition: StateMachine.h:237
XBot::LoggerClass
Logger class.
Definition: RtLog.hpp:230
RobotInterface.h
XBot::FSM::State
By inheriting from the State class, the user of the FSM defines a base class for all custom states.
Definition: StateMachine.h:54
XBot::FSM::State::get_previous_state_name
std::string get_previous_state_name() const
Definition: StateMachine.h:258
XBot::FSM::State::transit
bool transit(const std::string &next_state_name, const MessageType &msg)
Definition: StateMachine.h:248
XBot::FSM::StateMachine::StateMachine
StateMachine()
Definition: StateMachine.h:80
XBot::FSM::SharedDataBase
Default SharedData class.
Definition: StateMachine.h:60
Logger.hpp
XBot::FSM::Event::name
std::string name
Definition: StateMachine.h:50
XBot::FSM::StateMachine::init
bool init(const std::string &initial_state_name, const MessageType &msg)
Definition: StateMachine.h:92
XBot::FSM::Message
Base class for defining custom messages that can be processed by the states during the entry phase.
Definition: StateMachine.h:41
XBot::FSM::StateMachine::send_event
bool send_event(const EventType &event)
Definition: StateMachine.h:133
XBot::FSM::State::run
virtual void run(double time, double period)
Definition: StateMachine.h:229
XBot::FSM::StateMachine::run
bool run(double time, double period)
Definition: StateMachine.h:146
XBot::FSM::StateMachine
Class implementing a finite state machine with states inheriting from the user-defined class StateTyp...
Definition: StateMachine.h:74
XBot::FSM::StateMachine::shared_data
SharedDataType & shared_data()
Definition: StateMachine.h:164
XBot::FSM::State::exit
virtual void exit()
Definition: StateMachine.h:230
XBot::FSM::Event
Base class for defining custom events which states can react to.
Definition: StateMachine.h:49
XBot::FSM::State::react
void react(const Event &e)
Definition: StateMachine.h:232
XBot
Definition: IXBotModel.h:20
XBot::FSM::State::get_name
virtual std::string get_name() const =0
XBot::FSM::State::console
XBot::LoggerClass & console()
Definition: StateMachine.h:242