NimbRo ROS Soccer Package
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
behaviour_template_defns.h
Go to the documentation of this file.
1 // Behaviour Control Framework - Template function definitions
2 // Author: Philipp Allgeuer <pallgeuer@ais.uni-bonn.de>
3 
15 // Ensure header is only included once
16 #ifndef BEHAVIOUR_TEMPLATE_DEFNS_H
17 #define BEHAVIOUR_TEMPLATE_DEFNS_H
18 
19 // Includes
21 
22 // Behaviour control namespace
23 namespace behaviourcontrol
24 {
25  //
26  // SensorManager class
27  //
28 
29  // Sensor declaration function
30  template <class SClass>
31  void SensorManager::declareSensor(SClass* sensor)
32  {
33  // Ensure at compile time that this function is only called with derived classes of SensorBase
34  BOOST_STATIC_ASSERT_MSG((boost::is_base_of<SensorBase, SClass>::value), "SClass template parameter must be a derived class of behaviourcontrol::SensorBase");
35 
36  // Error checking
37  ASSERT_WARNING(sensor != NULL, MBase, "Failed to declare the requested sensor as a child of the '" + LBase->name + "' layer sensor manager - Provided sensor pointer was null!");
38  ASSERT_WARNING(!MBase->isInitialising(), MBase, "Attempted to declare the '" + sensor->signalName + "'sensor as a child of the '" + LBase->name + "' layer sensor manager during initialisation - All sensor declarations should be in the sensor manager constructor!");
39  ASSERT_WARNING(!MBase->wasInitialised(), MBase, "Attempted to declare the '" + sensor->signalName + "'sensor as a child of the '" + LBase->name + "' layer sensor manager after initialisation - All sensor declarations should be in the sensor manager constructor!");
40 
41  // Add the sensor to the sensor list
42  SList.push_back(sensor->getBasePtr());
43  }
44 
45  //
46  // Sensor class
47  //
48 
49  // Default constructor
59  template <class T>
60  Sensor<T>::Sensor(SensorManager* SMBase, const std::string& signalName)
61  : SensorBase(SMBase, signalName)
62  , typeInfo(&typeid(T)) // This is safe because type_info objects don't get destroyed until the program ends
63  , sourceAct(NULL)
64  , data() // Initialise template data member to zero
65  , actWasWrittenTo(false)
66  {
67  }
68 
69  // Destructor
70  template <class T>
72  {
73  }
74 
75  // Actuator compatibility check function
76  template <class T>
77  bool Sensor<T>::isCompatibleWith(const ActuatorBase* ABase) const
78  {
79  // Verify that the actuator has the same data type as the sensor
80  if(ABase == NULL)
81  return false;
82  else
83  return (*typeInfo == *(ABase->getTypeInfo()));
84  }
85 
86  // Bind to an actuator of the same data type
87  template <class T>
89  {
90  // Check for null pointer
91  if(ABase == NULL)
92  return RET_NULL_POINTER;
93 
94  // Ensure that we are still in the initialisation phase (no re-routing bindings on the fly!)
95  if(MBase->wasInitialised())
96  {
97  REPORT_WARNING(MBase, "Request to bind to actuator '" + ABase->signalName + "' denied - The behaviour manager has already been successfully initialised!");
99  }
100 
101  // Verify actuator compatibility
102  if(!isCompatibleWith(ABase))
103  {
104  REPORT_WARNING(MBase, "Request to bind to actuator '" + ABase->signalName + "' denied - This actuator has the wrong data type ('" + std::string(ABase->getTypeInfo()->name()) + "')!");
105  return RET_BIND_FAILED_ASI;
106  }
107 
108  // Retrieve a pointer to the actual Actuator<T> class
109  try { sourceAct = dynamic_cast<const Actuator<T>*>(ABase); } // The whole try/catch is overkill here, but I don't want to risk anything (this framework could be used in some safety critical application - no crashing allowed!)
110  catch(...)
111  {
112  sourceAct = NULL;
113  REPORT_WARNING(MBase, "Request to bind to actuator '" + ABase->signalName + "' failed - Dynamic cast to type 'const Actuator<T> *' for T = '" + std::string(ABase->getTypeInfo()->name()) + "' failed!");
114  return RET_BIND_FAILED_ASI;
115  }
116 
117  // Successful binding to the actuator
118  return RET_OK;
119  }
120 
121  // Get the latest data from the bound actuator
122  template <class T>
124  {
125  if(sourceAct != NULL)
126  {
127  data = sourceAct->read();
128  actWasWrittenTo = sourceAct->wasWrittenTo();
129  }
130  }
131 
132  //
133  // ActuatorManager class
134  //
135 
136  // Actuator declaration function
137  template <class AClass>
138  void ActuatorManager::declareActuator(AClass* actuator)
139  {
140  // Ensure at compile time that this function is only called with derived classes of ActuatorBase
141  BOOST_STATIC_ASSERT_MSG((boost::is_base_of<ActuatorBase, AClass>::value), "AClass template parameter must be a derived class of behaviourcontrol::ActuatorBase");
142 
143  // Error checking
144  ASSERT_WARNING(actuator != NULL, MBase, "Failed to declare the requested actuator as a child of the '" + LBase->name + "' layer actuator manager - Provided actuator pointer was null!");
145  ASSERT_WARNING(!MBase->isInitialising(), MBase, "Attempted to declare the '" + actuator->signalName + "'actuator as a child of the '" + LBase->name + "' layer actuator manager during initialisation - All actuator declarations should be in the actuator manager constructor!");
146  ASSERT_WARNING(!MBase->wasInitialised(), MBase, "Attempted to declare the '" + actuator->signalName + "'actuator as a child of the '" + LBase->name + "' layer actuator manager after initialisation - All actuator declarations should be in the actuator manager constructor!");
147 
148  // Add the actuator to the actuator list
149  AList.push_back(actuator->getBasePtr());
150  }
151 
152  //
153  // Actuator class
154  //
155 
156  // Default constructor
177  template <class T>
178  Actuator<T>::Actuator(ActuatorManager* AMBase, const std::string& signalName, bool aggregatable)
179  : ActuatorBase(AMBase, signalName)
180  , aggregatable(aggregatable)
181  , typeInfo(&typeid(T)) // This is safe because type_info objects don't get destroyed until the program ends
182  , data() // Initialise template data member to zero
183  , weightSum(0.0)
184  , lastModifier(NULL)
185  {
186  }
187 
188  // Destructor
189  template <class T>
191  {
192  }
193 
194  // Sensor compatibility check function
195  template <class T>
196  bool Actuator<T>::isCompatibleWith(const SensorBase* SBase) const
197  {
198  // Verify that the sensor has the same data type as the actuator
199  if(SBase == NULL)
200  return false;
201  else
202  return (*typeInfo == *(SBase->getTypeInfo()));
203  }
204 
205  // Write functions
206  template <class T>
207  void Actuator<T>::write(const T& newdata, const Behaviour* BBase)
208  {
209  // Declare variables
210  level_t weight = 0.0;
211 // bool firstWrite = (weightSum <= 0.0);
212 
213  // Error checking
214  ASSERT_WARNING(MBase->wasInitialised(), MBase, "A call to write() was attempted on the actuator '" + signalName + "' (part of the '" + LBase->name + "' layer) before or during initialisation - consider using writeHard() instead!");
215  ASSERT_WARNING(BBase != NULL, MBase, "Attempted to write to the actuator '" + signalName + "' with null behaviour pointer!");
216  ASSERT_WARNING(BBase != lastModifier, MBase, "The behaviour '" + BBase->name + "' attempted multiple writes to the actuator '" + signalName + "'!");
217  ASSERT_WARNING(!LBase->isInterface, MBase, "A call to write() was attempted on an actuator ('" + signalName + "') that belongs to an interface layer ('" + LBase->name + "') - consider using writeHard() instead!");
218 
219  // Disabled as these would get annoying for the user if this is intended behaviour (even if it is not recommended)
220 // ASSERT_WARNING(firstWrite, MBase, "More than one write to the actuator '" + signalName + "' was detected within the cycle " + std::string(MBase->cycleID()) + " (part of the '" + LBase->name + "' layer)!");
221 // ASSERT_WARNING(!aggregatable, MBase, "A call to write() was made for the aggregatable actuator '" + signalName + "' (part of the '" + LBase->name + "' layer) - consider using writeAgg() instead!");
222 
223  // Retrieve the required activation level (i.e. incremental averaging weight)
224  weight = BBase->getA();
225  lastModifier = BBase;
226 
227  // Ignore function call if weight is zero (or negative for some mysterious reason)
228  if(weight <= 0.0) return;
229 
230  // Update the weight sum
231  weightSum += weight; // We are guaranteed to have weightSum > 0.0 after this => firstWrite will be false in subsequent calls until weightSum is reset (e.g. in update())
232 
233  // Update the internal actuator data (a hard write)
234  data = newdata;
235  }
236  template <class T>
237  void Actuator<T>::writeAgg(const T& newdata, const Behaviour* BBase)
238  {
239  // Declare variables
240  level_t weight = 0.0;
241  bool firstWrite = (weightSum <= 0.0);
242 
243  // Error checking
244  ASSERT_WARNING(MBase->wasInitialised(), MBase, "A call to write() was attempted on the actuator '" + signalName + "' (part of the '" + LBase->name + "' layer) before or during initialisation - consider using writeHard() instead!");
245  ASSERT_WARNING(BBase != NULL, MBase, "Attempted to write to the actuator '" + signalName + "' with null behaviour pointer!");
246  ASSERT_WARNING(BBase != lastModifier, MBase, "The behaviour '" + BBase->name + "' attempted multiple writes to the actuator '" + signalName + "'!");
247  ASSERT_WARNING(!LBase->isInterface, MBase, "A call to write() was attempted on an actuator ('" + signalName + "') that belongs to an interface layer ('" + LBase->name + "') - consider using writeHard() instead!");
248  ASSERT_WARNING(aggregatable, MBase, "A call to writeAgg() was made for the non-aggregatable actuator '" + signalName + "' (part of the '" + LBase->name + "' layer) - consider using write() instead!");
249 
250  // Retrieve the required activation level (i.e. incremental averaging weight)
251  weight = BBase->getA();
252  lastModifier = BBase;
253 
254  // Ignore function call if weight is zero (or negative for some mysterious reason)
255  if(weight <= 0.0) return;
256 
257  // Update the weight sum
258  weightSum += weight; // We are guaranteed to have weightSum > 0.0 after this => firstWrite will be false in subsequent calls until weightSum is reset (e.g. in update())
259 
260  // Update the internal actuator data
261  if(firstWrite)
262  data = newdata;
263  else
264  {
265  // Calculate the ratio of how important the new data is
266  level_t p = weight/weightSum;
267 
268  // Update the internal actuator data
269  // Removed due to possible system incompatabilities: if(boost::is_integral<T>::value || !(boost::has_multiplies<T, level_t, T>::value && boost::has_plus<T>::value)) // In summary: A type T is aggregatable if it is integral, or it can't do either T * level_t or T + T
270  data = data*(1-p) + newdata*p; // Aggregatable case
271  }
272  }
273  template <class T>
274  void Actuator<T>::writeHard(const T& newdata)
275  {
276  // Determine whether this is the first write
277  bool firstWrite = (weightSum <= 0.0);
278 
279  // Error checking
280  ASSERT_WARNING((LBase->isInterface || !MBase->wasInitialised()), MBase, "A call to writeHard() was attempted on the actuator '" + signalName + "' (part of non-interface layer '" + LBase->name + "') after initialisation - consider using write() instead!");
281  ASSERT_WARNING((firstWrite || MBase->wasInitialised()), MBase, "More than one write to the actuator '" + signalName + "' was detected during initialisation (part of the '" + LBase->name + "' layer)!");
282 
283  // Disabled because we want to be able to write to the actuator multiple times in for example a ROS callback, and only use the latest value.
284 // ASSERT_WARNING(firstWrite, MBase, "More than one write to the actuator '" + signalName + "' was detected in the '" + LBase->name + "' interface layer!");
285 
286  // Overwrite the data in the actuator
287  data = newdata;
288  weightSum = 1.0; // Non-zero so that multiple writes can be detected
289  lastModifier = NULL;
290  }
291 
292  //
293  // BehaviourManager class
294  //
295 
296  // Layer declaration function
297  template <class LClass>
298  void BehaviourManager::declareLayer(LClass* layer)
299  {
300  // Ensure at compile time that this function is only called with derived classes of BehaviourLayer
301  BOOST_STATIC_ASSERT_MSG((boost::is_base_of<BehaviourLayer, LClass>::value), "LClass template parameter must be a derived class of behaviourcontrol::BehaviourLayer");
302 
303  // Error checking
304  ASSERT_WARNING(layer != NULL, this, "Failed to declare the requested layer as a child of the '" + name + "' behaviour manager - Provided layer pointer was null!");
305  ASSERT_WARNING(!isInitialising(), this, "Attempted to declare the '" + layer->name + "'layer as a child of the '" + name + "' behaviour manager during initialisation - All layer declarations should be in the behaviour manager constructor!");
306  ASSERT_WARNING(!wasInitialised(), this, "Attempted to declare the '" + layer->name + "'layer as a child of the '" + name + "' behaviour manager after initialisation - All layer declarations should be in the behaviour manager constructor!");
307 
308  // Add the layer to the layer list
309  LList.push_back(layer->getBasePtr());
310  }
311 
312  //
313  // BehaviourLayer class
314  //
315 
316  // Behaviour declaration function
317  template <class BClass>
318  void BehaviourLayer::declareBehaviour(BClass* behaviour)
319  {
320  // Ensure at compile time that this function is only called with derived classes of Behaviour
321  BOOST_STATIC_ASSERT_MSG((boost::is_base_of<Behaviour, BClass>::value), "BClass template parameter must be a derived class of behaviourcontrol::Behaviour");
322 
323  // Error checking
324  ASSERT_WARNING(behaviour != NULL, MBase, "Failed to declare the requested behaviour as a child of the '" + name + "' layer - Provided behaviour pointer was null!");
325  ASSERT_WARNING(!MBase->isInitialising(), MBase, "Attempted to declare the '" + behaviour->name + "'behaviour as a child of the '" + name + "' layer during initialisation - All behaviour declarations should be in the layer constructor!");
326  ASSERT_WARNING(!MBase->wasInitialised(), MBase, "Attempted to declare the '" + behaviour->name + "'behaviour as a child of the '" + name + "' layer after initialisation - All behaviour declarations should be in the layer constructor!");
327 
328  // Add the behaviour to the behaviour list
329  BList.push_back(behaviour->getBasePtr());
330  }
331 }
332 
333 #endif /* BEHAVIOUR_TEMPLATE_DEFNS_H */
334 // EOF
bool wasInitialised() const
Boolean flag specifying whether the manager has been initialised yet or not.
Definition: behaviour_manager.h:44
Implements a single behaviour.
Definition: behaviour.h:26
int ret_t
Used to represent an error code/function return value.
Definition: behaviour_common.h:142
const std::string name
Human-friendly string name of the behaviour.
Definition: behaviour.h:42
virtual ~Actuator()
Actuator object destructor.
Definition: behaviour_template_defns.h:190
Implements a single actuator of a given data type.
Definition: behaviour_actuators.h:131
Sensor(SensorManager *SMBase, const std::string &signalName)
Default constructor.
Definition: behaviour_template_defns.h:60
BehaviourManager *const MBase
Pointer to the parent behaviour manager.
Definition: behaviour_layer.h:48
bool isInitialising() const
Boolean flag specifying whether the manager is currently initialising or not.
Definition: behaviour_manager.h:45
Signals successful execution of a function, with no error conditions encountered. ...
Definition: behaviour_common.h:69
Implements a manager of a particular group of actuators.
Definition: behaviour_actuators.h:26
virtual const std::type_info * getTypeInfo() const =0
Abstract callback that should be overridden to return the type information of the sensor (i...
#define REPORT_WARNING(MBasePtr, msg)
Reports a std::string warning message msg to the behaviour manager pointed to by MBasePtr (fatal = fa...
Definition: behaviour_common.h:40
const std::string name
Human-friendly string name of the behaviour manager.
Definition: behaviour_manager.h:39
level_t getA() const
Returns the current true activation level of the behaviour. The return value is valid only when calle...
Definition: behaviour.h:67
const std::string signalName
The name of the actuator, used as the lookup key for the BehaviourManager::findActuator() function...
Definition: behaviour_actuators.h:90
BehaviourLayer *const LBase
Pointer to the parent behaviour layer.
Definition: behaviour_actuators.h:38
Signals that a duplicate call of a once-only initialisation function was attempted.
Definition: behaviour_common.h:73
BehaviourLayer *const LBase
Pointer to the parent behaviour layer.
Definition: behaviour_sensors.h:38
virtual ret_t bindTo(const ActuatorBase *ABase)
Bind to the actuator ABase. This must be called with an ABase that is actually pointing to an Actuato...
Definition: behaviour_template_defns.h:88
void writeAgg(const T &newdata, const Behaviour *BBase)
General purpose write function to be used by behaviours to write to aggregatable actuators. Do not use this function on non-aggregatable actuators.
Definition: behaviour_template_defns.h:237
virtual ~Sensor()
Destructor.
Definition: behaviour_template_defns.h:71
virtual const std::type_info * getTypeInfo() const =0
Update callback for the ActuatorBase object. Refer to the default override defined in Actuator::updat...
void writeHard(const T &newdata)
Special write function that can be used during initialisation to set up the value of an actuator...
Definition: behaviour_template_defns.h:274
BehaviourManager *const MBase
Pointer to the parent behaviour manager.
Definition: behaviour_actuators.h:37
#define ASSERT_WARNING(cond, MBasePtr, msg)
Reports a std::string warning message msg to the behaviour manager pointed to by MBasePtr if cond eva...
Definition: behaviour_common.h:44
Implements a single actuator.
Definition: behaviour_actuators.h:76
Actuator(ActuatorManager *AMBase, const std::string &signalName=nullString, bool aggregatable=AGGREGATABLE)
Default constructor.
Definition: behaviour_template_defns.h:178
virtual bool isCompatibleWith(const ActuatorBase *ABase) const
Abstract callback that should evaluate whether the current sensor is compatible the actuator ABase (c...
Definition: behaviour_template_defns.h:77
BehaviourManager *const MBase
Pointer to the parent behaviour manager.
Definition: behaviour_sensors.h:37
virtual void getLatestData()
Get the latest data from the source actuator.
Definition: behaviour_template_defns.h:123
void write(const T &newdata, const Behaviour *BBase)
General purpose write function to be used by behaviours to write to non-aggregatable actuators...
Definition: behaviour_template_defns.h:207
virtual bool isCompatibleWith(const SensorBase *SBase) const
Abstract callback that should evaluate whether the current actuator is compatible the sensor SBase (c...
Definition: behaviour_template_defns.h:196
Implements a single sensor.
Definition: behaviour_sensors.h:76
const std::string name
Human-friendly string name of the behaviour layer.
Definition: behaviour_layer.h:50
Implements a manager of a particular group of sensors.
Definition: behaviour_sensors.h:26
Signals that an unexpected null pointer was encountered (usually as a function parameter) ...
Definition: behaviour_common.h:71
float level_t
Used to represent an activation level (raw activation levels should always be in the range [0...
Definition: behaviour_common.h:141
Common definitions include file for the internal Behaviour Control Framework source code...
Signals that an attempt to bind a sensor to an actuator failed because of an actuator/sensor data typ...
Definition: behaviour_common.h:76