Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

BehaviorBase.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_BehaviorBase_h_
00003 #define INCLUDED_BehaviorBase_h_
00004 
00005 #include "Events/EventListener.h"
00006 #include "Shared/ReferenceCounter.h"
00007 #include "Motion/MotionManagerMsg.h"
00008 #include "Behaviors/Controls/ControlBase.h"
00009 #include <string>
00010 #include <set>
00011 #include <map>
00012 
00013 class SharedObjectBase;
00014 class BehaviorSwitchControlBase;
00015 class RCRegion;
00016 
00017 //! Argument for REGISTER_BEHAVIOR_OPT and REGISTER_BEHAVIOR_MENU_OPT, indicates default options (does not start automatically)
00018 #define BEH_DEFAULTS ControlBase::DEFAULTS
00019 
00020 //! Argument for REGISTER_BEHAVIOR_OPT and REGISTER_BEHAVIOR_MENU_OPT, indicates the behavior should be activated at launch instead of waiting for the user to do it manually
00021 #define BEH_START ControlBase::BEH_START
00022 
00023 //! Argument for REGISTER_BEHAVIOR_OPT and REGISTER_BEHAVIOR_MENU_OPT, indicates the behavior's memory allocation will *not* be freed between activations, so state will be maintained
00024 #define BEH_RETAIN ControlBase::BEH_RETAIN
00025 
00026 //! Argument for REGISTER_BEHAVIOR_OPT and REGISTER_BEHAVIOR_MENU_OPT, indicates the behavior can be run alongside other behaviors
00027 #define BEH_NONEXCLUSIVE ControlBase::BEH_NONEXCLUSIVE
00028 
00029 
00030 //! The basis from which all other Behaviors should inherit
00031 /*! 
00032  *  For complex behaviors, it may be helpful to break aspects of the behaviors into independent 'states', and
00033  *  use a state machine formalism to control them.  See StateNode and Transition for more information.
00034  *
00035  *  Quick-start boilerplate is included in the distribution: <a href="http://cvs.tekkotsu.org/cgi/viewcvs.cgi/Tekkotsu/project/templates/behavior.h?rev=HEAD&content-type=text/vnd.viewcvs-markup"><i>project</i><tt>/templates/behavior.h</tt></a>:
00036  * 
00037  *  Tutorials:
00038  *  - <a href="../FirstBehavior.html">Tekkotsu's "First Behavior" Tutorial</a>
00039  *  - <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/behaviors.shtml">David Touretzky's "Behaviors" Chapter</a>
00040  *  - <a href="http://www.cs.cmu.edu/afs/cs/academic/class/15494-s06/www/lectures/behaviors.pdf">CMU's Cognitive Robotics course slides</a>
00041  *  
00042  *  start() and stop() are control functions to trigger the appropriate state change in the behavior.
00043  *  preStart(), doStart(), and postStart() are hooks to notify subclasses in order to enact this change.
00044  *  Thus, subclasses should override one (or more) of the latter 3 functions, and users should call
00045  *  the main start() / stop() methods to (de)activate the behavior, not the hooks.
00046  *
00047  *  Also, if you instantiate a behavior on the stack instead of the heap (this is very rarely done), remember to call 
00048  *  setAutoDelete(false) (provided from the ReferenceCounter base class) — don't want it to try to free memory
00049  *  on the stack when the behavior is stopped!  (The stack limits the allocation of the behavior
00050  *  to the current scope, which overrides the reference counting.)
00051  *
00052  *  Don't forget to include a call to the #REGISTER_BEHAVIOR macro so that your behavior will be inserted into the menu system!
00053  */
00054 class BehaviorBase : public ReferenceCounter, public EventListener {
00055 public:
00056   //! destructor - if is active when deleted, will display a warning (don't delete directly - use removeReference())
00057   virtual ~BehaviorBase();
00058   
00059   //! Calling this signals that the behavior should start running.  It will increment the reference counter, add to the registry, and call the subclass hooks (preStart() / doStart() postStart() )
00060   /*! Generally you shouldn't override this -- override some combination of preStart(), doStart(), and postStart() instead. */
00061   virtual void start();
00062 
00063   //! Calling this signals the behavior to stop running.  In turn, this calls doStop(), then removes the behavior from the registry and subtracts from the reference counter Ñ thus may delete the object if no other references remain
00064   /*! You shouldn't override this — override doStop instead.\n
00065    <b>Warning:</b> if you <i>do</i> override, call this at the <i>end</i> of your stop(), not beginning (as it might @c delete @c this !) */
00066   virtual void stop();
00067   
00068   //! Assigns @a curEvent to #event and calls to doEvent() for user processing
00069   /*! This is basically a hack for noobs who can't grok function arguments at the expense
00070    *  of creating a more complicated overall design for everyone else...\n
00071    *  On the up side, this also allows optional event references for StateNodes receiving
00072    *  a transition, so they can inspect the triggering event.  Also if we someday want to
00073    *  make BehaviorBase smarter and do some built-in event processing, it would go here. */
00074   virtual void processEvent(const EventBase& curEvent);
00075   
00076   //! Identifies the behavior in menus and such
00077   virtual std::string getName() const { return (instanceName.size()==0) ? getClassName() : instanceName; }
00078   
00079   //! Allows dynamic renaming of behaviors
00080   virtual void setName(const std::string& name) { instanceName=name; }
00081 
00082   //! Gives a short description of what this particular instantiation does (in case a more specific description is needed on an individual basis)
00083   /*! By default simply returns getName(), because any calls from a
00084    *  BehaviorBase function to getClassDescription() are going to call
00085    *  BehaviorBase::getClassDescription(), not
00086    *  ~YourSubClass~::getClassDescription(), because static functions
00087    *  can't be virtual in C++ (doh!)
00088    *
00089    *  This means that getDescription called on a pointer to a
00090    *  BehaviorBase of unknown subtype would always return an empty
00091    *  string, which is pretty useless.  So instead we return the name
00092    *  in this situation.  If you want getDescription to return
00093    *  getClassDescription, you'll have to override it in your subclass
00094    *  to do so. */
00095   virtual std::string getDescription() const {
00096     std::string d=getClassDescription();
00097     return (d.size()==0)?getName():d;
00098   }
00099 
00100   //! Returns the name of the class of this behavior (aka its type) using typeid and gcc's demangle 
00101   virtual std::string getClassName() const;
00102   
00103   //! Gives a short description of what this class of behaviors does... you should override this (but don't have to)
00104   /*! If you do override this, also consider overriding getDescription() to return it */
00105   static std::string getClassDescription() { return ""; }
00106 
00107   //! Returns true if the behavior is currently running
00108   virtual bool isActive() const { return started; }
00109   
00110   //! This read-only set allows us list all the currently instantiated behaviors
00111   /*! Not all of these behaviors are necessarily active, this is everything that has been allocated and not yet deallocated */
00112   static const std::set<BehaviorBase*>& getRegistry() { return getRegistryInstance(); }
00113   
00114   //! Registers a behavior class to be added to the specified Controller menu, use '/' to specify sub-menus, see REGISTER_BEHAVIOR macro.
00115   /*! This only works when called as an initializer to a static variable.  Once the menus have been initialized, later calls to this function won't update the menus. */
00116   template<class T> static BehaviorSwitchControlBase* registerControllerEntry(const std::string& name, const std::string& menu, int flags=BEH_DEFAULTS);
00117   
00118   //! A simple utility call for #REGISTER_BEHAVIOR and friends to remove trailing "Behavior" suffix from display names and fix CamelCase. Disabled because it interferes with the Storyboard and other components; should be re-implemented inside ControllerGUI.
00119   static std::string humanifyClassName(const std::string& name);
00120 
00121 protected:
00122   //! Typically would use MotionManager::MC_ID, but re-specified here for convenience and to avoid dependence on MotionManager.h
00123   typedef MotionManagerMsg::MC_ID MC_ID;
00124   //! Typically would use MotionManager::invalid_MC_ID, but re-specified here for convenience and to avoid dependence on MotionManager.h
00125   static const MC_ID invalid_MC_ID=MotionManagerMsg::invalid_MC_ID;
00126   
00127   //! Called by start() before the doStart(), allows superclasses to do some initialization startup preceeding subclass customization
00128   /*! For robustness to future change, subclasses should be sure to call the superclass implementation. */
00129   virtual void preStart() {}
00130   
00131   //! Delegate function for subclasses to be notified when the behavior starts up.
00132   /*! Should be overridden by subclasses to subscribe to events, install motion commands, etc.
00133    *
00134    *  doStart() is basically a hook to allow subclasses to jump in and do some customization
00135    *  of behavior parameters while the behavior is starting.  If you are writing a behavior
00136    *  class and do not expect further derivation, just override doStart() yourself.  However,
00137    *  if you do expect further derivation of your class, consider using preStart() or postStart()
00138    *  instead, and leave doStart() for the 'leaf' classes. */
00139   virtual void doStart() {}
00140   
00141   //! Called by start() after the doStart(), allows superclasses to complete initialization
00142   /*! For robustness to future change, subclasses should be sure to call the superclass implementation. */
00143   virtual void postStart() {}
00144   
00145   //! Delegate function for subclasses to be notified when the behavior starts up.
00146   /*! May be overridden to cleanup when the behavior is shutting down.  However
00147    *  events will automatically be unsubscribed, and by using addMotion(), motions
00148    *  will automatically be removed by stop(), so you may not need any cleanup.*/
00149   virtual void doStop() {}
00150   
00151   //! Delegate function for event processing, the event itself is pointed to (only for the duration of the doEvent() call!) by #event
00152   /*! Default implementation watches for 'private' text message events (those forwarded by a BehaviorSwitchControl from ControllerGUI input)
00153    *  and will publically rebroadcast them.  The idea is that your own processEvent gets first dibs, but if the behavior doesn't handle
00154    *  the text message, it will be handed off for others. */
00155   virtual void doEvent();
00156   
00157   //! Specifies parameters for addMotion()
00158   enum Prunability_t {
00159     PERSISTENT, //!< The motion will not be removed until forced to do so by behavior ending or a call to removeMotion()
00160     PRUNABLE //!< The motion can remove itself once it is "complete", which varies motion to motion.  Some may never "end", making this equivalent to #PERSISTENT in those cases.
00161   };
00162   
00163   //! Registers the MotionCommand (contained within a shared memory region) with the MotionManager, and allows the behavior to track active motions so they can be automatically removed on stop()
00164   /*! If you manually call motman->addPersistentMotion() or motman->addPrunableMotion(), you avoid
00165    *  this safety net, such that for better or worse the motion could be "leaked" and outlive the behavior.
00166    *  In rare cases, this may be desired if the motion is self-pruning or shared with another behavior.
00167    *
00168    *  Note that you can pass either SharedObject<MC> instances, or MotionPtr<MC> instances, which
00169    *  automatically expose their internal SharedObject when passed as such. */
00170   virtual MC_ID addMotion(const SharedObjectBase& mc, Prunability_t prune=PERSISTENT);
00171   
00172   //! Registers the MotionCommand (contained within a shared memory region) with the MotionManager, and allows the behavior to track active motions so they can be automatically removed on stop()
00173   /*! If you manually call motman->addPersistentMotion() or motman->addPrunableMotion(), you avoid
00174    *  this safety net, such that for better or worse the motion could be "leaked" and outlive the behavior.
00175    *  In rare cases, this may be desired if the motion is self-pruning or shared with another behavior.
00176    *
00177    *  Note that you can pass either SharedObject<MC> instances, or MotionPtr<MC> instances, which
00178    *  automatically expose their internal SharedObject when passed as such. */
00179   virtual MC_ID addMotion(const SharedObjectBase& mc, Prunability_t prune, float priority);
00180   
00181   //! Removes the motion from the MotionManager.
00182   /*! As long as there exists a SharedObject reference to the underlying memory region (such as within
00183    *  a MotionPtr instance), the memory is not actually deallocated, and you can resubmit the same motion
00184    *  later if desired. */
00185   virtual void removeMotion(MC_ID mcid);
00186   
00187   //! forwarding function so you can pass SharedObject<T> or MotionPtr<T> directly; extracts the MC_ID and passes to the other removeMotion
00188   template<template<typename T> class M, class T> void removeMotion(const M<T>& mc) { removeMotion(mc->getID()); }
00189   
00190   //! An instance is created for each motion activated through addMotion(), listening in case the motion is removed by some other means, thus invalidating the MC_ID.
00191   /*! This specifically addresses the use of prunable motions, which could disappear any time.
00192    *  We don't want BehaviorBase::autoMotions filling up with dead MC_IDs, which would cause
00193    *  trouble when the behavior ends and it tries to re-remove the motions.  (Particularly causing
00194    *  trouble if the MC_ID has since been reassigned to someone else!) */
00195   class MonitorMotion : public EventListener {
00196   public:
00197     //! Constructor, no-op; expects a call to monitor()
00198     MonitorMotion() : EventListener(), owner(NULL), mcid(invalid_MC_ID), mcregion(NULL) {}
00199     //! Copy constructor (shallow copy), begins monitoring the same MC_ID, on the assumption the original will be going away
00200     MonitorMotion(const MonitorMotion& m) : EventListener(), owner(NULL), mcid(invalid_MC_ID), mcregion(NULL) { monitor(*m.owner,m.mcid,m.mcregion); }
00201     //! Assignment (shallow copy), begins monitoring the same MC_ID, on the assumption the original will be going away
00202     MonitorMotion& operator=(const MonitorMotion& m) { monitor(*m.owner,m.mcid,m.mcregion); return *this; }
00203     //! Destructor, if #mcid is still valid (not invalid_MC_ID), then it removes it from owner->autoMotions
00204     ~MonitorMotion();
00205     //! Begins listening for a (motmanEGID, mcid, deactivate) event, storing the #owner so it can be updated when the motion is removed
00206     void monitor(BehaviorBase& parent, MC_ID mc_id, RCRegion* region);
00207   protected:
00208     //! Assumes the event indicates the motion has been removed, so sets mcid to invalid_MC_ID and removes it from owner->autoMotions
00209     /*! Note that as a result of removing the BehaviorBase::autoMotions entry, this class has also been destructed, so nothing else should happen afterward. */
00210     virtual void processEvent(const EventBase& event);
00211     
00212     BehaviorBase * owner; //!< the behavior which created the motion in #mcid
00213     MC_ID mcid; //!< the motion which is being monitored for removal
00214     RCRegion* mcregion; //!< keep a reference to the motion region
00215   };
00216   
00217   //! A list of active motions registered with this behavior to be removed when the behavior stops
00218   /*! If a motion is externally removed, e.g. prunes itself, the MonitorMotion instance kicks in to remove the dead MC_ID from this list */
00219   std::map<MC_ID,MonitorMotion> autoMotions;
00220   
00221   //! static function to provide well-defined initialization order
00222   static std::set<BehaviorBase*>& getRegistryInstance();
00223 
00224   //! constructor, will use getClassName() as the instance name
00225   BehaviorBase();
00226   //! constructor, @a name is used as both instance name and class name
00227   explicit BehaviorBase(const std::string& name);
00228   //! copy constructor; assumes subclass handles copying approriately - i.e. if @a b is active, the copy will be as well, even though doStart was never called..
00229   BehaviorBase(const BehaviorBase& b);
00230   //! assignment operator; assumes subclass handles assignment appropriately - i.e. if @a b is active, the copy will be as well, even though doStart was never called..
00231   BehaviorBase& operator=(const BehaviorBase& b);
00232 
00233   bool started; //!< true when the behavior is active
00234   std::string instanceName; //!< holds the name of this instance of behavior, if empty then getName() forwards to getClassName()
00235   const EventBase* event; //!< the event, received by processEvent, stored for duration of call to doEvent() (also doStart() in the case of a StateNode receiving a transition), NULL at all other times
00236 
00237 private:
00238   virtual void DoStart(struct __USE_doStart_NOT_DoStart__&) {} //!< temporary to produce warnings to help people update
00239   virtual void DoStop(struct __USE_doStart_NOT_DoStart__&) {} //!< temporary to produce warnings to help people update
00240 };
00241 
00242 // this is a bit of a hack to resolve mutual references...
00243 #ifndef INCLUDED_BehaviorSwitchControl_h_
00244 #include "Controls/BehaviorSwitchControl.h"
00245 
00246 template<class T> BehaviorSwitchControlBase* BehaviorBase::registerControllerEntry(const std::string& name, const std::string& menu, int flags/*=BEH_DEFAULTS*/) {
00247   ControlBase::ControlRegistry_t& reg = ControlBase::getControllerEntries();
00248   bool isnew = reg.find(menu)==reg.end() || reg[menu].find(name)==reg[menu].end();
00249   if(!isnew) {
00250     std::cerr << "Warning: attempted to register duplicate behavior class " << name << " in menu " << menu << std::endl;
00251     return NULL; // avoid memory leak on previous entry
00252   }
00253   BehaviorSwitchControlBase* entry = new BehaviorSwitchControl<T>(name,flags & BEH_RETAIN);
00254   //reg[menu][name] = std::make_pair(entry,flags);
00255   ControlBase::registerControllerEntry(entry,menu,flags);
00256   return entry;
00257 }
00258 #endif
00259 
00260 //! Menu name to place user behaviors by default when using #REGISTER_BEHAVIOR
00261 #define DEFAULT_MENU "User Behaviors"
00262 //! Menu name for framework behaviors, to override #DEFAULT_MENU
00263 #define DEFAULT_TK_MENU "Framework Demos"
00264 
00265 
00266 //! Should be called in the global namespace of a translation unit (i.e. a '.cc' file) in order to register a behavior in the controller menu system.
00267 /*! Specify the menu name (use '/' to demark submenus) and allows you to pass optional flags (see #BEH_START, #BEH_RETAIN, #BEH_NONEXCLUSIVE). */
00268 #define REGISTER_BEHAVIOR_MENU_OPT(behaviorClass, menu, flags) \
00269 const BehaviorSwitchControlBase* AUTO_REGISTER_NAME(behaviorClass,__LINE__) \
00270  = BehaviorBase::registerControllerEntry<behaviorClass>(#behaviorClass,menu,flags)
00271 
00272 //! Should be called in the global namespace of a translation unit (i.e. a '.cc' file) in order to register a behavior in the controller menu system.
00273 /*! This version assumes the DEFAULT_MENU but allows you to pass optional flags (see #BEH_START, #BEH_RETAIN, #BEH_NONEXCLUSIVE). */
00274 #define REGISTER_BEHAVIOR_OPT(behaviorClass, flags) REGISTER_BEHAVIOR_MENU_OPT(behaviorClass, DEFAULT_MENU, flags)
00275 
00276 //! Should be called in the global namespace of a translation unit (i.e. a '.cc' file) in order to register a behavior in the controller menu system.
00277 /*! This version allows you to specify a menu (use '/' to demark submenus), but uses the default style (exclusive execution, no auto-start). */
00278 #define REGISTER_BEHAVIOR_MENU(behaviorClass, menu) REGISTER_BEHAVIOR_MENU_OPT(behaviorClass, menu, BEH_DEFAULTS)
00279 
00280 //! Should be called in the global namespace of a translation unit (i.e. a '.cc' file) in order to register a behavior in the controller menu system.  See also #REGISTER_BEHAVIOR_OPT, #REGISTER_BEHAVIOR_MENU, and #REGISTER_BEHAVIOR_MENU_OPT.
00281 /*! This version assumes the #DEFAULT menu and will add the behavior to a behavior group so only one runs at a time. */
00282 #define REGISTER_BEHAVIOR(behaviorClass) REGISTER_BEHAVIOR_MENU_OPT(behaviorClass, DEFAULT_MENU, BEH_DEFAULTS)
00283 
00284 
00285 
00286 /*! @file
00287  * @brief Describes BehaviorBase from which all Behaviors should inherit
00288  * @author ejt (Creator)
00289  */
00290 
00291 #endif

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:36 2016 by Doxygen 1.6.3