Skip to content

Choreo v2025.0.0-beta-8

Pre-release
Pre-release
Compare
Choose a tag to compare
@github-actions github-actions released this 19 Dec 07:14
· 80 commits to main since this release
2a73934

Choreo v2025.0.0-beta-8

Please read through the post entirely, since many breaking changes have been made.

This release focuses on internal infrastructure and breaking API improvements in ChoreoLib.

v2025.0.0-beta-8 is built for WPILib beta 3. It is likely mostly identical to the first full 2025 release of Choreo, which will be released after the WPILib full 2025 release.

NOTE: This changelog describes changes since beta-6.

https://choreo.autos : New Docs Domain

We recently registered the domain choreo.autos to replace sleipnirgroup.github.io/Choreo. We have set up the latter to redirect to the former. Documentation is still being updated over the coming weeks before kickoff.

Document Schemas and Auto Upgrade

The version control in the .chor and .traj schemas is no longer a semver string. It is now an integer, starting at 1, and is different for .traj and .chor. A string in the version key is interpreted as version 0.

The Choreo app is able to automatically load non-current versions of both files (including existing files from beta-6) and upgrade them to the current schema. Usually, this will require regeneration, depending on the changes in the update.

This is a feature Choreo had in 2024, but it has been completely reimplemented.

For contributors, a guide to defining new schema versions has been added here.

The three ChoreoLib languages will not automatically upgrade old trajectories when reading them.

Removal of C++ AutoFactory API

Unfortunately, we found many severe bugs in our port of the Java AutoFactory API to C++, and decided to delete that attempt. We apologize for the inconvenience.

ChoreoLib Changes (Mostly Breaking)

See below for details on these changes.

General

  • Changes to how Choreo handles alliance flipping. See below.
  • Many bugs with the sample flipping algorithms have been fixed.
  • ChoreoLib no longer reads the .chor file to know what sample type to expect, or what the differential track width is, as needed for DifferentialSample.getChassisSpeeds(). This information is now in the .traj file. Details below.

Raw API

Trajectory

  • [Java] Trajectory.getInitialSample(), getFinalSample(), getInitialPose(), getFinalPose(), sampleAt() now return Optional<Pose2d> instead of a potentially null Pose2d. This matches prior behavior of the other two languages (C++ with std::optional and Python with returning None)
  • [C++] Trajectory::GetInitialState() is now GetInitialSample().
  • [Java, C++] Trajectory.getInitialSample()/GetInitialSample() and getFinalSample()/GetFinalSample() now take a boolean parameter that is true if the sample should be returned flipped. This does not check the current alliance; if the parameter is true, the sample will be flipped.
  • [Java] Trajectory.sampleArray() has been removed due to causing runtime crashes and being type-unsafe.

ProjectFile

Removed, since it is no longer needed.

DifferentialSample

A new field omega was added, instead of calculating angular velocity from vl, vr and the trackwidth from the robot config in the .chor file.

Java Auto API

  • Driver Station warnings from ChoreoLib have moved to use the new Alerts API.

New Recommended Practices

  • The AutoRoutine.trajectory(String name) has been added and is the new recommended way to load AutoTrajectories, instead of AutoFactory.trajectory(String name, AutoRoutine routine).
  • Trigger AutoRoutine.observe(BooleanSupplier condition) has been added. This can be used to create Triggers that are part of the AutoRoutine and will only be polled during the routine. It can also be used to "sanitize" Triggers that are used elsewhere. See below for details on why this is necessary.
  • To help handle odometry resetting when the start pose depends on alliance, AutoFactory and AutoTrajectory now have resetOdometry capability. More details in the changelog just below.

AutoLoop

  • choreo.auto.AutoLoop is now choreo.auto.AutoRoutine.
    • AutoFactory.newLoop() and voidLoop() were renamed to newRoutine() and voidRoutine().
  • AutoRoutine.cmd() will end immediately with a console warning if alliance flipping is enabled and the alliance is not known on command initialize.
  • AutoLoop.enabled() was replaces with AutoRoutine.active().
  • AutoLoop.poll() will return immediately if the alliance is needed for flipping and not known. This is the same behavior as if poll() is called on a killed routine, or not while enabled and in autonomous.
  • Trigger anyDone(AutoTrajectory... trajectories) has been added, which creates a trigger that is true for one cycle when any of the input trajectories finishes. A variant also exists that applies a delay to the rising edge.
  • Trigger anyActive(AutoTrajectory... trajectories) creates a trigger that is true whenever any input trajectory is active.

AutoTrajectory

  • AutoTrajectory.done() behavior has changed. The trigger will become true for one cycle when the trajectory completes without being interrupted. Previously, interrupted trajectories would still fire the done() trigger.
  • AutoTrajectory.getInitialPose() and getFinalPose() will now return Optional.empty() if alliance flipping is enabled and the alliance is not known.
  • Removed AutoTrajectory.atTimeAndPlace(). Use trajectory.atTime(String eventName).and(trajectory.atPose(String eventName)) or similar.
  • AutoTrajectory.atPose(...) did not check the rotation portion of the pose. atPose(...) now takes a rotation tolerance (default 3 degrees).
  • For the previous behavior of just checking the translation, AutoTrajectory.atTranslation() has been added, which is similar to atPose() but accepts Translation2ds.
  • AutoTrajectory.atPose(...) and atTranslation(..) now properly flip the target pose/translation every time the Trigger is checked, based on the current alliance if alliance flipping is enabled. If the alliance is unknown and flipping is enabled, the Trigger will be false.
  • AutoTrajectory.collectEventPoses now returns an ArrayList<Supplier<Optional<Pose2d>>> of poses that flip based on the current alliance and flipping enabled status.

AutoFactory

  • The Choreo controller function now only takes a SwerveSample or DifferentialSample, not an additional Pose2d for the current pose.
  • AutoFactory.clearCache() was replaced with AutoFactory.cache().clear() since the user can now access the trajectory cache.
  • A new parameter Consumer<Pose2d> resetOdometry has been added. This is used with AutoTrajectory to create a Command that calls the resetOdometry callback with the first pose of
  • trajectoryCommand() has been renamed to trajectoryCmd()
  • trajectoryLogger is no longer an Optional. It is a no-op if left unspecified.

AutoChooser

  • AutoChooser now implements Sendable, so can be logged with SmartDashboard.putData() or similar.

  • The API to add options has changed.

    • One option is to call addRoutine(String name, Supplier<AutoRoutine> generator).
    • The other is to call addCmd(String name, Supplier<Command> generator).
    • Both versions will call the given function when the option becomes selected.
  • AutoChooser's options are now functions that consume nothing and return an AutoRoutine or a Command. It is expected that users will call to their AutoFactory instance like they would a subsystem, instead of having it passed into the function.

  • The constructor is now new AutoChooser(), since the table name is handled by logging it like a Sendable, and the chooser does not need to pass a factory into the generator functions.

  • AutoChooser.getSelectedAutoRoutine() has been removed.

  • To run the selected auto, use Command selectedCommand() or Command selectedCommandScheduler().

  • The former is the analogue to the SendableChooser approach of getting the selected command and directly scheduling it in autonomousInit().
  • The latter returns a deferred Command. Use this if binding autonomous commands to run on autonomousInit() with RobotModeTriggers.autonomous(), since it does not evaluate the selected command as of the time of binding.
  • AutoChooser will only update if the DriverStation is connected (so that the alliance is known).

Changes to alliance-based trajectory flipping

Several issues were identified with the way ChoreoLib, especially the Java higher-level API, handled alliance flipping, given that the alliance can change after auto routines are created, and the alliance can be unknown before the call of autonmousInit.

  • The higher-level API now uses Optional<Pose2d> and Supplier<Optional<Pose2d>> instead of Pose2d in many places, to better represent poses that depend on the currently selected alliance.
  • AutoFactory/Choreo.createAutoFactory no longer take a BooleanSupplier mirrorTrajectory that returns true when trajectories should be flipped. Instead they take a BooleanSupplier useAllianceFlipping to enable alliance-based flipping in general and a separate Supplier<Optional<Alliance>> that defaults to DriverStation::getAlliance(). The BooleanSupplier was moved elsewhere in the parameter list to force a compiler error.

Trigger Sanitization

AutoRoutine.observe was added to help prevent problems where a Trigger on the default CommandScheduler loop is used when creating an AutoRoutine. This is especially easy to mess up when that Trigger is combined with a Trigger on the AutoRoutine event loop, using decorators like .and(), .or(), etc.

Combined Triggers are polled on the first Trigger's loop. Thus if the default-loop Trigger is first in a combination, the combined trigger will be polled every loop, even if the auto routine is not running and has not been run.

Example:

Pose2d shotLocation = ...;
// trajectory.atPose(...) is only polled during the AutoRoutine.
Trigger atShotLocation = trajectory.atPose("shoot", 0.5);
// shooter has a public static Trigger hasGamepiece.
// This is on the default loop
Trigger hasGamepiece = shooter.hasGamepiece;
// Compare:
// This is polled every loop during auto and teleop!
// If the robot is at any "shoot" marker's location during teleop, the game piece will be shot.
hasGamepiece.and(atShotLocation).onTrue(shooter.shoot()); // BAD

// RECOMMENDED:
// To fix this, use AutoRoutine.observe() to make a hasGamepiece condition that is routine-specific:
Trigger hasGamepiece = routine.observe(shooter.hasGamepiece)

// ALTERNATIVES:
// Put the AutoRoutine-specific Trigger first:
atShotLocation.and(hasGamepiece).onTrue(shooter.shoot());
// Or, access the routine's EventLoop directly to create a new Trigger
shooter.hasGamepiece(routine.loop()).and(atShotLocation).onTrue(shooter.shoot());

File Schema Changes

.TRAJ SCHEMA VERSION: 1

The field trajectory.sampleType will be either "Swerve" or "Differential", according to the type of trajectory represented.

The field omega in a differential sample was added, and represents the chassis angular velocity in radians per second, just like in the swerve sample.

.CHOR SCHEMA VERSION: 1

Added wheel coefficient of friction cof as a robot configuration option. This helps constrain robot acceleration.

Choreo Changes

  • Files written by Choreo now end with a newline, as required by formatters like wpiformat.
  • Fixed a bug with control interval guessing between two translation waypoints.
  • Added wheel coefficient of friction as a robot configuration option. This helps constrain robot acceleration.
  • Reimplemented expression input boxes to fix bugs with undo histories
  • Expression input and non-expression numerical input boxes no longer select all the contents when being edited.
  • Changed "zone" to "region" in the text relating to keep-in and keep-out regions.
  • Fixed a bug with .chor file saving that prevented some changes from triggering resaves, even though the file contents would have changed.
  • Motor Calculator Panel is removed from the robot config. It was broken and historically not very accurate anyway.

New Contributors

Full Changelog: v2025.0.0-beta-6...v2025.0.0-beta-8