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

Modules/BallLocator/GT2004BallLocator.cpp

Go to the documentation of this file.
00001 /**
00002 * @file GT2004BallLocator.cpp
00003 * Contains a BallLocator implementation using Kalman filtering
00004 *
00005 * @author <a href="mailto:stefanuhrig@gmx.net">Stefan Uhrig</a>
00006 */
00007 //------------------------------------------------------------------------------
00008 #include "GT2004BallLocator.h"
00009 #include "Tools/Debugging/Debugging.h"
00010 #include "Tools/Actorics/RobotDimensions.h"
00011 #include "Tools/FieldDimensions.h"
00012 #include "Platform/SystemCall.h"
00013 #include "Tools/Debugging/DebugDrawings.h"
00014 #include "Tools/Debugging/GT2004BallLocatorDebugData.h"
00015 #include "GT2004ProcessModels/FixedPositionModel.h"
00016 #include "GT2004ProcessModels/ConstantSpeedModel.h"
00017 //------------------------------------------------------------------------------
00018 double GT2004BallLocator::dFieldDiagonalLength =
00019   1.2*sqrt((2.0*xPosOpponentGoal)*(2.0*xPosOpponentGoal) +
00020            (2.0*yPosLeftFlags)*(2.0*yPosLeftFlags));
00021 //------------------------------------------------------------------------------
00022 GT2004BallLocator::GT2004BallLocator(BallLocatorInterfaces& interfaces)
00023  : BallLocator(interfaces)
00024   
00025 {
00026   // Initialise member variables
00027   bSendProcessModelStates = false;
00028   ballWasSeen = false;
00029   ballWasSeenInLastImage = false;
00030   x_abs = 0.0;
00031   y_abs = 0.0;
00032   x_rel = 0.0;
00033   y_rel = 0.0;
00034   vx_abs = 0.0;
00035   vy_abs = 0.0;
00036   vx_rel = 0.0;
00037   vy_rel = 0.0;
00038 
00039   // initializing the sliding average to 5 frames...
00040   //avx_rel.reset(5);
00041   //avy_rel.reset(5);
00042   
00043   // Add the models the filter is to work with
00044   // addModel(new KalmanFixedPositionModel);
00045   addModel(new KalmanConstantSpeedModel);
00046 
00047   // initializing some data for ball state information
00048   // used by setBallStateV2();
00049   freshDefend  = true;
00050   ballSensedPos.x = 0;
00051   ballSensedPos.y = 0;
00052   ballSensedTime = 0;
00053   ballSensedRelPos.x = 0;
00054   ballSensedRelPos.y = 0;
00055   last_seen_x_rel = 0;
00056   last_seen_y_rel = 0;
00057 }
00058 //------------------------------------------------------------------------------
00059 GT2004BallLocator::~GT2004BallLocator()
00060 {
00061   // Free the models
00062   destroyModels();
00063 }
00064 //------------------------------------------------------------------------------
00065 void GT2004BallLocator::execute()
00066 {
00067   Player::teamColor ownColor = getPlayer().getTeamColor();
00068   colorClass opponentGoalColor = ownColor == Player::red ? skyblue : yellow;
00069   ballModel.seen.ballInFrontOfOpponentGoal = false;
00070   if(landmarksPercept.numberOfGoals > 0)
00071   {
00072     double angleToBall = ballPercept.getAngleSizeBased();
00073     double ballDistance = ballPercept.getDistanceSizeBased();
00074     if(
00075       landmarksPercept.goals[0].color == opponentGoalColor &&
00076       ballPercept.ballWasSeen &&
00077       landmarksPercept.goals[0].x.min < angleToBall &&
00078       angleToBall < landmarksPercept.goals[0].x.max &&
00079       ballDistance < 1100
00080       )
00081     {
00082       ballModel.seen.ballInFrontOfOpponentGoal = true;
00083     }
00084   }
00085   
00086   static bool prevCameraMatrixUninitialized = true;
00087   if (prevCameraMatrixUninitialized && cameraMatrix.frameNumber != 0)
00088   {
00089     prevCameraMatrix = cameraMatrix;
00090     prevCameraMatrixUninitialized = false;
00091   }
00092 
00093   determineNumberOfImagesWith_WithoutBall();
00094   
00095   // calculate error (why?)
00096   double ballMeasurementError = 159.1 * tan(openingAngleHeight_ERS210/2)/176*3;
00097   ballModel.seen.distanceError = 
00098     ballMeasurementError *
00099     ballPercept.getDistance() * ballPercept.getDistance() /
00100     (ballRadius * 159.1 /* focal length ers219 */);
00101   ballModel.seen.angleError = 0.05;
00102 
00103   compensateOdometry();
00104 
00105   // Distinguish between seen and unseen ball
00106   if (ballPercept.ballWasSeen)
00107   {
00108     handleSeenBall();
00109     ballWasSeen = true;
00110   }
00111   else
00112   {
00113     handleUnseenBall();
00114     ballWasSeen = false;
00115   }
00116 
00117   // Set frame number
00118   ballModel.frameNumber = cameraMatrix.frameNumber;
00119 
00120   // Set ball state (none, rollByRight, rollByLeft)
00121   setBallState();
00122 //  setBallStateV2();
00123 
00124   // Send the results of the process models as debug messages
00125   if (bSendProcessModelStates)
00126     sendProcessModelStates();
00127 
00128   // Draw the ball position on the field
00129   drawBallPosition();
00130   
00131   prevCameraMatrix = cameraMatrix;
00132 
00133   // percept-part of balllocator
00134   if(ballPercept.ballWasSeen) // ball was seen
00135   {
00136     Vector2<double> ballOffset;
00137     ballPercept.getOffset(ballOffset);
00138 
00139     lastBallSeen = ballOffset;
00140   }
00141   else // ball was not seen
00142   {
00143     lastBallSeen = (lastRobotOdometry + Pose2D(lastBallSeen) - odometryData).translation;
00144   }
00145   
00146   ballModel.seen = 
00147     Geometry::relative2FieldCoord(robotPose, lastBallSeen.x, lastBallSeen.y); 
00148 
00149   lastRobotOdometry = odometryData;
00150 }
00151 //------------------------------------------------------------------------------
00152 void GT2004BallLocator::handleSeenBall()
00153 {
00154   int i;
00155 
00156   // If ball wasn't seen the last time, set the time the ball was seen first
00157   if (!ballWasSeen)
00158     ballModel.seen.timeWhenFirstSeenConsecutively 
00159     = SystemCall::getCurrentSystemTime();
00160 
00161   // Time in seconds
00162   double time = (double)SystemCall::getCurrentSystemTime() / 1000.0;
00163 
00164   // Get seen coordinates
00165   Vector2<double> ballOffset;
00166 //  ballPercept.getOffsetSizeBased(ballOffset);
00167   ballPercept.getOffset(ballOffset);
00168 
00169   // Ignore impossible coordinates
00170   if (isNonSensePos(ballOffset.x, ballOffset.y))
00171   {
00172     handleUnseenBall();
00173     return;
00174   }
00175 
00176   // Relative coordinates to robot in meter
00177   x_rel = ballOffset.x / 1000.0;
00178   y_rel = ballOffset.y / 1000.0;
00179 
00180   Vector3<double> vectorInDirectionOfViewCamera(1,0,0);
00181   Vector3<double> vectorInDirectionOfViewWorld, vectorInDirectionOfViewWorldOld;
00182   vectorInDirectionOfViewWorld = cameraMatrix.rotation * vectorInDirectionOfViewCamera;
00183   vectorInDirectionOfViewWorldOld = prevCameraMatrix.rotation * vectorInDirectionOfViewCamera;
00184   long frameNumber = cameraMatrix.frameNumber, 
00185     prevFrameNumber = prevCameraMatrix.frameNumber;
00186   const RobotDimensions& r = getRobotConfiguration().getRobotDimensions();
00187   double timeDiff = (frameNumber - prevFrameNumber) * r.motionCycleTime; // in seconds
00188   Vector2<double> currentOnGround(vectorInDirectionOfViewWorld.x, vectorInDirectionOfViewWorld.y), 
00189       oldOnGround(vectorInDirectionOfViewWorldOld.x, vectorInDirectionOfViewWorldOld.y);
00190   currentOnGround.normalize();
00191   oldOnGround.normalize();
00192   double panningVelocity = 0;
00193   if (timeDiff > 0)
00194   {
00195     double cosAng = currentOnGround*oldOnGround;
00196     if (cosAng > 1.0)
00197       cosAng = 1.0;
00198     else
00199     if (cosAng < -1.0)
00200       cosAng = -1.0;
00201     panningVelocity = fabs(normalize(acos(cosAng))/timeDiff);    
00202   }
00203   // Update process models
00204   double liklihoodSum = 0.0;
00205   try
00206   {
00207     for (i = 0; i < (int)kalmanModels.size(); ++i)
00208     {
00209       // check if the model is used
00210       if (!kalmanModels[i]->useModel())
00211         continue;
00212       
00213       // Send change of odometry to model
00214       kalmanModels[i]->adapt(lastOdometry, odometryData);
00215 
00216       // Do update and save result
00217       kalmanUpdateResults[i] = kalmanModels[i]->update(time, x_rel, y_rel, robotPose, panningVelocity);
00218       liklihoodSum += kalmanUpdateResults[i].liklihood;
00219 
00220       // Reset process model if result is not good
00221       if (kalmanModels[i]->isNonSensePos(kalmanUpdateResults[i].state.x,
00222                                          kalmanUpdateResults[i].state.y))
00223         kalmanModels[i]->reset();
00224     }
00225   }
00226   catch (...)
00227   {
00228     // Here we should never end, but better safe than sorry
00229     OUTPUT(idText, text,
00230            "Unknown Exception in GT2004BallLocator::handleSeenBall");
00231     setUnknownResult();
00232     return;
00233   }
00234   lastOdometry = odometryData;
00235 
00236   // Get weighted position and speed
00237   if (liklihoodSum != 0.0)
00238   {
00239     x_rel = 0.0;
00240     y_rel = 0.0;
00241     vx_rel = 0.0;
00242     vy_rel = 0.0;
00243     double probability;
00244 
00245     //std::vector<KalmanUpdateResult>::iterator pos;
00246     /*
00247     for (pos = kalmanUpdateResults.begin();
00248          pos != kalmanUpdateResults.end();
00249          ++pos)
00250     */
00251     for (i = 0; i < (int)kalmanModels.size(); ++i)
00252     {
00253       if (!kalmanModels[i]->useModel())
00254         continue;
00255 
00256       std::vector<KalmanUpdateResult>::iterator pos =
00257         kalmanUpdateResults.begin() + i;
00258       if (pos->liklihood != 0.0)
00259         probability = pos->liklihood = pos->liklihood / liklihoodSum;
00260       else
00261         probability = 0.0;
00262       x_rel += pos->state.x * probability;
00263       y_rel += pos->state.y * probability;
00264       vx_rel += pos->state.vx * probability;
00265       vy_rel += pos->state.vy * probability;
00266     }
00267 
00268     // Change meter to millimeter and meter per second to millimeter per second
00269     x_rel *= 1000.0;
00270     y_rel *= 1000.0;
00271     vx_rel *= 1000.0;
00272     vy_rel *= 1000.0;
00273 
00274     // Save last seen position
00275     last_seen_x_rel = x_rel;
00276     last_seen_y_rel = y_rel;
00277 
00278     // Translate relative coordinates to robot into field coordinates
00279     ballOffset = Geometry::relative2FieldCoord(robotPose, x_rel, y_rel);
00280     x_abs = ballOffset.x;
00281     y_abs = ballOffset.y;
00282     vx_abs =  vx_rel*cos(robotPose.rotation) + vy_rel*sin(robotPose.rotation); 
00283     vy_abs = -vx_rel*sin(robotPose.rotation) + vy_rel*cos(robotPose.rotation);
00284     
00285     // Set seen ball data
00286     ballModel.seen = ballOffset;
00287     
00288     // changed to relative values
00289     ballModel.seen.speed.x = vx_rel;
00290     ballModel.seen.speed.y = vy_rel;
00291 
00292     // Set the propagated data, too
00293     ballModel.propagated.timeOfObservation = SystemCall::getCurrentSystemTime();
00294     ballModel.propagated.x = ballOffset.x;
00295     ballModel.propagated.y = ballOffset.y;
00296     ballModel.propagated.positionWhenLastObserved = ballOffset;
00297     
00298     // changed to relative values
00299     ballModel.propagated.observedSpeed.x = vx_rel;
00300     ballModel.propagated.observedSpeed.y = vy_rel;
00301   }
00302   else
00303   {
00304     // Probably process models are not initialised yet
00305 
00306     // Change meter to millimeter
00307     x_rel *= 1000.0;
00308     y_rel *= 1000.0;
00309 
00310     // Translate relative coordinates to robot into field coordinates
00311     ballOffset = Geometry::relative2FieldCoord(robotPose, x_rel, y_rel);
00312     x_abs = ballOffset.x;
00313     y_abs = ballOffset.y;
00314     vx_rel = 0.0;
00315     vy_rel = 0.0;
00316     vx_abs = 0.0;
00317     vy_abs = 0.0;
00318     
00319     // Set seen (=measured) ball position, speed is unknown
00320     ballModel.seen = ballOffset;
00321     ballModel.seen.speed.x = 0.0;
00322     ballModel.seen.speed.y = 0.0;
00323   }
00324 
00325   // Set times
00326   ballModel.seen.timeWhenLastSeen = SystemCall::getCurrentSystemTime();
00327   ballModel.seen.timeUntilSeenConsecutively = SystemCall::getCurrentSystemTime();
00328 }
00329 //------------------------------------------------------------------------------
00330 void GT2004BallLocator::handleUnseenBall()
00331 {
00332   // Use predict function of the models to predict the position and
00333   // speed of the ball
00334 
00335   // Time in seconds
00336   double time = (double)SystemCall::getCurrentSystemTime() / 1000.0;
00337   
00338   int i;
00339   double liklihoodSum = 0.0;
00340   try
00341   {
00342     for (i = 0; i < (int)kalmanModels.size(); ++i)
00343     {
00344       // Check if model is used
00345       if (!kalmanModels[i]->useModel())
00346         continue;
00347       
00348       // Send change of odometry to model
00349       kalmanModels[i]->adapt(lastOdometry, odometryData);
00350 
00351       // Predict next state
00352       kalmanPredictResults[i] = kalmanModels[i]->predict(time);
00353       liklihoodSum += kalmanPredictResults[i].liklihood;
00354 
00355       // Reset process model if results are not good
00356       if (kalmanModels[i]->isNonSensePos(kalmanPredictResults[i].state.x,
00357                                          kalmanPredictResults[i].state.y))
00358         kalmanModels[i]->reset();
00359     }
00360   }
00361   catch (...)
00362   {
00363     // Here we should never end, but better safe than sorry
00364     OUTPUT(idText, text,
00365            "Unknown Exception in GT2004BallLocator::handleUnseenBall");
00366     setUnknownResult();
00367     return;
00368   }
00369   lastOdometry = odometryData;
00370 
00371   // Get weighted position and speed
00372   if (liklihoodSum != 0.0)
00373   {
00374     x_rel = 0.0;
00375     y_rel = 0.0;
00376     vx_rel = 0.0;
00377     vy_rel = 0.0;
00378     double probability;
00379 
00380     /*
00381     std::vector<KalmanPredictResult>::iterator pos;
00382     for (pos = kalmanPredictResults.begin();
00383          pos != kalmanPredictResults.end();
00384          ++pos)
00385     */
00386     for (i = 0; i < (int)kalmanModels.size(); ++i)
00387     {
00388       if (!kalmanModels[i]->useModel())
00389         continue;
00390 
00391       std::vector<KalmanPredictResult>::iterator pos =
00392         kalmanPredictResults.begin() + i;
00393       
00394       if (pos->liklihood != 0.0)
00395         probability = pos->liklihood = pos->liklihood / liklihoodSum;
00396       else
00397         probability = 0.0;
00398       x_rel += pos->state.x * probability;
00399       y_rel += pos->state.y * probability;
00400       vx_rel += pos->state.vx * probability;
00401       vy_rel += pos->state.vy * probability;
00402     }
00403 
00404     // Change meter to millimeter and meter per second to millimeter per second
00405     x_rel *= 1000.0;
00406     y_rel *= 1000.0;
00407     vx_rel *= 1000.0;
00408     vy_rel *= 1000.0;
00409 
00410     // Translate relative coordinates to robot into field coordinates
00411     Vector2<double> ballOffset =
00412       Geometry::relative2FieldCoord(robotPose, x_rel, y_rel);
00413     x_abs = ballOffset.x;
00414     y_abs = ballOffset.y;
00415     vx_abs =  vx_rel*cos(robotPose.rotation) + vy_rel*sin(robotPose.rotation); 
00416     vy_abs = -vx_rel*sin(robotPose.rotation) + vy_rel*cos(robotPose.rotation);
00417 
00418     // Set estimated position
00419     ballModel.propagated.x = ballOffset.x;
00420     ballModel.propagated.y = ballOffset.y;
00421   }
00422   else
00423   {
00424     // Probably process models are not initialised yet
00425     
00426     // Get time difference in seconds
00427     double dt = (SystemCall::getCurrentSystemTime() -
00428                  ballModel.propagated.timeOfObservation) / 1000.0;
00429     
00430     // Assume the ball is moving equally and set estimated position
00431     ballModel.propagated.x =
00432       ballModel.propagated.positionWhenLastObserved.x + 
00433       ballModel.propagated.observedSpeed.x*dt;
00434     ballModel.propagated.y =
00435       ballModel.propagated.positionWhenLastObserved.y + 
00436       ballModel.propagated.observedSpeed.y*dt;
00437   }
00438 
00439   // write last seen position to seen ball
00440   Vector2<double> ballOnField = 
00441     Geometry::relative2FieldCoord(robotPose, last_seen_x_rel, last_seen_y_rel);
00442   ballModel.seen.x = ballOnField.x;
00443   ballModel.seen.y = ballOnField.y;
00444 }
00445 //------------------------------------------------------------------------------
00446 void GT2004BallLocator::compensateOdometry()
00447 {
00448   Vector2<double> lastBallSeenRelative
00449     = (lastOdometry +
00450        Pose2D(last_seen_x_rel,last_seen_y_rel) -
00451        odometryData).translation;
00452   last_seen_x_rel = lastBallSeenRelative.x;
00453   last_seen_y_rel = lastBallSeenRelative.y;
00454 
00455   //~ lastOdometry = odometryData;
00456 }        
00457 //------------------------------------------------------------------------------
00458 void GT2004BallLocator::setBallState()
00459 {
00460   ballModel.ballState.reset();
00461 
00462   // Ball must be approaching faster than 50 millimeters per second
00463   if (vx_rel > -50.0)
00464     return;
00465 
00466   // Calculate y-position (side) of ball when the ball has the same height
00467   // as the robot und set appropriate ball state
00468   ballModel.ballState.projectedDistanceOnYAxis = y_rel - (vy_rel/vx_rel)*x_rel;
00469 
00470   ballModel.ballState.timeBallCrossesYAxis = (long)(ballModel.ballState.projectedDistanceOnYAxis / vx_rel) * 1000; // mm/s to mm/ms
00471  
00472   // Ball must be nearer than 1 meter
00473   double dist = sqrt(x_rel*x_rel + y_rel*y_rel);
00474   if (dist > 1000.0)
00475     return;
00476   
00477   if ((ballModel.ballState.projectedDistanceOnYAxis < -100.0) 
00478       && (ballModel.ballState.projectedDistanceOnYAxis > -500.0))
00479   {
00480     ballModel.ballState.ballRollsByRight = true;
00481   }
00482   else if ((ballModel.ballState.projectedDistanceOnYAxis > 100.0) 
00483       && (ballModel.ballState.projectedDistanceOnYAxis < 500.0))
00484   {
00485     ballModel.ballState.ballRollsByLeft = true;
00486   }
00487   else if ((ballModel.ballState.projectedDistanceOnYAxis >= -100.0) 
00488       && (ballModel.ballState.projectedDistanceOnYAxis <= 100.0))
00489   {
00490     ballModel.ballState.ballRollsTowardsRobot = true;
00491   }
00492 }
00493 //------------------------------------------------------------------------------
00494 void GT2004BallLocator::setBallStateV2()
00495 {
00496   // some constants
00497 
00498   static int const defendZone1Border = 550;
00499   static int const defendZone2Border = 1000; // should be at least greater defendZone1Border+100
00500   static int const defendZone3Border = 1000;
00501 
00502   static double const ballHasMovedThreshold = 20.0;
00503 
00504 //  not used in the moment...
00505 //  static double const ballIsFastThreshold = 500;
00506 
00507   static unsigned long const speedTrigger = 1000;
00508 
00509   /**
00510   *   Meanings of the constants:
00511   *
00512   *   If the ball is farer away than defendZone2Border from the robot
00513   *   then freshDefend is set to true. This is just a kind of hysteresis
00514   *   to reset the "sensing" for the ballStates.
00515   *
00516   *   To sense a ball state, the ball has to be detected first in a range
00517   *   smaller than defendZone2Border, and after that in a range smaller than
00518   *   defendZone1Border. The maximum time between the detections in zone2 and
00519   *   zone1 has to be smaller than speedTrigger (in ms). 
00520   *
00521   *   The ballHasMovedThreshold is used to determine, if the ball has moved
00522   *   or the robot, since only relative ball positions are used. The difference
00523   *   between the absolute ball positions in zone2 and zone1 has to be greater
00524   *   than this threshold to identify the ball as moving, rather than the robot.
00525   *
00526   *   The ballIsFastThreshold is used to determine if the ball rolls fast.
00527   *   Value is mm/s.
00528   */
00529   
00530   ballModel.ballState.reset();
00531 
00532   // getting some ball information...
00533   double ballRelDist = 
00534     Geometry::distanceTo(robotPose.getPose(),ballModel.seen);
00535 
00536   Vector2<double> ballRelPos;
00537   ballRelPos.x = ballRelDist * 
00538     cos(Geometry::angleTo(robotPose.getPose(),ballModel.seen));
00539   ballRelPos.y = ballRelDist * 
00540     sin(Geometry::angleTo(robotPose.getPose(),ballModel.seen));
00541 
00542   double ballRelAngle = toDegrees(Geometry::angleTo(robotPose.getPose(),
00543     ballModel.seen));
00544 
00545   if ((ballRelDist > (defendZone1Border+100)) && (ballRelDist < defendZone2Border))
00546   { 
00547     ballSensedPos = ballModel.seen;
00548 
00549     ballSensedRelPos = ballRelPos;
00550     if ((ballRelAngle > -90) && (ballRelAngle <= 90))
00551       ballSensedTime = SystemCall::getCurrentSystemTime();
00552   }
00553 
00554   if (ballRelDist > defendZone3Border) {
00555     freshDefend  = true;
00556   }
00557 
00558   double side;
00559   side = ballSensedRelPos.y + (ballSensedRelPos.x / (ballRelPos.x - ballSensedRelPos.x))*(ballRelPos.y - ballSensedRelPos.y);
00560   ballModel.ballState.projectedDistanceOnYAxis = side;
00561   ballModel.ballState.timeBallCrossesYAxis = (long)(ballModel.ballState.projectedDistanceOnYAxis / vx_rel) * 1000; // mm/s to mm/ms
00562   if (    (ballRelAngle > -90)
00563        && (ballRelAngle <  90)
00564        && (ballRelDist  <  defendZone1Border)
00565        && (freshDefend == true))
00566   {
00567     freshDefend = false;
00568     unsigned long travelTime = SystemCall::getCurrentSystemTime() - ballSensedTime;
00569     double travelDist = (ballSensedPos - ballModel.seen).abs();
00570     if (    (travelTime <  speedTrigger)
00571          && (ballSensedRelPos.x - ballRelPos.x  >= 1)
00572          && (travelDist > ballHasMovedThreshold)
00573        )
00574     {
00575       if ((side > -150) && (side < 150))
00576         ballModel.ballState.ballRollsTowardsRobot = true;
00577       else if ((side > -500) && (side <= -150))
00578         ballModel.ballState.ballRollsByRight = true;
00579       else if ((side >= 150) && (side < 500))
00580         ballModel.ballState.ballRollsByLeft = true;
00581     }
00582   }
00583 
00584   // determining ballModel.ballState.ballRollsFast is not done yet...
00585 
00586 }
00587 //------------------------------------------------------------------------------
00588 void GT2004BallLocator::setUnknownResult()
00589 {
00590   // Sets the result to the last known results
00591   ballModel.propagated.x = x_abs;
00592   ballModel.propagated.y = y_abs;
00593 }
00594 //------------------------------------------------------------------------------
00595 bool GT2004BallLocator::isNonSensePos(double x, double y)
00596 {
00597   double dist = sqrt(x*x + y*y);
00598   if (dist > dFieldDiagonalLength)
00599     return true;
00600   else
00601     return false;
00602 }
00603 //------------------------------------------------------------------------------
00604 void GT2004BallLocator::addModel(KalmanProcessModelBase* pModel)
00605 {
00606   // Add the model and make room in the result vectors
00607   kalmanModels.push_back(pModel);
00608   kalmanUpdateResults.push_back(KalmanUpdateResult());
00609   kalmanPredictResults.push_back(KalmanPredictResult());
00610 }
00611 //------------------------------------------------------------------------------
00612 void GT2004BallLocator::destroyModels()
00613 {
00614   // Free the models
00615   std::vector<KalmanProcessModelBase*>::iterator pos;
00616   for (pos = kalmanModels.begin(); pos != kalmanModels.end(); ++pos)
00617     delete *pos;
00618 }
00619 //------------------------------------------------------------------------------
00620 bool GT2004BallLocator::handleMessage(InMessage& message)
00621 {
00622   // Handle only GT2004Data messages
00623   if (message.getMessageID() != idGT2004BallLocatorData)
00624     return false;
00625 
00626   // Get type of action
00627   char action;
00628   message.bin >> action;
00629 
00630   switch (action)
00631   {
00632     case GT2004BallLocatorDebugData::idRequestParameters:
00633     {
00634       // Parameters of the process models were requested
00635 
00636       // Start message and send number of models
00637       getDebugOut().bin << (char)GT2004BallLocatorDebugData::idSendingParameters 
00638                         << kalmanModels.size();
00639       
00640       // Send the data of the models
00641       std::vector<KalmanProcessModelBase*>::iterator pos;
00642       for (pos = kalmanModels.begin(); pos != kalmanModels.end(); ++pos)
00643         (*pos)->toStream(getDebugOut().bin);
00644       
00645       // Finish message
00646       getDebugOut().finishMessage(idGT2004BallLocatorData);
00647     }
00648     return true;
00649 
00650     case GT2004BallLocatorDebugData::idSetParameters:
00651     {
00652       // The parameters of a model are to be set
00653 
00654       // Read index of the model
00655       int modelIndex;
00656       message.bin >> modelIndex;
00657       
00658       // Set data of the model
00659       kalmanModels[modelIndex]->fromStream(message.bin);
00660     }
00661     return true;
00662   }
00663 
00664   // Message is unknown, reset position in queue
00665   message.resetReadPosition();
00666   return false;
00667 }
00668 //------------------------------------------------------------------------------
00669 void GT2004BallLocator::sendProcessModelStates()
00670 {
00671   // Get debug stream
00672   OutMessage& stream = getDebugOut();
00673 
00674   // Write ID of message
00675   stream.bin << (char)GT2004BallLocatorDebugData::idFilterState;
00676   
00677   // Time stamp of the data
00678   stream.bin << SystemCall::getCurrentSystemTime();
00679 
00680   // Write robot position
00681   stream.bin << robotPose;
00682 
00683   // Write relative coordinates and speeds
00684   // (in millimeters and millimeters per second)
00685   stream.bin << x_rel << y_rel;
00686   stream.bin << vx_rel << vy_rel;
00687 
00688   // Write if ball was seen or not
00689   stream.bin << (char)ballWasSeen;
00690 
00691   // Write number of models
00692   stream.bin << kalmanUpdateResults.size();
00693   
00694   // Write result of models
00695   std::vector<KalmanUpdateResult>::const_iterator urpos;
00696   std::vector<KalmanPredictResult>::const_iterator prpos;
00697   std::vector<KalmanProcessModelBase*>::const_iterator mpos;
00698   for (mpos = kalmanModels.begin(),
00699          urpos = kalmanUpdateResults.begin(),
00700          prpos = kalmanPredictResults.begin();
00701        mpos != kalmanModels.end();
00702        ++mpos, ++urpos, ++prpos)
00703   {
00704     
00705     if (ballWasSeen)
00706     {
00707       // Write position in millimeters
00708       stream.bin << urpos->state.x*1000.0 << urpos->state.y*1000.0;
00709       // Write speed in millimeters per second
00710       stream.bin << urpos->state.vx*1000.0 << urpos->state.vy*1000.0;
00711       // Write probability (weight was converted to probability)
00712       stream.bin << urpos->liklihood;
00713     }
00714     else
00715     {
00716       // Write position in millimeters
00717       stream.bin << prpos->state.x*1000.0 << prpos->state.y*1000.0;
00718       // Write speed in millimeters per second
00719       stream.bin << prpos->state.vx*1000.0 << prpos->state.vy*1000.0;
00720       // Write probability (weight was converted to probability)
00721       stream.bin << prpos->liklihood;
00722     }
00723 
00724     // Write dimensioni of state
00725     int n = (*mpos)->getStateDim();
00726     stream.bin << n;
00727     
00728     // Write internal covarinace matrix of process model
00729     double* M = new double[n*n];
00730     (*mpos)->getP(M);
00731     int i;
00732     for (i = 0; i < n*n; ++i)
00733       stream.bin << M[i];
00734     delete [] M;
00735   }
00736   
00737   // Finish message
00738   stream.finishMessage(idGT2004BallLocatorData);
00739 }
00740 //------------------------------------------------------------------------------
00741 void GT2004BallLocator::drawBallPosition()
00742 {
00743   // Draw global positions
00744   if (ballWasSeen)
00745   {
00746     CIRCLE(ballLocatorField, x_abs, y_abs, 90, 3, 0, Drawings::orange);
00747     LINE(ballLocatorField, x_abs, y_abs, 
00748          x_abs + vx_abs*3, y_abs + vy_abs*3,
00749          3, 0, Drawings::orange);
00750   }
00751   else
00752   {
00753     CIRCLE(ballLocatorField, x_abs, y_abs, 90, 3, 0, Drawings::blue);
00754     LINE(ballLocatorField, x_abs, y_abs, 
00755          x_abs + vx_abs*3, y_abs + vy_abs*3,
00756          3, 0, Drawings::blue);
00757   }
00758 
00759   // Draw positions of models
00760   std::vector<KalmanUpdateResult>::const_iterator urpos;
00761   std::vector<KalmanPredictResult>::const_iterator prpos;
00762   std::vector<KalmanProcessModelBase*>::const_iterator mpos;
00763   for (mpos = kalmanModels.begin(),
00764          urpos = kalmanUpdateResults.begin(),
00765          prpos = kalmanPredictResults.begin();
00766        mpos != kalmanModels.end();
00767        ++mpos, ++urpos, ++prpos)
00768   {
00769     
00770     if (ballWasSeen)
00771     {
00772       // Calculate field coordinates
00773       Vector2<double> ballOffset =
00774         Geometry::relative2FieldCoord(robotPose, urpos->state.x*1000.0,
00775                                       urpos->state.y*1000.0);
00776       CIRCLE(ballLocatorField, ballOffset.x, ballOffset.y,
00777              60, 2, 0, Drawings::yellowOrange);
00778     }
00779     else
00780     {
00781       // Calculate field coordinates
00782       Vector2<double> ballOffset =
00783         Geometry::relative2FieldCoord(robotPose, prpos->state.x*1000.0,
00784                                       prpos->state.y*1000.0);
00785       CIRCLE(ballLocatorField, ballOffset.x, ballOffset.y,
00786              60, 2, 0, Drawings::skyblue);
00787     }
00788   }  
00789   
00790   DEBUG_DRAWING_FINISHED(ballLocatorField);
00791 }
00792 //------------------------------------------------------------------------------
00793 void GT2004BallLocator::determineNumberOfImagesWith_WithoutBall()
00794 {
00795   unsigned char diff = 1;
00796   switch (lastFrameNumber)
00797   {
00798   case  4: diff = 1; break;
00799   case  5: diff = 1; break;
00800   case  8: diff = 2; break;
00801   case  9: diff = 2; break;
00802   case 12: diff = 3; break;
00803   case 13: diff = 3; break;
00804   case 16: diff = 4; break;
00805   case 17: diff = 4; break;
00806   case 18: diff = 4; break;
00807   }
00808 
00809 
00810   if(ballWasSeenInLastImage)
00811   {
00812     if(!ballPercept.ballWasSeen)
00813     {
00814       ballModel.numberOfImagesWithoutBallPercept = 1;
00815     }
00816     else
00817     {
00818       ballModel.numberOfImagesWithBallPercept += diff;
00819     }
00820   }
00821   else // !lastBallWasSeen
00822   {
00823     if(ballPercept.ballWasSeen)
00824     {
00825       ballModel.numberOfImagesWithBallPercept = 1;
00826     }
00827     else
00828     {
00829       ballModel.numberOfImagesWithoutBallPercept += diff;
00830     }
00831   }
00832   ballModel.ballWasSeen = ballPercept.ballWasSeen;
00833   ballWasSeenInLastImage = ballPercept.ballWasSeen;
00834 }
00835 //------------------------------------------------------------------------------
00836 /*
00837  * Change log :
00838  * $Log: GT2004BallLocator.cpp,v $
00839  * Revision 1.1  2004/07/14 20:56:34  spranger
00840  * moved KalmanCombo (incl percept stuff) to gt2004balllocator
00841  *
00842  * Revision 1.21  2004/06/28 02:00:35  spranger
00843  * bugfix
00844  *
00845  * Revision 1.20  2004/06/23 18:18:47  spranger
00846  * reintroduced ballModel.seen.ballInFrontOfOpponentGoal
00847  *
00848  * Revision 1.19  2004/06/23 11:37:43  dassler
00849  * New Ballsymbols introduced
00850  * ball.projected-distance-on-y-axis" description="Projected Distance of the ball to the y axis of the robot
00851  * ball.time-until-ball-crosses-y-axis" description="Time until the ball crosses the y axis of the robot
00852  *
00853  * Revision 1.18  2004/06/22 08:24:38  nistico
00854  * Reintroduced clipping between [-1; 1] before acos()
00855  *
00856  * Revision 1.17  2004/06/21 08:15:57  nistico
00857  * The dot product of normalized vectors (versors) is guaranteed to be within [-1, 1] ;
00858  * the angle was not normalized, however. (-pi, pi)
00859  *
00860  * Revision 1.16  2004/06/19 08:02:29  roefer
00861  * Initialize ball position
00862  * Clip parameter of acos to [-1 .. 1]
00863  *
00864  * Revision 1.15  2004/06/18 12:29:17  nistico
00865  * Added (redundant?) check for division_by_zero
00866  *
00867  * Revision 1.14  2004/06/18 10:24:51  nistico
00868  * Kalman measurement covariance matrix now adjusted also based on
00869  * head panning angular velocity
00870  *
00871  * Revision 1.13  2004/06/16 17:57:00  nistico
00872  * Speed covariance submatrix dynamically calculated
00873  * based on distance from ball
00874  * More detailed identification of exception
00875  * Bug fixes
00876  *
00877  * Revision 1.11  2004/06/15 21:40:14  uhrig
00878  * Added possibility to disable and enable process models in the Kalman filter.
00879  *
00880  * Revision 1.10  2004/06/15 17:48:32  juengel
00881  * Added method determineNumberOfImagesWith_WithoutBall().
00882  *
00883  * Revision 1.9  2004/06/14 10:44:28  risler
00884  * removed speed averaging
00885  * reactivated old working ball state
00886  *
00887  * Revision 1.8  2004/06/08 13:06:20  kerdels
00888  * slightly improved side-decision in ball-blocking, but there's still space for improvement ;-)
00889  *
00890  * Revision 1.7  2004/06/04 08:46:49  juengel
00891  * Position is determined based on the bearing to the ball.
00892  *
00893  * Revision 1.6  2004/05/27 18:49:17  kerdels
00894  * added a small 5 frames sliding average for the relative ballspeed,
00895  * added new ballState Representation and adjusted the apropriate files
00896  *
00897  * Revision 1.5  2004/05/27 09:53:33  loetzsch
00898  * removed "timeOfImageProcessing"
00899  *
00900  * Revision 1.4  2004/05/26 10:08:03  loetzsch
00901  * correct use of odometry
00902  *
00903  * Revision 1.2  2004/05/22 22:52:01  juengel
00904  * Renamed ballP_osition to ballModel.
00905  *
00906  * Revision 1.1.1.1  2004/05/22 17:15:19  cvsadm
00907  * created new repository GT2004_WM
00908  *
00909  * Revision 1.8  2004/05/03 15:32:25  uhrig
00910  * Added additional ball state and disabled sending of Kalman filter process model states.
00911  *
00912  * Revision 1.7  2004/04/27 09:09:22  uhrig
00913  * Using own side ball detection again
00914  *
00915  * Revision 1.6  2004/04/22 14:28:02  roefer
00916  * .NET errors/warnings removed
00917  *
00918  * Revision 1.5  2004/04/20 14:12:16  uhrig
00919  *  - odometry processing corrected
00920  *  - fixed position model disabled
00921  *  - covariance matrices tuned
00922  *
00923  * Revision 1.4  2004/04/07 12:28:56  risler
00924  * ddd checkin after go04 - first part
00925  *
00926  * Revision 1.5  2004/03/31 00:09:46  risler
00927  * set last seen position when ball is not seen
00928  *
00929  * Revision 1.4  2004/03/30 15:48:04  risler
00930  * various bugfixes from stefan
00931  *
00932  * Revision 1.1.1.1  2004/03/29 08:28:51  Administrator
00933  * initial transfer from tamara
00934  *
00935  * Revision 1.3  2004/03/27 21:51:32  risler
00936  * process model message sending disabled
00937  *
00938  * Revision 1.2  2004/03/15 12:28:52  risler
00939  * change log added
00940  *
00941  *
00942  */

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