Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
BehaviorBase.hGo 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 |