Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

BatteryMonitorBehavior.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_BatteryMonitorBehavior_h_
00003 #define INCLUDED_BatteryMonitorBehavior_h_
00004 
00005 #include "Behaviors/BehaviorBase.h"
00006 #include "Shared/debuget.h"
00007 #include "Shared/WorldState.h"
00008 #include "Events/EventRouter.h"
00009 #include "IPC/SharedObject.h"
00010 #include "Motion/MotionManager.h"
00011 #include "Motion/PostureMC.h"
00012 #include "Shared/ERS210Info.h"
00013 #include "Shared/ERS220Info.h"
00014 #include "Shared/ERS7Info.h"
00015 #include "Motion/MMAccessor.h"
00016 #include "Sound/SoundManager.h"
00017 #include "Shared/RobotInfo.h"
00018 #ifdef TGT_HAS_LEDS
00019 #  include "Motion/LedMC.h"
00020 #endif
00021 
00022 //! A background behavior that monitors the power level and has the robot indicate when its battery is getting low.
00023 /*! On an AIBO, it flips the ears on an ERS-210 or ERS-7, or blinks the headlight on an ERS-220. 
00024  *  On the Chiara it speaks a warning message.
00025  *  Think of this as a simple example class.  For exercise, try using a MotionSequenceMC instead
00026  *  of switching the ears back manually using a PostureMC */
00027 class BatteryMonitorBehavior : public BehaviorBase {
00028 public:
00029   static const unsigned int max_t=10000; //!< max time between ear flips when at "high power" mark
00030   static const unsigned int high_power_p=20; //!< percent of 100 which is point at which to begin warning
00031   static const unsigned int no_power_p=14; //!< percent of 100 at which power will fail (approximate!)
00032   static const double low_voltage_threshold;//!< for Chiara: point at which to begin warning (normal is 12 volts)
00033 
00034   //! constructor
00035   BatteryMonitorBehavior() : BehaviorBase("BatteryMonitorBehavior"), pose(NULL), pose_id(MotionManager::invalid_MC_ID), led_id(MotionManager::invalid_MC_ID) {}
00036 
00037   //! destructor
00038   virtual ~BatteryMonitorBehavior() {}
00039 
00040   //! Listens for the PowerSrcID::LowPowerWarnSID
00041   virtual void doStart() {
00042 #if defined(TGT_IS_BIOLOID)
00043     erouter->addTimer(this,0,20000);  // 20 seconds between battery warnings
00044 #else   
00045     erouter->addListener(this,EventBase::powerEGID,PowerSrcID::LowPowerWarnSID);
00046     erouter->addListener(this,EventBase::powerEGID,PowerSrcID::ExternalPowerSID);
00047     erouter->addListener(this,EventBase::powerEGID,PowerSrcID::BatteryConnectSID);
00048     erouter->addListener(this,EventBase::powerEGID,PowerSrcID::UpdatedSID);
00049 #endif    
00050     //if the low power warning is *already* on, better forge an event and send it to myself
00051     if(shouldWarn())
00052       processEvent(EventBase(EventBase::powerEGID,PowerSrcID::UpdatedSID,EventBase::statusETID));
00053   }
00054 
00055   //! Stops listening for events
00056   virtual void doStop() {
00057     if(pose!=NULL)
00058       stopWarning();
00059   }
00060 
00061   //! Adds a BatteryMonitorMC to motman if power goes low
00062   virtual void doEvent() {
00063 #if defined(TGT_HAS_POWER_STATUS)
00064     if(event->getGeneratorID()==EventBase::powerEGID) {
00065       //just check for low power status
00066       bool shouldwarn=shouldWarn();
00067       if(pose!=NULL && !shouldwarn)
00068         stopWarning();
00069       else if(pose==NULL && shouldwarn)
00070         startWarning();
00071     } else {
00072       ASSERTRET(event->getGeneratorID()==EventBase::timerEGID,"Unrequested event "<<event->getName());
00073       switch(event->getSourceID()) {
00074       case 0:{
00075         //just check for low power status
00076         bool shouldwarn=shouldWarn();
00077         if(pose!=NULL && !shouldwarn)
00078           stopWarning();
00079         else if(pose==NULL && shouldwarn)
00080           startWarning();
00081                                 break;
00082       }
00083       case 1: { // toggle the ears (signals low battery), show battery level on LEDs
00084           std::cout<<"The switch is entering the wrong case"<<std::endl;
00085         ASSERTRET(pose!=NULL,"Extra timer 1");
00086         setFlipper(true);
00087         unsigned int flipdelay=calcFlipDelay();
00088         // if we're just constantly flipping the ears, a slight change is needed so the battery
00089         // level isn't obscuring the LED settings
00090         if(flipdelay<=NumFrames*FrameTime) {
00091           static bool on=false;
00092           on = !on;
00093 #if defined(TGT_HAS_LEDS)
00094           if(on) {
00095             motman->setPriority(led_id,MotionManager::kEmergencyPriority+1);
00096             MMAccessor<LedMC> led(led_id);
00097             led->displayPercent(state->sensors[PowerRemainOffset],LedEngine::major,LedEngine::major);
00098           } else
00099             motman->setPriority(led_id,MotionManager::kIgnoredPriority);
00100 #endif
00101           erouter->addTimer(this,1,128+flipdelay,false);
00102         } else {
00103 #if defined(TGT_HAS_LEDS)
00104           motman->setPriority(led_id,MotionManager::kEmergencyPriority+1);
00105           MMAccessor<LedMC> led(led_id);
00106           led->displayPercent(state->sensors[PowerRemainOffset],LedEngine::major,LedEngine::major);
00107 #endif
00108           erouter->addTimer(this,2,128,false);
00109         }
00110       } break;
00111       case 2: { // release ear until next flap, hide LEDs display
00112         ASSERTRET(pose!=NULL,"Extra timer 1");
00113         setFlipper(false);
00114         motman->setPriority(led_id,MotionManager::kIgnoredPriority);
00115       
00116         erouter->addTimer(this,1,calcFlipDelay(),false);
00117       } break;
00118       default:
00119         ASSERTRET(false,"Unrequested timer " << event->getName());
00120         break;
00121       }
00122     }
00123 #endif
00124   }
00125 
00126   static std::string getClassDescription() { return "Reports the current battery status, and has the robot indicate when the battery gets too low"; }
00127   virtual std::string getDescription() const { return getClassDescription(); }
00128 
00129   //! returns true if the warning should be active (power remaining less than high_power_p, no external power, but also checks that a power update has been received)
00130 
00131   static bool shouldWarn() { 
00132 #if defined(TGT_IS_AIBO)
00133     return state!=NULL && state->powerFlags[PowerSrcID::BatteryConnectSID] && (state->sensors[PowerRemainOffset]*100<=high_power_p || state->powerFlags[PowerSrcID::LowPowerWarnSID]) && !state->powerFlags[PowerSrcID::ExternalPowerSID];
00134 #elif defined(TGT_HAS_POWER_STATUS)
00135     return state!=NULL && (state->sensors[PowerVoltageOffset] <= low_voltage_threshold) && (state->sensors[PowerVoltageOffset] > 0);
00136 #else
00137     return false;
00138 #endif
00139      }
00140 
00141 protected:
00142   //! adds a pose and a timer to get the ears flipping
00143   void startWarning() {
00144 #if defined(TGT_IS_AIBO)
00145     serr->printf("LOW BATTERY\n");
00146     pose_id=motman->addPersistentMotion(SharedObject<PostureMC>(),MotionManager::kEmergencyPriority+1);
00147     pose=(PostureMC*)motman->peekMotion(pose_id);
00148     SharedObject<LedMC> led;
00149     led->displayPercent(state->sensors[PowerRemainOffset],LedEngine::major,LedEngine::major);
00150     led_id=motman->addPersistentMotion(led,MotionManager::kEmergencyPriority+1);
00151     setFlipper(true);
00152     //Not setoff for Chiara
00153     erouter->addTimer(this,2,128,false);
00154 #elif defined(TGT_HAS_POWER_STATUS)
00155     char batteryWarning[100];
00156     sprintf(batteryWarning,"Low battery: %4.1f volts",state->sensors[PowerVoltageOffset]);
00157     std::cout << "*** WARNING: " << batteryWarning << std::endl;
00158     sndman->speak(batteryWarning);
00159 #endif  
00160   }
00161 
00162   //! removes pose, in case battery magically charges
00163   void stopWarning() {
00164     serr->printf("BATTERY GOOD\n");
00165     motman->removeMotion(pose_id);
00166     motman->removeMotion(led_id);
00167     led_id=pose_id=MotionManager::invalid_MC_ID;
00168     pose=NULL;
00169     erouter->removeTimer(this,1);
00170     erouter->removeTimer(this,2);
00171     erouter->removeTimer(this,0);
00172   }
00173 
00174   //! makes the ears flip more rapidly as power declines.  Flips back and forth once every 15 seconds at 15%, down to flipping constantly at 5%.
00175   unsigned int calcFlipDelay() {
00176 #if defined(TGT_HAS_POWER_STATUS)
00177     const float high_power=high_power_p/100.f;
00178     const float no_power=no_power_p/100.f;
00179     float cur_power=state->sensors[PowerRemainOffset];
00180     if(cur_power<no_power)
00181       return 0;
00182     return (unsigned int)(max_t*(cur_power-no_power)/(high_power-no_power));
00183 #else
00184     return 0;
00185 #endif
00186   }
00187 
00188   //!sets the ears on a 210 & 7 or the headlight on a 220 - true toggles current, false clears
00189   void setFlipper(bool set) {
00190     if(RobotName == ERS210Info::TargetName) {
00191       int ear=capabilities.getOutputOffset(ERS210Info::outputNames[ERS210Info::EarOffset]);
00192       for(unsigned int i=ear; i<ear+ERS210Info::NumEarJoints; i++)
00193         pose->setOutputCmd(i,set?!state->outputs[i]:OutputCmd());
00194     } else if(RobotName == ERS220Info::TargetName) {
00195       int light=capabilities.getOutputOffset(ERS220Info::outputNames[ERS220Info::RetractableHeadLEDOffset]);
00196       pose->setOutputCmd(light,set?(state->outputs[light]>.5?0:1):OutputCmd());
00197     } else if(RobotName == ERS7Info::TargetName) {
00198       int ear=capabilities.getOutputOffset(ERS7Info::outputNames[ERS7Info::EarOffset]);
00199       for(unsigned int i=ear; i<ear+ERS7Info::NumEarJoints; i++)
00200         pose->setOutputCmd(i,set?!state->outputs[i]:OutputCmd());
00201     }
00202   }
00203 
00204   PostureMC* pose; //!< if we are currently warning of low battery, holds a pose, NULL otherwise
00205   MotionManager::MC_ID pose_id; //!< id of pose if we are currently warning, MotionManager::invalid_MC_ID otherwise
00206   MotionManager::MC_ID led_id; //!< id of LedMC if we are currently warning, MotionManager::invalid_MC_ID otherwise
00207 
00208 private:
00209   BatteryMonitorBehavior(const BatteryMonitorBehavior&); //!< don't copy behaviors
00210   BatteryMonitorBehavior operator=(const BatteryMonitorBehavior&); //!< don't assign behaviors
00211 };
00212 
00213 /*! @file
00214  * @brief Defines BatteryMonitorBehavior, a background behavior to trigger BatteryMonitorMC to warn when the power is low
00215  * @author ejt (Creator)
00216  */
00217 
00218 #endif

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