00001
00002 #include "Tools/Math/PIDsmoothedValue.h"
00003 #include "GT2005WalkCalibrationBasicBehaviors.h"
00004 #include "Tools/Math/Geometry.h"
00005 #include "Tools/Math/Matrix2x2.h"
00006 #include "Tools/Math/Common.h"
00007
00008 #include "Tools/Debugging/DebugDrawings2.h"
00009 #include "Tools/Debugging/Debugging.h"
00010
00011 GT2005WalkCalibrationMainBehavior::GT2005WalkCalibrationMainBehavior(BehaviorControlInterfaces& interfaces, Xabsl2ErrorHandler& errorHandler)
00012 : Xabsl2BasicBehavior("walk-calibration", errorHandler),
00013 BehaviorControlInterfaces(interfaces)
00014
00015 {
00016 registerParameter("walk-calibration.initialize", initializeParameter);
00017 registerParameter("walk-calibration.rotation", rotationParameter);
00018
00019 result = resultUnready;
00020 state = stateNotInitialized;
00021 tempPoseCount = 0;
00022 startPoseCalculated = false;
00023 }
00024
00025 void GT2005WalkCalibrationMainBehavior::removeExtreme(bool *pBadIndex, bool removeMaximum)
00026 {
00027 int extremeIndex;
00028 double extremeSpeed;
00029 double tempSpeed;
00030
00031
00032 extremeIndex = -1;
00033
00034 if(removeMaximum)
00035 extremeSpeed = 0.0;
00036 else
00037 extremeSpeed = 1000000;
00038
00039
00040 for(int i = 0; i < tempPoseCount; i++)
00041 {
00042 if(!pBadIndex[i])
00043 {
00044 tempSpeed = pow(tempPose[i].translation.x, 2) + pow(tempPose[i].translation.y, 2);
00045 if(removeMaximum && tempSpeed > extremeSpeed)
00046 {
00047 extremeSpeed = tempSpeed;
00048 extremeIndex = i;
00049 }
00050 else if(!removeMaximum && tempSpeed < extremeSpeed)
00051 {
00052 extremeSpeed = tempSpeed;
00053 extremeIndex = i;
00054 }
00055 }
00056 }
00057 if(extremeIndex >= 0)
00058 pBadIndex[extremeIndex] = true;
00059 }
00060
00061
00062 void GT2005WalkCalibrationMainBehavior::execute()
00063 {
00064 if(initializeParameter)
00065 Initialize();
00066 else
00067 {
00068 bool performMeasure = true;
00069
00070 #ifdef _WIN32
00071 camRobotPose = robotPose;
00072 camTimestamp = SystemCall::getCurrentSystemTime();
00073 robotNotDetectedCount = 0;
00074
00075 #else
00076 camRobotPose = gtCamWorldState.getRobotPose(robotNumber, robotColor);
00077 camTimestamp = gtCamWorldState.getTimestamp();
00078 if((camRobotPose.translation.x == 0.0) &&
00079 (camRobotPose.translation.y == 0.0) &&
00080 (camRobotPose.rotation == 0.0))
00081 robotNotDetectedCount++;
00082 else
00083 robotNotDetectedCount = 0;
00084 #endif
00085
00086
00087 if(robotNotDetectedCount > 0)
00088 {
00089 state = stateMeasureStart;
00090 result = (robotNotDetectedCount >= 10) ? resultInteraction : resultReposition;
00091 performMeasure = false;
00092 OUTPUT(idText, text, "GTWalkCalibration: Robot not recognized or worldstate missing (" << robotNotDetectedCount << ". times)");
00093 }
00094
00095
00096 Vector2<double> temp = camRobotPose.translation;
00097 if(fabs(temp.y) > 1900 || temp.x > 2400 || temp.x < 0)
00098 {
00099 result = resultReposition;
00100 state = stateMeasureStart;
00101 startPoseBadCount++;
00102 performMeasure = false;
00103 OUTPUT(idText, text, "GTWalkCalibration: Robot out of measure arrea (" << startPoseBadCount << ". times)");
00104 }
00105
00106 if(performMeasure)
00107 Measure();
00108
00109
00110 if(startPoseBadCount >= 5)
00111 {
00112 OUTPUT(idText, text, "start pose was bad " << startPoseBadCount << " times in a row, requesting manual interaction");
00113 state = stateMeasureStart;
00114 result = resultInteraction;
00115 }
00116
00117
00118 if(result == resultReposition)
00119 {
00120 if(tempPoseCount > 0)
00121 {
00122 Pose2D mid;
00123
00124 for(int i=0;i< tempPoseCount; i++)
00125 {
00126 mid.translation.x += tempPose[i].translation.x;
00127 mid.translation.y += tempPose[i].translation.y;
00128 mid.rotation += tempPose[i].rotation;
00129 }
00130 mid.translation.x /= (double)tempPoseCount;
00131 mid.translation.y /= (double)tempPoseCount;
00132 mid.rotation /= (double)tempPoseCount;
00133
00134 startPose = calculateStartPose(mid);
00135 startPoseCalculated = true;
00136
00137 }
00138 else
00139 {
00140 startPose = calculateStartPose(measurePoints[currentPoint].controlled);
00141 startPoseCalculated = false;
00142 }
00143 startPoseAngle = toDegrees(startPose.rotation);
00144 }
00145 }
00146 }
00147
00148 void GT2005WalkCalibrationMainBehavior::Initialize()
00149 {
00150 OUTPUT(idText, text, "GTWalkCalibration: Initializing");
00151 state = stateMeasureStart;
00152 measureStatus = before;
00153 robotColor = getPlayer().getTeamColor();
00154 robotNumber = getPlayer().getPlayerNumber();
00155 currentTable = 0;
00156 currentPoint = 0;
00157 currentRotation = 0;
00158 startOffset = 2000.0;
00159 measureDuration = 4500.0;
00160 stopOffset = 500.0;
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 double measurePointsX[] = {-300, -250, -200, -150, -125, -100, -50, 0, 50, 100, 125, 150, 200, 250, 300};
00186 double measurePointsY[] = {-300, -250, -200, -150, -100, -50, 0, 50, 100, 150, 200, 250, 300};
00187 for(int i = 0; i < 15; i++)
00188 {
00189 for(int j = 0; j < 13; j++)
00190 {
00191 measurePoints[i * 13 + j].controlled = Pose2D(rotationParameter / 180.0 * pi, measurePointsX[i], measurePointsY[j]);
00192 }
00193 }
00194
00195 InBinaryFile file("_Measure.bin");
00196 if(file.exists())
00197 {
00198 Pose2D controlled;
00199 for(int i = 0; i < measureSize; i++)
00200 {
00201 if(file.eof())
00202 break;
00203
00204 file >> controlled;
00205
00206 if(controlled != measurePoints[i].controlled)
00207 {
00208 OUTPUT(idText, text, "controlled Points mismatch, cannot resume ");
00209 currentPoint = 0;
00210 break;
00211 }
00212
00213 if(file.eof())
00214 break;
00215
00216 file >> measurePoints[i].measured;
00217 currentPoint = i + 1;
00218 }
00219 if(currentPoint > 0)
00220 OUTPUT(idText, text, "GTWalkCalibration: resuming at measure #" << currentPoint);
00221
00222 sprintf(filename, "od_%i%s.dat", (int)fabs(rotationParameter), rotationParameter < 0 ? "m" : "");
00223 }
00224
00225 center.x = 1200.0;
00226 center.y = 0.0;
00227
00228 startPoseBadCount = 0;
00229 measureCount = 0;
00230 initializationTime = SystemCall::getCurrentSystemTime();
00231 result = resultReady;
00232 }
00233
00234
00235
00236 void GT2005WalkCalibrationMainBehavior::Measure()
00237 {
00238 switch(state)
00239 {
00240 case stateMeasureStart:
00241 {
00242 motionRequest.motionType = MotionRequest::walk;
00243 motionRequest.walkRequest.walkType = WalkRequest::normal;
00244 motionRequest.walkRequest.walkParams = Pose2D(0, 0, 0);
00245
00246 measureStartTime = camTimestamp + startOffset;
00247 measureStopTime = measureStartTime + measureDuration;
00248 rotationTemp = 0;
00249 tempPoseCount = 0;
00250
00251 double timePerMeasure, timeLeft;
00252 if(measureCount > 0)
00253 timePerMeasure = (SystemCall::getCurrentSystemTime() - initializationTime) / ((double)measureCount);
00254 else
00255 timePerMeasure = 0.0;
00256
00257 timeLeft = (measureSize - currentPoint) * timePerMeasure;
00258 OUTPUT(idText, text, "PWR: " << SystemCall::getRemainingPower() << "%, ETA: " << timeLeft / 1000.0 / 60.0 << "min");
00259
00260 OUTPUT(idText, text, "GTWalkCalibration: starting measure #" << currentPoint);
00261 state = stateMeasure;
00262 measureStatus = before;
00263 result = resultMeasure;
00264
00265
00266 qSum = 0.0;
00267 qCount = 0;
00268
00269 break;
00270 }
00271 case stateMeasure:
00272 {
00273 Pose2D request;
00274
00275 motionRequest.motionType = MotionRequest::walk;
00276 motionRequest.walkRequest.walkType = WalkRequest::normal;
00277 request = measurePoints[currentPoint].controlled;
00278
00279 request.translation.x /= 1.5;
00280 request.translation.y /= 1.5;
00281 request.rotation *= 1.5;
00282 motionRequest.walkRequest.walkParams = request;
00283
00284 if(measureStatus == measuring)
00285 {
00286 double qRms, qDist;
00287
00288
00289 qCount++;
00290 qDist = (center - camRobotPose.translation).abs();
00291 qSum += qDist * qDist;
00292 qRms = sqrt(qSum/(double)qCount);
00293
00294
00295
00296 if(!startPoseCalculated && qRms > 800.0 && tempPoseCount > 0)
00297 {
00298 result = resultReposition;
00299 state = stateMeasureStart;
00300 startPoseBadCount++;
00301 OUTPUT(idText, text, "start positioning was too bad(" << startPoseBadCount << "), repeating measure");
00302 break;
00303 }
00304
00305 if(qRms > 1000.0)
00306 {
00307 result = resultReposition;
00308 state = stateMeasureStart;
00309 startPoseBadCount++;
00310 OUTPUT(idText, text, "we are too far off(" << startPoseBadCount <<") !!");
00311 break;
00312 }
00313 }
00314
00315 if(camTimestamp >= measureStartTime && measureStatus == before)
00316 {
00317 translationStartPoint = camRobotPose.translation;
00318 rotationStartAngle = camRobotPose.rotation;
00319 tempTimeStart = measureStartTime = camTimestamp;
00320
00321 tempTime = measureStartTime + 400;
00322 measureStatus = measuring;
00323
00324
00325 measureStartTime0 = measureStartTime;
00326 translationStartPoint0 = translationStartPoint;
00327 rotationStartAngle0 = rotationStartAngle;
00328 }
00329 else if(camTimestamp >= tempTime && measureStatus == measuring)
00330 {
00331 translationStopPoint = camRobotPose.translation;
00332 rotationStopAngle = camRobotPose.rotation;
00333 tempTimeStop = camTimestamp;
00334
00335 if(tempTimeStart == tempTimeStop)
00336 {
00337 OUTPUT(idText, text, "GTWalkCalibration: measureStartTime = measureStopTime");
00338 state = stateMeasureStart;
00339 result = resultInteraction;
00340 break;
00341 }
00342
00343 double angle = rotationStartAngle;
00344 Vector2<double> robotx, roboty;
00345 double a, b;
00346 robotx.x = cos(angle);
00347 robotx.y = sin(angle);
00348 roboty.x = -robotx.y;
00349 roboty.y = robotx.x;
00350 a = ((translationStopPoint.x - translationStartPoint.x) * roboty.y
00351 + (translationStartPoint.y - translationStopPoint.y) * roboty.x)
00352 / (robotx.x * roboty.y - robotx.y * roboty.x);
00353 b = (translationStopPoint.y - translationStartPoint.y - a * robotx.y) / roboty.y;
00354 tempPose[tempPoseCount].translation.x = a / ((tempTimeStop - tempTimeStart) / 1000);
00355 tempPose[tempPoseCount].translation.y = b / ((tempTimeStop - tempTimeStart) / 1000);
00356 tempPose[tempPoseCount].rotation = normalize(rotationStopAngle - rotationStartAngle) / ((tempTimeStop - tempTimeStart) / 1000);
00357
00358 OUTPUT(idText, text, "GTWalkCalibration: rot(" << tempPoseCount << "): " << tempPose[tempPoseCount].rotation);
00359
00360
00361 translationStartPoint = camRobotPose.translation;
00362 rotationStartAngle = camRobotPose.rotation;
00363 tempTimeStart = camTimestamp;
00364 tempTime = tempTimeStart + 400;
00365
00366
00367 if(tempPoseCount < 49) tempPoseCount++;
00368 }
00369 if(camTimestamp >= measureStopTime && measureStatus == measuring)
00370 {
00371
00372 measureStopTime0 = camTimestamp;
00373 translationStopPoint0 = camRobotPose.translation;
00374 rotationStopAngle0 = camRobotPose.rotation;
00375
00376 state = stateMeasureFinished;
00377 result = resultMeasure;
00378 measureStatus = end;
00379 break;
00380 }
00381 break;
00382 }
00383 case stateMeasureFinished:
00384 {
00385 bool badIndex[measureSize];
00386
00387 OUTPUT(idText, text, " ");
00388 OUTPUT(idText, text, "GTWalkCalibration: finished measure #" << currentPoint);
00389
00390 for(int i = 0 ;i < measureSize; i++)
00391 badIndex[i] = false;
00392
00393 removeExtreme(badIndex, true);
00394 removeExtreme(badIndex, true);
00395 removeExtreme(badIndex, false);
00396 removeExtreme(badIndex, false);
00397
00398 measurePoints[currentPoint].measured = Pose2D(0, 0, 0);
00399 int dieNackteWahrheit = 0;
00400 for(int i = 0; i < tempPoseCount; i++)
00401 {
00402 if (badIndex[i])
00403 {
00404 OUTPUT(idText, text, "discarded index " << i);
00405 }
00406 else
00407 {
00408 measurePoints[currentPoint].measured.translation.x += tempPose[i].translation.x;
00409 measurePoints[currentPoint].measured.translation.y += tempPose[i].translation.y;
00410 measurePoints[currentPoint].measured.rotation += tempPose[i].rotation;
00411 dieNackteWahrheit++;
00412 }
00413
00414 }
00415 if(dieNackteWahrheit > 0)
00416 {
00417
00418 measurePoints[currentPoint].measured.translation.x /= dieNackteWahrheit;
00419 measurePoints[currentPoint].measured.translation.y /= dieNackteWahrheit;
00420 measurePoints[currentPoint].measured.rotation /= dieNackteWahrheit;
00421 }
00422 else
00423 {
00424 OUTPUT(idText, text, "Illegal value. Repeat measure.");
00425 result = resultReposition;
00426 state = stateMeasureStart;
00427 break;
00428 }
00429
00430 OUTPUT(idText, text, "count: " << dieNackteWahrheit);
00431
00432 OUTPUT(idText, text, "Controlled: " << measurePoints[currentPoint].controlled.translation.x << ", " << measurePoints[currentPoint].controlled.translation.y << ", " << measurePoints[currentPoint].controlled.rotation);
00433 OUTPUT(idText, text, "Measured: " << measurePoints[currentPoint].measured.translation.x << ", " << measurePoints[currentPoint].measured.translation.y << ", " << measurePoints[currentPoint].measured.rotation);
00434 if(qCount > 0)
00435 OUTPUT(idText, text, "Last rms error: " << sqrt(qSum/(double)qCount));
00436 OUTPUT(idText, text, "");
00437
00438
00439 currentPoint++;
00440 measureCount++;
00441
00442
00443
00444
00445 if(currentPoint < measureSize)
00446 {
00447
00448 OutBinaryFile file("_Measure.bin");
00449 for(int i = 0; i < currentPoint; i++)
00450 file << measurePoints[i].controlled << measurePoints[i].measured;
00451
00452 OUTPUT(idText, text, "GT2005 Walk-Calibration done measure #" << currentPoint - 1);
00453
00454 state = stateMeasureStart;
00455 result = resultReposition;
00456 startPoseBadCount = 0;
00457 }
00458 else
00459 {
00460 OutBinaryFile deleteFile("_Measure.bin");
00461 OutBinaryFile file(filename);
00462 for(int i = 0; i < measureSize; i++)
00463 file << measurePoints[i].controlled << measurePoints[i].measured;
00464
00465 OUTPUT(idText, text, "GT2005 Walk-Calibration finished");
00466 state = stateCalibrationFinished;
00467 result = resultUnready;
00468 }
00469 break;
00470 }
00471 case stateCalibrationFinished:
00472 OUTPUT(idText, text, "calibration finished.");
00473 result = resultUnready;
00474 state = stateCalibrationFinished;
00475 return;
00476
00477 case stateNotInitialized:
00478 OUTPUT(idText, text, "not yet initialized.");
00479 result = resultUnready;
00480 state = stateNotInitialized;
00481 return;
00482
00483 default:
00484 OUTPUT(idText, text, "unknown state " << state);
00485 result = resultUnready;
00486 return;
00487 }
00488 }
00489
00490
00491 double GT2005WalkCalibrationMainBehavior::minDistanceToBorder(Vector2<double>& t)
00492 {
00493 double dist;
00494
00495 if(t.x < 0.0 || t.x > 2400.0 || fabs(t.y) > 1900.0)
00496 return 0.0;
00497
00498 dist = fabs(2400.0 - t.x);
00499 dist = min(dist, t.x);
00500 dist = min(dist, 1900.0 - fabs(t.y));
00501
00502 return dist;
00503 }
00504
00505
00506 Pose2D GT2005WalkCalibrationMainBehavior::calculateStartPose(const Pose2D& base)
00507 {
00508 const int count = 9;
00509 double dist1, dist2, dist3;
00510 double maxDist1 = 0, minDist2 = 10000;
00511
00512 Pose2D bestPose;
00513 Pose2D pose[count];
00514
00515 for(double r = -pi; r <= pi; r += pi / 40.0)
00516 {
00517 for(int x = 100; x <= 2300; x += 200)
00518 {
00519 for(int y = -1800; y <= 1800; y += 200)
00520 {
00521 pose[0].rotation = r;
00522 pose[0].translation.x = x;
00523 pose[0].translation.y = y;
00524 dist1 = 10000.0;
00525 dist2 = 0.0;
00526
00527 for(int i = 1; i < count; i++)
00528 pose[i] = pose[i - 1] + base;
00529
00530
00531 for(int i = 0; i < count; i++)
00532 dist1 = min(dist1, minDistanceToBorder(pose[i].translation));
00533
00534
00535 if(count > 2)
00536 {
00537 for(int i = 2; i < count; i++)
00538 {
00539 double dist = (pose[i].translation - center).abs();
00540 dist2 += sqrt(dist*dist);
00541 }
00542 dist2 /= (double)(count - 2);
00543 }
00544
00545
00546 dist3 = (pose[0].translation - camRobotPose.translation).abs();
00547 dist2 += dist3 * 0.5;
00548
00549 if((dist1 > maxDist1)||
00550 (dist1 == maxDist1 && dist2 < minDist2))
00551 {
00552 maxDist1 = dist1;
00553 minDist2 = dist2;
00554 bestPose = pose[0];
00555 }
00556 }
00557 }
00558 }
00559
00560 pose[0] = bestPose;
00561 for(int i = 0; i < count; i++)
00562 {
00563 if(i == 0)
00564 {
00565 NCIRCLE("GT2005WalkCalibration:walkpath", pose[i].translation.x, pose[i].translation.y, 15,1,Drawings::ps_solid,Drawings::blue);
00566 }
00567 else
00568 {
00569 pose[i] = pose[i - 1] + base;
00570 NCIRCLE("GT2005WalkCalibration:walkpath", pose[i].translation.x, pose[i].translation.y, 15,1,Drawings::ps_solid,Drawings::white);
00571 }
00572 }
00573 NCROSS("GT2005WalkCalibration:walkpath", center.x, center.y, 50, 10, Drawings::ps_solid, Drawings::black);
00574
00575 return bestPose;
00576 }
00577
00578
00579
00580
00581 void GT2005WalkCalibrationMainBehavior::registerSymbols(Xabsl2Engine& engine)
00582 {
00583 engine.registerDecimalInputSymbol("walk-calibration.result", &result);
00584 engine.registerDecimalInputSymbol("walk-calibration.start.x", &startPose.translation.x);
00585 engine.registerDecimalInputSymbol("walk-calibration.start.y", &startPose.translation.y);
00586 engine.registerDecimalInputSymbol("walk-calibration.start.angle", &startPoseAngle);
00587 }
00588
00589 void GT2005WalkCalibrationBasicBehaviors::registerBasicBehaviors(Xabsl2Engine& engine)
00590 {
00591 engine.registerBasicBehavior(gt2005WalkCalibrationMainBehavior);
00592 gt2005WalkCalibrationMainBehavior.registerSymbols(engine);
00593 }
00594
00595
00596