Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MotionHook.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_MotionHook_h_
00003 #define INCLUDED_MotionHook_h_
00004 
00005 #include <cstring>
00006 #include "Shared/plist.h"
00007 #include "Shared/RobotInfo.h"
00008 #include <vector>
00009 
00010 //! Interface for connections to remote hosts and hardware devices which should be polled with output values
00011 /*! 
00012  *  - Override motionCheck() if your hardware needs to have a value specified for every output
00013  *    on every update, regardless of whether it changes.
00014  *  - Override motionUpdated() if you only need to process the outputs which have changed.
00015  *
00016  *  You can expect to be called every FrameTime*NumFrame milliseconds in terms of simulator time.
00017  *  However, keep in mind this is relative to SharedGlobals::timeScale (Config.Speed) in terms of
00018  *  wall-clock time, and is also subject to the simulator being paused, set to full-speed mode, or hitting 
00019  *  a breakpoint in the debugger.  See enteringRealtime() and leavingRealtime() if you want updates 
00020  *  when the user switches simulation modes, although there's still no way to get notification if a
00021  *  debugger breakpoint is hit.
00022  */
00023 class MotionHook {
00024 public:
00025   //! used as input to updatePIDs()
00026   struct PIDUpdate {
00027     //! default constructor (unknown output, 0 pids)
00028     PIDUpdate() : idx(-1U) { pids[0]=0; pids[1]=0; pids[2]=0; }
00029     //! constructor, pass output index and pid array
00030     PIDUpdate(const std::pair<unsigned int, float[3]>& x) : idx(x.first) { memcpy(pids,x.second,sizeof(pids)); }
00031     unsigned int idx; //!< output index
00032     float pids[3]; //!< pid values
00033   };
00034   
00035   //! constructor
00036   MotionHook() : verbose(0), isFirstCheck(true) {}
00037   
00038   //! no-op destructor
00039   virtual ~MotionHook() {}
00040   
00041   //! Called when motion process is starting
00042   virtual void motionStarting() {}
00043   
00044   //! Should return true if the MotionHook is successfully connected to physical hardware.
00045   /*! If relevant, this will only be called after motionStarting() has been called in order to 
00046    *  initialize a connection.
00047    *
00048    *  This is used mainly to cancel out of the WaitForSensors if all MotionHooks return false.
00049    *  If you are still in the process of connecting or unsure of status, be optimistic and return true.
00050    *  This function will be polled at a coarse rate while blocked on sensors in case of timeouts
00051    *  on the part of the MotionHook render it moot. */
00052   virtual bool isConnected()=0;
00053   
00054   //! Called each time the motion process has polled active motion commands
00055   /*! When in realtime mode, this should be called every FrameTime*NumFrames (defined in the RobotInfo)
00056    *  milliseconds if running at full speed.  See enteringRealtime() and leavingRealtime().
00057    *
00058    *  This default implementation checks to see which outputs have changed value since the last call and
00059    *  passes the summary on to motionUpdated().  #lastOutputs will be updated with the new values @e after
00060    *  the call to motionUpdated().
00061    *
00062    *  If you need to process all the outputs on every frame, you only need to override this function.
00063    *  Your subclass doesn't need to call the MotionHook implementation unless you want to have
00064    *  lastOutputs updated for you.
00065    *
00066    *  If you only need to process the @e changed outputs for each frame, override motionUpdated() instead.
00067    *  motionUpdated() is always called for each update, even if there aren't any changes, so you can still
00068    *  use that if there are some outputs which need to be updated every cycle.  */
00069   virtual void motionCheck(const float outputs[][NumOutputs]) {
00070     std::vector<size_t> changedIndices;
00071     changedIndices.reserve(NumOutputs);
00072     for(size_t i=0; i<NumOutputs; ++i) {
00073       if(isFirstCheck) {
00074         changedIndices.push_back(i);
00075       } else {
00076         for(size_t j=0; j<NumFrames; ++j) { // if *any* of the frames have changed, update the output
00077           if(outputs[j][i]!=lastOutputs[i]) { // (not just checking last frame for each output)
00078             changedIndices.push_back(i);
00079             break;
00080           }
00081         }
00082       }
00083     }
00084     motionUpdated(changedIndices,outputs);
00085     for(size_t i=0; i<NumOutputs; ++i)
00086       lastOutputs[i] = outputs[NumFrames-1][i];
00087     isFirstCheck=false;
00088   }
00089   
00090   //! Called by motionCheck(), after comparing the new output values to #lastOutputs, and before lastOutputs is updated
00091   /*! Override this if you only need to send commands to the hardware for values that have changed. 
00092    *  This function is always called for each update, even though changedIndices might be empty. */
00093   virtual void motionUpdated(const std::vector<size_t>& /*changedIndices*/, const float /*outputs*/[][NumOutputs]) {}
00094   
00095   //! Called when PID values change
00096   virtual void updatePIDs(const std::vector<PIDUpdate>& pids) {}
00097   
00098   //! Called when motion process is stopping
00099   virtual void motionStopping() { isFirstCheck=true; }
00100   
00101   //! Called when the controller is going to be running in realtime mode, which is probably the normal mode you'd expect.
00102   /*! You might be in realtime mode, but a debugger breakpoint will still pause things, or thread scheduling could hiccup, so try to be robust.\n
00103    *  The argument is a reference to SharedGlobals::timeScale, so the data source can subscribe to changes in
00104    *  simulation speed if it can use that information.  (We avoid direct dependency on the tekkotsu simulator
00105    *  so this code can be reused for other tools too.) */
00106   virtual void enteringRealtime(const plist::Primitive<double>& /*simTimeScale*/) {}
00107   
00108   //! Called when leaving realtime mode, which means you have no idea when motionCheck() is going to be called in terms of wall-clock time.
00109   /*! Argument set to true if entering full speed mode, which @e may mean motionCheck will be
00110    *  called at a high(er) frequency, or slower the computation is overwhelming the host hardware.
00111    *  However, if false, almost certainly indicates updates will be sparse.
00112    *  May be called multiple times if changing between full-speed mode and paused
00113    *
00114    *  A non-realtime mode might be triggered if the user wants to pause the simulator/controller to step through something...
00115    *  No guarantees though!  The debugger might catch a breakpoint and stop things, and this won't be called! */
00116   virtual void leavingRealtime(bool /*isFullSpeed*/) {}
00117   
00118   //! Called by simulator thread to indicate level of verbosity for diagnostics and reporting errors
00119   virtual void setMotionHookVerbose(int v) { verbose=v; }
00120 
00121 protected:
00122   //! stores current verbosity
00123   int verbose;
00124   //! set to false following the first motionCheck, reset to true by motionStopping
00125   bool isFirstCheck;
00126   //! stores the last frame of the outputs, updated by motionCheck()
00127   float lastOutputs[NumOutputs];
00128 };
00129 
00130 /*! @file
00131  * @brief Describes MotionHook, an interface for connections to remote hosts and hardware devices which should be polled with output values
00132  * @author Ethan Tira-Thompson (ejt) (Creator)
00133  */
00134 
00135 #endif

Tekkotsu Hardware Abstraction Layer 5.1CVS
Generated Mon May 9 05:01:39 2016 by Doxygen 1.6.3