-
Notifications
You must be signed in to change notification settings - Fork 12
/
Robot_Navigation.java
314 lines (259 loc) · 14.4 KB
/
Robot_Navigation.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
package org.firstinspires.ftc.teamcode.FTCVuforiaDemo;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.robot.Robot;
import org.firstinspires.ftc.robotcore.external.ClassFactory;
import org.firstinspires.ftc.robotcore.external.matrices.OpenGLMatrix;
import org.firstinspires.ftc.robotcore.external.matrices.VectorF;
import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
import org.firstinspires.ftc.robotcore.external.navigation.AxesOrder;
import org.firstinspires.ftc.robotcore.external.navigation.AxesReference;
import org.firstinspires.ftc.robotcore.external.navigation.Orientation;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaLocalizer;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaTrackable;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaTrackableDefaultListener;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaTrackables;
import org.firstinspires.ftc.teamcode.R;
import java.util.ArrayList;
import java.util.List;
import static android.R.attr.angle;
import static android.R.attr.targetName;
import static android.view.View.X;
/**
* This is NOT an opmode.
*
* This class is used to define all the specific navigation tasks for the Target Tracking Demo
* It focuses on setting up and using the Vuforia Library, which is part of the 2016-2017 FTC SDK
*
* Once a target is identified, its information is displayed as telemetry data.
* To approach the target, three motion priorities are created:
* - Priority #1 Rotate so the robot is pointing at the target (for best target retention).
* - Priority #2 Drive laterally based on distance from target center-line
* - Priority #3 Drive forward based on the desired target standoff distance
*
*/
public class Robot_Navigation
{
// Constants
private static final int MAX_TARGETS = 4;
private static final double ON_AXIS = 10; // Within 1.0 cm of target center-line
private static final double CLOSE_ENOUGH = 20; // Within 2.0 cm of final target standoff
// Select which camera you want use. The FRONT camera is the one on the same side as the screen. Alt. is BACK
private static final VuforiaLocalizer.CameraDirection CAMERA_CHOICE = VuforiaLocalizer.CameraDirection.FRONT;
public static final double YAW_GAIN = 0.018; // Rate at which we respond to heading error
public static final double LATERAL_GAIN = 0.0027; // Rate at which we respond to off-axis error
public static final double AXIAL_GAIN = 0.0017; // Rate at which we respond to target distance errors
/* Private class members. */
private LinearOpMode myOpMode; // Access to the OpMode object
private Robot_OmniDrive myRobot; // Access to the Robot hardware
private VuforiaTrackables targets; // List of active targets
// Navigation data is only valid if targetFound == true;
private boolean targetFound; // set to true if Vuforia is currently tracking a target
private String targetName; // Name of the currently tracked target
private double robotX; // X displacement from target center
private double robotY; // Y displacement from target center
private double robotBearing; // Robot's rotation around the Z axis (CCW is positive)
private double targetRange; // Range from robot's center to target in mm
private double targetBearing; // Heading of the target , relative to the robot's unrotated center
private double relativeBearing;// Heading to the target from the robot's current bearing.
// eg: a Positive RelativeBearing means the robot must turn CCW to point at the target image.
/* Constructor */
public Robot_Navigation(){
targetFound = false;
targetName = null;
targets = null;
robotX = 0;
robotY = 0;
targetRange = 0;
targetBearing = 0;
robotBearing = 0;
relativeBearing = 0;
}
/***
* Send telemetry data to indicate navigation status
*/
public void addNavTelemetry() {
if (targetFound)
{
// Display the current visible target name, robot info, target info, and required robot action.
myOpMode.telemetry.addData("Visible", targetName);
myOpMode.telemetry.addData("Robot", "[X]:[Y] (B) [%5.0fmm]:[%5.0fmm] (%4.0f°)",
robotX, robotY, robotBearing);
myOpMode.telemetry.addData("Target", "[R] (B):(RB) [%5.0fmm] (%4.0f°):(%4.0f°)",
targetRange, targetBearing, relativeBearing);
myOpMode.telemetry.addData("- Turn ", "%s %4.0f°", relativeBearing < 0 ? ">>> CW " : "<<< CCW", Math.abs(relativeBearing));
myOpMode.telemetry.addData("- Strafe ", "%s %5.0fmm", robotY < 0 ? "LEFT" : "RIGHT", Math.abs(robotY));
myOpMode.telemetry.addData("- Distance", "%5.0fmm", Math.abs(robotX));
}
else
{
myOpMode.telemetry.addData("Visible", "- - - -" );
}
}
/***
* Start tracking Vuforia images
*/
public void activateTracking() {
// Start tracking any of the defined targets
if (targets != null)
targets.activate();
}
/***
* use target position to determine the best way to approach it.
* Set the Axial, Lateral and Yaw axis motion values to get us there.
*
* @return true if we are close to target
* @param standOffDistance how close do we get the center of the robot to target (in mm)
*/
public boolean cruiseControl(double standOffDistance) {
boolean closeEnough;
// Priority #1 Rotate to always be pointing at the target (for best target retention).
double Y = (relativeBearing * YAW_GAIN);
// Priority #2 Drive laterally based on distance from X axis (same as y value)
double L =(robotY * LATERAL_GAIN);
// Priority #3 Drive forward based on the desiredHeading target standoff distance
double A = (-(robotX + standOffDistance) * AXIAL_GAIN);
// Send the desired axis motions to the robot hardware.
myRobot.setYaw(Y);
myRobot.setAxial(A);
myRobot.setLateral(L);
// Determine if we are close enough to the target for action.
closeEnough = ( (Math.abs(robotX + standOffDistance) < CLOSE_ENOUGH) &&
(Math.abs(robotY) < ON_AXIS));
return (closeEnough);
}
/***
* Initialize the Target Tracking and navigation interface
* @param opMode pointer to OpMode
* @param robot pointer to Robot hardware class
*/
public void initVuforia(LinearOpMode opMode, Robot_OmniDrive robot) {
// Save reference to OpMode and Hardware map
myOpMode = opMode;
myRobot = robot;
/**
* Start up Vuforia, telling it the id of the view that we wish to use as the parent for
* the camera monitor.
* We also indicate which camera on the RC that we wish to use.
*/
// VuforiaLocalizer.Parameters parameters = new VuforiaLocalizer.Parameters(R.id.cameraMonitorViewId); // Use this line to see camera display
VuforiaLocalizer.Parameters parameters = new VuforiaLocalizer.Parameters(); // OR... Use this line to improve performance
// Get your own Vuforia key at https://developer.vuforia.com/license-manager
// and paste it here...
parameters.vuforiaLicenseKey = "Afbu2Uv/////AAAAGVouNdSAD0P8la+sq37vCdQ6uLVH8NWrBLnfZ1R5rObJQpVVHJzqvIgMZO5gTqXG6DYJZcgwtSVZXU2g20FAJobxCog9Wc5vtqgJJmrsJ0NOABRbi9vy4Y9IzBVfaDoRsQTmjxxFf62Z9slttsb44KopGpVGTQ83iHnTo/wDvnZBWRhmckG6IKuqkbRYCFD+w1hHvVLuDoIYLgfpa1Rw1Pc7rszP/CDzUfeO9KwodFpEsfZHIZI8KHIYzfRIOhg1Tg0T4eRsLCO8s9vfZd6vfTuUA/sZkID3N7BsrlLaL6vUqheGPvsbPuQQsMqgPNYTqbhvv3KI/SR5WxUaccuVHnpVMhAjkdpruWVliCCZqp1t";
parameters.cameraDirection = CAMERA_CHOICE;
parameters.useExtendedTracking = false;
VuforiaLocalizer vuforia = ClassFactory.createVuforiaLocalizer(parameters);
/**
* Load the data sets that for the trackable objects we wish to track.
* These particular data sets are stored in the 'assets' part of our application
* They represent the four image targets used in the 2016-17 FTC game.
*/
targets = vuforia.loadTrackablesFromAsset("FTC_2016-17");
targets.get(0).setName("Blue Near");
targets.get(1).setName("Red Far");
targets.get(2).setName("Blue Far");
targets.get(3).setName("Red Near");
/** For convenience, gather together all the trackable objects in one easily-iterable collection */
List<VuforiaTrackable> allTrackables = new ArrayList<VuforiaTrackable>();
allTrackables.addAll(targets);
// create an image translation/rotation matrix to be used for all images
// Essentially put all the image centers 6" above the 0:0:0 origin,
// but rotate them so they along the -X axis.
OpenGLMatrix targetOrientation = OpenGLMatrix
.translation(0, 0, 150)
.multiplied(Orientation.getRotationMatrix(
AxesReference.EXTRINSIC, AxesOrder.XYZ,
AngleUnit.DEGREES, 90, 0, -90));
/**
* Create a transformation matrix describing where the phone is on the robot.
*
* The coordinate frame for the robot looks the same as the field.
* The robot's "forward" direction is facing out along X axis, with the LEFT side facing out along the Y axis.
* Z is UP on the robot. This equates to a bearing angle of Zero degrees.
*
* The phone starts out lying flat, with the screen facing Up and with the physical top of the phone
* pointing to the LEFT side of the Robot. If we consider that the camera and screen will be
* in "Landscape Mode" the upper portion of the screen is closest to the front of the robot.
*
* If using the rear (High Res) camera:
* We need to rotate the camera around it's long axis to bring the rear camera forward.
* This requires a negative 90 degree rotation on the Y axis
*
* If using the Front (Low Res) camera
* We need to rotate the camera around it's long axis to bring the FRONT camera forward.
* This requires a Positive 90 degree rotation on the Y axis
*
* Next, translate the camera lens to where it is on the robot.
* In this example, it is centered (left to right), but 110 mm forward of the middle of the robot, and 200 mm above ground level.
*/
final int CAMERA_FORWARD_DISPLACEMENT = 110; // Camera is 110 mm in front of robot center
final int CAMERA_VERTICAL_DISPLACEMENT = 200; // Camera is 200 mm above ground
final int CAMERA_LEFT_DISPLACEMENT = 0; // Camera is ON the robots center line
OpenGLMatrix phoneLocationOnRobot = OpenGLMatrix
.translation(CAMERA_FORWARD_DISPLACEMENT, CAMERA_LEFT_DISPLACEMENT, CAMERA_VERTICAL_DISPLACEMENT)
.multiplied(Orientation.getRotationMatrix(
AxesReference.EXTRINSIC, AxesOrder.YZX,
AngleUnit.DEGREES, CAMERA_CHOICE == VuforiaLocalizer.CameraDirection.FRONT ? 90 : -90, 0, 0));
// Set the all the targets to have the same location and camera orientation
for (VuforiaTrackable trackable : allTrackables)
{
trackable.setLocation(targetOrientation);
((VuforiaTrackableDefaultListener)trackable.getListener()).setPhoneInformation(phoneLocationOnRobot, parameters.cameraDirection);
}
}
/***
* See if any of the vision targets are in sight.
*
* @return true if any target is found
*/
public boolean targetsAreVisible() {
int targetTestID = 0;
// Check each target in turn, but stop looking when the first target is found.
while ((targetTestID < MAX_TARGETS) && !targetIsVisible(targetTestID)) {
targetTestID++ ;
}
return (targetFound);
}
/***
* Determine if specified target ID is visible and
* If it is, retreive the relevant data, and then calculate the Robot and Target locations
*
* @param targetId
* @return true if the specified target is found
*/
public boolean targetIsVisible(int targetId) {
VuforiaTrackable target = targets.get(targetId);
VuforiaTrackableDefaultListener listener = (VuforiaTrackableDefaultListener)target.getListener();
OpenGLMatrix location = null;
// if we have a target, look for an updated robot position
if ((target != null) && (listener != null) && listener.isVisible()) {
targetFound = true;
targetName = target.getName();
// If we have an updated robot location, update all the relevant tracking information
location = listener.getUpdatedRobotLocation();
if (location != null) {
// Create a translation and rotation vector for the robot.
VectorF trans = location.getTranslation();
Orientation rot = Orientation.getOrientation(location, AxesReference.EXTRINSIC, AxesOrder.XYZ, AngleUnit.DEGREES);
// Robot position is defined by the standard Matrix translation (x and y)
robotX = trans.get(0);
robotY = trans.get(1);
// Robot bearing (in +vc CCW cartesian system) is defined by the standard Matrix z rotation
robotBearing = rot.thirdAngle;
// target range is based on distance from robot position to origin.
targetRange = Math.hypot(robotX, robotY);
// target bearing is based on angle formed between the X axis to the target range line
targetBearing = Math.toDegrees(-Math.asin(robotY / targetRange));
// Target relative bearing is the target Heading relative to the direction the robot is pointing.
relativeBearing = targetBearing - robotBearing;
}
targetFound = true;
}
else {
// Indicate that there is no target visible
targetFound = false;
targetName = "None";
}
return targetFound;
}
}