00001
00002
00003
00004
00005
00006
00007
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)
00071 genes[i] = o.genes[i] + (o.genes[i] - genes[i]) * (1 - f);
00072 else
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;
00166 parameters.legPhase[3] = fmod(100 + g[1], 1.0);
00167 parameters.legPhase[1] = 0.5;
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(¶meters[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(
00282 (walkRequest.walkParams.translation.abs() > 50 ||
00283 fabs(walkRequest.walkParams.rotation) > 0.3) &&
00284 !sensorDataBuffer.lastFrame().data[SensorData::back])
00285 {
00286
00287 if(!evolutions && !currentIndividual && !currentFrame)
00288 setParameters((*population)[currentIndividual]);
00289
00290
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
00299 measured = Pose2D();
00300 target = Pose2D();
00301 }
00302
00303
00304 if(currentFrame == numOfFramesPerIndividual)
00305 {
00306
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
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
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
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
00352 currentIndividual = 0;
00353 }
00354 setParameters((*population)[currentIndividual]);
00355 currentFrame = 0;
00356 }
00357 }
00358 else
00359 currentFrame = 0;
00360
00361
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];
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
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
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528