-
Notifications
You must be signed in to change notification settings - Fork 63
Update C++ Autonomous Functionality #849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
164202c
got autofactory up to date
r4stered 7842cb6
Merge branch 'main' into cpp_cmds
r4stered b3e8d5d
Merge branch 'main' into cpp_cmds
r4stered 973fbb2
Added docs
r4stered 8dd86ef
Merge branch 'cpp_cmds' of github.com:r4stered/Choreo into cpp_cmds
r4stered 2c010b5
more docs fixes
r4stered feefa6b
Merge branch 'main' into cpp_cmds
r4stered 3b5c594
added autochooser
r4stered d678751
added default template params
r4stered 28e6e76
Update choreolib/src/main/native/include/choreo/auto/AutoTrajectory.h
spacey-sooty 9d40b1d
Update choreolib/src/main/native/include/choreo/auto/AutoChooser.h
spacey-sooty bc1a910
Merge branch 'main' into cpp_cmds
spacey-sooty 28f843b
auto factory docs
spacey-sooty c0a93d8
make docs more consistent
spacey-sooty 591bdf8
Merge branch 'main' into cpp_cmds
spacey-sooty 9132551
got autofactory event markers working as intended
r4stered 2c86c52
fixed autochooser showing as chooser
r4stered File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,6 @@ | |
|
|
||
| #include <string> | ||
| #include <string_view> | ||
| #include <unordered_map> | ||
| #include <vector> | ||
|
|
||
| #include <fmt/format.h> | ||
|
|
@@ -59,7 +58,7 @@ class Choreo { | |
| std::error_code ec; | ||
| auto fileBuffer = | ||
| wpi::MemoryBuffer::GetFile(matchingFiles[0].string(), ec); | ||
| if (!fileBuffer || !ec) { | ||
| if (!fileBuffer || ec) { | ||
| FRC_ReportError(frc::warn::Warning, | ||
| "Could not open choreo project file"); | ||
| } | ||
|
|
@@ -104,7 +103,7 @@ class Choreo { | |
|
|
||
| std::error_code ec; | ||
| auto fileBuffer = wpi::MemoryBuffer::GetFile(trajectoryFileName, ec); | ||
| if (!fileBuffer || !ec) { | ||
| if (!fileBuffer || ec) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
| FRC_ReportError(frc::warn::Warning, "Could not find trajectory file: {}", | ||
| trajectoryName); | ||
| return {}; | ||
|
|
@@ -157,81 +156,4 @@ class Choreo { | |
|
|
||
| Choreo(); | ||
| }; | ||
|
|
||
| /** | ||
| * A utility for caching loaded trajectories. This allows for loading | ||
| * trajectories only once, and then reusing them. | ||
| */ | ||
| template <choreo::TrajectorySample SampleType> | ||
| class TrajectoryCache { | ||
| public: | ||
| /** | ||
| * Load a trajectory from the deploy directory. Choreolib expects .traj files | ||
| * to be placed in src/main/deploy/choreo/[trajectoryName].traj. | ||
| * | ||
| * This method will cache the loaded trajectory and reused it if it is | ||
| * requested again. | ||
| * | ||
| * @param trajectoryName the path name in Choreo, which matches the file name | ||
| * in the deploy directory, file extension is optional. | ||
| * @return the loaded trajectory, or `empty std::optional` if the trajectory | ||
| * could not be loaded. | ||
| * @see Choreo#LoadTrajectory(std::string_view) | ||
| */ | ||
| static std::optional<choreo::Trajectory<SampleType>> LoadTrajectory( | ||
| std::string_view trajectoryName) { | ||
| if (cache.contains(trajectoryName)) { | ||
| return cache[trajectoryName]; | ||
| } else { | ||
| cache[trajectoryName] = | ||
| Choreo::LoadTrajectory<SampleType>(trajectoryName); | ||
| return cache[trajectoryName]; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Load a section of a split trajectory from the deploy directory. Choreolib | ||
| * expects .traj files to be placed in | ||
| * src/main/deploy/choreo/[trajectoryName].traj. | ||
| * | ||
| * This method will cache the loaded trajectory and reused it if it is | ||
| * requested again. The trajectory that is split off of will also be cached. | ||
| * | ||
| * @param trajectoryName the path name in Choreo, which matches the file name | ||
| * in the deploy directory, file extension is optional. | ||
| * @param splitIndex the index of the split trajectory to load | ||
| * @return the loaded trajectory, or `empty std::optional` if the trajectory | ||
| * could not be loaded. | ||
| * @see Choreo#LoadTrajectory(std::string_view) | ||
| */ | ||
| static std::optional<choreo::Trajectory<SampleType>> LoadTrajectory( | ||
| std::string_view trajectoryName, int splitIndex) { | ||
| std::string key = fmt::format("{}.:.{}", trajectoryName, splitIndex); | ||
|
|
||
| if (!cache.contains(key)) { | ||
| if (cache.contains(trajectoryName)) { | ||
| cache[key] = cache[trajectoryName].GetSplit(splitIndex); | ||
| } else { | ||
| auto possibleTrajectory = LoadTrajectory(trajectoryName); | ||
| cache[trajectoryName] = possibleTrajectory; | ||
|
|
||
| if (possibleTrajectory.has_value()) { | ||
| cache[key] = possibleTrajectory.value().GetSplit(splitIndex); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return cache[key]; | ||
| } | ||
|
|
||
| /** | ||
| * Clears the trajectory cache. | ||
| */ | ||
| static void Clear() { cache.clear(); } | ||
|
|
||
| private: | ||
| static inline std::unordered_map<std::string, choreo::Trajectory<SampleType>> | ||
| cache; | ||
| }; | ||
|
|
||
| } // namespace choreo | ||
71 changes: 71 additions & 0 deletions
71
choreolib/src/main/native/include/choreo/auto/AutoBindings.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| // Copyright (c) Choreo contributors | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <string> | ||
| #include <string_view> | ||
| #include <unordered_map> | ||
| #include <utility> | ||
|
|
||
| #include <frc2/command/CommandPtr.h> | ||
|
|
||
| namespace choreo { | ||
|
|
||
| /** | ||
| * A class used to bind commands to events in all trajectories created by an | ||
| * AutoFactory. | ||
| */ | ||
| class AutoBindings { | ||
| public: | ||
| AutoBindings() = default; | ||
| AutoBindings(const AutoBindings&) = delete; | ||
| AutoBindings& operator=(const AutoBindings&) = delete; | ||
|
|
||
| /** | ||
| * The default move constructor | ||
| */ | ||
| AutoBindings(AutoBindings&&) = default; | ||
|
|
||
| /** | ||
| * The default move assignment operator | ||
| * | ||
| * @return the moved autobindings | ||
| */ | ||
| AutoBindings& operator=(AutoBindings&&) = default; | ||
|
|
||
| /** | ||
| * Binds a command to an event in all trajectories created by the owener of | ||
| * the bindings. | ||
| * | ||
| * @param name The name of the event to bind the command to | ||
| * @param cmd A function that returns a CommandPtr that you want to bind. | ||
| * @return a reference to itself because we need to keep track of our moved | ||
| * binds (and function chaining) | ||
| */ | ||
| AutoBindings& Bind(std::string_view name, | ||
| std::function<frc2::CommandPtr()> cmd) & { | ||
| bindings.emplace(name, std::move(cmd)); | ||
| return *this; | ||
| } | ||
|
|
||
| /** | ||
| * Gets a read-only reference to the underlying map of events -> Commands | ||
| * | ||
| * @return the underlying map of event names to command factories | ||
| */ | ||
| const std::unordered_map<std::string, std::function<frc2::CommandPtr()>>& | ||
| GetBindings() const { | ||
| return bindings; | ||
| } | ||
|
|
||
| private: | ||
| void Merge(AutoBindings&& other) { | ||
| for (auto& [key, value] : other.bindings) { | ||
| bindings.emplace(std::move(key), std::move(value)); | ||
| } | ||
| other.bindings.clear(); | ||
| } | ||
|
|
||
| std::unordered_map<std::string, std::function<frc2::CommandPtr()>> bindings; | ||
| }; | ||
| } // namespace choreo |
169 changes: 169 additions & 0 deletions
169
choreolib/src/main/native/include/choreo/auto/AutoChooser.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| // Copyright (c) Choreo contributors | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <networktables/NetworkTable.h> | ||
| #include <networktables/NetworkTableInstance.h> | ||
| #include <networktables/StringArrayTopic.h> | ||
| #include <networktables/StringTopic.h> | ||
|
|
||
| #include <functional> | ||
| #include <memory> | ||
| #include <string> | ||
| #include <unordered_map> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| #include <frc/DriverStation.h> | ||
| #include <frc/Errors.h> | ||
| #include <frc/RobotBase.h> | ||
| #include <frc2/command/CommandPtr.h> | ||
| #include <frc2/command/Commands.h> | ||
|
|
||
| #include "choreo/auto/AutoFactory.h" | ||
| #include "choreo/util/AllianceFlipperUtil.h" | ||
| #include "networktables/Topic.h" | ||
|
|
||
| namespace choreo { | ||
|
|
||
| /** | ||
| * An auto chooser that allows for the selection of auto routines at runtime. | ||
| * | ||
| * This chooser takes a lazy loading approach to auto routines, only generating | ||
| * the auto routine when it is selected. This approach has the benefit of not | ||
| * loading all autos on startup, but also not loading the auto during auto start | ||
| * causing a delay. | ||
| * | ||
| * Once the AutoChooser is made you can add auto routines to it using the | ||
| * AddAutoRoutine() function . Unlike Sendable Chooser this chooser has to be | ||
| * updated every cycle by calling the Update function in your Robot periodic | ||
| * function. | ||
| * | ||
| * You can retrieve the auto routine CommandPtr that is currently | ||
| * selected by calling the GetSelectedAutoRoutine() function. | ||
| * | ||
| * @tparam SampleType The type of samples in the trajectory. | ||
| * @tparam Year The field year. Defaults to the current year. | ||
| */ | ||
| template <choreo::TrajectorySample SampleType, int Year = util::kDefaultYear> | ||
| class AutoChooser { | ||
| public: | ||
| /** | ||
| * Create a new auto chooser. | ||
| * | ||
| * @param factory The auto factory to use for auto routine generation. | ||
| * @param tableName The name of the network table to use for the chooser, | ||
| * passing in an empty string will put this chooser at the root of the network | ||
| * tables. | ||
| */ | ||
| AutoChooser(AutoFactory<SampleType, Year>& factory, | ||
| std::string_view tableName) | ||
| : factory{factory} { | ||
| std::string path = | ||
| nt::NetworkTable::NormalizeKey(tableName, true) + "/AutoChooser"; | ||
| std::shared_ptr<nt::NetworkTable> table = | ||
| nt::NetworkTableInstance::GetDefault().GetTable(path); | ||
|
|
||
| selected = table->GetStringTopic("selected").GetEntry(NONE_NAME); | ||
| table->GetStringTopic(".type").Publish().Set("String Chooser"); | ||
| table->GetStringTopic("default").Publish().SetDefault(NONE_NAME); | ||
| active = table->GetStringTopic("active").GetEntry(NONE_NAME); | ||
|
|
||
| std::vector<std::string> keys; | ||
| for (const auto& pair : autoRoutines) { | ||
| keys.push_back(pair.first); | ||
| } | ||
|
|
||
| options = table->GetStringArrayTopic("options").GetEntry(keys); | ||
| } | ||
|
|
||
| /** | ||
| * Update the auto chooser. | ||
| * | ||
| * This method should be called every cycle in the Robot periodic function. It | ||
| * will check if the selected auto routine has changed and update the active | ||
| * auto routine. | ||
| */ | ||
| void Update() { | ||
| if (frc::DriverStation::IsDisabled() || frc::RobotBase::IsSimulation()) { | ||
| std::string selectedString = selected.Get(); | ||
| if (selectedString == lastAutoRoutineName) { | ||
| return; | ||
| } | ||
| if (!autoRoutines.contains(selectedString)) { | ||
| selected.Set(NONE_NAME); | ||
| selectedString = NONE_NAME; | ||
| FRC_ReportError(frc::warn::Warning, | ||
| "Selected an auto that isn't an option!"); | ||
| } | ||
| lastAutoRoutineName = selectedString; | ||
| lastAutoRoutine = autoRoutines[lastAutoRoutineName](factory); | ||
| active.Set(lastAutoRoutineName); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Add an auto routine to the chooser. | ||
| * | ||
| * An auto routine is a function that takes an AutoFactory and returns a | ||
| * CommandPtr. These functions can be static, a lambda or belong to a local | ||
| * variable. | ||
| * | ||
| * A good paradigm is making an `AutoRoutines` class that has a reference | ||
| * to all your subsystems and has helper methods for auto commands inside it. | ||
| * Then you crate methods inside that class that take an `AutoFactory` and | ||
| * return a `CommandPtr`. | ||
| * | ||
| * @param name The name of the auto routine. | ||
| * @param generator The function that generates the auto routine. | ||
| */ | ||
| void AddAutoRoutine( | ||
| std::string name, | ||
| std::function<frc2::CommandPtr(AutoFactory<SampleType, Year>& factory)> | ||
| generator) { | ||
| autoRoutines[name] = generator; | ||
|
|
||
| std::vector<std::string> keys; | ||
| for (const auto& pair : autoRoutines) { | ||
| keys.push_back(pair.first); | ||
| } | ||
|
|
||
| options.Set(keys); | ||
| } | ||
|
|
||
| /** | ||
| * Choose an auto routine by name. | ||
| * | ||
| * @param choice The name of the auto routine to choose. | ||
| */ | ||
| void Choose(std::string_view choice) { | ||
| selected.Set(choice); | ||
| Update(); | ||
| } | ||
|
|
||
| /** | ||
| * Get the currently selected auto routine. | ||
| * | ||
| * @return The currently selected auto routine. | ||
| */ | ||
| frc2::CommandPtr GetSelectedAutoRoutine() { | ||
| return std::move(lastAutoRoutine); | ||
| } | ||
|
|
||
| private: | ||
| static inline std::string NONE_NAME = "Nothing"; | ||
| std::unordered_map<std::string, std::function<frc2::CommandPtr( | ||
| AutoFactory<SampleType, Year>& factory)>> | ||
| autoRoutines; | ||
|
|
||
| nt::StringEntry selected; | ||
| nt::StringEntry active; | ||
|
|
||
| nt::StringArrayEntry options; | ||
|
|
||
| AutoFactory<SampleType, Year>& factory; | ||
|
|
||
| std::string lastAutoRoutineName = NONE_NAME; | ||
| frc2::CommandPtr lastAutoRoutine{frc2::cmd::None()}; | ||
| }; | ||
| } // namespace choreo |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll have to update this for 2025