22
33#pragma once
44
5+ #include < functional>
6+ #include < optional>
57#include < string>
68#include < string_view>
9+ #include < unordered_map>
710#include < vector>
811
912#include < fmt/format.h>
1013#include < frc/Errors.h>
1114#include < frc/Filesystem.h>
15+ #include < frc/geometry/Pose2d.h>
16+ #include < frc2/command/Subsystem.h>
1217#include < wpi/MemoryBuffer.h>
1318#include < wpi/json.h>
1419
1520#include " choreo/SpecVersion.h"
21+ #include " choreo/auto/AutoTrajectory.h"
1622#include " choreo/trajectory/ProjectFile.h"
1723#include " choreo/trajectory/Trajectory.h"
24+ #include " choreo/trajectory/TrajectorySample.h"
25+ #include " choreo/util/AllianceFlipperUtil.h"
1826
1927namespace choreo {
2028
29+ template <TrajectorySample SampleType, int Year>
30+ class AutoFactory ;
31+
2132/* *
2233 * A class that handles loading choreo and caching choreo trajectories.
2334 */
@@ -31,7 +42,7 @@ class Choreo {
3142 *
3243 * @return the project file
3344 */
34- static choreo:: ProjectFile GetProjectFile () {
45+ static ProjectFile GetProjectFile () {
3546 if (LAZY_PROJECT_FILE.has_value ()) {
3647 return LAZY_PROJECT_FILE.value ();
3748 }
@@ -67,8 +78,8 @@ class Choreo {
6778 throw fmt::format (" .chor project file: Wrong version {}. Expected {}" ,
6879 version, kSpecVersion );
6980 }
70- choreo:: ProjectFile resultProjectFile;
71- choreo:: from_json (json, resultProjectFile);
81+ ProjectFile resultProjectFile;
82+ from_json (json, resultProjectFile);
7283 LAZY_PROJECT_FILE = resultProjectFile;
7384 } catch (const std::filesystem::filesystem_error&) {
7485 FRC_ReportError (frc::warn::Warning, " Error finding choreo directory!" );
@@ -88,8 +99,8 @@ class Choreo {
8899 * @return The loaded trajectory, or `empty std::optional` if the trajectory
89100 * could not be loaded.
90101 */
91- template <choreo:: TrajectorySample SampleType>
92- static std::optional<choreo:: Trajectory<SampleType>> LoadTrajectory (
102+ template <TrajectorySample SampleType>
103+ static std::optional<Trajectory<SampleType>> LoadTrajectory (
93104 std::string_view trajectoryName) {
94105 if (trajectoryName.ends_with (TRAJECTORY_FILE_EXTENSION)) {
95106 trajectoryName = trajectoryName.substr (
@@ -130,28 +141,221 @@ class Choreo {
130141 * @return The loaded trajectory, or `empty std::optional` if the trajectory
131142 * could not be loaded.
132143 */
133- template <choreo:: TrajectorySample SampleType>
134- static std::optional<choreo:: Trajectory<SampleType>> LoadTrajectoryString (
144+ template <TrajectorySample SampleType>
145+ static std::optional<Trajectory<SampleType>> LoadTrajectoryString (
135146 std::string_view trajectoryJsonString, std::string_view trajectoryName) {
136147 wpi::json json = wpi::json::parse (trajectoryJsonString);
137148 std::string version = json[" version" ];
138149 if (kSpecVersion != version) {
139150 throw fmt::format (" {}.traj: Wrong version {}. Expected {}" ,
140151 trajectoryName, version, kSpecVersion );
141152 }
142- choreo:: Trajectory<SampleType> trajectory;
143- choreo:: from_json (json, trajectory);
153+ Trajectory<SampleType> trajectory;
154+ from_json (json, trajectory);
144155 return trajectory;
145156 }
146157
158+ /* *
159+ * A utility for caching loaded trajectories. This allows for loading
160+ * trajectories only once, and then reusing them.
161+ */
162+ template <TrajectorySample SampleType>
163+ class TrajectoryCache {
164+ public:
165+ /* *
166+ * Load a trajectory from the deploy directory. Choreolib expects .traj
167+ * files to be placed in src/main/deploy/choreo/[trajectoryName].traj.
168+ *
169+ * This method will cache the loaded trajectory and reused it if it is
170+ * requested again.
171+ *
172+ * @param trajectoryName the path name in Choreo, which matches the file
173+ * name in the deploy directory, file extension is optional.
174+ * @return the loaded trajectory, or `empty std::optional` if the trajectory
175+ * could not be loaded.
176+ * @see Choreo#LoadTrajectory(std::string_view)
177+ */
178+ static std::optional<Trajectory<SampleType>> LoadTrajectory (
179+ std::string_view trajectoryName) {
180+ if (cache.contains (std::string{trajectoryName})) {
181+ return cache[std::string{trajectoryName}];
182+ } else {
183+ cache[std::string{trajectoryName}] =
184+ Choreo::LoadTrajectory<SampleType>(trajectoryName);
185+ return cache[std::string{trajectoryName}];
186+ }
187+ }
188+
189+ /* *
190+ * Load a section of a split trajectory from the deploy directory. Choreolib
191+ * expects .traj files to be placed in
192+ * src/main/deploy/choreo/[trajectoryName].traj.
193+ *
194+ * This method will cache the loaded trajectory and reused it if it is
195+ * requested again. The trajectory that is split off of will also be cached.
196+ *
197+ * @param trajectoryName the path name in Choreo, which matches the file
198+ * name in the deploy directory, file extension is optional.
199+ * @param splitIndex the index of the split trajectory to load
200+ * @return the loaded trajectory, or `empty std::optional` if the trajectory
201+ * could not be loaded.
202+ * @see Choreo#LoadTrajectory(std::string_view)
203+ */
204+ static std::optional<Trajectory<SampleType>> LoadTrajectory (
205+ std::string_view trajectoryName, int splitIndex) {
206+ std::string key = fmt::format (" {}.:.{}" , trajectoryName, splitIndex);
207+
208+ if (!cache.contains (key)) {
209+ if (cache.contains (std::string{trajectoryName})) {
210+ cache[key] =
211+ cache[std::string{trajectoryName}].value ().GetSplit (splitIndex);
212+ } else {
213+ auto possibleTrajectory = LoadTrajectory (trajectoryName);
214+ cache[std::string{trajectoryName}] = possibleTrajectory;
215+
216+ if (possibleTrajectory.has_value ()) {
217+ cache[key] = possibleTrajectory.value ().GetSplit (splitIndex);
218+ }
219+ }
220+ }
221+
222+ return cache[key];
223+ }
224+
225+ /* *
226+ * Clears the trajectory cache.
227+ */
228+ static void Clear () { cache.clear (); }
229+
230+ private:
231+ static inline std::unordered_map<std::string,
232+ std::optional<Trajectory<SampleType>>>
233+ cache;
234+ };
235+
236+ /* *
237+ * Create a factory that can be used to create AutoRoutine and AutoTrajectory.
238+ *
239+ * @tparam SampleType The type of samples in the trajectory.
240+ * @tparam Year The field year. Defaults to the current year.
241+ * @param poseSupplier A function that returns the current field-relative
242+ * Pose2d of the robot.
243+ * @param controller A function for following the current trajectory.
244+ * @param mirrorTrajectory If this returns true, the path will be mirrored to
245+ * the opposite side, while keeping the same coordinate system origin.
246+ * This will be called every loop during the command.
247+ * @param driveSubsystem The drive Subsystem to require for AutoTrajectory
248+ * Commands.
249+ * @return An AutoFactory that can be used to create AutoRoutines and
250+ * AutoTrajectories.
251+ * @see AutoChooser using this factory with AutoChooser to generate auto
252+ * routines.
253+ */
254+ template <TrajectorySample SampleType, int Year = util::kDefaultYear >
255+ static AutoFactory<SampleType, Year> CreateAutoFactory (
256+ std::function<frc::Pose2d()> poseSupplier,
257+ std::function<void(frc::Pose2d, SampleType)> controller,
258+ std::function<bool()> mirrorTrajectory, frc2::Subsystem driveSubsystem);
259+
260+ /* *
261+ * Create a factory that can be used to create AutoRoutines and
262+ * AutoTrajectories.
263+ *
264+ * @tparam SampleType The type of samples in the trajectory.
265+ * @tparam Year The field year. Defaults to the current year.
266+ * @param poseSupplier A function that returns the current field-relative
267+ * Pose2d of the robot.
268+ * @param controller A function for following the current trajectory.
269+ * @param mirrorTrajectory If this returns true, the path will be mirrored to
270+ * the opposite side, while keeping the same coordinate system origin.
271+ * This will be called every loop during the command.
272+ * @param driveSubsystem The drive Subsystem to require for AutoTrajectory
273+ * Commands.
274+ * @param trajectoryLogger A TrajectoryLogger to log trajectories as they
275+ * start and finish.
276+ * @return An AutoFactory that can be used to create AutoRoutines and
277+ * AutoTrajectories.
278+ * @see AutoChooser using this factory with AutoChooser to generate auto
279+ * routines.
280+ */
281+ template <TrajectorySample SampleType, int Year = util::kDefaultYear >
282+ static AutoFactory<SampleType, Year> CreateAutoFactory (
283+ std::function<frc::Pose2d()> poseSupplier,
284+ std::function<void(frc::Pose2d, SampleType)> controller,
285+ std::function<bool()> mirrorTrajectory, frc2::Subsystem driveSubsystem,
286+ TrajectoryLogger<SampleType> trajectoryLogger);
287+
147288 private:
148289 static constexpr std::string_view TRAJECTORY_FILE_EXTENSION = " .traj" ;
149290
150- static inline std::optional<choreo:: ProjectFile> LAZY_PROJECT_FILE = {};
291+ static inline std::optional<ProjectFile> LAZY_PROJECT_FILE = {};
151292
152293 static inline const std::string CHOREO_DIR =
153294 frc::filesystem::GetDeployDirectory () + " /choreo" ;
154295
155296 Choreo ();
156297};
298+
299+ } // namespace choreo
300+
301+ #include " choreo/auto/AutoFactory.h"
302+
303+ namespace choreo {
304+
305+ /* *
306+ * Create a factory that can be used to create AutoRoutine and AutoTrajectory.
307+ *
308+ * @tparam SampleType The type of samples in the trajectory.
309+ * @param poseSupplier A function that returns the current field-relative
310+ * Pose2d of the robot.
311+ * @param controller A function for following the current trajectory.
312+ * @param mirrorTrajectory If this returns true, the path will be mirrored to
313+ * the opposite side, while keeping the same coordinate system origin.
314+ * This will be called every loop during the command.
315+ * @param driveSubsystem The drive Subsystem to require for AutoTrajectory
316+ * Commands.
317+ * @return An AutoFactory that can be used to create AutoRoutines and
318+ * AutoTrajectories.
319+ * @see AutoChooser using this factory with AutoChooser to generate auto
320+ * routines.
321+ */
322+ template <TrajectorySample SampleType>
323+ static AutoFactory<SampleType> CreateAutoFactory (
324+ std::function<frc::Pose2d()> poseSupplier,
325+ std::function<void(frc::Pose2d, SampleType)> controller,
326+ std::function<bool()> mirrorTrajectory, frc2::Subsystem driveSubsystem) {
327+ return AutoFactory{poseSupplier, controller, mirrorTrajectory, driveSubsystem,
328+ std::nullopt };
329+ }
330+
331+ /* *
332+ * Create a factory that can be used to create AutoRoutines and
333+ * AutoTrajectories.
334+ *
335+ * @tparam SampleType The type of samples in the trajectory.
336+ * @param poseSupplier A function that returns the current field-relative
337+ * Pose2d of the robot.
338+ * @param controller A function for following the current trajectory.
339+ * @param mirrorTrajectory If this returns true, the path will be mirrored to
340+ * the opposite side, while keeping the same coordinate system origin.
341+ * This will be called every loop during the command.
342+ * @param driveSubsystem The drive Subsystem to require for AutoTrajectory
343+ * Commands.
344+ * @param trajectoryLogger A TrajectoryLogger to log trajectories as they
345+ * start and finish.
346+ * @return An AutoFactory that can be used to create AutoRoutines and
347+ * AutoTrajectories.
348+ * @see AutoChooser using this factory with AutoChooser to generate auto
349+ * routines.
350+ */
351+ template <TrajectorySample SampleType>
352+ static AutoFactory<SampleType> CreateAutoFactory (
353+ std::function<frc::Pose2d()> poseSupplier,
354+ std::function<void(frc::Pose2d, SampleType)> controller,
355+ std::function<bool()> mirrorTrajectory, frc2::Subsystem driveSubsystem,
356+ TrajectoryLogger<SampleType> trajectoryLogger) {
357+ return AutoFactory{poseSupplier, controller, mirrorTrajectory, driveSubsystem,
358+ trajectoryLogger};
359+ }
360+
157361} // namespace choreo
0 commit comments