# PARTs Library

The PARTs Utility Library explained with examples.

# About PARTs Library

The PARTs library is a public Java / Gradle library full of utilities that we use for our robot.  
We've felt a need to make our own library as our amount of reusable code skyrocketed.  
It's hard to keep track of all code that's reusable and with the more modular direction we were heading, it was obvious that we need a reusable library. Hence the PARTs Library was born. This lets us write game agnostic code that can be reused as we need down the line. Better yet, it's public so everyone can use our code!

The code can be found [here](https://www.github.com/3492PARTs/PARTsLib).

# How-To: Setup and use PARTsLib

### Explanation

<table id="bkmrk-%E2%9A%A0%EF%B8%8F-warning-this-page" style="width: 80%; margin: 0 auto; border-collapse: collapse;"> <thead> <tr> <th style="text-align: center;">⚠️ Warning</th> </tr> </thead> <tbody> <tr> <td style="text-align: center;">This page only contains technical information.</td> </tr> </tbody></table>

<center id="bkmrk-last-updated%3A-april-">Last updated: April 2nd, 2026</center>This guide explains how to setup and include PARTsLib into your robot project. There are two ways to add PARTsLib into your robot project. #### Requirements

The library requrires the following vendor dependincies to be installed.

- WPILib-New-Commands
- PathplannerLib
- CTRE-Phoenix (v6)

#### Method A - Git

This method involves adding PARTsLib as a submodule in your robot project.  
The main advantage to adding the library as a submodule is getting the latest updates.  
Experimental library versions are available for testing.

<div id="bkmrk-%F0%9F%94%8E-note-this-rquires-" style="border-left: 4px solid #2f81f7; padding: 0.75em 1em;"> **🔎 Note**  
 This rquires your robot project to be in a git repository. </div>  
<details id="bkmrk-install-steps-adding"><summary>Install Steps</summary>

**Adding the library as a submodule.**

1. In your terminal, navigate to your project folder.
2. Add the repository as a submodule. ```
    git submodule add PARTsLib https://github.com/3492PARTs/PARTsLib.git
    ```
3. Initialize and update the submodule. ```
    git submodule update --init -r
    ```
 
**Adding the library into the gradle project.**

1. In settings.gradle add thr following to the bottom of the file on a new line. ```
    include("PARTsLib")
    ```
2. Navigate to build.gradle. Look for the dependencides and add the following line to the bottom. ```
    dependencies {
        // All other stuff in here.
        implementation(project(':PARTsLib'))
    }
    ```
3. Save and build the project.
 
</details>#### Method B - Jitpack.io

This method is more stable because a stable release of the library is used.  
Adding the library this way is easier due to it just being a dependency.  
A git repository is not required.

<details id="bkmrk-install-steps-adding-1"><summary>Install Steps</summary>

**Adding the library as a dependency.**

1. In your terminal, navigate to your project folder.
2. Navigate to build.gradle and add the following lines under the java segmemt. For the version, put any release listed on the [Jitpack](https://jitpack.io/#3492PARTs/PARTsLib) site. E.g. "v2026.1.0". ```
    java {<br></br>    // ...<br></br>}<br></br><br></br>repositories {<br></br>    mavenCentral()<br></br>    maven { url "https://jitpack.io" }<br></br>}<br></br><br></br>def PARTSLIB_VERSION = "[VERSION_HERE]"
    ```
3. In the same file, scroll down to the dependencies section and add the following line to the bottom of that segment. ```
    dependencies {<br></br>    // Other things.<br></br><br></br>    implementation("com.github.3492PARTs:PARTsLib:${PARTSLIB_VERSION}")<br></br>}
    ```
 
</details>

# PARTs Unit

### Explanation &amp; History

A PARTs Unit is a simple and robust way to manage different used units across the robot code.  
The user creates a new PARTs Unit and specifies the starting value and its unit. After that, the PARTs Unit can be used anywhere to convert the unit on the fly. E.g. feet to meters.  
We created this mainly because we were having issues with the base WPI unit conversions; there were issues where types didn't convert correctly for us. Not only did it solve our unit issues, it also allowed us to have full control over our units. Since the source code is so straight forward, it's easier to troubleshoot and use.

### Code Example

Using PARTs Units really is easy! Just import the two PARTs Unit classes and create a new PARTs Unit.

```java
package;

// Import the PARTs Units.
import org.parts3492.partslib.PARTsUnit;

// Import the Unit types.
import org.parts3492.partslib.PARTsUnit.PARTsUnitType;


public class MyClass {
        // Create our PARTs Unit.                Value,  The type of the unit.
        public PARTsUnit myAngle = new PARTsUnit(180.0,  PARTsUnitType.Angle);

        // Keep in mind how units convert, some units cannot convert with
        // other units. E.g. Meters to Percent.
        
        // Convert our angle to radians!            Convert TO radians.
        public double myAngleInRadians = myAngle.to(PARTsUnitType.Radian);
}

```

# PARTs Preferences

### Explanation &amp; History

PARTs Preferences is a wrapper and handler for the WPI Lib Preferences feature. There are two parts to this feature, PARTs Preferences, and PARTs Preference. PARTs Preference is the object that handles the preference's type of data, and its key, or label with easy methods to get the value back. PARTs Preferences is the manager of each preference. In each subsystem, a PARTs Preferences instance is created. With this instance, preferences can be created and retrieved. This feature is automatically set up in our [PARTs Subsystem](#bkmrk-package%3B-import-org.).

### Code Example

```java
package;

import org.parts3492.partslib.PARTsPreferences;

public class MyClass {
    
    public MyClass() {
        super();

        // Create new PARTs Preferences manager.
        // Keep in mind that this is not required in a PARTsSubsystem, as it already has one built in.
        PARTsPreferences partsPrefrences = new PARTsPreferences();

        // Create our preferences.
        // Each type is an overload, or version of the same function.
        partsPrefrences.addPreference("MyBoolean", true);
        partsPrefrences.addPreference("MyInt", 42);
        partsPrefrences.addPreference("MyDouble", 3.14);
        partsPrefrences.addPreference("MyFloat", 1.23f);
        partsPrefrences.addPreference("MyString", "MyValue");
    }
}

```

# PARTs Subsystem

### Explanation &amp; History

<table id="bkmrk-%F0%9F%94%8E-keep-in-mind-this-"><thead><tr><th><center>🔎 Keep in Mind<center></center></center></th></tr></thead><tbody><tr><td>This includes IPARTsSubsystem as it acts as the recipe for the subsystem.</td></tr></tbody></table>

We have all these tools that we use but now we run in the issue of repeating all this code just to use them. We also want a good custom logging and telemetry solution. This is what inspired us to make our custom subsystem too.

With that, our subsystem currently features:

- Telemetry
- Logging
- Stop
- Reset

We included both stop and reset features for convenience and simplicity.

### Code Example

Please note that the PARTs Subsystem is meant to be extended, not used directly.

```java
package;

// Import the subsystem so we can extend it.
import org.parts3492.partslib.command.PARTsSubsystem;

public class MySubsystem extends PARTsSubsystem {

    private boolean publishTelemetry = true;
    private boolean enableLogging = true;

    // My awesome logged string.
    public String myAwesomeString = "Hello world!";
    
    public MySubsystem() {
        super();
    }

    @Override
    public void outputTelemetry() {
        partsNT.putString("My Awesome Telemetry", myAwesomeString, publishTelemetry);
    }

    @Override
    public void stop() {
        // Stop the logging and telemetry since the subsystem is stopped.
        publishTelemetry = false;
        enableLogging = false;

    }

    @Override
    public void reset() {
        // Reset the telemetry and logging to be published again when we reset the subsystem.
        publishTelemetry = true;
        enableLogging = true;
    }

    @Override
    public void log() {
        // Log our string.     The log name.    The log value.   Whether to log or not.
        partsLogger.logString("My Awesome Log", myAwesomeString, enableLogging);
    }   
}

```

# PARTs Command Utilities

### Explanation &amp; History

PARTs Command Utilities are used for commands in the robot project. Commands are actions that tell the robot what to do with its subsystems. Currently the only feature this class provides is naming our commands for logging and debugging reasons. We do it this way because it allows us to easily chain other actions or configurations with the command.

### Code Example

```java
package;

import org.parts3492.partslib.command.PARTsCommandUtils;
import org.parts3492.partslib.command.PARTsSubsystem;

import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.Commands;

public class MySubsystem extends PARTsSubsystem {
    
    public MySubsystem() {
        super();
    }

    public Command commandDoNothing() {
        // Return our command.                   Our command name.   The command.
        return PARTsCommandUtils.setCommandName("MySubsystem.print", Commands.idle(this));
    }

    @Override
    public void outputTelemetry() {}

    @Override
    public void stop() {}

    @Override
    public void reset() {}

    @Override
    public void log() {}
}

```

# April Tag

### Explanation &amp; History

The days of Retroreflection are over, AprilTags are here. AprilTags are small QR-Code-like visual tags used in robotics. They provide low overhead, high accuracy localization for lots of applications. They are used in FRC for robot localization to the field, or specific element. AprilTags have unique IDs that are used to identify where they are at on the field. The IDs are mapped to known positions on the field.

All this feature encompasses is to make a container specifying its ID and the known 3D pose of that AprilTag.

### Code Example

```java
package;

import edu.wpi.first.math.geometry.Pose3d;
import edu.wpi.first.math.geometry.Rotation3d;

import org.parts3492.partslib.game.AprilTag;
import org.parts3492.partslib.PARTsUnit;

public class MyClass {

    int tagID = 1;
    // In meters.
    double positionX = PARTsUnit.InchesToMeters.apply(467.64);
    double positionY = PARTsUnit.InchesToMeters.apply(292.31);
    double positionZ = PARTsUnit.InchesToMeters.apply(35.00);
    
    // In radians.
    double rotationX = 0;
    double rotationY = 0;
    double rotationZ = 3.141593; // 180 in Degrees.

    // Create our AprilTag object.
    AprilTag tag = new AprilTag(
        tagID, 
        new Pose3d(
            positionX,
            positionY,
            positionZ,

            new Rotation3d(
                rotationX,
                rotationY,
                rotationZ
            )
        )
    );
}


```

# Field Base

### Explanation &amp; History

Since we've started working with full-field localization, we have had a need for a software defined field with the april tags and other field data. This base field is meant to be game-agnostic. It gets extended and that years AprilTags are created in that years field in the robot program. The base field contains the size of the field, along with helpers for field position calcualtions and AprilTag checks.

For AprilTags, refer to the [April Tag](https://wiki.parts3492.org/books/parts-library/page/april-tag) page.

### Code Example

```java
package;

import org.parts3492.partslib.game.AprilTag;
import org.parts3492.partslib.game.FieldBase;

import edu.wpi.first.math.geometry.Pose3d;
import edu.wpi.first.math.geometry.Rotation3d;
import edu.wpi.first.math.util.Units;

public class MyField implements FieldBase {

    // My 2026 AprilTags.
    AprilTag[] APRILTAGS = {
        new AprilTag(1, new Pose3d(
                Units.inchesToMeters(467.64),
                Units.inchesToMeters(292.31),
                Units.inchesToMeters(35.00),
                new Rotation3d(
                    Units.degreesToRadians(0), 
                    Units.degreesToRadians(0), 
                    Units.degreesToRadians(180)
                )
            )
        ),

        new AprilTag(2, new Pose3d(
                Units.inchesToMeters(469.11), 
                Units.inchesToMeters(182.60),
                Units.inchesToMeters(44.25),
                new Rotation3d(
                    Units.degreesToRadians(0), 
                    Units.degreesToRadians(0), 
                    Units.degreesToRadians(90)
                )
            )
        ),

        new AprilTag(3, new Pose3d(
                    Units.inchesToMeters(445.35),
                    Units.inchesToMeters(172.84),
                    Units.inchesToMeters(44.25),
                new Rotation3d(
                    Units.degreesToRadians(0), 
                    Units.degreesToRadians(0), 
                    Units.degreesToRadians(180)
                )
            )
        )

        // More apriltags can be added here.
    };

    // ...
}

```

# PARTs NetworkTables

### Explanation &amp; History

Sending and getting data from the dashboard and other network devices requires a lot of tedious work which clutters up our code as we work and test. This utility of the library fixes that issue by making the proces extremely easy. Not only does the utility make it easy to send and recieve data through the robots network, it also optimizes the data it handles. This is important when multiple subsystems are all sending data periodically.

### Code Example

```java
package;

import org.parts3492.partslib.network.PARTsNT;

public class MyClass {

    // The PARTsNT instance for this class.
    PARTsNT partsNT;

    // Flag to allow sending and receiving the real network data.
    // This is useful for conditionally enabling network access. E.g. sending data
    // to the dashboard only in debug mode.
    boolean allowNetworkAccess = true;

    // My cool boolean.
    boolean myBoolean = true;

    public MyClass() {
        // Initialize the PARTsNT instance for this class.
        partsNT = new PARTsNT("MyClass");

        // Send myBoolean to the network. This will create a new entry in the network
        // table with the key "MyClass/MyBoolean" and the value of myBoolean.
        partsNT.putBoolean("MyBoolean", myBoolean, allowNetworkAccess);

        // Get modified myBoolean from the network. This will return the value of the
        // entry with the key "MyClass/MyBoolean" if it exists, or the default value of
        // myBoolean if it doesn't exist. This allows us to modify myBoolean from the
        // network and have it update in our code.
        myBoolean = getMyNetworkBoolean();
    }

    // Method to get myBoolean from the network.
    public boolean getMyNetworkBoolean() {
        return partsNT.getBoolean("MyBoolean", allowNetworkAccess);
    }
}


```

# PARTs Dashboard

### Explanation &amp; History

When constructing a the right dashboard for competition, we found it difficult to easily control the dashboard in a reliable fashion. That's why we make PARTs Dashboard which serves as a helper to control the dashboard.

# PARTs Logger

### Explanation &amp; History

As our complexity of our robot grew, logging became important. Not only is it a good source of information for debugging, but the data can also be used for simulation of the robot. Robot simulation is an essential tool in programming and debugging the robot. It allows the programmers to iron out code bugs and test logic flows before they even get the robot. Even better, it's possible to simulate hardware such as motors. Another use for logging is reading the logs after a match.

### Code Example

```java
package;

import org.parts3492.partslib.PARTsLogger;

public class MyClass {

    private boolean loggingEnabled = true;
    public boolean myCoolBoolean = true;
    PARTsLogger logger;

    public MyClass() {
        logger = new PARTsLogger("MyClass");

        logger.logBoolean("MyCoolBoolean", myCoolBoolean, loggingEnabled);
    }
}


```