Oluşturulan Kodu Bir Robot Programında Kullanma

GRIP, roboRIO üzerinde ve çok fazla ek kod olmadan çalışan FRC® ‘e eklenebilecek bir program sınıfı üretir, çıktıya göre robotu sürün.

Burada, bir robotu bir retroreflektif malzemeye doğru yönlendiren bir GRIP katmanı kullanan eksiksiz bir örnek program bulunmaktadır.

Bu program, görüntü kodunun nasıl çalıştığını göstermek için tasarlanmıştır ve robot programınızı yazmak için en iyi tekniği temsil etmesi gerekmez. Kendi programınızı yazarken aşağıdaki hususlara dikkat edin:

  1. ** Robotu yönlendirmek için kamera çıktısını kullanmak sorunlu olabilir **. Bu örnekteki görüntüleri yakalayan ve işleyen kamera kodu, robotu yönlendirmek için bir kontrol döngüsü için arzu edilen çok daha yavaş bir hızda çalışır. Daha iyi ve yalnızca biraz daha karmaşık bir çözüm, kameradan başlıkları ve işlem oranını almak, ardından bir jiroskop sensörü kullanarak bu başlıklara çok daha hızlı bir kontrol döngüsü yönlendirmesi sağlamaktır.

  2. ** Görüş kodunu ardışık düzeni saran sınıfta tutun **. Nesne yönelimli kod yazmanın daha iyi bir yolu, oluşturulan boru hattı sınıfını alt sınıflara ayırmak veya örneklendirmek ve OpenCV sonuçlarını robot programı yerine orada işlemektir. Bu örnekte robot kodu, ortaya çıkan OpenCV konturlarını değiştirerek sürüş yönünü çıkarır. OpenCV kodunun robot programı boyunca ifşa edilmesi, daha iyi bir algoritmaya sahip olmanız durumunda vizyon algoritmasını değiştirmeyi zorlaştırır.

Iterative-Yinelemeli program tanımları

package org.usfirst.frc.team190.robot;

import org.usfirst.frc.team190.grip.MyVisionPipeline;

import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc;

import edu.wpi.cscore.UsbCamera;
import edu.wpi.first.cameraserver.CameraServer;
import edu.wpi.first.wpilibj.drive.DifferentialDrive;
import edu.wpi.first.wpilibj.PWMSparkMax;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.vision.VisionRunner;
import edu.wpi.first.vision.VisionThread;

public class Robot extends TimedRobot {

    private static final int IMG_WIDTH = 320;
    private static final int IMG_HEIGHT = 240;

    private VisionThread visionThread;
    private double centerX = 0.0;
    private DifferentialDrive drive;
    private PWMSparkMax left;
    private PWMSparkMax right;

    private final Object imgLock = new Object();

Programın bu ilk bölümünde, bu program için kullanılan WPILib sınıfları için tüm içe aktarma ifadelerini görebilirsiniz.

  • ** image width and height-görüntü genişliği ve yüksekliği ** 320x240 piksel olarak tanımlanmıştır.

  • ** VisionThread ** bir WPILib sınıfıdır, kamera işlemenizi robot programının geri kalanından ayrı bir iş parçacığında yapmanızı kolaylaştırır.

  • centerX değeri, tespit edilen hedefin hesaplanan merkez X değeri olacaktır.

  • DifferentialDrive encapsulates the drive motors on this robot and allows simplified driving.

  • imgLock, her görüntü edinme geçişi ve koordinatları işleyen ve robotu yönlendiren koda eşzamanlı olarak güncellenen verilere erişimi senkronize etmek için bir değişkendir.

@Override
public void robotInit() {
    UsbCamera camera = CameraServer.startAutomaticCapture();
    camera.setResolution(IMG_WIDTH, IMG_HEIGHT);

    visionThread = new VisionThread(camera, new MyVisionPipeline(), pipeline -> {
        if (!pipeline.filterContoursOutput().isEmpty()) {
            Rect r = Imgproc.boundingRect(pipeline.filterContoursOutput().get(0));
            synchronized (imgLock) {
                centerX = r.x + (r.width / 2);
            }
        }
    });
    visionThread.start();

    left = new PWMSparkMax(0);
    right = new PWMSparkMax(1);
    drive = new DifferentialDrive(left, right);
}

robotInit() methodu, program başladığında bir kez çağrılır. İstenen çözünürlükte (IMG_WIDTH, IMG_HEIGHT) görüntüleri yakalamaya başlayan bir ** CameraServer ** örneği oluşturur.

Daha sonra VisionThread sınıfının bir örneği oluşturulur. VisionThread, kameradaki görüntüleri eşzamansız olarak ayrı bir iş parçacığında yakalamaya başlar. Her bir görüntüyü işledikten sonra, hedefin etrafındaki hesaplanan bounding box-sınırlayıcı kutu geri alınır ve center X değeri hesaplanır. Bu centerX değeri, görüntüdeki dikdörtgenin merkezinin x piksel değeri olacaktır.

VisionThread ayrıca bir VisionPipeline örneğini (burada GRIP tarafından oluşturulan bir alt sınıfımız MyVisionPipeline var) ve ayrıca ardışık düzen çıkışını işlemek için kullandığımız bir geri arama var. Bu örnekte, boru hattı, bir türden hedefleri veya hedefleri işaretleyen bir kontur listesi (bir görüntüdeki alanların ana hatları) çıkarır. Geri arama, merkezini bulmak için ilk konturun sınırlayıcı kutusunu bulur ve ardından bu değeri centerX değişkenine kaydeder. Atamanın etrafındaki senkronize bloğa dikkat edin: Bu, değişkeni okumak için senkronize bloklar kullandığı sürece ana robot iş parçacığının her zaman değişkenin en güncel değerine sahip olmasını sağlar.

@Override
public void autonomousPeriodic() {
    double centerX;
    synchronized (imgLock) {
        centerX = this.centerX;
    }
    double turn = centerX - (IMG_WIDTH / 2);
    drive.arcadeDrive(-0.6, turn * 0.005);
}

Bu, programın son kısmı, maçın otonom süresi boyunca tekrar tekrar çağrılır. Hedefin centerX piksel değerini alır görüntüde dikdörtgen ortalandığında sıfır olan bir değere değiştirmek için görüntü genişliğinin yarısını çıkarır. ** hedef merkez çerçevenin solunda veya sağında olduğunda pozitif veya negatif. ** bir değer ile değiştirir. Bu değer, robotu hedefe yönlendirmek için kullanılır.

Başlangıçta ** senkronize ** bloğuna dikkat edin. Bu, VisionThread tarafından bulunan en son centerX değerinin anlık görüntüsünü alır.