# Absolute Encoders

YAGSL supports most common FRC absolute encoders. Absolute encoders are required if you are using a brushed motor .

The absolute encoder value will show up in your driver dashboard under `swerve/modules/.../Raw Absolute Encoder` and can be used to tune the `absoluteEncoderOffset` in module JSON configuration files under most circumstances.

## Absolute Encoder Checklist

* [ ] All Absolute Encoder's spin counterclockwise positive.
* [ ] Magnetic Absolute encoders have a good read on the magnet while still and in operation (while the robot moves).
* [ ] Absolute Encoders have unique CAN ID's or Analog Input Channel's.
* [ ] Absolute Encoder are defined with the correct ID or Analog Input Channel.
* [ ] Absolute Encoders have full range (`0`-`360`)

## Swerve Absolute Encoder Wrapper

YAGSL created wrappers over all supported Absolute Encoders to uniformly fetch and set data that is needed for a Swerve Module to operate. This wrapper is called [`SwerveAbsoluteEncoder`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/encoders/SwerveAbsoluteEncoder.html). All [`SwerveAbsoluteEncoder`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/encoders/SwerveAbsoluteEncoder.html)'s can be fetched via the [`SwerveModule`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/SwerveModule.html#configuration) configuration object [`SwerveModuleConfiguration`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/parser/SwerveModuleConfiguration.html) absolute encoder attribute [`absoluteEncoder`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/parser/SwerveModuleConfiguration.html#absoluteEncoder). The [`SwerveModule`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/SwerveModule.html) is able to be fetched by [`SwerveDrive.getModules()`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/SwerveDrive.html#getModules\(\)) easily.

YAGSL created wrappers over all supported Motor Controllers to uniformly fetch and set data that is needed for a Swerve Drive to operate. This wrapper is called [`SwerveMotor`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/motors/SwerveMotor.html). All [`SwerveMotor`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/motors/SwerveMotor.html)'s can be fetched via the [`SwerveModule`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/SwerveModule.html#configuration) configuration object [`SwerveModuleConfiguration`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/parser/SwerveModuleConfiguration.html) motor definitions [`angleMotor`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/parser/SwerveModuleConfiguration.html#angleMotor) and [`driveMotor`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/parser/SwerveModuleConfiguration.html#driveMotor). The [`SwerveModule`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/SwerveModule.html) is able to be fetched by [`SwerveDrive.getModules()`](https://yet-another-software-suite.github.io/YAGSL/javadocs/swervelib/SwerveDrive.html#getModules\(\)) easily.

<pre class="language-java"><code class="lang-java">import com.ctre.phoenix6.hardware.CANcoder;
 
   /**
   * Initialize {@link SwerveDrive} with the directory provided.
   *
   * @param directory Directory of swerve drive config files.
   */
  public SwerveSubsystem(File directory)
  {
    // Angle conversion factor is 360 / (GEAR RATIO * ENCODER RESOLUTION)
    //  In this case the gear ratio is 12.8 motor revolutions per wheel rotation.
    //  The encoder resolution per motor revolution is 1 per motor revolution.
    double angleConversionFactor = SwerveMath.calculateDegreesPerSteeringRotation(12.8, 1);
    // Motor conversion factor is (PI * WHEEL DIAMETER IN METERS) / (GEAR RATIO * ENCODER RESOLUTION).
    //  In this case the wheel diameter is 4 inches, which must be converted to meters to get meters/second.
    //  The gear ratio is 6.75 motor revolutions per wheel rotation.
    //  The encoder resolution per motor revolution is 1 per motor revolution.
    double driveConversionFactor = SwerveMath.calculateMetersPerRotation(Units.inchesToMeters(4), 6.75, 1);

    // Configure the Telemetry before creating the SwerveDrive to avoid unnecessary objects being created.
    SwerveDriveTelemetry.verbosity = TelemetryVerbosity.HIGH;
    try
    {
      swerveDrive = new SwerveParser(directory).createSwerveDrive(maximumSpeed, angleConversionFactor, driveConversionFactor);
    } catch (Exception e)
    {
      throw new RuntimeException(e);
    }
    swerveDrive.setHeadingCorrection(false); // Heading correction should only be used while controlling the robot via angle.

    for(SwerveModule m : swerveDrive.getModules())
    {
      System.out.println("Module Name: "+m.configuration.name);
      <a data-footnote-ref href="#user-content-fn-1">CANcoder</a> absoluteEncoder = (<a data-footnote-ref href="#user-content-fn-2">CANcoder</a>)m.configuration.absoluteEncoder.getAbsoluteEncoder();
    }
  }
</code></pre>

## Absolute Encoder Configuration

{% hint style="warning" %}
Only CTRE devices currently support the `canbus` option, if your device is using the roboRIO `canbus` you must use the value of `null` or `"rio"` for supported CTRE devices. If you are using a CANivore, and the device is on the CANivore bus, the name must match the CANivore name.
{% endhint %}

{% hint style="success" %}
If your absolute encoder is attached to your SparkMAX, use the function [`SwerveDrive.pushOffsetsToEncoders()`](https://broncbotz3481.github.io/YAGSL-Lib/docs/swervelib/SwerveDrive.html#pushOffsetsToEncoders\(\)) for the best performance. This sets the onboard PID sensor to the attached encoder!
{% endhint %}

Inside any module JSON such as `frontleft.json`,`frontright.json`,`backleft.json`,`backright.json` this is what you would see to configure a absolute encoder.

<pre class="language-json"><code class="lang-json">{
  "drive": {
    "type": <a data-footnote-ref href="#user-content-fn-3">"sparkmax"</a>,
    "id": <a data-footnote-ref href="#user-content-fn-4">5</a>,
    "canbus": <a data-footnote-ref href="#user-content-fn-5">null</a>
  },
  "angle": {
    "type": <a data-footnote-ref href="#user-content-fn-3">"sparkmax"</a>,
    "id": <a data-footnote-ref href="#user-content-fn-6">6</a>,
    "canbus": <a data-footnote-ref href="#user-content-fn-5">null</a>
  },
  "encoder": {
    "type": <a data-footnote-ref href="#user-content-fn-7">"cancoder"</a>,
    "id": <a data-footnote-ref href="#user-content-fn-8">11</a>,
    "canbus": <a data-footnote-ref href="#user-content-fn-9">null</a>
  },
  "inverted": {
    "drive": <a data-footnote-ref href="#user-content-fn-10">false</a>,
    "angle": <a data-footnote-ref href="#user-content-fn-11">false</a>
  },
  "absoluteEncoderOffset": <a data-footnote-ref href="#user-content-fn-12">-18.281</a>,
  "absoluteEncoderInverted": <a data-footnote-ref href="#user-content-fn-13">false</a>,
  "location": {
    "front": <a data-footnote-ref href="#user-content-fn-14">-12</a>,
    "left": <a data-footnote-ref href="#user-content-fn-15">-12</a>
  }
}
</code></pre>

## Possible Absolute Encoder Types

{% hint style="warning" %}
Try inverting your steering/angle/azimuth motor if your module keeps spinning around.
{% endhint %}

<table data-full-width="true"><thead><tr><th width="538">Device</th><th width="269">type</th></tr></thead><tbody><tr><td>None</td><td><code>none</code></td></tr><tr><td><a href="https://docs.revrobotics.com/brushless/spark-max/encoders/absolute#data-port-connector-information">Integrated/Attached</a> (via SparkMAX DutyCycle)</td><td><a data-footnote-ref href="#user-content-fn-16"><code>attached</code></a></td></tr><tr><td><a href="https://docs.revrobotics.com/brushless/spark-max/encoders/absolute#data-port-connector-information">SparkMax Analog</a> (via SparkMAX Analog Pin)</td><td><a data-footnote-ref href="#user-content-fn-17"><code>sparkmax_analog</code></a></td></tr><tr><td><a href="https://docs.revrobotics.com/brushless/spark-max/encoders/absolute#data-port-connector-information">SparkMax Analog</a> (via SparkMAX Analog Pin with 5V power)</td><td><a data-footnote-ref href="#user-content-fn-18"><code>sparkmax_analog5v</code></a></td></tr><tr><td><a href="https://docs.reduxrobotics.com/canandmag/spark-max#using-the-pwm-output-with-spark-max">Canandmag</a> (via SparkMAX)</td><td><a data-footnote-ref href="#user-content-fn-19"><code>canandmag</code></a></td></tr><tr><td><a href="https://docs.reduxrobotics.com/canandmag/getting-started">Canandmag </a>(via CAN)</td><td><a data-footnote-ref href="#user-content-fn-20"><code>canandmag_can</code></a></td></tr><tr><td><a href="https://pro.docs.ctr-electronics.com/en/latest/docs/hardware-reference/cancoder/index.html">CANcoder</a></td><td><a data-footnote-ref href="#user-content-fn-21"><code>cancoder</code></a></td></tr><tr><td><a href="https://www.revrobotics.com/rev-11-1271/">Throughbore</a> (via DIO)</td><td><a data-footnote-ref href="#user-content-fn-22"><code>throughbore</code></a></td></tr><tr><td><a href="https://www.thethriftybot.com/products/thrifty-absolute-magnetic-encoder">Thrifty Absolute Magnetic Encoder</a> (via Analog Input)</td><td><a data-footnote-ref href="#user-content-fn-23"><code>thrifty</code></a></td></tr><tr><td><a href="https://www.andymark.com/products/ma3-absolute-encoder-with-cable">MA3</a> (via Analog Input)</td><td><a data-footnote-ref href="#user-content-fn-24"><code>ma3</code></a></td></tr><tr><td><a href="https://store.ctr-electronics.com/srx-mag-encoder/">SRX Mag</a> (via PWM)</td><td><a data-footnote-ref href="#user-content-fn-25"><code>ctre_mag</code></a></td></tr><tr><td><a href="https://www.andymark.com/products/am-mag-encoder">AM Mag</a> (via PWM)</td><td><a data-footnote-ref href="#user-content-fn-26"><code>am_mag</code></a></td></tr><tr><td>PWM DutyCycle</td><td><code>dutycycle</code></td></tr><tr><td>Analog Encoder</td><td><code>analog</code></td></tr></tbody></table>

[^1]: [`CANcoder`](https://api.ctr-electronics.com/phoenix6/release/java/com/ctre/phoenix6/hardware/CANcoder.html) from Phoenix 6, initialized via CAN bus and CAN ID from configurations.

[^2]: [`CANcoder`](https://api.ctr-electronics.com/phoenix6/release/java/com/ctre/phoenix6/hardware/CANcoder.html) from Phoenix 6, initialized via CAN bus and CAN ID from configurations. Cast `Object` to [`CANcoder`](https://api.ctr-electronics.com/phoenix6/release/java/com/ctre/phoenix6/hardware/CANcoder.html)

[^3]: SparkMAX brushless mode is selected.

[^4]: The SparkMAX has a CAN ID of `5`.

[^5]: SparkMAX is not compatible with CANivore so the `canbus` should be `null` or `""`.

[^6]: The SparkMAX has a CAN ID of `6`.

[^7]: [`CANcoder`](https://api.ctr-electronics.com/phoenix6/release/java/com/ctre/phoenix6/hardware/CANcoder.html) is selected using the CAN ID and bus bellow.

[^8]: [`CANcoder`](https://api.ctr-electronics.com/phoenix6/release/java/com/ctre/phoenix6/hardware/CANcoder.html) id for this module.

[^9]: CANivore name of which the [`CANcoder`](https://api.ctr-electronics.com/phoenix6/release/java/com/ctre/phoenix6/hardware/CANcoder.html) resides on.

[^10]: The drive motor spins counter clockwise positive without any inversion.

[^11]: The steering/angle/azimuth motor spins counterclockwise positive without inversion.

[^12]: Offset read from `Module[...] Raw Absolute Encoder` when the wheel was facing straight and bevels the same way.\
    \
    Offsets are in degrees.

[^13]: This should rarely, if ever, be true.

[^14]: The center of this module is `-12`in from the center of the robot "frontwise".

[^15]: The center of this module is `-12`in from the center of the robot "left".

[^16]: ```json
    "encoder": {
        "type": "attached",
        "id": 11,
        "canbus": null
      },
    ```

[^17]: ```json
    "encoder": {
        "type": "sparkmax_analog",
        "id": 11,
        "canbus": null
      },
    ```

[^18]: ```json
    "encoder": {
        "type": "sparkmax_analog5v",
        "id": 11,
        "canbus": null
      },
    ```

[^19]: ```json
    "encoder": {
        "type": "canandmag",
        "id": 11,
        "canbus": null
      },
    ```

[^20]: ```json
    "encoder": {
        "type": "canandmag_can",
        "id": 11,
        "canbus": null
      },
    ```

[^21]: ```json
    "encoder": {
        "type": "cancoder",
        "id": 11,
        "canbus": null
      },
    ```

[^22]: ```json
    "encoder": {
        "type": "throughbore",
        "id": 11,
        "canbus": null
      },
    ```

[^23]: ```json
    "encoder": {
        "type": "thrifty",
        "id": 11,
        "canbus": null
      },
    ```

[^24]: ```json
    "encoder": {
        "type": "ma3",
        "id": 11,
        "canbus": null
      },
    ```

[^25]: ```json
    "encoder": {
        "type": "ctre_mag",
        "id": 11,
        "canbus": null
      },
    ```

[^26]: ```json
    "encoder": {
        "type": "am_mag",
        "id": 11,
        "canbus": null
      },
    ```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.yagsl.com/devices/absolute-encoders.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
