Difference between revisions of "Zoom Radar"

From Robowiki
Jump to navigation Jump to search
m (Revised LaTeX after Voidious fixed!)
(Readjusted the algorithm based on discussion Rednaxela.)
Line 48: Line 48:
 
     </TD>
 
     </TD>
 
     <TD ROWSPAN="2">
 
     <TD ROWSPAN="2">
Calculate the maximum distance the enemy can possibly move according to the physics.
+
Calculate the maximum distance the enemy can possibly move according to the physics. The error added to the distance each turn is 8. The body of the robot is 18.
 
     </TD>
 
     </TD>
 
   </TR>
 
   </TR>
Line 56: Line 56:
 
       <PRE>
 
       <PRE>
 
double targetError = (currentTime - targetLastScan + 1) * 8 + 18;
 
double targetError = (currentTime - targetLastScan + 1) * 8 + 18;
double targetErrorFinal = targetError + 8
+
double targetErrorFinal = targetError + 8;
 
       </PRE>
 
       </PRE>
 
     </TD>
 
     </TD>
Line 69: Line 69:
 
     </TD>
 
     </TD>
 
     <TD ROWSPAN="2">
 
     <TD ROWSPAN="2">
Standard Euclidean distance formula for our distance to target.
+
Standard Euclidean distance formula for our distance to target. The maximum distance we can close to the robots last known position is 8.
 
     </TD>
 
     </TD>
 
   </TR>
 
   </TR>
Line 83: Line 83:
 
     </TD>
 
     </TD>
 
   </TR>
 
   </TR>
 
 
   <TR>
 
   <TR>
 
     <TD>
 
     <TD>
<MATH>\text{x = }\pm \frac{1}{2} \sqrt{4 \text{targetError}^2-\frac{\text{targetError}^4}{\text{targetDistance}^2}}</MATH>
+
<MATH>\angle\theta_\text{Bounding} = \sin ^{-1}\left(\frac{targetError}{targetDistance}\right)</MATH>
<BR />
 
<BR />
 
<MATH>\text{y = }\frac{2 \text{targetDistance}^2-\text{targetError}^2}{2 \text{targetDistance}}</MATH>
 
 
     </TD>
 
     </TD>
 
     <TD ROWSPAN="2">
 
     <TD ROWSPAN="2">
The maximum angle that the enemy could have traveled is the intersection of the targetError and targetDistance circles.
+
Calculate the maximum bearing that the enemy could have traveled. This is our bounding bearing range.<BR />[[File:ZoomRadarBounding.png]]
 
     </TD>
 
     </TD>
 
   </TR>
 
   </TR>
Line 99: Line 95:
 
     <TD>
 
     <TD>
 
       <PRE>
 
       <PRE>
double x = Math.sqrt(
+
double thetaBounding = Math.asin(targetError/targetDistance);
  targetError * targetError - (targetError * targetError * targetError * targetError)
 
  / (targetDistance * targetDistance)) / 2;
 
double y = (2 * targetDistance * targetDistance - targetError * targetError)
 
  / (2 * targetDistance);
 
 
       </PRE>
 
       </PRE>
 
     </TD>
 
     </TD>
 
   </TR>
 
   </TR>
 
  <TR>
 
    <TD>
 
<MATH>\angle\theta_\text{Bounding} = \tan ^{-1}\left(\frac{x}{y}\right)</MATH>
 
    </TD>
 
    <TD ROWSPAN="2">
 
Calculate the maximum bearing that the enemy could have traveled. This is our bounding bearing range.
 
    </TD>
 
  </TR>
 
 
  <TR>
 
    <TD>
 
      <PRE>
 
double thetaBounding = Math.atan2(y,x);
 
      </PRE>
 
    </TD>
 
  </TR>
 
  <TR>
 
  </TR>
 
 
 
 
 
   <TR>
 
   <TR>
    <TD>
 
<MATH>\text{x = }\pm \frac{1}{2} \sqrt{4 \text{targetErrorFinal}^2-\frac{\text{targetErrorFinal}^4}{\text{targetDistanceFinal}^2}}</MATH>
 
<BR />
 
<BR />
 
<MATH>\text{y = }\frac{2 \text{targetDistanceFinal}^2-\text{targetErrorFinal}^2}{2 \text{targetDistanceFinal}}</MATH>
 
    </TD>
 
    <TD ROWSPAN="2">
 
The maximum angle that the enemy could have traveled is the intersection of the targetErrorFinal and targetDistanceFinal circles.
 
    </TD>
 
 
   </TR>
 
   </TR>
  
  <TR>
 
    <TD>
 
      <PRE>
 
x = Math.sqrt(
 
  targetErrorFinal * targetErrorFinal - (targetErrorFinal * targetErrorFinal * targetErrorFinal * targetErrorFinal)
 
  / (targetDistanceFinal * targetDistanceFinal)) / 2;
 
y = (2 * targetDistanceFinal * targetDistanceFinal - targetErrorFinal * targetErrorFinal)
 
  / (2 * targetDistanceFinal);
 
      </PRE>
 
    </TD>
 
  </TR>
 
  
 
   <TR>
 
   <TR>
 
     <TD>
 
     <TD>
<MATH>\angle\theta_\text{Final} = \tan ^{-1}\left(\frac{x}{y}\right)</MATH>
+
<MATH>\angle\theta_\text{Final} = \tan ^{-1}\left(\frac{targetErrorFinal}{targetDistanceFinal}\right)</MATH>
 
     </TD>
 
     </TD>
 
     <TD ROWSPAN="2">
 
     <TD ROWSPAN="2">
Calculate the maximum bearing that the enemy may travel after our next turn. This is our final bearing range.
+
Calculate the maximum bearing that the enemy may travel after our next turn. This is our final bearing range.<BR />[[File:ZoomRadarFinal.png]]
 
     </TD>
 
     </TD>
 
   </TR>
 
   </TR>
Line 165: Line 115:
 
     <TD>
 
     <TD>
 
       <PRE>
 
       <PRE>
double thetaFinal = Math.atan2(y,x);
+
double thetaFinal = Math.asin(targetErrorFinal/targetDistanceFinal);
 
       </PRE>
 
       </PRE>
 
     </TD>
 
     </TD>
Line 171: Line 121:
 
   <TR>
 
   <TR>
 
   </TR>
 
   </TR>
 
  <TR><TD>[[File:Radarzoombasis.png]][[File:radarZoomFinal.png]]</TD><TD>Graphic explanation of mathematics.</TD></TR>
 
 
</TABLE>
 
</TABLE>
  
  
When the radar's bearing is between the thetaBounding and thetaFinal bearings, this signals the completion of the scan in the corresponding direction. The scan direction should be reversed to (re)cover the target area. When a target has been scanned, the radar must reverse direction to ensure a scan on the next subsequent turn. This enables a precision lock on the target. The variable lastScanDirection should be initialized with the value that corresponds to the direction (1 = CW, -1 = CCW) of the scan used to find all targets. The variable scanDirection should be initialized with 0 to force a new search. When initiating a new search, if it is determined that the CW and CCW scans will be equal, the direction of search should be the one that will scan the most targets along the path to the desired target.
+
The completion of scanning in a direction is indicated when the radar's bearing is beyond the thetaBounding bearing for the direction that it is scanning. The scan direction should be reversed to (re)cover the target area. When a target has been scanned, the radar must reverse direction to ensure a scan on the next subsequent turn. This enables a precision lock on the target. The variable lastScanDirection should be initialized with the value that corresponds to the direction (1 = CW, -1 = CCW) of the scan used to find all targets. The variable scanDirection should be initialized with 0 to force a new search. When initiating a new search, if it is determined that the CW and CCW scans will be equal, the direction of search should be the one that will scan the most targets along the path to the desired target.
  
 
<PRE>
 
<PRE>
 
// Bearings are negative in the CCW direction.
 
// Bearings are negative in the CCW direction.
 
if(scanDirection == -1) {
 
if(scanDirection == -1) {
        // Check to see if we have completed our move.
+
// Check to see if we have completed our move.
        if(radarBearing >= -thetaFinal && radarBearing <= -thetaBounding) {
+
if(radarBearing <= -thetaBounding) {
                // Should have scanned target by now. Resume in opposite direction
+
// Should have scanned target by now. Resume in opposite direction
                scanDirection = 1;
+
scanDirection = 1;
        }
+
}
        else {
+
else {
                // Continue in the CCW direction.
+
// Continue in the CCW direction.
                scanDirection = -1;
+
scanDirection = -1;
        }
+
}
 
}
 
}
 
else if(scanDirection == 1) {
 
else if(scanDirection == 1) {
        // Check to see if we have completed our move.
+
// Check to see if we have completed our move.
        if(radarBearing <= thetaFinal && radarBearing >= thetaBounding) {
+
if(radarBearing >= thetaBounding) {
                // Should have scanned target by now. Resume in opposite direction
+
// Should have scanned target by now. Resume in opposite direction
                scanDirection = -1;
+
scanDirection = -1;
        }
+
}
        else {
+
else {
                // Continue in the CW direction.
+
// Continue in the CW direction.
                scanDirection = 1;
+
scanDirection = 1;
        }
+
}
 
}
 
}
 
// Set scanDirection = 0 if we just scanned the target we were looking for so that we can continue scanning in the most manner.
 
// Set scanDirection = 0 if we just scanned the target we were looking for so that we can continue scanning in the most manner.
 
else {
 
else {
        // Check to see if we are within bounds.
+
// Check to see if we are within bounds.
        if(radarBearing >= -thetaBounding && radarBearing <= thetaBounding) {
+
if(radarBearing >= -thetaFinal && radarBearing <= thetaFinal) {
                // Start scanning in the opposite direction to ensure that we scan the target on this turn.
+
// Start scanning in the opposite direction to ensure that we scan the target on this turn.
                scanDirection = lastScanDirection * -1;
+
scanDirection = lastScanDirection * -1;
        }
+
}
        // Check to see if the CW bound is closer.
+
// Check to see if the CW bound is closer.
        else if(Math.abs(thetaFinal - radarBearing) < Math.abs((-thetaFinal) - radarBearing)) {
+
else if(Math.ceil(Math.abs(thetaFinal - radarBearing) / (Math.PI / 4)) < Math.ceil(Math.abs((-thetaFinal) - radarBearing) / (Math.PI / 4))) {
                // Scan in the CCW direction ending at the CCW bound.
+
// Scan in the CCW direction ending at the CCW bound.
                scanDirection = -1;
+
scanDirection = -1;
        }
+
}
        // Check to see if the CCW bound is closer.
+
// Check to see if the CCW bound is closer.
        else if(Math.abs(thetaFinal - radarBearing) > Math.abs((-thetaFinal) - radarBearing)) {
+
else if(Math.ceil(Math.abs(thetaFinal - radarBearing) / (Math.PI / 4)) > Math.ceil(Math.abs((-thetaFinal) - radarBearing) / (Math.PI / 4))) {
                // Scan in the CW direction ending at the CW bound.
+
// Scan in the CW direction ending at the CW bound.
                scanDirection = 1;
+
scanDirection = 1;
        }
+
}
        // Both bounds are equal.
+
// Both bounds are equal.
        else {
+
else {
 +
int targetsCW = 0;
 +
int targetsCCW = 0;
 +
 
 
                 // Add code here....
 
                 // Add code here....
                // Just count the number of targets you expect to scan along the CW and CCW directions and start scanning in the most advantageous direction.
+
// Just count the number of targets you expect to scan along the CW and CCW directions and start scanning in the most advantageous direction.
                if(targetsCW >= targetsCCW) {
+
if(targetsCCW > targetsCW) {
                        scanDirection = 1;
+
scanDirection = 1;
                }
+
}
                else {
+
else if(targetsCCW < targetsCW) {
                        scanDirection = -1;
+
scanDirection = -1;
                }
+
}
        }
+
else {
 +
scanDirection = -1 * lastScanDirection;
 +
}
 +
}
 
}
 
}
  
 +
lastScanDirection = scanDirection;
 
setTurnRadarRightRadians((scanDirection * thetaFinal) – radarBearing);
 
setTurnRadarRightRadians((scanDirection * thetaFinal) – radarBearing);
lastScanDirection = scanDirection;
 
  
 
</PRE>
 
</PRE>
  
If <MATH>2 \times \text{targetDistanceFinal} < \text{targetErrorFinal}</MATH> then it will be impossible to resolve bearings that the target may not be at. It is best to continue scanning in the same direction as previous, but with no bounds.
+
If <MATH>\text{targetDistanceFinal} \le \text{targetErrorFinal}</MATH> then it will be impossible to resolve bearings that the target may not be at. It is best to continue scanning in the same direction as previous, but with no bounds.
  
 
<PRE>
 
<PRE>
if(2 * targetDistanceFinal < targetErrorFinal) {
+
if(targetDistanceFinal <= targetErrorFinal) {
 
         scanDirection = lastScanDirection;
 
         scanDirection = lastScanDirection;
 
         setTurnRadarRightRadians(scanDirection * 2* Math.PI);
 
         setTurnRadarRightRadians(scanDirection * 2* Math.PI);
 
}
 
}
 
</PRE>
 
</PRE>

Revision as of 05:34, 28 February 2010

Zoom radar is a precise lock radar with a minimum cost feature for melee. Created by Frolicking Zombie.

Mathematics Explanation
RoboCode Java

<MATH>\angle\text{targetHeading} = \tan ^{-1}\left(\frac{\text{targetY}-\text{myY}}{\text{targetX}-\text{myX}}\right)</MATH>

<MATH>\angle\text{radarBearing} = \lVert {\text{getRadarHeadingRadians()} - \text{targetHeading}} \rVert</MATH>

Find the last known heading to the target and then our radar's bearing to that heading. Robocode trigonometry has <MATH>\tan \theta = \frac{\cos \theta}{\sin \theta}</MATH>

double targetHeading = Math.atan2(targetX - myX, targetY – myY);
double radarBearing = getRadarHeadingRadians() - targetHeading;
while(radarBearing <= -Math.Pi) {
        radarBearing += 2 * Math.PI;
}
while(radarBearing > Math.Pi) {
        radarBearing -= 2 * Math.PI;
}
      

<MATH>\text{targetError} = (\text{currentTime} - \text{lastScanTime} + 1)\times 8 + 18</MATH>

<MATH>\text{targetErrorFinal} = \text{targetError} + 8</MATH>

Calculate the maximum distance the enemy can possibly move according to the physics. The error added to the distance each turn is 8. The body of the robot is 18.

double targetError = (currentTime - targetLastScan + 1) * 8 + 18;
double targetErrorFinal = targetError + 8;
      

<MATH>\text{targetDistance} = \sqrt{(\text{targetX} - \text{myX})^2+(\text{targetY}-\text{myY})^2}</MATH>

<MATH>\text{targetDistanceFinal} = \text{targetDistance} + 8</MATH>

Standard Euclidean distance formula for our distance to target. The maximum distance we can close to the robots last known position is 8.

double targetDistance = Math.sqrt(
  (targetX - myX) * (targetX - myX) + (targetY - myY) * (targetY - myY)
  );
double targetDistanceFinal = targetDistance + 8;
      

<MATH>\angle\theta_\text{Bounding} = \sin ^{-1}\left(\frac{targetError}{targetDistance}\right)</MATH>

Calculate the maximum bearing that the enemy could have traveled. This is our bounding bearing range.
ZoomRadarBounding.png

double thetaBounding = Math.asin(targetError/targetDistance);
      

<MATH>\angle\theta_\text{Final} = \tan ^{-1}\left(\frac{targetErrorFinal}{targetDistanceFinal}\right)</MATH>

Calculate the maximum bearing that the enemy may travel after our next turn. This is our final bearing range.
ZoomRadarFinal.png

double thetaFinal = Math.asin(targetErrorFinal/targetDistanceFinal);
      


The completion of scanning in a direction is indicated when the radar's bearing is beyond the thetaBounding bearing for the direction that it is scanning. The scan direction should be reversed to (re)cover the target area. When a target has been scanned, the radar must reverse direction to ensure a scan on the next subsequent turn. This enables a precision lock on the target. The variable lastScanDirection should be initialized with the value that corresponds to the direction (1 = CW, -1 = CCW) of the scan used to find all targets. The variable scanDirection should be initialized with 0 to force a new search. When initiating a new search, if it is determined that the CW and CCW scans will be equal, the direction of search should be the one that will scan the most targets along the path to the desired target.

// Bearings are negative in the CCW direction.
if(scanDirection == -1) {
	// Check to see if we have completed our move.
	if(radarBearing <= -thetaBounding) {
		// Should have scanned target by now. Resume in opposite direction
		scanDirection = 1;
	}
	else {
		// Continue in the CCW direction.
		scanDirection = -1;
	}
}
else if(scanDirection == 1) {
	// Check to see if we have completed our move.
	if(radarBearing >= thetaBounding) {
		// Should have scanned target by now. Resume in opposite direction
		scanDirection = -1;
	}
	else {
		// Continue in the CW direction.
		scanDirection = 1;
	}
}
// Set scanDirection = 0 if we just scanned the target we were looking for so that we can continue scanning in the most manner.
else {
	// Check to see if we are within bounds.
	if(radarBearing >= -thetaFinal && radarBearing <= thetaFinal) {
		// Start scanning in the opposite direction to ensure that we scan the target on this turn.
		scanDirection = lastScanDirection * -1;
	}
	// Check to see if the CW bound is closer.
	else if(Math.ceil(Math.abs(thetaFinal - radarBearing) / (Math.PI / 4)) < Math.ceil(Math.abs((-thetaFinal) - radarBearing) / (Math.PI / 4))) {
		// Scan in the CCW direction ending at the CCW bound.
		scanDirection = -1;
	}
	// Check to see if the CCW bound is closer.
	else if(Math.ceil(Math.abs(thetaFinal - radarBearing) / (Math.PI / 4)) > Math.ceil(Math.abs((-thetaFinal) - radarBearing) / (Math.PI / 4))) {
		// Scan in the CW direction ending at the CW bound.
		scanDirection = 1;
	}
	// Both bounds are equal.
	else {
		int targetsCW = 0;
		int targetsCCW = 0;

                // Add code here....
		// Just count the number of targets you expect to scan along the CW and CCW directions and start scanning in the most advantageous direction.
		if(targetsCCW > targetsCW) {
			scanDirection = 1;
		}
		else if(targetsCCW < targetsCW) {
			scanDirection = -1;
		}
		else {
			scanDirection = -1 * lastScanDirection;
		}
	}
}

lastScanDirection = scanDirection;
setTurnRadarRightRadians((scanDirection * thetaFinal) – radarBearing);

If <MATH>\text{targetDistanceFinal} \le \text{targetErrorFinal}</MATH> then it will be impossible to resolve bearings that the target may not be at. It is best to continue scanning in the same direction as previous, but with no bounds.

if(targetDistanceFinal <= targetErrorFinal) {
        scanDirection = lastScanDirection;
        setTurnRadarRightRadians(scanDirection * 2* Math.PI);
}