Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 1 | #include "frc971/control_loops/drivetrain/splinedrivetrain.h" |
| 2 | |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 3 | #include <iostream> |
| 4 | |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 5 | #include "Eigen/Dense" |
| 6 | |
| 7 | #include "frc971/control_loops/drivetrain/drivetrain.q.h" |
| 8 | #include "frc971/control_loops/drivetrain/drivetrain_config.h" |
| 9 | |
| 10 | const int kMaxSplineConstraints = 6; |
| 11 | |
| 12 | namespace frc971 { |
| 13 | namespace control_loops { |
| 14 | namespace drivetrain { |
| 15 | |
| 16 | SplineDrivetrain::SplineDrivetrain(const DrivetrainConfig<double> &dt_config) |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 17 | : dt_config_(dt_config), |
| 18 | current_state_(::Eigen::Matrix<double, 2, 1>::Zero()) {} |
| 19 | |
| 20 | void 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 Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 28 | |
| 29 | // TODO(alex): put in another thread to avoid malloc in RT. |
| 30 | void 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 Perry | a71badb | 2019-02-06 19:40:41 -0800 | [diff] [blame] | 78 | current_xva_ = current_trajectory_->FFAcceleration(0); |
| 79 | current_xva_(1) = 0.0; |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 80 | current_state_ = ::Eigen::Matrix<double, 2, 1>::Zero(); |
Alex Perry | a71badb | 2019-02-06 19:40:41 -0800 | [diff] [blame] | 81 | } |
| 82 | } |
| 83 | |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 84 | // TODO(alex): Hold position when done following the spline. |
| 85 | // TODO(Austin): Compensate for voltage error. |
| 86 | void 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(); |
James Kuszmaul | 1057ce8 | 2019-02-09 17:58:24 -0800 | [diff] [blame^] | 91 | if (!IsAtEnd()) { |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 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); |
James Kuszmaul | 1057ce8 | 2019-02-09 17:58:24 -0800 | [diff] [blame^] | 98 | ::Eigen::Matrix<double, 5, 1> goal_state = CurrentGoalState(); |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 99 | ::Eigen::Matrix<double, 5, 1> state_error = goal_state - state; |
| 100 | ::Eigen::Matrix<double, 2, 1> U_fb = K * state_error; |
| 101 | next_U_ = U_ff + U_fb; |
| 102 | uncapped_U_ = next_U_; |
| 103 | ScaleCapU(&next_U_); |
| 104 | |
Alex Perry | a71badb | 2019-02-06 19:40:41 -0800 | [diff] [blame] | 105 | next_xva_ = current_trajectory_->GetNextXVA(dt_config_.dt, ¤t_state_); |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 106 | } |
| 107 | } |
| 108 | |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 109 | void SplineDrivetrain::SetOutput( |
| 110 | ::frc971::control_loops::DrivetrainQueue::Output *output) { |
| 111 | if (!output) { |
| 112 | return; |
| 113 | } |
Alex Perry | a71badb | 2019-02-06 19:40:41 -0800 | [diff] [blame] | 114 | if (!current_trajectory_) { |
| 115 | return; |
| 116 | } |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 117 | if (current_spline_handle_ == current_spline_idx_) { |
James Kuszmaul | 1057ce8 | 2019-02-09 17:58:24 -0800 | [diff] [blame^] | 118 | if (!IsAtEnd()) { |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 119 | output->left_voltage = next_U_(0); |
| 120 | output->right_voltage = next_U_(1); |
Alex Perry | a71badb | 2019-02-06 19:40:41 -0800 | [diff] [blame] | 121 | current_xva_ = next_xva_; |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 122 | } |
| 123 | } |
| 124 | } |
| 125 | |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 126 | void SplineDrivetrain::PopulateStatus( |
| 127 | ::frc971::control_loops::DrivetrainQueue::Status *status) const { |
| 128 | if (status && enable_) { |
| 129 | status->uncapped_left_voltage = uncapped_U_(0); |
| 130 | status->uncapped_right_voltage = uncapped_U_(1); |
| 131 | status->robot_speed = current_xva_(1); |
| 132 | } |
| 133 | } |
| 134 | |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 135 | } // namespace drivetrain |
| 136 | } // namespace control_loops |
| 137 | } // namespace frc971 |