blob: 303701f6476c79c7b914fcd972015279f0bf3c50 [file] [log] [blame]
#ifndef FRC971_CONTROL_LOOPS_DRIVETRAIN_SPLINEDRIVETRAIN_H_
#define FRC971_CONTROL_LOOPS_DRIVETRAIN_SPLINEDRIVETRAIN_H_
#include <atomic>
#include <thread>
#include "Eigen/Dense"
#include "aos/condition.h"
#include "aos/mutex/mutex.h"
#include "frc971/control_loops/control_loops_generated.h"
#include "frc971/control_loops/drivetrain/distance_spline.h"
#include "frc971/control_loops/drivetrain/drivetrain_config.h"
#include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h"
#include "frc971/control_loops/drivetrain/drivetrain_output_generated.h"
#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
#include "frc971/control_loops/drivetrain/spline.h"
#include "frc971/control_loops/drivetrain/trajectory.h"
namespace frc971 {
namespace control_loops {
namespace drivetrain {
class SplineDrivetrain {
public:
SplineDrivetrain(const DrivetrainConfig<double> &dt_config);
void SetGoal(const ::frc971::control_loops::drivetrain::Goal *goal);
// Note that the user maintains ownership of the trajectory flatbuffer for the
// entire time; once AddTrajectory() is called, the trajectory pointer must
// stay valid until the spline has finished executing and HasTrajectory()
// returns false.
bool HasTrajectory(const fb::Trajectory *trajectory) const;
void AddTrajectory(const fb::Trajectory *trajectory);
bool IsCurrentTrajectory(const fb::Trajectory *trajectory) const;
void DeleteTrajectory(const fb::Trajectory *trajectory);
void Update(bool enabled, const ::Eigen::Matrix<double, 5, 1> &state,
const ::Eigen::Matrix<double, 2, 1> &voltage_error);
void SetOutput(::frc971::control_loops::drivetrain::OutputT *output);
flatbuffers::Offset<TrajectoryLogging> MakeTrajectoryLogging(
aos::Sender<drivetrain::Status>::Builder *builder) const;
flatbuffers::Offset<TrajectoryLogging> MakeTrajectoryLogging(
flatbuffers::FlatBufferBuilder *builder) const;
void PopulateStatus(drivetrain::Status::Builder *status) const;
// Accessor for the current goal state, pretty much only present for debugging
// purposes.
::Eigen::Matrix<double, 5, 1> CurrentGoalState() const {
return executing_spline_ ? current_trajectory().GoalState(current_xva_(0),
current_xva_(1))
: ::Eigen::Matrix<double, 5, 1>::Zero();
}
bool IsAtEnd() const {
return executing_spline_
? current_trajectory().is_at_end(current_xva_.block<2, 1>(0, 0))
: true;
}
size_t trajectory_count() const { return trajectories_.size(); }
// Returns true if the splinedrivetrain is enabled.
bool enable() const { return enable_; }
private:
void ScaleCapU(Eigen::Matrix<double, 2, 1> *U);
// This is called to update the internal state for managing all the splines.
// Calling it redundantly does not cause any issues. It checks the value of
// commanded_spline_ to determine whether we are being commanded to run a
// spline, and if there is any trajectory in the list of trajectories matching
// the command, we begin/continue executing that spline. If commanded_spline_
// is empty or has changed, we stop executing the previous trajectory and
// remove it from trajectories_. Then, when the drivetrain code checks
// HasTrajectory() for the old trajectory, it will return false and the
// drivetrain can free up the fetcher to get the next trajectory.
void UpdateSplineHandles();
// Deletes the currently executing trajectory.
void DeleteCurrentSpline();
const FinishedTrajectory &current_trajectory() const {
return *CHECK_NOTNULL(current_trajectory_);
}
const DrivetrainConfig<double> dt_config_;
bool executing_spline_ = false;
// TODO(james): Sort out construction to avoid so much dynamic memory
// allocation...
std::vector<std::unique_ptr<FinishedTrajectory>> trajectories_;
const FinishedTrajectory *current_trajectory_ = nullptr;
std::optional<int> commanded_spline_;
// State required to compute the next iteration's output.
::Eigen::Matrix<double, 3, 1> current_xva_, next_xva_;
::Eigen::Matrix<double, 2, 1> next_U_;
// Information used for status message.
::Eigen::Matrix<double, 2, 1> uncapped_U_;
bool enable_ = false;
bool output_was_capped_ = false;
};
} // namespace drivetrain
} // namespace control_loops
} // namespace frc971
#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_SPLINEDRIVETRAIN_H_