Aller au contenu principal

Guide de programmation FTC Java & Blockly

(Captures d'écran Blockly à venir !)

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

Javadoc : [Lien vers la Javadoc à venir]

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

Conseils pour réussir

  • Commencez par la solution la plus 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 couleur standard à 90FPS au lieu d'un réseau neuronal pour suivre les pièces de jeu.

Voici un exemple du type de question à se poser en commençant à programmer : En téléopération, 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 une balise spécifique (vitesseLaterale = resultat.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 modifient 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 passer de l'un à l'autre :

limelight.pipelineSwitch(0); // Passer au pipeline numéro 0

C'est une opération "fire-and-forget". Limelight changera son pipeline en quelques millisecondes, mais votre code ne l'attendra pas 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. Obtention et utilisation des 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 a la cible (0%-100% de l'image)

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

4. Communication avec les SnapScripts Python

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

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

// Envoi de 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ération 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 des AprilTags. Votre Limelight est livré pré-installé avec une carte AprilTag 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é de lacet 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.getX();
double y = botpose.getY();
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 est orienté
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.getX();
double y = botpose_mt2.getY();
telemetry.addData("Position MT2 :", "(" + x + ", " + y + ")");
}
}

7. Types de résultats internes

Selon la configuration de 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 méthodes 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 de couleur", "occupe " + area + "% de l'image");
}

7.2 Résultats de fiduciaires/AprilTag

Les fiduciaires sont des marqueurs spéciaux (comme les AprilTags) qui aident Limelight à déterminer sa position :

List<FiducialResult> fiducials = result.getFiducialResults();
for (FiducialResult fiducial : fiducials) {
int id = fiducial.getFiducialId(); // Le numéro d'identification du fiduciaire
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("Fiduciaire " + 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 par rapport au système de coordonnées de l'AprilTag (le plus utile)
fiducial.getCameraPoseTargetSpace(); // Pose de la caméra par rapport à l'AprilTag (utile)
fiducial.getRobotPoseFieldSpace(); // Pose du robot dans le système de coordonnées du terrain basé uniquement sur cette balise (utile)
fiducial.getTargetPoseCameraSpace(); // Pose de l'AprilTag dans le système de coordonnées de la caméra (pas très utile)
fiducial.getTargetPoseRobotSpace(); // Pose de l'AprilTag dans le système de coordonnées du robot (pas très utile)

7.3 Résultats de codes-barres

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

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 classification

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", className + " (" + confidence + "%)");
}

7.5 Résultats de détection

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

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 récentes ?

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. Prise de 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 d'écran :

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