FTC Java & Blockly プログラミングガイド
(Blocklyのスクリーンショットは近日公開予定!)
まずFTCプログラミングクイックスタートをお読みください。
FTC Limelight Javadoc: Javadoc
基本的なFTCサンプル: FTC Sample
完全なサンプルリポジトリ: Limelight FTC Examples Repo
成功のためのヒント
- まずシンプルなことから始めましょう。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にデータを要求する頻度を設定します(1秒間に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パイプラインの「Advanced」タブで「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結果
フィデューシャルは、Limelightが自分の位置を把握するのに役立つ特別なマーカー(AprilTagなど)です:
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のバーコードパイプラインは、QRコードの検出と追跡に優れています。
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 + "%)");
}