Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

CreateMotionModel.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef _CreateMotionModel_h_
00003 #define _CreateMotionModel_h_
00004 
00005 #include "Shared/RobotInfo.h"
00006 
00007 #ifdef TGT_IS_CREATE
00008 
00009 #include "Behaviors/BehaviorBase.h"
00010 #include "Shared/zignor.h"
00011 #include "Shared/Measures.h"
00012 #include "Shared/ParticleFilter.h"
00013 #include "Shared/WorldState.h"
00014 
00015 template<class ParticleT>
00016 class CreateMotionModel : public BehaviorBase, public ParticleFilter<ParticleT>::MotionModel {
00017 private:
00018   float lastdist;
00019   AngTwoPi lastang;
00020 
00021   /* mean and variance for added gaussian noise */
00022   float dmean;
00023   AngTwoPi amean;
00024   float ddvar, davar, aavar, advar;
00025 
00026   static const float minUpdateDistance;
00027   static const float minUpdateAngle;
00028 
00029 public:
00030   bool wasUpdated;
00031   
00032   typedef typename ParticleFilter<ParticleT>::MotionModel::particle_type particle_type;
00033   typedef typename ParticleFilter<ParticleT>::MotionModel::particle_collection particle_collection;
00034   typedef typename particle_collection::size_type index_t;
00035 
00036   //! Constructor
00037   CreateMotionModel(float dm=0.1f, float am=0.2f, float ddv=0.001f, float dav=0.001f, float aav=0.001f, float adv=0.000001f) :
00038     BehaviorBase("CreateMotionModel"), ParticleFilter<ParticleT>::MotionModel(),
00039     lastdist(state->sensors[EncoderDistanceOffset]),
00040     lastang(state->sensors[EncoderAngleOffset]/180*(float)M_PI),
00041     dmean(dm), amean(am), ddvar(ddv), davar(dav), aavar(aav), advar(adv),
00042     wasUpdated(false)
00043   {}
00044 
00045   float sampleNormal(float mean, float var) {
00046     // N(m,s^2) ~ s*N(0,1) + m
00047     return mean + (float)DRanNormalZig32()*std::sqrt(var);
00048   }
00049 
00050   virtual void updateMotion(particle_collection& particles, particle_type& estimate) {
00051     float dist = state->sensors[EncoderDistanceOffset];
00052     AngTwoPi ang = state->sensors[EncoderAngleOffset]/180*(float)M_PI;
00053 
00054     float dd = dist - lastdist;
00055     AngSignPi da = float(ang - lastang);
00056 
00057     // if we haven't moved far enough, don't bother moving the particles
00058     if (fabs(dd) < minUpdateDistance && fabs(da) < minUpdateAngle) {
00059       // std::cout << "Returning distance was not far enough\n";
00060       wasUpdated = false;
00061       return;
00062     }
00063 
00064     lastdist = dist;
00065     lastang = ang;
00066 
00067     // First update the estimate, using zero noise
00068     float dx, dy, dtheta;
00069     computeCreateMotion(dd, float(da), estimate.theta, dx, dy, dtheta);
00070     estimate.x += dx;
00071     estimate.y += dy;
00072     estimate.theta += dtheta;
00073 
00074     // Now  update the particles using our noise model
00075     for(typename particle_collection::iterator it=particles.begin(); it!=particles.end(); ++it) {
00076       // noise perturbed distance and angle travelled
00077       // Note: original code was:
00078       //
00079       //    float dnoise = sampleNormal(dmean*dd, ddvar*dd*dd + davar*da*da);
00080       //    float anoise = sampleNormal(amean*da, aavar*da*da + advar*dd*dd);
00081       //
00082       // but with current parameters, this caused a 10% distance
00083       // overshoot, while the actual robot seems to show a 3%
00084       // undershoot.  Also, for long turns (90 degrees) the angular
00085       // error was way too high.  So the version below gives zero mean
00086       // translational error; might replace this later with original
00087       // code plus better parameter settings.  Our trick doesn't work
00088       // for the angular component because if we don't command a turn,
00089       // the Create will always report 0 angular change so scaling by
00090       // da would zero the noise entirely.
00091 
00092       float dnoise, anoise;
00093       dnoise = dmean * dd * sampleNormal(0, ddvar*dd*dd + davar*da*da);
00094       anoise = float(amean) * sampleNormal(0, aavar*da*da + advar*dd*dd);
00095       float ddn = dd + dnoise;
00096       AngSignPi dan = float(da) + anoise;
00097       computeCreateMotion(ddn, float(dan), float(it->theta), dx, dy, dtheta);
00098       it->x += dx;
00099       it->y += dy;
00100       it->theta += dtheta;
00101     }
00102 
00103     wasUpdated = true;
00104   }
00105 
00106 
00107 private:
00108   // compute distance update for a given linear distance
00109   // and a given angular distance traveled
00110   virtual void computeCreateMotion(float len, float omega, float theta, float &dx, float &dy, float &dtheta) { 
00111     // check for linear motion
00112     if ( omega == 0 ) {
00113       dx = len*std::cos(theta);
00114       dy = len*std::sin(theta);
00115       dtheta = 0;
00116     }
00117     // curved motion, if len = 0, just rotation
00118     else {
00119       // solve for radius of circle
00120       // note that we don't need to use abs here
00121       // if len, omega are negative then we want r to be
00122       // negative because we are effectively flipping the circle
00123       float r = len / omega;
00124       
00125       // find new angles
00126       // would be this if theta was position around circle:
00127       //dx = r*cos(theta + omega) - r*cos(theta);
00128       //dy = r*sin(theta + omega) - r*sin(theta);
00129       // but it's actually the tangent to the circle,
00130       // so we shift by -pi/2 giving:
00131       dx = r*std::sin(theta + omega) - r*std::sin(theta);
00132       dy = -r*std::cos(theta + omega) + r*std::cos(theta);
00133       dtheta = omega;
00134     }
00135   }
00136 
00137 };
00138 
00139 template<class ParticleT> const float CreateMotionModel<ParticleT>::minUpdateDistance = 5.0f;    
00140 template<class ParticleT> const float CreateMotionModel<ParticleT>::minUpdateAngle = 0.05f;    
00141 
00142 #endif
00143 
00144 #endif
00145 

Tekkotsu v5.1CVS
Generated Fri Mar 16 05:26:36 2012 by Doxygen 1.6.3