blob: 09bdc71016a0d40bfe510a4ab9ddb4299aefe36d [file] [log] [blame]
Alex Perry731b4602019-02-02 22:13:01 -08001#ifndef FRC971_CONTROL_LOOPS_DRIVETRAIN_SPLINEDRIVETRAIN_H_
2#define FRC971_CONTROL_LOOPS_DRIVETRAIN_SPLINEDRIVETRAIN_H_
3
Alex Perrycc3ee4c2019-02-09 21:20:41 -08004#include <atomic>
5#include <thread>
6
Alex Perrya71badb2019-02-06 19:40:41 -08007#include "Eigen/Dense"
Philipp Schrader790cb542023-07-05 21:06:52 -07008
Alex Perrycc3ee4c2019-02-09 21:20:41 -08009#include "aos/condition.h"
10#include "aos/mutex/mutex.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070011#include "frc971/control_loops/control_loops_generated.h"
Alex Perry731b4602019-02-02 22:13:01 -080012#include "frc971/control_loops/drivetrain/distance_spline.h"
Alex Perry731b4602019-02-02 22:13:01 -080013#include "frc971/control_loops/drivetrain/drivetrain_config.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070014#include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h"
15#include "frc971/control_loops/drivetrain/drivetrain_output_generated.h"
16#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
Alex Perry731b4602019-02-02 22:13:01 -080017#include "frc971/control_loops/drivetrain/spline.h"
18#include "frc971/control_loops/drivetrain/trajectory.h"
19
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080020namespace frc971::control_loops::drivetrain {
Alex Perry731b4602019-02-02 22:13:01 -080021
22class SplineDrivetrain {
23 public:
James Kuszmaul6a1ffe32023-03-23 19:40:26 -070024 static constexpr size_t kMaxTrajectories = 6;
Alex Perry731b4602019-02-02 22:13:01 -080025 SplineDrivetrain(const DrivetrainConfig<double> &dt_config);
26
Alex Perrycb7da4b2019-08-28 19:35:56 -070027 void SetGoal(const ::frc971::control_loops::drivetrain::Goal *goal);
James Kuszmaul75a18c52021-03-10 22:02:07 -080028 // Note that the user maintains ownership of the trajectory flatbuffer for the
29 // entire time; once AddTrajectory() is called, the trajectory pointer must
30 // stay valid until the spline has finished executing and HasTrajectory()
31 // returns false.
32 bool HasTrajectory(const fb::Trajectory *trajectory) const;
33 void AddTrajectory(const fb::Trajectory *trajectory);
James Kuszmaul99af8b52021-03-28 10:50:15 -070034 bool IsCurrentTrajectory(const fb::Trajectory *trajectory) const;
35 void DeleteTrajectory(const fb::Trajectory *trajectory);
Alex Perry731b4602019-02-02 22:13:01 -080036
James Kuszmaulaa2499d2020-06-02 21:31:19 -070037 void Update(bool enabled, const ::Eigen::Matrix<double, 5, 1> &state,
38 const ::Eigen::Matrix<double, 2, 1> &voltage_error);
Alex Perrya71badb2019-02-06 19:40:41 -080039
Alex Perrycb7da4b2019-08-28 19:35:56 -070040 void SetOutput(::frc971::control_loops::drivetrain::OutputT *output);
41
42 flatbuffers::Offset<TrajectoryLogging> MakeTrajectoryLogging(
43 aos::Sender<drivetrain::Status>::Builder *builder) const;
44 flatbuffers::Offset<TrajectoryLogging> MakeTrajectoryLogging(
45 flatbuffers::FlatBufferBuilder *builder) const;
Austin Schuhd749d932020-12-30 21:38:40 -080046 void PopulateStatus(drivetrain::Status::Builder *status) const;
James Kuszmaul1057ce82019-02-09 17:58:24 -080047
48 // Accessor for the current goal state, pretty much only present for debugging
49 // purposes.
Alex Perrycc3ee4c2019-02-09 21:20:41 -080050 ::Eigen::Matrix<double, 5, 1> CurrentGoalState() const {
Austin Schuh6bdcc372024-06-27 14:49:11 -070051 if (executing_spline_) {
52 const FinishedTrajectory *finished = current_trajectory();
53 CHECK(finished != nullptr);
54 return finished->GoalState(current_xva_(0), current_xva_(1));
55 } else {
56 return ::Eigen::Matrix<double, 5, 1>::Zero();
57 }
James Kuszmaul1057ce82019-02-09 17:58:24 -080058 }
59
60 bool IsAtEnd() const {
Austin Schuh6bdcc372024-06-27 14:49:11 -070061 if (!executing_spline_) {
62 return true;
63 }
64
65 const FinishedTrajectory *finished = current_trajectory();
66 CHECK(finished != nullptr);
67 return finished->is_at_end(current_xva_.block<2, 1>(0, 0));
James Kuszmaul1057ce82019-02-09 17:58:24 -080068 }
Alex Perrycc3ee4c2019-02-09 21:20:41 -080069
James Kuszmaul99af8b52021-03-28 10:50:15 -070070 size_t trajectory_count() const { return trajectories_.size(); }
71
Alex Perrycb7da4b2019-08-28 19:35:56 -070072 // Returns true if the splinedrivetrain is enabled.
73 bool enable() const { return enable_; }
74
Alex Perry731b4602019-02-02 22:13:01 -080075 private:
Alex Perrye32eabc2019-02-08 19:51:19 -080076 void ScaleCapU(Eigen::Matrix<double, 2, 1> *U);
77
James Kuszmaul75a18c52021-03-10 22:02:07 -080078 // This is called to update the internal state for managing all the splines.
79 // Calling it redundantly does not cause any issues. It checks the value of
James Kuszmauldc534432023-02-05 14:51:11 -080080 // commanded_spline to determine whether we are being commanded to run a
James Kuszmaul75a18c52021-03-10 22:02:07 -080081 // spline, and if there is any trajectory in the list of trajectories matching
James Kuszmauldc534432023-02-05 14:51:11 -080082 // the command, we begin/continue executing that spline. If commanded_spline
James Kuszmaul75a18c52021-03-10 22:02:07 -080083 // is empty or has changed, we stop executing the previous trajectory and
84 // remove it from trajectories_. Then, when the drivetrain code checks
85 // HasTrajectory() for the old trajectory, it will return false and the
86 // drivetrain can free up the fetcher to get the next trajectory.
James Kuszmauldc534432023-02-05 14:51:11 -080087 void UpdateSplineHandles(std::optional<int> commanded_spline);
James Kuszmaul75a18c52021-03-10 22:02:07 -080088
89 // Deletes the currently executing trajectory.
90 void DeleteCurrentSpline();
91
James Kuszmauldc534432023-02-05 14:51:11 -080092 FinishedTrajectory *current_trajectory();
93 const FinishedTrajectory *current_trajectory() const;
James Kuszmaul75a18c52021-03-10 22:02:07 -080094
Alex Perry731b4602019-02-02 22:13:01 -080095 const DrivetrainConfig<double> dt_config_;
96
Austin Schuhf7c65202022-11-04 21:28:20 -070097 std::shared_ptr<
98 StateFeedbackLoop<2, 2, 2, double, StateFeedbackHybridPlant<2, 2, 2>,
99 HybridKalman<2, 2, 2>>>
100 velocity_drivetrain_;
101
James Kuszmaul75a18c52021-03-10 22:02:07 -0800102 bool executing_spline_ = false;
Alex Perrye32eabc2019-02-08 19:51:19 -0800103
James Kuszmaul75a18c52021-03-10 22:02:07 -0800104 // TODO(james): Sort out construction to avoid so much dynamic memory
105 // allocation...
James Kuszmauldc534432023-02-05 14:51:11 -0800106 aos::SizedArray<FinishedTrajectory, kMaxTrajectories> trajectories_;
James Kuszmaul75a18c52021-03-10 22:02:07 -0800107
108 std::optional<int> commanded_spline_;
Alex Perrycc3ee4c2019-02-09 21:20:41 -0800109
110 // State required to compute the next iteration's output.
111 ::Eigen::Matrix<double, 3, 1> current_xva_, next_xva_;
112 ::Eigen::Matrix<double, 2, 1> next_U_;
113
114 // Information used for status message.
115 ::Eigen::Matrix<double, 2, 1> uncapped_U_;
James Kuszmaula5a418f2024-03-17 17:16:06 -0700116 ::Eigen::Matrix<double, 5, 1> last_state_error_;
117 ::Eigen::Matrix<double, 2, 5> last_U_components_;
118 ::Eigen::Matrix<double, 2, 1> last_U_ff_;
Alex Perrycc3ee4c2019-02-09 21:20:41 -0800119 bool enable_ = false;
120 bool output_was_capped_ = false;
Alex Perry731b4602019-02-02 22:13:01 -0800121};
122
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800123} // namespace frc971::control_loops::drivetrain
Alex Perry731b4602019-02-02 22:13:01 -0800124
125#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_SPLINEDRIVETRAIN_H_