Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

PIDMC.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_PIDMC_h_
00003 #define INCLUDED_PIDMC_h_
00004 
00005 #include "MotionCommand.h"
00006 #include "MotionManager.h"
00007 #include "OutputPID.h"
00008 #include "Events/EventBase.h"
00009 
00010 //! A nice little MotionCommand for manually manipulating the PID values
00011 /*! This will, by default, autoprune after its PID values have been set.
00012  *  
00013  *  Although this doesn't handle directly sending PID commands to the
00014  *  system (the MotionManager::updatePIDs() does that) a little
00015  *  documentation on how Tekkotsu ad OPEN-R handle the PIDs might be
00016  *  nice.
00017  *
00018  *  In Tekkotsu, each of P,I, and D are a single floating point
00019  *  number.  However, OPEN-R has, in essence, a limited precision
00020  *  floating point number.  Each value is broken into a gain
00021  *  (mantissa) and shift (exponent).  The shifts appear to be 4 bit
00022  *  values, and are inverted.  In other words, x = g/(1<<(0x10-s)), or
00023  *  @f$ x = \frac{g}{2^{16-s}} @f$ The gain is probably 6-8 bits of
00024  *  resolution.
00025  *
00026  *  On the ERS-2xx series, each joint is completely independent.  One
00027  *  caveat is that the shift value 0x0A gives a warning
00028  *  (AGRMSDriver::SetGain() : 0x0A IS USED FOR GAIN SHIFT VALUE.) for
00029  *  some unknown reason.
00030  *
00031  *  On the ERS-7, all the joints share the last set shift values, so
00032  *  a global set of shifts must be enforced.  This of course, pretty
00033  *  much kills the whole point of having the shifts.
00034  *
00035  *  To understand the conversion from Tekkotsu format to the
00036  *  OPEN-R format, see MotionManager::updatePIDs().
00037  *  
00038  *  A final note: the OPENR::SetJointGain function seems to be
00039  *  a rather costly function call.  You should probably try to avoid
00040  *  setting PIDs at too high a frequency.
00041  */
00042 class PIDMC : public MotionCommand {
00043 public:
00044   //!Constructor, uses default PIDs and 0 weight for all
00045   PIDMC() : MotionCommand(), dirty(false), completionReported(false) {
00046     setDefaults(0);
00047     dirty=false;
00048   }
00049   //!Constructor, sets general power level of all 
00050   PIDMC(float powerlevel, float w=1) : MotionCommand(), dirty(false), completionReported(false) {
00051     setAllPowerLevel(powerlevel,w);
00052   }
00053   //!Constructor, sets general power level of a range of joints, uses default and 0 weight for others, see setRangePowerLevel()
00054   /*! @param low the first joint to apply @a powerlevel to
00055    *  @param high one-past last joint to apply @a powerlevel to (i.e. exclusive upper limit)
00056    *  @param powerlevel scaling factor for all of the default PID parameters
00057    *  @param w MotionManager weight for averaging conflicting commands
00058    *
00059    *  Note that if you want to set a single joint @e i, then @a low = @e i, and @a high = @e i + 1 because high is an exclusive upper limit*/
00060   PIDMC(unsigned int low, unsigned int high, float powerlevel, float w=1) : 
00061     MotionCommand(), dirty(false), completionReported(false) {
00062     setRangePowerLevel(PIDJointOffset,low,1.f,0.f);
00063     setRangePowerLevel(low,high,powerlevel,w);
00064     setRangePowerLevel(high,PIDJointOffset+NumPIDJoints,1.f,0.f);
00065   }
00066 
00067   //!Destructor
00068   virtual ~PIDMC() {}
00069 
00070   //!Inherited
00071   //@{
00072   virtual int updateOutputs() {
00073     for(unsigned int i=0; i<NumPIDJoints; i++)
00074       motman->setOutput(this,i+PIDJointOffset,PIDs[i]);
00075     int wasDirty=dirty;
00076     dirty=false;
00077     if ( ! completionReported ) {
00078       postEvent(EventBase(EventBase::motmanEGID,getID(),EventBase::statusETID));
00079       completionReported = true;
00080     }
00081     return wasDirty;
00082   }
00083   virtual int isDirty() { return dirty; }
00084   virtual int isAlive() { return dirty; }
00085 
00086   void setDirty() { dirty = true; }
00087 
00088   //! marks this as dirty each time it is added
00089   virtual void doStart() {
00090     MotionCommand::doStart();
00091     completionReported = false;
00092     dirty=true;
00093   }
00094   //@}
00095 
00096   //!Sets the PIDs to the defaults specified in RobotInfo
00097   void setDefaults(float weight=1) {
00098     setAllPowerLevel(1.f,weight);
00099   }
00100 
00101   //!Sets the PIDs to a percentage of default for a given joint, and sets weight
00102   void setJointPowerLevel(unsigned int i, float p, float w=1) {
00103     i-=PIDJointOffset;
00104     for(unsigned int j=0;j<3;j++)
00105       PIDs[i].pid[j]=DefaultPIDs[i][j]*p;
00106     PIDs[i].weight=w;
00107     dirty=true;
00108   }
00109 
00110   //!Sets the PIDs to a percentage of default for all joints
00111   void setAllPowerLevel(float p, float w=1) {
00112     for(unsigned int i=0; i<NumPIDJoints; i++) {
00113       for(unsigned int j=0;j<3;j++)
00114         PIDs[i].pid[j]=DefaultPIDs[i][j]*p;
00115       PIDs[i].weight=w;
00116     }
00117     dirty=true;
00118   }
00119 
00120   //!Sets a range of joints' PIDs to a given power level and weight
00121   /*! @param low the first joint to apply power level @a p to
00122    *  @param high one-past last joint to apply power level @a p to (i.e. exclusive upper limit)
00123    *  @param p scaling factor for all of the default PID parameters
00124    *  @param w MotionManager weight for averaging conflicting commands
00125    *
00126    *  Note that if you want to set a single joint @e i with this function (as opposed to setJointPowerLevel() which is designed for that...)
00127    *  then you would need to pass @a low = @e i, and @a high = @e i + 1 because high is an exclusive upper limit*/
00128   void setRangePowerLevel(unsigned int low, unsigned int high, float p, float w=1) {
00129     low-=PIDJointOffset;
00130     high-=PIDJointOffset;
00131     for(unsigned int i=low; i<high; i++) {
00132       for(unsigned int j=0;j<3;j++)
00133         PIDs[i].pid[j]=DefaultPIDs[i][j]*p;
00134       PIDs[i].weight=w;
00135     }
00136     dirty=true;
00137   }
00138 
00139 
00140   //!Use this to set the PID value and weight
00141   void setPID(unsigned int i, const OutputPID& pid) {
00142     i-=PIDJointOffset;
00143     PIDs[i]=pid;
00144     dirty=true;
00145   }
00146 
00147   //!Use this if you want to double check the PID you set
00148   OutputPID& getPID(unsigned int i) {
00149     return PIDs[i-PIDJointOffset];
00150   }
00151 
00152   //!Use this if you want to double check the PID you set
00153   const OutputPID& getPID(unsigned int i) const {
00154     return PIDs[i-PIDJointOffset];
00155   }
00156 
00157 protected:
00158   //! returns true if the output i is a PID joint
00159   static inline bool isPID(unsigned int i) {
00160     return ((int)i>=(int)PIDJointOffset && i<PIDJointOffset+NumPIDJoints); //casting to int just to get rid of compiler warning.. sigh
00161   }
00162 
00163   bool dirty; //!< true if there are changes that have not been picked up by Motion
00164   bool completionReported; //!< true if we've reported completion of this motion command
00165   OutputPID PIDs[NumPIDJoints]; //!< the PIDs being requested
00166 };
00167 
00168 /*! @file
00169  * @brief Defines PIDMC, a nice little MotionCommand for manually manipulating the PID values
00170  * @author ejt (Creator)
00171  */
00172 
00173 #endif

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