Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

LedEngine.h

Go to the documentation of this file.
00001 #ifndef INCLUDED_LedEngine_h
00002 #define INCLUDED_LedEngine_h
00003 
00004 #include "Shared/RobotInfo.h"
00005 #include "Shared/get_time.h"
00006 #include "OutputCmd.h"
00007 #include <math.h>
00008 
00009 class MotionCommand;
00010 
00011 // LEDBitMask_t and associated constants are defined in RobotInfo.h
00012 
00013 //! Provides basic LED effects via subclassing (e.g. LedMC) or embedding (e.g. EmergencyStopMC)
00014 /*! This implements a collection of LED special effects so that the code can be
00015  *  reused various places as feedback to to the user.
00016  *
00017  * The basic effects provided are:
00018  * - static brightness (set(), cset(), invert(), clear())
00019  * - temporary setting (flash(), cflash())
00020  * - pulsing/blinking (cycle(), ccycle())
00021  * - numeric display (displayNumber(), displayPercent())
00022  *
00023  * The 'c' prefix on a function (cset(), cflash(), ccycle()) means it will call clear() before doing its own setting.  This is
00024  * a quick way to replace whatever is currently displayed with whatever you are about to display.
00025  * 
00026  * A flash() will invert and override the current setting, so that it
00027  * will "reset" after the flash.  Flashes change mid-range values to
00028  * extremes to make the flash visible (ie not just (1-current)) Normal
00029  * invert() will do simple inverses (just (1-current)), and doesn't change back automatically.
00030  *
00031  * Cycling ("pulsing") and single-value setting are mutually exclusive;
00032  * one will cut off the other
00033  *
00034  * getSetting() returns value of last set();
00035  * getValue() returns what's actually being returned to Motion at the moment
00036  *
00037  * There's some nice functions for using the LEDs to display numbers.
00038  * This is handy for when you want to be free of the terminal.
00039  * <img src="NumberLEDs.jpg">
00040  *
00041  * The ERS-220 and ERS-7 have enough LEDs that they just use a "count
00042  * the lights" style of display instead of this pseudo-arabic display.
00043  * (look close to see that green bar LED at the top of the 210, which 
00044  * doesn't show up well in the camera image for some reason. )
00045  * <img src="NumberLEDs-ERS7.jpg">
00046  *
00047  * The ERS-7 also has a "mode" which controls how certain face LEDs are
00048  * interpreted.  By setting ERS7Info::LEDABModeOffset /
00049  * ERS7Info::LEDABModeMask, you can switch between the modes -- a value
00050  * of 0 is mode "A", and a value of 1 is mode "B".
00051  * <img src="ERS7-LED-Modes.png">
00052  *
00053  * Things to note for the ERS-7:
00054  * - There are many fewer LEDs than there are holes in the "grill" (the holes you see on the face are not the positions of the LEDs.
00055  * - Each LED covers several holes.
00056  * - Not all holes have LEDs behind them -- some areas of the face panel are always dark.
00057  * - Some LEDs (12 and 13) control two symmetrical physical LEDs.
00058  * - Some LEDs change color based on mode (0-1), some don't change at all (2-11), and some change position and color (12-13)
00059  * - We don't have individual names for all of the LEDs on the panel.  Instead you base off of FaceLEDPanelOffset or FaceLEDPanelMask to address the LEDs, e.g., to set the <i>n</i>th led to <i>x</i>:
00060  *   @code
00061  *   LedEngine::set(FaceLEDPanelMask << n, x)
00062  *   @endcode
00063  *   or (if using other classes, e.g. PostureEngine)
00064  *   @code
00065  *   PostureEngine::setOutputCmd(FaceLEDPanelOffset + n, x)
00066  *   @endcode
00067  */
00068 
00069 class LedEngine {
00070  public:
00071   //!constructor - don't forget to call if you inherit
00072   LedEngine();
00073   //!destructor
00074   virtual ~LedEngine() {}
00075   
00076   //! call this from a MotionCommand's updateOutputs() - makes calls to MotionManager to update LED values
00077   /*! @param caller pass the "parent" motioncommand's address here (usually will pass 'this')
00078    *  @param mask a bitmask of which leds to update (uses weight of 1) */
00079   int updateLEDs(const MotionCommand* caller,LEDBitMask_t mask=AllLEDMask);
00080   
00081   //! call this from a MotionCommand's updateOutputs() - performs the calculations to update LEDs' values
00082   /*! @param cmds on input, used for weight values - on return, holds the resulting OutputCmd's*/
00083   int updateLEDs(OutputCmd cmds[NumLEDs]);
00084 
00085   //! call this from a MotionCommand's updateOutputs() - performs the calculations to update LEDs' values
00086   /*! @param cmds on input, used for weight values - on return, holds the resulting OutputCmd's*/
00087   int updateLEDFrames(OutputCmd cmds[NumLEDs][NumFrames]);
00088   
00089   //! recalculates #nextFlashEnd so we can tell when a flash has completed
00090   void recalcFlashEnd();
00091 
00092   //! returns true if there are changes since the last updateLEDs()
00093   int isDirty();
00094 
00095   //!sets the leds specified by @a leds to the inverse of their current value
00096   void invert(LEDBitMask_t leds);
00097   //!sets the leds specified by @a leds to @a value, clears all the rest
00098   inline void cset(LEDBitMask_t leds, float value) { clear(); set(leds,value); }
00099   //!sets the leds specified by @a leds to @a value
00100   void set(LEDBitMask_t leds, float value);
00101   //!sets the leds specified by @a leds to @a value for @a ms milliseconds, then sets back.  Clears ~leds
00102   void cflash(LEDBitMask_t leds, float value, unsigned int ms);
00103   //!sets the leds specified by @a leds to @a value for @a ms milliseconds, then sets back.
00104   void flash(LEDBitMask_t leds, float value, unsigned int ms);
00105   //!sets the leds specified by @a leds to either a much higher or much lower value for @a ms milliseconds, then sets back.
00106   void flash(LEDBitMask_t leds, unsigned int ms);
00107   //!causes the leds specified by @a leds to cycle between low and high, clears others.  See cycle() for parameter documentation.
00108   inline void ccycle(LEDBitMask_t leds, unsigned int period, float amp, float offset=0, int phase=0) { clear(); cycle(leds,period,amp,offset,phase); }
00109   //!causes the leds specified by @a leds to cycle between low and high; values calculated for cycle will be clipped to [0,1] for more sensible blending of square wave approximations (high amplitude sine wave)
00110   void cycle(LEDBitMask_t leds, unsigned int period, float amp, float offset=0, int phase=0);
00111   //!sets all leds to 0.
00112   void clear();
00113   
00114   //!adds @a ms to all flash times (may resurrect previously completed flashes)
00115   void extendFlash(unsigned int ms);
00116 
00117   //!returns the current setting of the LED specified by @a led_id (the value you passed in set())
00118   float getSetting(LEDOffset_t led_id) {
00119 #ifndef TGT_HAS_LEDS
00120     (void)led_id; // avoid unused argument warning
00121     return 0;
00122 #else
00123     return infos[led_id-LEDOffset].value;
00124 #endif
00125   }
00126   //!returns the current value of the LED specified by @a led_id (the value being expressed - may change if cycling for instance)
00127   float getValue(LEDOffset_t led_id,unsigned int planahead=0) {
00128 #ifndef TGT_HAS_LEDS
00129     (void)led_id; (void)planahead; // avoid unused argument warnings
00130     return 0;
00131 #else
00132     return calcValue(led_id-LEDOffset,get_time()+planahead);
00133 #endif
00134   }
00135   
00136 #ifdef TGT_HAS_LED_PANEL
00137   //!holds a series of bit masks for the onedigit style of numerical display (-9:9 and '.')
00138   /*!the hope is that these actually resemble the shapes of the numbers so people can
00139    * recognize them more easily - without counting or converting base 2 in their heads. */
00140   static const LEDBitMask_t defaultMimicNumMasks[11];
00141   static const LEDBitMask_t ERS220numMasks[11]; //!< bit masks for the ondigit style of numberical display - just count the LEDs on the head
00142   static const LEDBitMask_t ERS7numMasks[11]; //!< bit masks for the ondigit style of numberical display - just count the LEDs on the head
00143 #endif
00144   static const LEDBitMask_t defaultCountNumMasks[11]; //!< bit masks for the ondigit style of numberical display - just count the LEDs on the head
00145   //!Use these to specify a style for displaying numbers using displayNumber()
00146   enum numStyle_t {
00147     onedigit, //!< can display a number -9 thru 9, using the current robot model's numMask.  For negative numbers, blinks the top bar - fast if it's supposed to be on, slow if it would otherwise be off
00148     twodigit  //!< can display a number -99 thru 99, using setOneOfTwo().  For negative numbers, sets the top bar to 1 (off otherwise).
00149   };
00150   //!Use these to specify a style for displaying a percentage value [0-1] using displayPercent()
00151   enum percentStyle_t {
00152     major, //!< shows overall value
00153     minor, //!< shows value within major tick
00154     none   //!< if you want to leave blank
00155   };
00156     
00157   //!Allows convenient display of numerical information to the LEDs on the face.
00158   /*!If overflow occurs, the face LEDs are set to flash on and off 3 every 333 milliseconds*/
00159   void displayNumber(int x, numStyle_t style);
00160   //!Allows convenient display of percentage information to the LEDs on the face.
00161   /*!Besides allowing a two-digit display, the 'edge' bar for each type is blinked to
00162    * denote how full it is.  So you can get up to a two-digit, base 5 display, with an
00163    * extra digit of estimated value.
00164    *
00165    * If overflow (>1) occurs, sets everything to .75. <br>
00166    * If underflow (<0) occurs, sets everything to .25.
00167    * 
00168    * The left and right columns are combined with an OR operation.  (they overlap on the top bar)
00169    * Left and right designations are <em>dog centric!</em> */
00170   void displayPercent(float x, percentStyle_t left_style, percentStyle_t right_style);
00171   
00172  protected:
00173   //!Performs the 'invert' calculation based on current value (returns 1-value)
00174   static float calcInvert(float value) {
00175     return 1-value;
00176   }
00177   //!Performs the 'flash' calculation based on current value (uses calcInvert() if value upper or lower third, 0 or 1 otherwise)
00178   static float calcFlash(float value) {
00179     if(value>.33333 && value<.66666)
00180       return (value<.5 ? 1 : 0);
00181     else
00182       return calcInvert(value);
00183   }
00184   //!Performs the 'cycle' calculation based on desired period, amplituted, amplitude offset, and time since start.  See cycle()
00185   static float calcCycle(unsigned int period, float amp, float offset, unsigned int t) {
00186     //    cout << period << ',' << amp << ',' << offset << ',' << time << " -> " << x;
00187     float x=float(cos(t*2*M_PI/period))*(-amp/2)+.5f+offset;
00188     if(x<0)
00189       return 0;
00190     if(x>1)
00191       return 1;
00192     return x;
00193   }
00194   //!Calculates the current value of led @a i for current time t
00195   float calcValue(unsigned int i, unsigned int t) {
00196     if(t<infos[i].flashtime)
00197       return infos[i].flashvalue;
00198     else if(infos[i].isCycling)
00199       return calcCycle(infos[i].period,infos[i].amp,infos[i].offset,t-infos[i].starttime);
00200     else
00201       return infos[i].value;
00202   }
00203   //!used by displayNumber() to determine settings of LEDs when using numStyle_t::twodigit
00204   void setOneOfTwo(unsigned int x, unsigned int low, unsigned int mid, unsigned int high);
00205   //!used by displayPercent() to determine settings of LEDs
00206   void setColumn(float x, unsigned int low, unsigned int mid, unsigned int high, unsigned int top);
00207 
00208   //!Holds all the information needed by each of the LEDs
00209   struct LEDInfo {
00210     float value;           //!< the current value being expressed
00211     float amp;             //!< the amplitude of the cycle (if cycling)
00212     unsigned int period;    //!< the period of the cycle (if cycling)
00213     unsigned int starttime; //!< the start time of the cycle (if cycling)
00214     float offset;          //!< the phase shift from normal of the cycle (if cycling)
00215     float flashvalue;      //!< the value being 'flashed' (only valid if current time is less than flashtime
00216     unsigned int flashtime; //!< the time the 'flash' should retire
00217     bool isCycling;         //!< true if in cycle mode
00218   };
00219   
00220   LEDInfo infos[NumLEDs]; //!< the information regarding each of the LEDs
00221   bool dirty;             //!< true if changes since last updateLEDs: either at least one LED is cycling or a flash has begun/ended
00222   unsigned int numCycling;//!< the number of LEDs currently cycling (if non-zero, always dirty)
00223   unsigned int nextFlashEnd; //!< the soonest time a flash will end (and we'll become dirty)
00224 };
00225   
00226 /*! @file
00227  * @brief Describes LedEngine, which provides basic LED effects to anything that inherits or instantiates it
00228  * @author ejt (Creator)
00229  *
00230  * $Author: ejt $
00231  * $Name: tekkotsu-4_0 $
00232  * $Revision: 1.30 $
00233  * $State: Exp $
00234  * $Date: 2007/11/18 06:47:03 $
00235  */
00236 
00237 #endif

Tekkotsu v4.0
Generated Thu Nov 22 00:54:53 2007 by Doxygen 1.5.4