Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

Modules/WalkingEngine/BB2004InvKinWalkingEngine.cpp

Go to the documentation of this file.
00001 /**
00002 * @file BB2004InvKinWalkingEngine.cpp
00003 * 
00004 * This file contains an approach to evolutionary algorithms based on 
00005 * a parameter set for the InvKinWalkingEngine.
00006 *
00007 * @author <a href="mailto:roefer@tzi.de">Thomas Röfer</a>
00008 */
00009 
00010 #include "BB2004InvKinWalkingEngine.h"
00011 #include "Platform/GTAssert.h"
00012 #include "Tools/Location.h"
00013 #include "Tools/Debugging/Debugging.h"
00014 #include "Tools/Debugging/GenericDebugData.h"
00015 
00016 static const double MAX_SPEED = 350,
00017                     MAX_ROT_SPEED = 2.24;
00018 
00019 double BBInvKinIndividual::geneScale[numOfGenes] =
00020 {
00021   200, 200, 200, 
00022   200, 200, 200,
00023   50, 50, 
00024   1, 1,
00025   1, 1, 1,
00026   50, 50,
00027   100,
00028   1, 1, 1, 
00029   1, 1, 1,
00030   0.5, 0.5,
00031   10, 10, 10
00032 };
00033 
00034 void BBInvKinIndividual::init(const BBIndividual& initial)
00035 {
00036   ASSERT(sizeof(geneScale) / sizeof(geneScale[0]) == numOfGenes);
00037   *this = (const BBInvKinIndividual&) initial;
00038   fitness = 1; 
00039   mutate();
00040 }
00041   
00042 void BBInvKinIndividual::interpolate(const BBIndividual& other)
00043 {
00044   const BBInvKinIndividual& o = (const BBInvKinIndividual&) other;
00045   for(int i = 0; i < numOfGenes; ++i)
00046   {
00047     double f = random(),
00048           f1 = f * fitness,
00049           f2 = (1 - f) * o.fitness;
00050     f = f1 / (f1 + f2);
00051     genes[i] = genes[i] * f + o.genes[i] * (1 - f);
00052   }
00053 }
00054 
00055 void BBInvKinIndividual::mutate()
00056 {
00057   for(int i = 0; i < numOfGenes; ++i)
00058     genes[i] += geneScale[i] * (-0.5 + random()) * 0.1;
00059 }
00060 
00061 void BBInvKinIndividual::extrapolate(const BBIndividual& other)
00062 {
00063   const BBInvKinIndividual& o = (const BBInvKinIndividual&) other;
00064   for(int i = 0; i < numOfGenes; ++i)
00065   {
00066     double f = random(),
00067            f1 = f * fitness,
00068            f2 = (1 - f) * o.fitness;
00069     f = f1 / (f1 + f2) * 2;
00070     if(f < 1) // other dominates
00071       genes[i] = o.genes[i] + (o.genes[i] - genes[i]) * (1 - f);
00072     else // this dominates
00073       genes[i] += (genes[i] - o.genes[i]) * (f - 1);
00074   }
00075 }
00076 
00077 void BBInvKinIndividual::setWalkCharacteristics(double speed, double smoothness)
00078 {
00079   this->speed = speed;
00080   this->smoothness = smoothness;
00081   fitness = exp((speed + smoothness) / 50);
00082 }
00083 
00084 BBInvKinIndividual::BBInvKinIndividual(const InvKinWalkingParameters& parameters)
00085 {
00086   double* g = &genes[0];
00087   *g++ = parameters.foreHeight;
00088   *g++ = parameters.foreWidth;
00089   *g++ = parameters.foreCenterX;
00090   
00091   *g++ = parameters.hindHeight;
00092   *g++ = parameters.hindWidth;
00093   *g++ = parameters.hindCenterX;
00094   
00095   *g++ = parameters.foreFootLift;
00096   *g++ = parameters.hindFootLift;
00097   
00098   *g++ = parameters.foreFootTilt;
00099   *g++ = parameters.hindFootTilt;
00100   
00101   *g++ = parameters.legSpeedFactorX;
00102   *g++ = parameters.legSpeedFactorY;
00103   *g++ = parameters.legSpeedFactorR;
00104   
00105   *g++ = parameters.maxStepSizeX;
00106   *g++ = parameters.maxStepSizeY;
00107   
00108   *g++ = parameters.stepLen;
00109   
00110   int i;
00111   for(i = 0; i < 2; ++i)
00112   {
00113     *g++ = parameters.groundPhase[i];
00114     *g++ = parameters.liftPhase[i];
00115     *g++ = parameters.loweringPhase[i];
00116   }
00117 
00118   *g++ = parameters.legPhase[0];
00119   *g++ = parameters.legPhase[3] - parameters.legPhase[0];
00120   
00121   *g++ = parameters.bodyShiftX;
00122   *g++ = parameters.bodyShiftY;
00123   *g++ = parameters.bodyShiftOffset;
00124   ASSERT(g - &genes[0] == numOfGenes);
00125 }
00126 
00127 void BBInvKinIndividual::getParameters(InvKinWalkingParameters& parameters) const
00128 {
00129   parameters.footMode = InvKinWalkingParameters::halfCircle;
00130   const double* g = &genes[0];
00131   parameters.foreHeight = *g++;
00132   parameters.foreWidth = *g++;
00133   parameters.foreCenterX = *g++;
00134   
00135   parameters.hindHeight = *g++;
00136   parameters.hindWidth = *g++;
00137   parameters.hindCenterX = *g++;
00138   
00139   parameters.foreFootLift = *g++;
00140   parameters.hindFootLift = *g++;
00141   
00142   parameters.foreFootTilt = *g++;
00143   parameters.hindFootTilt = *g++;
00144   
00145   parameters.legSpeedFactorX = *g++;
00146   parameters.legSpeedFactorY = *g++;
00147   parameters.legSpeedFactorR = *g++;
00148   
00149   parameters.maxStepSizeX = *g++;
00150   parameters.maxStepSizeY = *g++;
00151   
00152   ASSERT(g == &genes[15]);
00153   parameters.stepLen = int(*g++);
00154   
00155   parameters.counterRotation = 0;
00156   
00157   int i;
00158   for(i = 0; i < 2; ++i)
00159   {
00160     parameters.groundPhase[i] = *g++;
00161     parameters.liftPhase[i] = *g++;
00162     parameters.loweringPhase[i] = *g++;
00163   }
00164 
00165   parameters.legPhase[0] = 0; // fmod(100 + g[0], 1.0);
00166   parameters.legPhase[3] = fmod(100 + g[1], 1.0);
00167   parameters.legPhase[1] = 0.5; //fmod(100.5 + g[0], 1.0);
00168   parameters.legPhase[2] = fmod(100.5 + g[1], 1.0);
00169   g += 2;
00170   
00171   parameters.bodyShiftX = *g++;
00172   parameters.bodyShiftY = *g++;
00173   parameters.bodyShiftOffset = *g++;
00174   ASSERT(g - &genes[0] == numOfGenes);
00175 }
00176 
00177 void BBInvKinIndividual::dump() const
00178 {
00179   ERS7EvolveWalkingParameters temp;
00180   getParameters(temp);
00181   char buf[1000];
00182   OutTextMemory stream(buf);
00183   stream << temp;
00184   buf[stream.getLength()] = 0;
00185   getDebugOut().text << buf;
00186   getDebugOut().finishMessage(idText);
00187 }
00188 
00189 BB2004InvKinWalkingEngine::BB2004InvKinWalkingEngine(InvKinWalkingEngine* pEngine)
00190 : WalkingEngine(*pEngine),
00191   pEngine(pEngine),
00192   currentParameters(0),
00193   currentIndividual(0),
00194   currentFrame(0),
00195   evolutions(0),
00196   bestFitness(0),
00197   odometryScaleX(1),
00198   odometryScaleY(1),
00199   odometryScaleRotation(1),
00200   odometryCounterRotation(0)
00201 {
00202   loadParameters(forward, "forward");  
00203   loadParameters(fastForward, "fastForward");
00204   loadParameters(backward, "backward");
00205   loadParameters(stand, "stand");
00206   parameters[0] = parameters[1] = bestParameters = forward;
00207   population = new BBPopulation<BBInvKinIndividual>(numOfIndividuals, BBInvKinIndividual(bestParameters));
00208   InConfigFile stream("OdoScale.cfg", getRobotConfiguration().getRobotDesign() == RobotDesign::ERS210 ? "ERS210" : "ERS7");
00209   if(stream.exists())
00210     stream >> odometryScaleX >> odometryScaleY >> odometryScaleRotation >> odometryCounterRotation;
00211   buffer.init();
00212 }
00213 
00214 void BB2004InvKinWalkingEngine::setParameters(const BBIndividual& p)
00215 {
00216   currentParameters = 1 - currentParameters;
00217   ((const BBInvKinIndividual&) p).getParameters(parameters[currentParameters]);
00218   InvKinWalkingParameters& wp = parameters[currentParameters];
00219   wp.init();
00220   wp.leaveAnytime = true;
00221   wp.correctionValues.forward = wp.maxStepSizeX / MAX_SPEED;
00222   wp.correctionValues.backward = wp.maxStepSizeX / MAX_SPEED;
00223   wp.correctionValues.sideward = wp.maxStepSizeY / MAX_SPEED;
00224   wp.correctionValues.turning = wp.maxStepSizeR / MAX_ROT_SPEED;
00225   pEngine->setParameters(&parameters[currentParameters],64);
00226 }
00227 
00228 void BB2004InvKinWalkingEngine::loadParameters(InvKinWalkingParameters& parameters, const char* name)
00229 {
00230   char section[100];
00231   strcpy(section, getRobotConfiguration().getRobotDesign() == RobotDesign::ERS210 ? "ERS210_" : "ERS7_");
00232   strcat(section, name);
00233   InConfigFile stream("Walking.cfg", section);
00234   if(stream.exists())
00235   {
00236     stream >> parameters;
00237     parameters.init();
00238     double speed;
00239     stream >> speed;
00240     parameters.correctionValues.forward = parameters.maxStepSizeX / speed;
00241     stream >> speed;
00242     parameters.correctionValues.backward = parameters.maxStepSizeX / speed;
00243     stream >> speed;
00244     parameters.correctionValues.sideward = parameters.maxStepSizeY / speed;
00245     stream >> speed;
00246     parameters.correctionValues.turning = parameters.maxStepSizeR / speed;
00247     stream >> parameters.correctionValues.rotationCenter;
00248     parameters.leaveAnytime = true;
00249   }
00250 }
00251 
00252 bool BB2004InvKinWalkingEngine::executeParameterized(JointData& jointData,
00253                                                      const WalkRequest& walkRequest,
00254                                                      double positionInWalkingCycle)
00255 {
00256   if(!getDebugKeyTable().isActive(DebugKeyTable::learnWalking))
00257     if(currentIndividual || evolutions)
00258       pEngine->setParameters(&bestParameters, 64);
00259     else if(walkRequest.walkParams.translation.x < 0)
00260       pEngine->setParameters(&backward, 64);
00261     else if(walkRequest.walkParams.translation.x == 0 &&
00262             walkRequest.walkParams.translation.y == 0 &&
00263             walkRequest.walkParams.rotation == 0)
00264       pEngine->setParameters(&stand, 64);
00265     else
00266       pEngine->setParameters(&fastForward, 64);
00267   else 
00268     learn(walkRequest);
00269 
00270   Pose2D odometry = odometryData;
00271   bool result = pEngine->executeParameterized(jointData, walkRequest, positionInWalkingCycle);
00272 #ifndef _WIN32
00273   (Pose2D&) odometryData = odometry;
00274   updateOdometry();
00275 #endif
00276   return result;
00277 }
00278 
00279 void BB2004InvKinWalkingEngine::learn(const WalkRequest& walkRequest)
00280 {
00281   if(/*walkRequest.walkParams.translation.x > 0 &&*/
00282      (walkRequest.walkParams.translation.abs() > 50 ||
00283      fabs(walkRequest.walkParams.rotation) > 0.3) &&
00284      !sensorDataBuffer.lastFrame().data[SensorData::back])
00285   {
00286     // set walking parameters on first call
00287     if(!evolutions && !currentIndividual && !currentFrame)
00288       setParameters((*population)[currentIndividual]);
00289 
00290     // update sensor data history
00291     for(int i = 0; i < sensorDataBuffer.numOfFrames; ++i)
00292       if(sensorDataBuffer.frame[i].frameNumber > buffer[0].frameNumber)
00293         buffer.add(sensorDataBuffer.frame[i]);
00294 
00295 
00296     if(++currentFrame == ignoreFrames)
00297     {
00298       //reset
00299       measured = Pose2D();
00300       target = Pose2D();
00301     }
00302 
00303     // test of current individual finished?
00304     if(currentFrame == numOfFramesPerIndividual)
00305     {
00306       // calc fitness of individual
00307       BBInvKinIndividual& p = (BBInvKinIndividual&) (*population)[currentIndividual];
00308       double smoothness = (9e6 - stdV(SensorData::accelerationX) -
00309                                  stdV(SensorData::accelerationY) -
00310                                  stdV(SensorData::accelerationZ)) / 5e4,
00311              speed = 2100 - (fabs(measured.translation.x - target.translation.x) + 
00312                              fabs(measured.translation.y - target.translation.y) + 
00313                              fabs(measured.rotation - target.rotation) * 100);
00314 
00315       OUTPUT(idText, text, speed << " " << smoothness);
00316       p.setWalkCharacteristics(speed, smoothness);
00317 
00318       // test of population finished?
00319       if(++currentIndividual == numOfIndividuals)
00320       {
00321         const BBInvKinIndividual& best = (const BBInvKinIndividual&) population->getFittest();
00322         if(best.getFitness() > bestFitness)
00323         {
00324           best.getParameters(bestParameters);
00325           bestFitness = best.getFitness();
00326         }
00327         ++evolutions;
00328         OUTPUT(idText, text, "Generation " << evolutions << ", speed " << best.getSpeed() 
00329                << ", smoothness " << best.getSmoothness() << ", genes:");
00330         best.dump();
00331 
00332         // interchangingly interpolate and extrapolate
00333         if(evolutions & 1)
00334         {
00335           population->interpolate();
00336           getDebugOut().text << "Interpolating:";
00337         }
00338         else
00339         {
00340           population->extrapolate();
00341           getDebugOut().text << "Extrapolating:";
00342         }
00343         
00344         // print statistics
00345         Statistics& s = population->getStatistics();
00346         int num = s.analyze();
00347         for(int i = 0; i < num; ++i)
00348           getDebugOut().text << " " << s[i];
00349         getDebugOut().finishMessage(idText);
00350 
00351         // restart with first individual
00352         currentIndividual = 0;
00353       }
00354       setParameters((*population)[currentIndividual]);
00355       currentFrame = 0;
00356     }
00357   }
00358   else
00359     currentFrame = 0;
00360 
00361   // update target motion
00362   target.translation.x += walkRequest.walkParams.translation.x * motionCycleTime;
00363   target.translation.y += walkRequest.walkParams.translation.y * motionCycleTime;
00364   target.rotation += walkRequest.walkParams.rotation * motionCycleTime;
00365 }
00366 
00367 double BB2004InvKinWalkingEngine::stdV(SensorData::sensors s) const
00368 {
00369   int i;
00370   double sum = 0;
00371   for(i = 0; i < useFrames; ++i)
00372     sum += buffer[i].data[s];
00373   double average = sum / numOfFramesPerIndividual;
00374   sum = 0;
00375   for(i = 0; i < numOfFramesPerIndividual; ++i)
00376     sum += pow(buffer[i].data[s] - average, 2);
00377   return sqrt(sum / numOfFramesPerIndividual);
00378 }
00379 
00380 void BB2004InvKinWalkingEngine::updateOdometry()
00381 {
00382   if(receivedNewSensorData)
00383   {
00384     int i,
00385         leg;
00386     for(i = 0; i < sensorDataBuffer.numOfFrames; ++i)
00387     {
00388       const SensorData& s = sensorDataBuffer.frame[i];
00389       RobotVertices robotVertices;
00390       Kinematics::calcNeckAndLegPositions(s, robotVertices);
00391 
00392       FootPositions currentPositions;
00393       for(leg = 0; leg < 2; ++leg)
00394       {
00395         currentPositions.positions[leg] = robotVertices.footPosition[2 + leg];
00396         currentPositions.onGround[leg] = s.data[leg ? SensorData::pawHL : SensorData::pawHR] != 0;
00397       }
00398       for(leg = 0; leg < 2; ++leg)
00399       {
00400         Vector2<double> sum;
00401         Vector3<double> diff3d = currentPositions.positions[leg] - prevPositions.positions[leg]; // legs move in opposite direction than the robot
00402         Vector2<double> diff2d(diff3d.x, diff3d.y);
00403         if(prevPositions.onGround[leg] && currentPositions.onGround[leg])
00404           sum += diff2d;
00405         if(prevPositions.onGround[1 - leg] && currentPositions.onGround[1 - leg])
00406           sum -= diff2d;
00407         odometrySums[leg].add(sum);
00408       }
00409       prevPositions = currentPositions;
00410     }
00411     Vector2<double> sums[2];
00412     const InvKinWalkingParameters& p = pEngine->getParameters();
00413     for(leg = 0; leg < 2; ++leg)
00414       for(i = 0; i < p.stepLen; ++i)
00415         sums[leg] += odometrySums[leg][i];
00416     sums[0] /= 2;
00417     sums[1] /= 2;
00418     odometrySpeed.translation.x = -(sums[0].x + sums[1].x) * odometryScaleX;
00419     odometrySpeed.translation.y = -(sums[0].y + sums[1].y - sums[1].x + sums[0].x);
00420     odometrySpeed.rotation = (sums[1].x - sums[0].x) * odometryScaleRotation / p.hindWidth +
00421                              odometryCounterRotation * odometrySpeed.translation.y;
00422     odometrySpeed.translation.y *= odometryScaleY;
00423     odometrySpeed.translation /= p.stepLen;
00424     odometrySpeed.rotation /= p.stepLen;
00425   }
00426   odometryData += odometrySpeed;
00427 
00428   if(getDebugKeyTable().isActive(DebugKeyTable::learnWalking))
00429   {
00430     // update measured motion
00431     measured.translation.x += odometrySpeed.translation.x;
00432     measured.translation.y += odometrySpeed.translation.y;
00433     measured.rotation += odometrySpeed.rotation;
00434   }
00435 }
00436 
00437 bool BB2004InvKinWalkingEngine::handleMessage(InMessage& message)
00438 {
00439   switch(message.getMessageID())
00440   {
00441     case idOdometryScale:
00442     {
00443       GenericDebugData d;
00444       message.bin >> d;
00445       odometryScaleX = d.data[0];
00446       odometryScaleY = d.data[1];
00447       odometryScaleRotation = d.data[2];
00448       odometryCounterRotation = d.data[3];
00449       if(!odometryScaleX)
00450         odometryScaleX = 1;
00451       if(!odometryScaleY)
00452         odometryScaleY = 1;
00453       if(!odometryScaleRotation)
00454         odometryScaleRotation = 1;
00455       return true;
00456     }
00457   }
00458   return pEngine->handleMessage(message);
00459 }
00460 
00461 /*
00462  * Change log :
00463  * 
00464  * $Log: BB2004InvKinWalkingEngine.cpp,v $
00465  * Revision 1.8  2004/06/18 00:35:08  risler
00466  * only fastForward parameters
00467  *
00468  * Revision 1.7  2004/06/14 16:55:19  juengel
00469  * Removed some WalkingEngineParameterSets.
00470  *
00471  * Revision 1.6  2004/06/07 18:47:50  spranger
00472  * extended interface of executeParametrized by positionInWalkCycle
00473  *
00474  * Revision 1.5  2004/06/02 17:18:22  spranger
00475  * MotionRequest cleanup
00476  *
00477  * Revision 1.4  2004/05/27 12:51:14  roefer
00478  * Minor error fixed
00479  *
00480  * Revision 1.3  2004/05/26 20:18:44  juengel
00481  * local calculation of robotVertices
00482  *
00483  * Revision 1.2  2004/05/26 09:29:30  roefer
00484  * Remove redundant code
00485  *
00486  * Revision 1.5  2004/04/09 11:35:53  roefer
00487  * Bremen Byters German Open check-in
00488  *
00489  * Revision 1.4  2004/03/27 09:32:42  tim
00490  * changed parameter set selection limits
00491  *
00492  * Revision 1.3  2004/03/22 21:58:12  roefer
00493  * True odometry
00494  *
00495  * Revision 1.2  2004/03/11 00:05:38  roefer
00496  * OUTPUT removed
00497  *
00498  * Revision 1.1  2004/03/03 21:17:08  roefer
00499  * For the sake of consistency, renamed BB* to BB2004*
00500  *
00501  * Revision 1.9  2004/02/13 13:45:09  roefer
00502  * Mistakes corrected
00503  *
00504  * Revision 1.8  2004/02/06 20:23:00  roefer
00505  * Further improvements
00506  *
00507  * Revision 1.7  2004/02/04 07:57:20  roefer
00508  * Further improvements
00509  *
00510  * Revision 1.6  2004/01/28 21:55:49  roefer
00511  * RobotDimensions revised
00512  *
00513  * Revision 1.5  2004/01/05 22:59:53  roefer
00514  * Different parameters for ERS-210 and ERS-7
00515  *
00516  * Revision 1.4  2004/01/02 13:37:26  roefer
00517  * Handle if a single individual was drawn too often
00518  *
00519  * Revision 1.3  2004/01/01 10:26:08  roefer
00520  * Missing initialization added
00521  *
00522  * Revision 1.2  2003/12/29 21:46:49  roefer
00523  * Allow leaving the walking engine
00524  *
00525  * Revision 1.1  2003/12/29 15:48:54  roefer
00526  * Bremen Byters evo walking added
00527  *
00528  */

Generated on Thu Sep 23 19:57:33 2004 for GT2004 by doxygen 1.3.6