Aller au contenu principal

Guide de programmation FTC Java & Blockly

(Captures d'écran Blockly à venir bientôt !)

Assurez-vous d'avoir lu le Démarrage rapide de programmation FTC.

Javadoc FTC Limelight : Javadoc

Exemple FTC basique : Exemple FTC

Dépôt d'exemples complets : Dépôt d'exemples Limelight FTC

Conseils pour réussir

  • Faites d'abord la chose simple. En FRC, nous avons appris que les meilleures équipes logicielles utilisent souvent les approches les plus simples. Par exemple, l'équipe FRC 2056 en 2024 a utilisé un pipeline de couleur standard à 90 FPS au lieu d'un réseau neuronal pour suivre les pièces de jeu.

Voici un exemple du type de question à poser lorsque vous commencez à programmer : En téléop, avez-vous besoin de connaître la position de votre robot sur le terrain, ou avez-vous simplement besoin de vous déplacer latéralement jusqu'à ce que votre réticule soit centré sur un tag spécifique (strafeSpeed = result.getTx()*.03) ?

Concepts clés

1. Initialisation

Nous devons configurer notre Limelight3A dans notre code robot.

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); // Ceci définit la fréquence à laquelle nous demandons des données à Limelight (100 fois par seconde)
limelight.start(); // Ceci dit à Limelight de commencer à regarder !
}

2. Gestion des pipelines

Les pipelines sont comme de petits programmes instantanément interchangeables qui changent la façon dont Limelight voit le monde. Vous pouvez configurer 10 pipelines différents dans l'interface web Limelight, chacun pour une tâche différente. Voici comment basculer entre eux :

limelight.pipelineSwitch(0); // Basculer vers le pipeline numéro 0

C'est du type "tire et oublie". Limelight changera son pipeline en quelques millisecondes, mais votre code n'attendra pas que cela soit fait avant de continuer. Si vous voulez vérifier l'index du pipeline actuel, appelez

result.getPipelineIndex()

Voir la section suivante pour apprendre à obtenir l'objet LLResult.

3. Obtenir et utiliser les résultats

LLResult est comme un conteneur rempli d'informations sur ce que Limelight voit. Voici comment nous acquérons et utilisons ces informations :

LLResult result = limelight.getLatestResult();
if (result != null && result.isValid()) {
double tx = result.getTx(); // À quelle distance à gauche ou à droite se trouve la cible (degrés)
double ty = result.getTy(); // À quelle distance en haut ou en bas se trouve la cible (degrés)
double ta = result.getTa(); // Quelle taille apparente a la cible (0%-100% de l'image)

telemetry.addData("Cible X", tx);
telemetry.addData("Cible Y", ty);
telemetry.addData("Surface cible", ta);
} else {
telemetry.addData("Limelight", "Pas de cibles");
}

4. Communiquer avec les SnapScripts Python

Vous pouvez écrire vos propres pipelines SnapScript Python dans l'interface web. Utilisez notre générateur SnapScript basé sur LLM pour vous aider à écrire votre code.

Voici comment envoyer des nombres du code robot vers Python et récupérer des nombres :

// Envoyer des nombres à Python
double[] inputs = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
limelight.updatePythonInputs(inputs);

// Récupérer des nombres de Python
double[] pythonOutputs = result.getPythonOutput();
if (pythonOutputs != null && pythonOutputs.length > 0) {
double firstOutput = pythonOutputs[0];
telemetry.addData("Sortie Python :", firstOutput);
}

5. Où est mon robot ? (MegaTag 1)

Limelight peut aider à déterminer où se trouve votre robot sur le terrain en utilisant les AprilTags. Votre Limelight est livré avec une carte AprilTag préinstallée pour le jeu actuel, mais vous pouvez concevoir et télécharger vos propres cartes en utilisant notre constructeur de cartes 3D.

Avant d'essayer d'obtenir la position de votre robot, faites ce qui suit :

  1. Activez "Full 3D" dans l'onglet "Advanced" de votre pipeline AprilTag dans l'interface web.
  2. Utilisez l'interface web pour positionner votre caméra par rapport au centre de l'empreinte de votre robot.

Le système de coordonnées pour botPose correspond au système de coordonnées FTC standard.

  • (0,0,0) est le centre du sol du terrain
  • Pour les configurations non-diamant, 0 degrés de Yaw signifie que l'alliance bleue est sur le côté gauche de votre robot, et l'alliance rouge est sur le côté droit de votre robot.
if (result != null && result.isValid()) {
Pose3D botpose = result.getBotpose();
if (botpose != null) {
double x = botpose.getPosition().x;
double y = botpose.getPosition().y;
telemetry.addData("Position MT1", "(" + x + ", " + y + ")");
}
}

6. Où est mon robot ? (MegaTag 2)

MegaTag 2 est comme MegaTag 1, mais il fusionne les données de votre IMU pour une précision accrue :

// D'abord, dites à Limelight dans quelle direction votre robot fait face
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("Position MT2 :", "(" + x + ", " + y + ")");
}
}

7. Types de résultats internes

Selon la façon dont vous avez configuré vos pipelines, vous aurez accès à différents types de listes de résultats détaillés au sein de l'objet parent LLResults.

Vous n'aurez probablement pas besoin d'utiliser ces listes de résultats. Nous recommandons d'utiliser les fonctions de base getTx(), getTy() chaque fois que possible.

7.1 Résultats de couleur

Les résultats de couleur aident à trouver des cibles colorées :

List<ColorResult> colorTargets = result.getColorResults();
for (ColorResult colorTarget : colorTargets) {
double x = detection.getTargetXDegrees(); // Où elle se trouve (gauche-droite)
double y = detection.getTargetYDegrees(); // Où elle se trouve (haut-bas)
double area = colorTarget.getTargetArea(); // taille (0-100)
telemetry.addData("Cible couleur", "occupe " + area + "% de l'image");
}

7.2 Résultats Fiducial/AprilTag

Les fiducials sont des marqueurs spéciaux (comme les AprilTags) qui aident Limelight à déterminer où il se trouve :

List<FiducialResult> fiducials = result.getFiducialResults();
for (FiducialResult fiducial : fiducials) {
int id = fiducial.getFiducialId(); // Le numéro d'identification du fiducial
double x = detection.getTargetXDegrees(); // Où il se trouve (gauche-droite)
double y = detection.getTargetYDegrees(); // Où il se trouve (haut-bas)
double StrafeDistance_3D = fiducial.getRobotPoseTargetSpace().getY();
telemetry.addData("Fiducial " + id, "est à " + distance + " mètres");
}

Si vous voulez utiliser les informations de pose 3D dans chaque FiducialResult, vous pouvez utiliser les méthodes suivantes :

fiducial.getRobotPoseTargetSpace(); // Pose du robot relative au système de coordonnées AprilTag (Le plus utile)
fiducial.getCameraPoseTargetSpace(); // Pose de la caméra relative à l'AprilTag (utile)
fiducial.getRobotPoseFieldSpace(); // Pose du robot dans le système de coordonnées du terrain basée sur ce tag seul (utile)
fiducial.getTargetPoseCameraSpace(); // Pose de l'AprilTag dans le système de coordonnées de la caméra (peu utile)
fiducial.getTargetPoseRobotSpace(); // Pose de l'AprilTag dans le système de coordonnées du robot (peu utile)

7.3 Résultats de codes-barres

Le pipeline de codes-barres de Limelight est efficace pour détecter et suivre les QR Codes.

List<BarcodeResult> barcodes = result.getBarcodeResults();
for (BarcodeResult barcode : barcodes) {
String data = barcode.getData(); // Ce que dit le code-barres
String family = barcode.getFamily(); // Quel type de code-barres c'est
telemetry.addData("Code-barres", data + " (" + family + ")");
}

7.4 Résultats de classificateur

Les classificateurs neuronaux permettent à Limelight de dire "Je pense que c'est une image de...".

List<ClassifierResult> classifications = result.getClassifierResults();
for (ClassifierResult classification : classifications) {
String className = classification.getClassName(); // Ce que Limelight pense voir
double confidence = classification.getConfidence(); // Score de confiance
telemetry.addData("Je vois un(e)", className + " (" + confidence + "%)");
}

7.5 Résultats de détecteur

Les détecteurs trouvent des objets spécifiques et nous disent où ils se trouvent :

List<DetectorResult> detections = result.getDetectorResults();
for (DetectorResult detection : detections) {
String className = detection.getClassName(); // Ce qui a été détecté
double x = detection.getTargetXDegrees(); // Où il se trouve (gauche-droite)
double y = detection.getTargetYDegrees(); // Où il se trouve (haut-bas)
telemetry.addData(className, "à (" + x + ", " + y + ") degrés");
}

8. Les données sont-elles fraîches ?

Parfois, nous voulons connaître l'âge (en millisecondes) de nos données de résultats.

long staleness = result.getStaleness();
if (staleness < 100) { // Moins de 100 millisecondes
telemetry.addData("Données", "Bonnes");
} else {
telemetry.addData("Données", "Anciennes (" + staleness + " ms)");
}

9. Cartes de terrain personnalisées

Vous pouvez informer Limelight de la disposition spécifique de votre terrain :

LLFieldMap fieldMap = new LLFieldMap(); // Vous devrez remplir ceci avec les données du terrain
boolean success = limelight.uploadFieldmap(fieldMap, null); // null signifie utiliser l'emplacement par défaut
if (success) {
telemetry.addData("Carte du terrain", "Téléchargée avec succès !");
} else {
telemetry.addData("Carte du terrain", "Oups, le téléchargement a échoué");
}

10. Prendre des captures d'écran :

Limelight peut prendre des captures d'écran pour vous aider à déboguer les pipelines hors du terrain :

limelight.captureSnapshot("auto_pov_10s");

Dans l'onglet Input de l'interface web, vous pouvez sélectionner cette capture comme "source d'image" pour vérifier/ajuster vos pipelines.

Pour effacer les anciennes captures :

limelight.deleteSnapshots();
telemetry.addData("Captures", "Toutes effacées !");