FTC Java 和 Blockly 编程指南
(Blockly 截图即将推出!)
请确保您已阅读 FTC 编程快速入门。
FTC Limelight Javadoc:Javadoc
基础 FTC 示例:FTC 示例
完整示例仓库:Limelight FTC 示例仓库
成功秘诀
- 先做简单的事情。在 FRC 中,我们了解到最优秀的软件团队往往使用最简单的方法。例如,2024 年 FRC 2056 队使用标准的 90FPS 颜色管道而不是神经网络来追踪游戏元件。
以下是您开始编程时应该问的问题类型示例:在遥控操作期间,您是否需要知道机器人在场地上的位置,还是只需要横移直到十字准星对准特定标签(strafeSpeed = result.getTx()*.03)?
关键概念
1. 初始化
我们需要在机器人代码中设置 Limelight3A。
import com.qualcomm.hardware.limelightvision.LLResult;
import com.qualcomm.hardware.limelightvision.LLResultTypes;
import com.qualcomm.hardware.limelightvision.LLStatus;
import com.qualcomm.hardware.limelightvision.Limelight3A;
Limelight3A limelight;
@Override
public void init() {
limelight = hardwareMap.get(Limelight3A.class, "limelight");
limelight.setPollRateHz(100); // 设置我们向 Limelight 请求数据的频率(每秒 100 次)
limelight.start(); // 告诉 Limelight 开始检测!
}
2. 管道管理
管道就像小型的、可即时切换的程序,改变 Limelight 观察世界的方式。您可以在 Limelight 网页界面中设置 10 个不同的管道,每个用于不同的任务。以下是切换管道的方法:
limelight.pipelineSwitch(0); // 切换到管道 0
这是即发即忘的操作。Limelight 会在几毫秒内更改管道,但您的代码不会等待此操作完成就继续执行。如果您想检查当前管道索引,请调用
result.getPipelineIndex()
请参阅下一节了解如何获取 LLResult 对象。
3. 获取和使用结果
LLResult 就像一个装满 Limelight 所见信息的容器。以下是我们获取和使用该信息的方法:
LLResult result = limelight.getLatestResult();
if (result != null && result.isValid()) {
double tx = result.getTx(); // 目标左右偏移量(度)
double ty = result.getTy(); // 目标上下偏移量(度)
double ta = result.getTa(); // 目标看起来有多大(图像的 0%-100%)
telemetry.addData("Target X", tx);
telemetry.addData("Target Y", ty);
telemetry.addData("Target Area", ta);
} else {
telemetry.addData("Limelight", "No Targets");
}
4. 与 Python SnapScripts 通信
您可以在网页界面中编写自己的 Python SnapScript 管道。使用我们基于 LLM 的 SnapScript 生成器来帮助您编写代码。
以下是如何从机器人代码向 Python 发送数字并获取返回数字的方法:
// 向 Python 发送数字
double[] inputs = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
limelight.updatePythonInputs(inputs);
// 从 Python 获取数字
double[] pythonOutputs = result.getPythonOutput();
if (pythonOutputs != null && pythonOutputs.length > 0) {
double firstOutput = pythonOutputs[0];
telemetry.addData("Python output:", firstOutput);
}
5. 我的机器人在哪里?(MegaTag 1)
Limelight 可以使用 AprilTag 帮助确定您的机器人在场地上的位置。您的 Limelight 预装了当前比赛的 AprilTag 地图,但您可以使用我们的 3D 地图构建器设计和上传自己的地图。
在尝试获取机器人位置之前,请执行以下操作:
- 在网页界面的 AprilTag 管道"高级"选项卡中启用"Full 3D"。
- 使用网页界面将相机相对于机器人底盘中心进行定位。
botPose 的坐标系与标准 FTC 坐标系匹配。
- (0,0,0) 是场地地面的中心
- 对于非菱形配置,0 度偏航角意味着蓝色联盟在机器人左侧,红色联盟在机器人右侧。
if (result != null && result.isValid()) {
Pose3D botpose = result.getBotpose();
if (botpose != null) {
double x = botpose.getPosition().x;
double y = botpose.getPosition().y;
telemetry.addData("MT1 Location", "(" + x + ", " + y + ")");
}
}
6. 我的机器人在哪里?(MegaTag 2)
MegaTag 2 类似于 MegaTag 1,但它融合了您的 IMU 数据以提高精度:
// 首先,告诉 Limelight 您的机器人面向哪个方向
double robotYaw = imu.getAngularOrientation().firstAngle;
limelight.updateRobotOrientation(robotYaw);
if (result != null && result.isValid()) {
Pose3D botpose_mt2 = result.getBotpose_MT2();
if (botpose_mt2 != null) {
double x = botpose_mt2.getPosition().x;
double y = botpose_mt2.getPosition().y;
telemetry.addData("MT2 Location:", "(" + x + ", " + y + ")");
}
}
7. 内部结果类型
根据您配置管道的方式,您将可以访问父 LLResults 对象中不同类型的详细结果列表。
您可能不需要使用这些结果列表。我们建议尽可能使用基本的 getTx()、getTy()。
7.1 颜色结果
颜色结果帮助查找彩色目标:
List<ColorResult> colorTargets = result.getColorResults();
for (ColorResult colorTarget : colorTargets) {
double x = detection.getTargetXDegrees(); // 位置(左右)
double y = detection.getTargetYDegrees(); // 位置(上下)
double area = colorTarget.getTargetArea(); // 大小(0-100)
telemetry.addData("Color Target", "takes up " + area + "% of the image");
}
7.2 基准标记/AprilTag 结果
基准标记是特殊标记(如 AprilTag),帮助 Limelight 确定其位置:
List<FiducialResult> fiducials = result.getFiducialResults();
for (FiducialResult fiducial : fiducials) {
int id = fiducial.getFiducialId(); // 基准标记的 ID 号
double x = detection.getTargetXDegrees(); // 位置(左右)
double y = detection.getTargetYDegrees(); // 位置(上下)
double StrafeDistance_3D = fiducial.getRobotPoseTargetSpace().getY();
telemetry.addData("Fiducial " + id, "is " + distance + " meters away");
}
如果您想利用每个 FiducialResult 中的 3D 位姿信息,可以使用以下方法:
fiducial.getRobotPoseTargetSpace(); // 机器人相对于 AprilTag 坐标系的位姿(最有用)
fiducial.getCameraPoseTargetSpace(); // 相机相对于 AprilTag 的位姿(有用)
fiducial.getRobotPoseFieldSpace(); // 仅基于此标签的机器人在场地坐标系中的位姿(有用)
fiducial.getTargetPoseCameraSpace(); // AprilTag 在相机坐标系中的位姿(不太有用)
fiducial.getTargetPoseRobotSpace(); // AprilTag 在机器人坐标系中的位姿(不太有用)
7.3 条形码结果
Limelight 的条形码管道擅长检 测和追踪二维码。
List<BarcodeResult> barcodes = result.getBarcodeResults();
for (BarcodeResult barcode : barcodes) {
String data = barcode.getData(); // 条形码内容
String family = barcode.getFamily(); // 条形码类型
telemetry.addData("Barcode", data + " (" + family + ")");
}
7.4 分类器结果
神经分类器允许 Limelight 说"我认为这是一张...的图像"。
List<ClassifierResult> classifications = result.getClassifierResults();
for (ClassifierResult classification : classifications) {
String className = classification.getClassName(); // Limelight 认为它看到了什么
double confidence = classification.getConfidence(); // 置信度分数
telemetry.addData("I see a", className + " (" + confidence + "%)");
}
7.5 检测器结果
检测器查找特定对象并告诉我们它们在哪里:
List<DetectorResult> detections = result.getDetectorResults();
for (DetectorResult detection : detections) {
String className = detection.getClassName(); // 检测到了什么
double x = detection.getTargetXDegrees(); // 位置(左右)
double y = detection.getTargetYDegrees(); // 位置(上下)
telemetry.addData(className, "at (" + x + ", " + y + ") degrees");
}
8. 数据是否新鲜?
有时,我们想知道结果数据的年龄(以毫秒为单位)。
long staleness = result.getStaleness();
if (staleness < 100) { // 小于 100 毫秒
telemetry.addData("Data", "Good");
} else {
telemetry.addData("Data", "Old (" + staleness + " ms)");
}
9. 自定义场地地图
您可以告诉 Limelight 您的特定场地布局:
LLFieldMap fieldMap = new LLFieldMap(); // 您需要用场地数据填充它
boolean success = limelight.uploadFieldmap(fieldMap, null); // null 表示使用默认槽位
if (success) {
telemetry.addData("Field Map", "Uploaded successfully!");
} else {
telemetry.addData("Field Map", "Oops, upload failed");
}
10. 拍摄快照:
Limelight 可以拍摄快照,帮助您在场外调试管道:
limelight.captureSnapshot("auto_pov_10s");
在网页界面的输入选项卡中,您可以选择此快照作为"图像源"来检查/调整您的管道。
要清除旧快照:
limelight.deleteSnapshots();
telemetry.addData("Snapshots", "All cleared out!");