> For the complete documentation index, see [llms.txt](https://yams.yassrobotics.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yams.yassrobotics.com/changelog/readme.md).

# Changelog

New updates and improvements

## 2026.8.26

### Added

* `SwerveDrive.getSimPose()` (Java) / `SwerveDrive::GetSimPose()` (C++) — a ground-truth simulated pose that assumes every module reached its last-commanded `SwerveModuleState` perfectly. It's integrated in `simIterate()`/`SimIterate()` from the desired (not measured) module states via a `Twist2d`/`frc::Twist2d`, independent of the noisy, gyro/odometry-fused pose returned by `getPose()`/`GetPose()`. `resetOdometry(...)`/`ResetOdometry(...)` also snaps it to the given pose, keeping it in sync with the fused estimate. Intended as a "known truth" source for simulated vision systems.
* `SwerveDrive.getRobotRelativeChassisSpeedsFromState(SwerveModuleState[])` (Java) / `SwerveDrive::GetRobotRelativeChassisSpeedsFromState(...)` (C++) — converts an arbitrary set of module states back into robot-relative chassis speeds.
* `SwerveDrive.getDesiredModuleStates()` (Java) / `SwerveDrive::GetDesiredModuleStates()` (C++) — returns the last-commanded module states, mirroring the existing `getDesiredChassisSpeeds()`/`GetDesiredChassisSpeeds()`.

### Removed

* **Breaking:** `SwerveDrive.getPoseEstimator()` (Java) / `SwerveDrive::GetPoseEstimator()` (C++) — direct access to the underlying `SwerveDrivePoseEstimator` was too easy to misuse (calling `update(...)`/`resetPosition(...)`/`resetPose(...)` on it directly corrupts the pose estimate or desyncs it from the drive's gyro offset). Use `getPose()`, `resetOdometry(Pose2d)`, and `addVisionMeasurement(...)` instead.

## 2026.8.20

### Added

* `BatterySim` (Java & C++) now models a single, shared robot battery in simulation. Every simulated `SmartMotorController` — via its `SimSupplier` (`ArmSimSupplier`, `ElevatorSimSupplier`, `DCMotorSimSupplier`) or hardware wrapper (`SparkWrapper`, `TalonFXWrapper`, `TalonFXSWrapper`) — reports its own current draw into one combined loaded-voltage calculation, instead of each mechanism computing `RoboRioSim` voltage sag from only its own current draw and overwriting the others.
* `BatterySim.enableDischarge(double, Voltage, Resistance)` (Java) / `BatterySim::EnableDischarge(double, units::volt_t, units::ohm_t)` (C++) — optional realistic battery discharge simulation. Current draw is integrated into amp-hours consumed over time, sagging the open-circuit voltage and raising internal resistance as the battery empties, following a typical FRC sealed lead-acid discharge curve. Also added `disableDischarge()`/`DisableDischarge()`, `resetDischarge()`/`ResetDischarge()`, and `getStateOfCharge()`/`GetStateOfCharge()`.
* `BatterySim.replaceSOCInterpolation(InterpolatingDoubleTreeMap)` (Java) / `BatterySim::ReplaceSOCInterpolation(const std::map<double, double>&)` (C++) — swap in a custom state-of-charge → voltage discharge curve, for modeling a well-used competition battery, a different chemistry, or a curve measured from a real battery on a load tester.

### Changed

* **C++:** `Arm`, `Elevator`, `Pivot`, and `FlyWheel` no longer call `RoboRioSim::SetVInVoltage(...)` directly from their own current draw. Voltage now comes from the shared `BatterySim`, so combined load across multiple mechanisms sags the simulated bus voltage realistically instead of only reflecting whichever mechanism updated last.

{% hint style="info" %}
Discharge simulation is off by default and only affects simulation — on a real robot, `RobotController.getBatteryVoltage()`/`frc::RobotController::GetBatteryVoltage()` always reflects actual hardware.
{% endhint %}

## 2026.8.18

### Added

* `SwerveDriveConfig.getDiscretization()` — returns the discretization time used by `optimizeRobotRelativeChassisSpeeds(...)`, automatically preferring the simulation-specific override from `withSimDiscretizationTime(...)` when running in simulation.

## 2026.8.17

### Added

* `SmartMotorControllerTelemetryConfig.withCustom(DoubleTelemetryField, boolean)` / `withCustom(BooleanTelemetryField, boolean)` (Java, plus array overloads) — an escape hatch to enable or disable a telemetry field directly when there isn't a dedicated `with*()` setter for it yet.

### Changed

* Telemetry now only publishes fields that are actually enabled, instead of publishing every registered field regardless of its enabled state.
* **Java & C++:** Swerve module telemetry now nests each module under `swerve/modules/<name>/...` instead of `swerve/<name>/...`, removing a double `/` that showed up in some NetworkTables/DataLog paths.

### Fixed

* **Java & C++:** Cosine compensation in `SwerveModuleConfig` now reads the azimuth angle once per control cycle and reuses that same value for both state optimization and the cosine scalar, instead of re-querying the absolute encoder separately for each step. Previously those two reads could disagree, which showed up as skewed drive speed or the wheel losing its commanded direction right around a 180° heading error.

## 2026.8.16

### Added

* `MechanismTelemetry` is now the primary coordinator of all mechanism telemetry, and gained explicit DataLog support alongside NetworkTables.
* `SwerveDriveConfig.withDataLogName(String)`/`getDataLogName()` — logs the drive's pose, gyro, and chassis speeds/module states to a WPILib DataLog under the given name, in addition to NetworkTables.
* `SwerveModuleConfig.withDataLogName(String)`/`getDataLogName()` — logs that module's absolute encoder angle to a WPILib DataLog under the given name, in addition to NetworkTables.

### Changed

* `SwerveModule` now shares a single `MechanismTelemetry` instance (and loop timer) across its drive and azimuth motors instead of each motor re-running its own telemetry setup.

{% hint style="info" %}
Neither `SwerveDriveConfig.withDataLogName(...)` nor `SwerveModuleConfig.withDataLogName(...)` cascades down to a module's drive/azimuth motors. Set a DataLog name on each motor's own `SmartMotorControllerConfig`/`SmartMotorControllerTelemetryConfig` for per-motor logging.
{% endhint %}

## 2026.7.10

### Added

* **C++:** `SmartMotorControllerConfig::WithFeedforward(...)` — a single overloaded setter that takes a WPILib feedforward object directly (`frc::ArmFeedforward`, `frc::ElevatorFeedforward`, or `frc::SimpleMotorFeedforward<units::turns>`), replacing the setters removed below.

### Removed

* **Breaking (C++):** `SmartMotorControllerConfig` removed `WithArmFeedforward`, `WithElevatorFeedforward`, `WithSimpleFeedforward`, and the standalone `WithKp`/`WithKi`/`WithKd`/`WithKs`/`WithKv`/`WithKa`/`WithKg` setters. See the migration note above.

## 2026.7.09

### Added

* `SwerveModule` now publishes the azimuth absolute encoder angle to telemetry.
* Added `SwerveModuleConfig.getAbsoluteEncoderSupplier()` and `getRawAbsoluteEncoderAngle()` (Java) to expose the absolute encoder reading directly, including a variant with the configured zero offset stripped out. Swerve telemetry now reports this raw, offset-free angle.

### Changed

* `SwerveModule.setSwerveModuleState(SwerveModuleState)` now returns the optimized `SwerveModuleState` instead of `void`.

### Fixed

* `SwerveDrive`'s desired module states now reflect the actual post-optimization `SwerveModuleState` returned by `setSwerveModuleState(...)` above, instead of the pre-optimization input — fixes desired-state telemetry/logging showing the wrong angle after a flip.

## 2026.7.06

### Fixed

* Fixed `SwerveModuleConfig`'s state optimizer entering an infinite re-optimization loop right at a flip boundary. The flip decision now debounces against the last *commanded* angle instead of being re-derived from the live absolute encoder every loop.

## 2026.6.25.1

### Added

* `SmartMotorControllerCommandRegistry` now throws `IllegalStateException` when two different `Subsystem` instances register commands under the same name, and adds `removeCommands(Subsystem)` to clear a subsystem's registered commands (e.g. between tests).

## 2026.6.25

### Added

* Added a full C++ port of YAMS: mechanisms (`Arm`, `Elevator`, `Pivot`, `FlyWheel`, `DoubleFlyWheel`, `DifferentialDrive`), motor controller wrappers (Spark, TalonFX, TalonFXS), telemetry, units, and unit tests, mirroring the existing Java API.
* Added `SwerveDrive` and `SwerveInputStream` (new in both Java and C++).
* Added Doxygen documentation generation for the C++ API.

### Removed

* **Breaking:** Removed ThriftyNova motor controller support (`NovaWrapper`) from the Java API; there is no direct replacement.

### Changed

* Adopted `wpiformat` for consistent Java/C++ formatting across the codebase.

## 2026.1.17

* Empirical Method for CRT by [@mjjbycicle](https://github.com/mjjbycicle) in [#68](https://github.com/Yet-Another-Software-Suite/YAMS/pull/68)
* SmartMotorController Control Request Fix by [@thenetworkgrinch](https://github.com/thenetworkgrinch) in [#69](https://github.com/Yet-Another-Software-Suite/YAMS/pull/69)
* Fixed the DCMotorSim to work with the correct units by [@thenetworkgrinch](https://github.com/thenetworkgrinch) in [#72](https://github.com/Yet-Another-Software-Suite/YAMS/pull/72)
* Swerve drive sysId by [@thenetworkgrinch](https://github.com/thenetworkgrinch) in [#73](https://github.com/Yet-Another-Software-Suite/YAMS/pull/73)
* Inversions shouldn't apply in Simulation by [@thenetworkgrinch](https://github.com/thenetworkgrinch) in [#74](https://github.com/Yet-Another-Software-Suite/YAMS/pull/74)
* MaybeCRT by [@alexalex02](https://github.com/alexalex02) in [#70](https://github.com/Yet-Another-Software-Suite/YAMS/pull/70)
* Kitbot added by [@nobodyhere4](https://github.com/nobodyhere4) in [#62](https://github.com/Yet-Another-Software-Suite/YAMS/pull/62)

## 2026.1.16

* Fixed non-profiled Closed Loop Control in TalonFXS, TalonFX, and SparkMax.
* Added `Conversion` for ThriftyNova encoder readings to account for encoder ticks.
* Fixed `SwerveDrive` template.
* Added Shoot on the move example.
* [Added Hood + Turret example ](https://github.com/Yet-Another-Software-Suite/YAMS/pull/63)(by 9738)

## 2026.1.4

* Added Imperial `YUnits.PoundSquareInches` `YUnits.PoundsSquareFeet`
* Deprecated `withMOI(double)` in favor of `withMOI(MomentOfInertia)`.
* Added `withMOI(MomentOfInertia)`

## 2026.1.2

* Added `SmartMotorControllerConfig().clone()` to allow for clonable configs.
* Added `MechanismConfig.withSmartMotorController()` for all mechanism and null param constructors
* Added `SensorData.set()` overloads
* 'Trapazoidal' Spelling Error Correction by [@akhaled247](https://github.com/akhaled247) in [#56](https://github.com/Yet-Another-Software-Suite/YAMS/pull/56)
* REV 2026 with Feedforwards and PIDs by [@thenetworkgrinch](https://github.com/thenetworkgrinch) in [#55](https://github.com/Yet-Another-Software-Suite/YAMS/pull/55)
* Added the option to loosely coupled followers. by [@thenetworkgrinch](https://github.com/thenetworkgrinch) in [#58](https://github.com/Yet-Another-Software-Suite/YAMS/pull/58)
* Allow for independently created config classes for constants files. by [@thenetworkgrinch](https://github.com/thenetworkgrinch) in [#59](https://github.com/Yet-Another-Software-Suite/YAMS/pull/59)
* Changed `SwerveInputStream.copy()` to `SwerveInputStream.clone()`
* Modified `SmartMotorControllerConfig` to allow for creation without a `Subsystem` but still require a subsystem eventually.
* Modified `SmartMotorController` telemetry to only create Live Tuning and other useful commands if tunable setpoints are not enabled.
* Added `MechanismGearing(double...)` overload
* Added DifferentialDrive example.

## 2025.12.22

* Added the ability to use multiple SMC's with Live Tuning in one subsystem
* Added AdvantageKit example
* Modified `SwerveDrive` to support AdvantageKit better.
* Updated Telemetry Setup for standalone SMC's to be automatic.
* Added Units to Telemetry Fields.
* Added DoubleFlyWheel example.
* Fixed ElevatorConfig comments saying "length" instead of "angle" [#54](https://github.com/Yet-Another-Software-Suite/YAMS/pull/54)
* Added support for user moment of inertia in ExponentialProfilePIDController [#50](https://github.com/Yet-Another-Software-Suite/YAMS/pull/50)
* Improved Exponential Elevator Examples [#46](https://github.com/Yet-Another-Software-Suite/YAMS/pull/46)
* Added ExponentialProfile.
* Add MapleSim Integration to SwerveDrive by [@konnorreynolds](https://github.com/konnorreynolds) in [#49](https://github.com/Yet-Another-Software-Suite/YAMS/pull/49)

## 2025.11.05

* Renamed `.withExternalGearing` to `.withExternalEncoderGearing`.
* Added several new easy commands, like "Up", "Down", and "ZeroEncoder".
* Moved commands to "SmartDashboard/Mechanisms/MECHNAME/MOTORNAME/Commands/".
* Fixed immutable SensorData fields.
* Fixed `SparkWrapper.setEncoderPosition` to set the sim position correctly.

## 2025.11.02

* Renamed `SmartMotorControllerConfig.withZeroOffset` to `SmartMotorControllerConfig.withExternalEncoderZeroOffset`

## 2025.10.31

* Updated `SwerveInputStream` to use `.with*` for shared styling.
* Added `swerve_drive` example.

## 2025.10.29

* Added setpoint visualization to Arm Mechanism2d
* Fixed ArmFeedforward calculation on Spark's, and Nova's. Changed velocity calculation from Rotations to Radians. Found by 8114 (The Rocketeers)

## 2025.10.27

* Renamed `Shooter` to `FlyWheel`
* Added Loop Time to each mechanism.

## 2025.10.14

* Added `YUnits` which allows you to include more exotic units in your code.
* Added `Sensor`s which allow you to seamlessly fetch automatically modified sensor data during sim and real data when running IRL.
