---
# System prepended metadata

title: 程式
tags: [FRC9427程式工作進度]

---

##### tags:`Limelight Code`

FRC 程式
===
---
## Limelight
1.在2024的比賽中有16個Apriltag，顯然地不可能每個按鈕都單獨拉一個AprilTag寫，按鈕不可能這麼多，實際上就算真的寫了16個按鈕Driver也記不起來，所以我們要想一個簡略的判斷方式以方便我們維護程式跟除錯。
2.因為這季沒有要用trap所以stage的Apriltag是可以不用對的，也就是說我們可以只需要對Amp,Source,Speaker就好，那這樣一個簡易的想法就出來了: **我們的判斷式主要有兩層，第一層式判斷紅藍方,第二層是判斷目標名稱**，那麼一個簡易的判斷想法就出來了
```java
 if(getTagID() == 7 || getTagID() == 4){
            TagName = "Speaker";
        }
        else if(getTagID() == 5 || getTagID() == 6){
            TagName = "Amp";
        }
        else if(getTagID() == 1 || getTagID() == 2 || getTagID() == 9 || getTagID() == 10){
            TagName = "LoadingStation";
        }
        if(getTagID() == 3 || getTagID() == 4 || getTagID() == 5 || getTagID() == 9 || getTagID() == 10){
            TagAlliance = "Red";
        }
        else if(getTagID() == 1 || getTagID() == 2 || getTagID() == 6 || getTagID() == 7 || getTagID() == 8){
            TagAlliance = "Blue";
        }
```
但要是這樣就直接丟給```Comand```的話整個判斷就太醜了，因此我們需要一個```Struct```來存取同樣是字串的紅藍方跟目標名稱，但問題來了: `JAVA`沒有```Struct```，所以我們建造一個名為```Student```的類別來解決這個問題。
```java
package frc.robot;

import java.util.HashMap;

public class Student {
    private HashMap<String, String> data;

    public Student(String tagAlliance, String tagName) {
        data = new HashMap<>();
        data.put("TagAlliance", tagAlliance);
        data.put("TagName", tagName);
    }

    // Getter for TagAlliance
    public String getTagAlliance() {
        return data.get("TagAlliance");
    }

    // Setter for TagAlliance
    public void setTagAlliance(String tagAlliance) {
        data.put("TagAlliance", tagAlliance);
    }

    // Getter for TagName
    public String getTagName() {
        return data.get("TagName");
    }

    // Setter for TagName
    public void setTagName(String tagName) {
        data.put("TagName", tagName);
    }
}
```
有了這個`Student`我們再使用集合物件優化程式碼就可以用一個新`Function`
如下:
```java
 public Student getTag() {
        if (getTagID() <= 0  || getTagID() > 10) {//避免NullPointerException
            return null;
        }    
        HashMap<Integer, Student> tagMap = new HashMap<>();
        tagMap.put(3, new Student("Red", "Speaker"));
        tagMap.put(4, new Student("Red", "Speaker"));
        tagMap.put(5, new Student("Red", "Amp"));
        tagMap.put(9, new Student("Red", "Source"));
        tagMap.put(10, new Student("Red", "Source"));
        tagMap.put(1, new Student("Blue", "Source"));
        tagMap.put(2, new Student("Blue", "Source"));
        tagMap.put(6, new Student("Blue", "Amp"));
        tagMap.put(7, new Student("Blue", "Speaker"));
        tagMap.put(8, new Student("Blue", "Speaker"));
        return tagMap.getOrDefault(getTagID(), new Student("", ""));
    }   
```
這樣的話就可以直接在Command裡面使用了，具體如下:
```java
package frc.robot.Apriltag;

import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj2.command.Command;
import frc.robot.subsystems.SwerveSubsystem;

public class LimelightCommand extends Command{
    private final SwerveSubsystem m_drive;
    private final LimelightSubsystem limelight;
    private final double Target = 0.8;
    private final double Zkp = 0.65;
    private final double Xkp = 0.3;
    private final double Yawkp = 0.5;
    private final String Name;
    public LimelightCommand(SwerveSubsystem m_drive,LimelightSubsystem limelight,String Name){
        this.limelight = limelight;
        this.m_drive = m_drive;
        this.Name = limelight.getTag().getTagName();
        addRequirements(m_drive);
    }
    @Override
    public void initialize(){
        limelight.setLEDMode("On");
        limelight.setCameraMode(0);
    }
    @Override
    public void execute(){
        if (limelight != null && limelight.getTv() != 0 && DriverStation.getAlliance() != null && limelight.getTag() != null &&
            !DriverStation.getAlliance().toString().isEmpty() && !limelight.getTag().getTagAlliance().isEmpty()) {
            String alliance = DriverStation.getAlliance().toString();
            String tagAlliance = limelight.getTag().getTagAlliance();
            if (alliance.equals(tagAlliance)) {
                switch (Name) {
                    case "Speaker":
                        m_drive.drive((Target + limelight.getTargetSpaceRobotPose()[2])*Zkp, 
                                      limelight.getTargetSpaceRobotPose()[0]*Xkp,
                                      limelight.getTargetSpaceRobotPose()[5]*Yawkp,
                                      true, true);
                        SmartDashboard.putString("goal", "Speaker");  
                        break;
                    case "Amp":
                        m_drive.drive((Target + limelight.getTargetSpaceRobotPose()[2])*Zkp, 
                                      limelight.getTargetSpaceRobotPose()[0]*Xkp,
                                      limelight.getTargetSpaceRobotPose()[5]*Yawkp,
                                      true, true);
                        SmartDashboard.putString("goal", "Amp");
                        break;
                    case "Source":
                        m_drive.drive((Target + limelight.getTargetSpaceRobotPose()[2])*Zkp, 
                                      limelight.getTargetSpaceRobotPose()[0]*Xkp,
                                      limelight.getTargetSpaceRobotPose()[5]*Yawkp,
                                      true, true);
                        SmartDashboard.putString("goal", "Source");
                        break;
                    default:
                        break;
                }
            } else {
                SmartDashboard.putString("goal", "Alliance color not the teamcolor");
            }
        } else {
            SmartDashboard.putString("goal", "NoGoalNow!!!!!");
        }
     
        }
    
    @Override
    public void end(boolean interrupted){
        System.out.println("Limelightend");
    }
    @Override
    public  boolean isFinished(){
        return false;
    }
}
```
但這個程式仍然有許多問題，像是使用Switch本身會讓程式結構變得攏長，不方便維護，跟擴展性極低......，雖然我們不能使用多型來編寫這個Limelight程式，但我們可以運用其他方法來解決這些問題:

首先我們先把我們的getTag```Function```變成這種形式，這樣才能最大化運用集合物件的概念，我們的目的是希望Limelight在看到Tag時能夠知道它的屬性，顯然上一版忘記了這個設計初衷，所以我們讓Limelight需要看到的ID都加上它的屬性，並讓Limelight在看到TagID的時候可以直接回傳它的屬性，而我們也在此加上了保護，為了避免在我們看到沒有編寫屬性的ID時系統會跳NullPointerException我們加了getOrDefault讓它直接回傳空的屬性
```java

    public Student getTag() {
        HashMap<Integer, Student> tagMap = new HashMap<>();
        tagMap.put(3, new Student("red", "Speaker"));
        tagMap.put(4, new Student("red", "Speaker"));
        tagMap.put(5, new Student("red", "Amp"));
        tagMap.put(9, new Student("red", "Source"));
        tagMap.put(10, new Student("red", "Source"));
        tagMap.put(1, new Student("blue", "Source"));
        tagMap.put(2, new Student("blue", "Source"));
        tagMap.put(6, new Student("blue", "Amp"));
        tagMap.put(7, new Student("blue", "Speaker"));
        tagMap.put(8, new Student("blue", "Speaker"));
        tagMap.getOrDefault((int) getTagID(), new Student("", ""));// 避免NullPointerException
        return tagMap.get((int) getTagID());

    }

```

之後我們在student這個類別裡加上一個```Function```來接收Limelight看到的Tag的屬性

```java
 public String[] CorrespondKey() {
        return new String[] { Fiedcharacteristic.get("TagAlliance"), Fiedcharacteristic.get("TagName") };
    }
```

然後我們就可以把我們的判斷式縮減成這樣一行，就能夠成功解決之前的問題

```java
    String[] TagField = limelight.getTag().CorrespondKey();
        String Nowalliance = DriverStation.getAlliance().toString();
        if (TagField == new String[] { Nowalliance, Name }) {
            m_drive.drive((Target + limelight.getTargetSpaceRobotPose()[2]) * Zkp,
                    limelight.getTargetSpaceRobotPose()[0] * Xkp,
                    limelight.getTargetSpaceRobotPose()[5] * Yawkp,
                    true, true);
        }
```










