blob: 262100786256e8b215cdc1fbbca941ba83952e39 [file] [log] [blame]
Alex Perry731b4602019-02-02 22:13:01 -08001#include "frc971/control_loops/drivetrain/splinedrivetrain.h"
2
3#include "Eigen/Dense"
4
Alex Perry1ec34522019-02-17 22:44:10 -08005#include "aos/init.h"
Alex Perry731b4602019-02-02 22:13:01 -08006#include "frc971/control_loops/drivetrain/drivetrain.q.h"
7#include "frc971/control_loops/drivetrain/drivetrain_config.h"
8
Alex Perry731b4602019-02-02 22:13:01 -08009namespace frc971 {
10namespace control_loops {
11namespace drivetrain {
12
13SplineDrivetrain::SplineDrivetrain(const DrivetrainConfig<double> &dt_config)
Alex Perrycc3ee4c2019-02-09 21:20:41 -080014 : dt_config_(dt_config), new_goal_(&mutex_) {
15 worker_thread_ = std::thread(&SplineDrivetrain::ComputeTrajectory, this);
16}
Alex Perrye32eabc2019-02-08 19:51:19 -080017
18void SplineDrivetrain::ScaleCapU(Eigen::Matrix<double, 2, 1> *U) {
Alex Perrycc3ee4c2019-02-09 21:20:41 -080019 output_was_capped_ =
20 ::std::abs((*U)(0, 0)) > 12.0 || ::std::abs((*U)(1, 0)) > 12.0;
Alex Perrye32eabc2019-02-08 19:51:19 -080021
Alex Perrycc3ee4c2019-02-09 21:20:41 -080022 if (output_was_capped_) {
Alex Perrye32eabc2019-02-08 19:51:19 -080023 *U *= 12.0 / U->lpNorm<Eigen::Infinity>();
24 }
25}
Alex Perry731b4602019-02-02 22:13:01 -080026
Alex Perrycc3ee4c2019-02-09 21:20:41 -080027void SplineDrivetrain::ComputeTrajectory() {
Alex Perry1ec34522019-02-17 22:44:10 -080028 ::aos::SetCurrentThreadRealtimePriority(1);
29
Alex Perrycc3ee4c2019-02-09 21:20:41 -080030 ::aos::MutexLocker locker(&mutex_);
31 while (run_) {
32 while (goal_.spline.spline_idx == future_spline_idx_) {
33 CHECK(!new_goal_.Wait());
34 if (!run_) {
35 return;
36 }
37 }
38 past_distance_spline_.reset();
39 past_trajectory_.reset();
40
41 plan_state_ = PlanState::kBuildingTrajectory;
42 const ::frc971::MultiSpline &multispline = goal_.spline;
43 future_spline_idx_ = multispline.spline_idx;
Alex Perry731b4602019-02-02 22:13:01 -080044 auto x = multispline.spline_x;
45 auto y = multispline.spline_y;
46 ::std::vector<Spline> splines = ::std::vector<Spline>();
47 for (int i = 0; i < multispline.spline_count; ++i) {
48 ::Eigen::Matrix<double, 2, 6> points =
49 ::Eigen::Matrix<double, 2, 6>::Zero();
50 for (int j = 0; j < 6; ++j) {
51 points(0, j) = x[i * 5 + j];
52 points(1, j) = y[i * 5 + j];
53 }
54 splines.emplace_back(Spline(points));
55 }
56
Alex Perrycc3ee4c2019-02-09 21:20:41 -080057 future_distance_spline_ = ::std::unique_ptr<DistanceSpline>(
Alex Perry731b4602019-02-02 22:13:01 -080058 new DistanceSpline(::std::move(splines)));
59
Alex Perrycc3ee4c2019-02-09 21:20:41 -080060 future_trajectory_ = ::std::unique_ptr<Trajectory>(
61 new Trajectory(future_distance_spline_.get(), dt_config_));
Alex Perry731b4602019-02-02 22:13:01 -080062
Alex Perrycc3ee4c2019-02-09 21:20:41 -080063 for (size_t i = 0; i < multispline.constraints.size(); ++i) {
Alex Perry731b4602019-02-02 22:13:01 -080064 const ::frc971::Constraint &constraint = multispline.constraints[i];
65 switch (constraint.constraint_type) {
66 case 0:
67 break;
68 case 1:
Alex Perrycc3ee4c2019-02-09 21:20:41 -080069 future_trajectory_->set_longitudal_acceleration(constraint.value);
Alex Perry731b4602019-02-02 22:13:01 -080070 break;
71 case 2:
Alex Perrycc3ee4c2019-02-09 21:20:41 -080072 future_trajectory_->set_lateral_acceleration(constraint.value);
Alex Perry731b4602019-02-02 22:13:01 -080073 break;
74 case 3:
Alex Perrycc3ee4c2019-02-09 21:20:41 -080075 future_trajectory_->set_voltage_limit(constraint.value);
Alex Perry731b4602019-02-02 22:13:01 -080076 break;
77 case 4:
Alex Perrycc3ee4c2019-02-09 21:20:41 -080078 future_trajectory_->LimitVelocity(constraint.start_distance,
79 constraint.end_distance,
80 constraint.value);
Alex Perry731b4602019-02-02 22:13:01 -080081 break;
82 }
83 }
Alex Perrycc3ee4c2019-02-09 21:20:41 -080084 plan_state_ = PlanState::kPlanningTrajectory;
Alex Perry731b4602019-02-02 22:13:01 -080085
Alex Perrycc3ee4c2019-02-09 21:20:41 -080086 future_trajectory_->Plan();
87 plan_state_ = PlanState::kPlannedTrajectory;
88 }
89}
90
91void SplineDrivetrain::SetGoal(
92 const ::frc971::control_loops::DrivetrainQueue::Goal &goal) {
93 current_spline_handle_ = goal.spline_handle;
94 // If told to stop, set the executing spline to an invalid index.
95 if (current_spline_handle_ == 0) {
96 current_spline_idx_ = -1;
97 }
98
99 ::aos::Mutex::State mutex_state = mutex_.TryLock();
100 if (mutex_state == ::aos::Mutex::State::kLocked) {
101 if (goal.spline.spline_idx && future_spline_idx_ != goal.spline.spline_idx) {
102 goal_ = goal;
103 new_goal_.Broadcast();
104 }
105 if (future_trajectory_ &&
106 (!current_trajectory_ ||
107 current_trajectory_->is_at_end(current_xva_.block<2, 1>(0, 0)) ||
108 current_spline_idx_ == -1)) {
109 // Move current data to other variables to be cleared by worker.
110 past_trajectory_ = std::move(current_trajectory_);
111 past_distance_spline_ = std::move(current_distance_spline_);
112
113 // Move the computed data to be executed.
114 current_trajectory_ = std::move(future_trajectory_);
115 current_distance_spline_ = std::move(future_distance_spline_);
116 current_spline_idx_ = future_spline_idx_;
117
118 // Reset internal state to a trajectory start position.
119 current_xva_ = current_trajectory_->FFAcceleration(0);
120 current_xva_(1) = 0.0;
121 }
122 mutex_.Unlock();
Alex Perrya71badb2019-02-06 19:40:41 -0800123 }
124}
125
Alex Perrye32eabc2019-02-08 19:51:19 -0800126// TODO(alex): Hold position when done following the spline.
127// TODO(Austin): Compensate for voltage error.
Alex Perrycc3ee4c2019-02-09 21:20:41 -0800128void SplineDrivetrain::Update(bool enable, const ::Eigen::Matrix<double, 5, 1> &state) {
129 next_U_ = ::Eigen::Matrix<double, 2, 1>::Zero();
Alex Perrye32eabc2019-02-08 19:51:19 -0800130 enable_ = enable;
131 if (enable && current_trajectory_) {
132 ::Eigen::Matrix<double, 2, 1> U_ff = ::Eigen::Matrix<double, 2, 1>::Zero();
Alex Perrycc3ee4c2019-02-09 21:20:41 -0800133 if (!IsAtEnd() &&
134 current_spline_handle_ == current_spline_idx_) {
Alex Perrye32eabc2019-02-08 19:51:19 -0800135 // TODO(alex): It takes about a cycle for the outputs to propagate to the
136 // motors. Consider delaying the output by a cycle.
137 U_ff = current_trajectory_->FFVoltage(current_xva_(0));
138 }
Alex Perrycc3ee4c2019-02-09 21:20:41 -0800139
Alex Perrye32eabc2019-02-08 19:51:19 -0800140 ::Eigen::Matrix<double, 2, 5> K =
141 current_trajectory_->KForState(state, dt_config_.dt, Q, R);
James Kuszmaul1057ce82019-02-09 17:58:24 -0800142 ::Eigen::Matrix<double, 5, 1> goal_state = CurrentGoalState();
Alex Perrye32eabc2019-02-08 19:51:19 -0800143 ::Eigen::Matrix<double, 5, 1> state_error = goal_state - state;
144 ::Eigen::Matrix<double, 2, 1> U_fb = K * state_error;
Alex Perrycc3ee4c2019-02-09 21:20:41 -0800145
146 ::Eigen::Matrix<double, 2, 1> xv_state = current_xva_.block<2,1>(0,0);
147 next_xva_ = current_trajectory_->GetNextXVA(dt_config_.dt, &xv_state);
Alex Perrye32eabc2019-02-08 19:51:19 -0800148 next_U_ = U_ff + U_fb;
149 uncapped_U_ = next_U_;
150 ScaleCapU(&next_U_);
Alex Perry731b4602019-02-02 22:13:01 -0800151 }
152}
153
Alex Perry731b4602019-02-02 22:13:01 -0800154void SplineDrivetrain::SetOutput(
155 ::frc971::control_loops::DrivetrainQueue::Output *output) {
156 if (!output) {
157 return;
158 }
159 if (current_spline_handle_ == current_spline_idx_) {
James Kuszmaul1057ce82019-02-09 17:58:24 -0800160 if (!IsAtEnd()) {
Alex Perrye32eabc2019-02-08 19:51:19 -0800161 output->left_voltage = next_U_(0);
162 output->right_voltage = next_U_(1);
Alex Perrya71badb2019-02-06 19:40:41 -0800163 current_xva_ = next_xva_;
Alex Perry731b4602019-02-02 22:13:01 -0800164 }
165 }
Alex Perrycc3ee4c2019-02-09 21:20:41 -0800166 output->left_voltage = next_U_(0);
167 output->right_voltage = next_U_(1);
Alex Perry731b4602019-02-02 22:13:01 -0800168}
169
Alex Perrye32eabc2019-02-08 19:51:19 -0800170void SplineDrivetrain::PopulateStatus(
171 ::frc971::control_loops::DrivetrainQueue::Status *status) const {
172 if (status && enable_) {
173 status->uncapped_left_voltage = uncapped_U_(0);
174 status->uncapped_right_voltage = uncapped_U_(1);
175 status->robot_speed = current_xva_(1);
Alex Perrycc3ee4c2019-02-09 21:20:41 -0800176 status->output_was_capped = output_was_capped_;
177 }
178
179 if (status) {
180 if (current_distance_spline_) {
181 ::Eigen::Matrix<double, 5, 1> goal_state = CurrentGoalState();
182 status->trajectory_logging.x = goal_state(0);
183 status->trajectory_logging.y = goal_state(1);
184 status->trajectory_logging.theta = goal_state(2);
185 status->trajectory_logging.left_velocity = goal_state(3);
186 status->trajectory_logging.right_velocity = goal_state(4);
187 }
188 status->trajectory_logging.planning_state = static_cast<int8_t>(plan_state_.load());
189 status->trajectory_logging.is_executing = !IsAtEnd();
190 status->trajectory_logging.current_spline_handle = current_spline_handle_;
191 status->trajectory_logging.current_spline_idx = current_spline_idx_;
Alex Perrye32eabc2019-02-08 19:51:19 -0800192 }
193}
194
Alex Perry731b4602019-02-02 22:13:01 -0800195} // namespace drivetrain
196} // namespace control_loops
197} // namespace frc971