blob: b45f218476cb93e26100447796a91d02869cb3a9 [file] [log] [blame]
Alex Perry731b4602019-02-02 22:13:01 -08001#include "frc971/control_loops/drivetrain/splinedrivetrain.h"
2
Alex Perrye32eabc2019-02-08 19:51:19 -08003#include <iostream>
4
Alex Perry731b4602019-02-02 22:13:01 -08005#include "Eigen/Dense"
6
7#include "frc971/control_loops/drivetrain/drivetrain.q.h"
8#include "frc971/control_loops/drivetrain/drivetrain_config.h"
9
10const int kMaxSplineConstraints = 6;
11
12namespace frc971 {
13namespace control_loops {
14namespace drivetrain {
15
16SplineDrivetrain::SplineDrivetrain(const DrivetrainConfig<double> &dt_config)
Alex Perrye32eabc2019-02-08 19:51:19 -080017 : dt_config_(dt_config),
18 current_state_(::Eigen::Matrix<double, 2, 1>::Zero()) {}
19
20void SplineDrivetrain::ScaleCapU(Eigen::Matrix<double, 2, 1> *U) {
21 bool output_was_capped = ::std::abs((*U)(0, 0)) > 12.0 ||
22 ::std::abs((*U)(1, 0)) > 12.0;
23
24 if (output_was_capped) {
25 *U *= 12.0 / U->lpNorm<Eigen::Infinity>();
26 }
27}
Alex Perry731b4602019-02-02 22:13:01 -080028
29// TODO(alex): put in another thread to avoid malloc in RT.
30void SplineDrivetrain::SetGoal(
31 const ::frc971::control_loops::DrivetrainQueue::Goal &goal) {
32 current_spline_handle_ = goal.spline_handle;
33 const ::frc971::MultiSpline &multispline = goal.spline;
34 if (multispline.spline_idx) {
35 current_spline_idx_ = multispline.spline_idx;
36 auto x = multispline.spline_x;
37 auto y = multispline.spline_y;
38 ::std::vector<Spline> splines = ::std::vector<Spline>();
39 for (int i = 0; i < multispline.spline_count; ++i) {
40 ::Eigen::Matrix<double, 2, 6> points =
41 ::Eigen::Matrix<double, 2, 6>::Zero();
42 for (int j = 0; j < 6; ++j) {
43 points(0, j) = x[i * 5 + j];
44 points(1, j) = y[i * 5 + j];
45 }
46 splines.emplace_back(Spline(points));
47 }
48
49 distance_spline_ = ::std::unique_ptr<DistanceSpline>(
50 new DistanceSpline(::std::move(splines)));
51
52 current_trajectory_ = ::std::unique_ptr<Trajectory>(
53 new Trajectory(distance_spline_.get(), dt_config_));
54
55 for (int i = 0; i < kMaxSplineConstraints; ++i) {
56 const ::frc971::Constraint &constraint = multispline.constraints[i];
57 switch (constraint.constraint_type) {
58 case 0:
59 break;
60 case 1:
61 current_trajectory_->set_longitudal_acceleration(constraint.value);
62 break;
63 case 2:
64 current_trajectory_->set_lateral_acceleration(constraint.value);
65 break;
66 case 3:
67 current_trajectory_->set_voltage_limit(constraint.value);
68 break;
69 case 4:
70 current_trajectory_->LimitVelocity(constraint.start_distance,
71 constraint.end_distance,
72 constraint.value);
73 break;
74 }
75 }
76
77 current_trajectory_->Plan();
Alex Perrya71badb2019-02-06 19:40:41 -080078 current_xva_ = current_trajectory_->FFAcceleration(0);
79 current_xva_(1) = 0.0;
Alex Perrye32eabc2019-02-08 19:51:19 -080080 current_state_ = ::Eigen::Matrix<double, 2, 1>::Zero();
Alex Perrya71badb2019-02-06 19:40:41 -080081 }
82}
83
Alex Perrye32eabc2019-02-08 19:51:19 -080084// TODO(alex): Hold position when done following the spline.
85// TODO(Austin): Compensate for voltage error.
86void SplineDrivetrain::Update(bool enable,
87 const ::Eigen::Matrix<double, 5, 1> &state) {
88 enable_ = enable;
89 if (enable && current_trajectory_) {
90 ::Eigen::Matrix<double, 2, 1> U_ff = ::Eigen::Matrix<double, 2, 1>::Zero();
91 if (!current_trajectory_->is_at_end(current_state_)) {
92 // TODO(alex): It takes about a cycle for the outputs to propagate to the
93 // motors. Consider delaying the output by a cycle.
94 U_ff = current_trajectory_->FFVoltage(current_xva_(0));
95 }
96 ::Eigen::Matrix<double, 2, 5> K =
97 current_trajectory_->KForState(state, dt_config_.dt, Q, R);
98 ::Eigen::Matrix<double, 5, 1> goal_state =
99 current_trajectory_->GoalState(current_xva_(0), current_xva_(1));
100 ::Eigen::Matrix<double, 5, 1> state_error = goal_state - state;
101 ::Eigen::Matrix<double, 2, 1> U_fb = K * state_error;
102 next_U_ = U_ff + U_fb;
103 uncapped_U_ = next_U_;
104 ScaleCapU(&next_U_);
105
Alex Perrya71badb2019-02-06 19:40:41 -0800106 next_xva_ = current_trajectory_->GetNextXVA(dt_config_.dt, &current_state_);
Alex Perry731b4602019-02-02 22:13:01 -0800107 }
108}
109
Alex Perry731b4602019-02-02 22:13:01 -0800110void SplineDrivetrain::SetOutput(
111 ::frc971::control_loops::DrivetrainQueue::Output *output) {
112 if (!output) {
113 return;
114 }
Alex Perrya71badb2019-02-06 19:40:41 -0800115 if (!current_trajectory_) {
116 return;
117 }
Alex Perry731b4602019-02-02 22:13:01 -0800118 if (current_spline_handle_ == current_spline_idx_) {
Alex Perrya71badb2019-02-06 19:40:41 -0800119 if (!current_trajectory_->is_at_end(current_state_)) {
Alex Perrye32eabc2019-02-08 19:51:19 -0800120 output->left_voltage = next_U_(0);
121 output->right_voltage = next_U_(1);
Alex Perrya71badb2019-02-06 19:40:41 -0800122 current_xva_ = next_xva_;
Alex Perry731b4602019-02-02 22:13:01 -0800123 }
124 }
125}
126
Alex Perrye32eabc2019-02-08 19:51:19 -0800127void SplineDrivetrain::PopulateStatus(
128 ::frc971::control_loops::DrivetrainQueue::Status *status) const {
129 if (status && enable_) {
130 status->uncapped_left_voltage = uncapped_U_(0);
131 status->uncapped_right_voltage = uncapped_U_(1);
132 status->robot_speed = current_xva_(1);
133 }
134}
135
Alex Perry731b4602019-02-02 22:13:01 -0800136} // namespace drivetrain
137} // namespace control_loops
138} // namespace frc971