Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 1 | #include "frc971/control_loops/drivetrain/splinedrivetrain.h" |
| 2 | |
| 3 | #include "Eigen/Dense" |
Philipp Schrader | 790cb54 | 2023-07-05 21:06:52 -0700 | [diff] [blame] | 4 | |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 5 | #include "aos/json_to_flatbuffer.h" |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 6 | #include "aos/realtime.h" |
James Kuszmaul | c73bb22 | 2019-04-07 12:15:35 -0700 | [diff] [blame] | 7 | #include "aos/util/math.h" |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 8 | #include "frc971/control_loops/control_loops_generated.h" |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 9 | #include "frc971/control_loops/drivetrain/drivetrain_config.h" |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 10 | #include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h" |
| 11 | #include "frc971/control_loops/drivetrain/drivetrain_output_generated.h" |
| 12 | #include "frc971/control_loops/drivetrain/drivetrain_status_generated.h" |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 13 | |
Stephan Pleines | f63bde8 | 2024-01-13 15:59:33 -0800 | [diff] [blame] | 14 | namespace frc971::control_loops::drivetrain { |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 15 | |
| 16 | SplineDrivetrain::SplineDrivetrain(const DrivetrainConfig<double> &dt_config) |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 17 | : dt_config_(dt_config), |
Austin Schuh | f7c6520 | 2022-11-04 21:28:20 -0700 | [diff] [blame] | 18 | velocity_drivetrain_( |
| 19 | std::make_shared<StateFeedbackLoop<2, 2, 2, double, |
| 20 | StateFeedbackHybridPlant<2, 2, 2>, |
| 21 | HybridKalman<2, 2, 2>>>( |
| 22 | dt_config_.make_hybrid_drivetrain_velocity_loop())), |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 23 | current_xva_(Eigen::Vector3d::Zero()), |
| 24 | next_xva_(Eigen::Vector3d::Zero()), |
| 25 | next_U_(Eigen::Vector2d::Zero()) {} |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 26 | |
| 27 | void SplineDrivetrain::ScaleCapU(Eigen::Matrix<double, 2, 1> *U) { |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 28 | output_was_capped_ = |
| 29 | ::std::abs((*U)(0, 0)) > 12.0 || ::std::abs((*U)(1, 0)) > 12.0; |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 30 | |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 31 | if (output_was_capped_) { |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 32 | *U *= 12.0 / U->lpNorm<Eigen::Infinity>(); |
| 33 | } |
| 34 | } |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 35 | |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 36 | void SplineDrivetrain::SetGoal( |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 37 | const ::frc971::control_loops::drivetrain::Goal *goal) { |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 38 | UpdateSplineHandles(goal->has_spline_handle() |
| 39 | ? std::make_optional<int>(goal->spline_handle()) |
| 40 | : std::nullopt); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 41 | } |
| 42 | |
James Kuszmaul | 99af8b5 | 2021-03-28 10:50:15 -0700 | [diff] [blame] | 43 | bool SplineDrivetrain::IsCurrentTrajectory( |
| 44 | const fb::Trajectory *trajectory) const { |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 45 | const FinishedTrajectory *current = current_trajectory(); |
| 46 | return (current != nullptr && |
| 47 | current->spline_handle() == trajectory->handle()); |
James Kuszmaul | 99af8b5 | 2021-03-28 10:50:15 -0700 | [diff] [blame] | 48 | } |
| 49 | |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 50 | bool SplineDrivetrain::HasTrajectory(const fb::Trajectory *trajectory) const { |
| 51 | if (trajectory == nullptr) { |
| 52 | return false; |
| 53 | } |
| 54 | for (size_t ii = 0; ii < trajectories_.size(); ++ii) { |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 55 | if (trajectories_[ii].spline_handle() == trajectory->handle()) { |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 56 | return true; |
| 57 | } |
| 58 | } |
| 59 | return false; |
| 60 | } |
| 61 | |
James Kuszmaul | 99af8b5 | 2021-03-28 10:50:15 -0700 | [diff] [blame] | 62 | void SplineDrivetrain::DeleteTrajectory(const fb::Trajectory *trajectory) { |
| 63 | CHECK(trajectory != nullptr); |
| 64 | |
| 65 | for (size_t ii = 0; ii < trajectories_.size(); ++ii) { |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 66 | if (trajectories_[ii].spline_handle() == trajectory->handle()) { |
James Kuszmaul | 99af8b5 | 2021-03-28 10:50:15 -0700 | [diff] [blame] | 67 | trajectories_.erase(trajectories_.begin() + ii); |
| 68 | return; |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | LOG(FATAL) << "Trying to remove unknown trajectory " << trajectory->handle(); |
| 73 | } |
| 74 | |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 75 | void SplineDrivetrain::AddTrajectory(const fb::Trajectory *trajectory) { |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 76 | CHECK_LT(trajectories_.size(), trajectories_.capacity()); |
James Kuszmaul | 5c4ccf6 | 2024-03-03 17:29:49 -0800 | [diff] [blame] | 77 | trajectories_.emplace_back(&dt_config_, trajectory, velocity_drivetrain_); |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 78 | UpdateSplineHandles(commanded_spline_); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 79 | } |
| 80 | |
| 81 | void SplineDrivetrain::DeleteCurrentSpline() { |
Austin Schuh | 6bdcc37 | 2024-06-27 14:49:11 -0700 | [diff] [blame] | 82 | const FinishedTrajectory *const trajectory = current_trajectory(); |
| 83 | CHECK(trajectory != nullptr); |
| 84 | DeleteTrajectory(&trajectory->trajectory()); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 85 | executing_spline_ = false; |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 86 | commanded_spline_.reset(); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 87 | current_xva_.setZero(); |
| 88 | } |
| 89 | |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 90 | void SplineDrivetrain::UpdateSplineHandles( |
| 91 | std::optional<int> commanded_spline) { |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 92 | // If we are currently executing a spline and have received a change |
| 93 | if (executing_spline_) { |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 94 | if (!commanded_spline) { |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 95 | // We've been told to stop executing a spline; remove it from our queue, |
| 96 | // and clean up. |
| 97 | DeleteCurrentSpline(); |
| 98 | return; |
| 99 | } else { |
Austin Schuh | 6bdcc37 | 2024-06-27 14:49:11 -0700 | [diff] [blame] | 100 | if (executing_spline_) { |
| 101 | const FinishedTrajectory *const trajectory = current_trajectory(); |
| 102 | CHECK(trajectory != nullptr); |
| 103 | |
| 104 | if (trajectory->spline_handle() != *commanded_spline) { |
| 105 | // If we are executing a spline, and the handle has changed, garbage |
| 106 | // collect the old spline. |
| 107 | DeleteCurrentSpline(); |
| 108 | } |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 109 | } |
| 110 | } |
| 111 | } |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 112 | commanded_spline_ = commanded_spline; |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 113 | // We've now cleaned up the previous state; handle any new commands. |
| 114 | if (!commanded_spline_) { |
| 115 | return; |
| 116 | } |
| 117 | for (size_t ii = 0; ii < trajectories_.size(); ++ii) { |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 118 | if (trajectories_[ii].spline_handle() == *commanded_spline_) { |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 119 | executing_spline_ = true; |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 120 | } |
| 121 | } |
| 122 | // If we didn't find the commanded spline in the list of available splines, |
| 123 | // that's fine; it just means, it hasn't been fully planned yet. |
Alex Perry | a71badb | 2019-02-06 19:40:41 -0800 | [diff] [blame] | 124 | } |
| 125 | |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 126 | FinishedTrajectory *SplineDrivetrain::current_trajectory() { |
| 127 | for (size_t ii = 0; ii < trajectories_.size(); ++ii) { |
| 128 | if (trajectories_[ii].spline_handle() == *commanded_spline_) { |
| 129 | return &trajectories_[ii]; |
| 130 | } |
| 131 | } |
| 132 | return nullptr; |
| 133 | } |
| 134 | |
| 135 | const FinishedTrajectory *SplineDrivetrain::current_trajectory() const { |
| 136 | for (size_t ii = 0; ii < trajectories_.size(); ++ii) { |
| 137 | if (trajectories_[ii].spline_handle() == *commanded_spline_) { |
| 138 | return &trajectories_[ii]; |
| 139 | } |
| 140 | } |
| 141 | return nullptr; |
| 142 | } |
| 143 | |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 144 | // TODO(alex): Hold position when done following the spline. |
James Kuszmaul | aa2499d | 2020-06-02 21:31:19 -0700 | [diff] [blame] | 145 | void SplineDrivetrain::Update( |
| 146 | bool enable, const ::Eigen::Matrix<double, 5, 1> &state, |
| 147 | const ::Eigen::Matrix<double, 2, 1> &voltage_error) { |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 148 | next_U_ = ::Eigen::Matrix<double, 2, 1>::Zero(); |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 149 | enable_ = enable; |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 150 | if (enable && executing_spline_) { |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 151 | ::Eigen::Matrix<double, 2, 1> U_ff = ::Eigen::Matrix<double, 2, 1>::Zero(); |
Austin Schuh | 6bdcc37 | 2024-06-27 14:49:11 -0700 | [diff] [blame] | 152 | const FinishedTrajectory *const trajectory = current_trajectory(); |
| 153 | CHECK(trajectory != nullptr); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 154 | if (!IsAtEnd() && executing_spline_) { |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 155 | // TODO(alex): It takes about a cycle for the outputs to propagate to the |
| 156 | // motors. Consider delaying the output by a cycle. |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 157 | U_ff = trajectory->FFVoltage(current_xva_(0)); |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 158 | } |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 159 | |
James Kuszmaul | aa2499d | 2020-06-02 21:31:19 -0700 | [diff] [blame] | 160 | const double current_distance = current_xva_(0); |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 161 | ::Eigen::Matrix<double, 2, 5> K = |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 162 | trajectory->GainForDistance(current_distance); |
James Kuszmaul | 1057ce8 | 2019-02-09 17:58:24 -0800 | [diff] [blame] | 163 | ::Eigen::Matrix<double, 5, 1> goal_state = CurrentGoalState(); |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 164 | const bool backwards = trajectory->drive_spline_backwards(); |
James Kuszmaul | 5e8ce31 | 2021-03-27 14:59:17 -0700 | [diff] [blame] | 165 | if (backwards) { |
James Kuszmaul | c73bb22 | 2019-04-07 12:15:35 -0700 | [diff] [blame] | 166 | ::Eigen::Matrix<double, 2, 1> swapU(U_ff(1, 0), U_ff(0, 0)); |
| 167 | U_ff = -swapU; |
| 168 | goal_state(2, 0) += M_PI; |
| 169 | double left_goal = goal_state(3, 0); |
| 170 | double right_goal = goal_state(4, 0); |
| 171 | goal_state(3, 0) = -right_goal; |
| 172 | goal_state(4, 0) = -left_goal; |
| 173 | } |
James Kuszmaul | aa2499d | 2020-06-02 21:31:19 -0700 | [diff] [blame] | 174 | const Eigen::Matrix<double, 5, 1> relative_goal = |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 175 | trajectory->StateToPathRelativeState(current_distance, goal_state, |
| 176 | backwards); |
James Kuszmaul | aa2499d | 2020-06-02 21:31:19 -0700 | [diff] [blame] | 177 | const Eigen::Matrix<double, 5, 1> relative_state = |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 178 | trajectory->StateToPathRelativeState(current_distance, state, |
| 179 | backwards); |
James Kuszmaul | aa2499d | 2020-06-02 21:31:19 -0700 | [diff] [blame] | 180 | Eigen::Matrix<double, 5, 1> state_error = relative_goal - relative_state; |
James Kuszmaul | c73bb22 | 2019-04-07 12:15:35 -0700 | [diff] [blame] | 181 | state_error(2, 0) = ::aos::math::NormalizeAngle(state_error(2, 0)); |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 182 | ::Eigen::Matrix<double, 2, 1> U_fb = K * state_error; |
James Kuszmaul | a5a418f | 2024-03-17 17:16:06 -0700 | [diff] [blame] | 183 | last_U_components_ = K * Eigen::DiagonalMatrix<double, 5>(state_error); |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 184 | |
James Kuszmaul | 5e8ce31 | 2021-03-27 14:59:17 -0700 | [diff] [blame] | 185 | if (backwards) { |
| 186 | Eigen::Matrix<double, 2, 1> swapU(U_fb(1), U_fb(0)); |
| 187 | U_fb = -swapU; |
| 188 | } |
| 189 | |
Austin Schuh | d749d93 | 2020-12-30 21:38:40 -0800 | [diff] [blame] | 190 | ::Eigen::Matrix<double, 2, 1> xv_state = current_xva_.block<2, 1>(0, 0); |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 191 | next_xva_ = trajectory->GetNextXVA(dt_config_.dt, &xv_state); |
James Kuszmaul | aa2499d | 2020-06-02 21:31:19 -0700 | [diff] [blame] | 192 | next_U_ = U_ff + U_fb - voltage_error; |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 193 | uncapped_U_ = next_U_; |
| 194 | ScaleCapU(&next_U_); |
James Kuszmaul | a5a418f | 2024-03-17 17:16:06 -0700 | [diff] [blame] | 195 | last_state_error_ = state_error; |
| 196 | last_U_ff_ = U_ff; |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 197 | } |
| 198 | } |
| 199 | |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 200 | void SplineDrivetrain::SetOutput( |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 201 | ::frc971::control_loops::drivetrain::OutputT *output) { |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 202 | if (!output) { |
| 203 | return; |
| 204 | } |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 205 | if (executing_spline_) { |
James Kuszmaul | 1057ce8 | 2019-02-09 17:58:24 -0800 | [diff] [blame] | 206 | if (!IsAtEnd()) { |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 207 | output->left_voltage = next_U_(0); |
| 208 | output->right_voltage = next_U_(1); |
Alex Perry | a71badb | 2019-02-06 19:40:41 -0800 | [diff] [blame] | 209 | current_xva_ = next_xva_; |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 210 | } |
| 211 | } |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 212 | output->left_voltage = next_U_(0); |
| 213 | output->right_voltage = next_U_(1); |
James Kuszmaul | ad394ac | 2024-04-05 17:31:44 -0700 | [diff] [blame] | 214 | if (IsAtEnd()) { |
| 215 | output->left_voltage = 0.0; |
| 216 | output->right_voltage = 0.0; |
| 217 | } |
Alex Perry | 731b460 | 2019-02-02 22:13:01 -0800 | [diff] [blame] | 218 | } |
| 219 | |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 220 | void SplineDrivetrain::PopulateStatus( |
Austin Schuh | d749d93 | 2020-12-30 21:38:40 -0800 | [diff] [blame] | 221 | drivetrain::Status::Builder *builder) const { |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 222 | if (builder && enable_) { |
| 223 | builder->add_uncapped_left_voltage(uncapped_U_(0)); |
| 224 | builder->add_uncapped_right_voltage(uncapped_U_(1)); |
| 225 | builder->add_robot_speed(current_xva_(1)); |
| 226 | builder->add_output_was_capped(output_was_capped_); |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 227 | } |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 228 | } |
Alex Perry | cc3ee4c | 2019-02-09 21:20:41 -0800 | [diff] [blame] | 229 | |
James Kuszmaul | a5a418f | 2024-03-17 17:16:06 -0700 | [diff] [blame] | 230 | namespace { |
| 231 | template <typename Matrix> |
| 232 | flatbuffers::Offset<SplineState> MakeSplineState( |
| 233 | const Matrix &state, flatbuffers::FlatBufferBuilder *fbb) { |
| 234 | SplineState::Builder builder(*fbb); |
| 235 | builder.add_x(state(0)); |
| 236 | builder.add_y(state(1)); |
| 237 | builder.add_theta(::aos::math::NormalizeAngle(state(2))); |
| 238 | builder.add_left_velocity(state(3)); |
| 239 | builder.add_right_velocity(state(4)); |
| 240 | return builder.Finish(); |
| 241 | } |
| 242 | } // namespace |
| 243 | |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 244 | flatbuffers::Offset<TrajectoryLogging> SplineDrivetrain::MakeTrajectoryLogging( |
| 245 | flatbuffers::FlatBufferBuilder *builder) const { |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 246 | int *spline_handles; |
| 247 | const flatbuffers::Offset<flatbuffers::Vector<int>> handles_vector = |
| 248 | builder->CreateUninitializedVector(trajectories_.size(), &spline_handles); |
| 249 | |
| 250 | for (size_t ii = 0; ii < trajectories_.size(); ++ii) { |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 251 | spline_handles[ii] = trajectories_[ii].spline_handle(); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 252 | } |
| 253 | |
James Kuszmaul | a5a418f | 2024-03-17 17:16:06 -0700 | [diff] [blame] | 254 | const flatbuffers::Offset<SplineState> state_error_offset = |
| 255 | MakeSplineState(last_state_error_, builder); |
| 256 | const flatbuffers::Offset<SplineState> left_voltage_components_offset = |
| 257 | MakeSplineState(last_U_components_.row(0), builder); |
| 258 | const flatbuffers::Offset<SplineState> right_voltage_components_offset = |
| 259 | MakeSplineState(last_U_components_.row(1), builder); |
| 260 | |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 261 | drivetrain::TrajectoryLogging::Builder trajectory_logging_builder(*builder); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 262 | if (executing_spline_) { |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 263 | ::Eigen::Matrix<double, 5, 1> goal_state = CurrentGoalState(); |
| 264 | trajectory_logging_builder.add_x(goal_state(0)); |
| 265 | trajectory_logging_builder.add_y(goal_state(1)); |
Austin Schuh | 6bdcc37 | 2024-06-27 14:49:11 -0700 | [diff] [blame] | 266 | const FinishedTrajectory *const trajectory = current_trajectory(); |
| 267 | CHECK(trajectory != nullptr); |
| 268 | if (trajectory->drive_spline_backwards()) { |
James Kuszmaul | 5e8ce31 | 2021-03-27 14:59:17 -0700 | [diff] [blame] | 269 | trajectory_logging_builder.add_left_velocity(-goal_state(4)); |
| 270 | trajectory_logging_builder.add_right_velocity(-goal_state(3)); |
| 271 | trajectory_logging_builder.add_theta( |
| 272 | ::aos::math::NormalizeAngle(goal_state(2) + M_PI)); |
| 273 | } else { |
| 274 | trajectory_logging_builder.add_theta( |
| 275 | ::aos::math::NormalizeAngle(goal_state(2))); |
| 276 | trajectory_logging_builder.add_left_velocity(goal_state(3)); |
| 277 | trajectory_logging_builder.add_right_velocity(goal_state(4)); |
| 278 | } |
James Kuszmaul | a5a418f | 2024-03-17 17:16:06 -0700 | [diff] [blame] | 279 | trajectory_logging_builder.add_state_error(state_error_offset); |
| 280 | trajectory_logging_builder.add_left_voltage_components( |
| 281 | left_voltage_components_offset); |
| 282 | trajectory_logging_builder.add_right_voltage_components( |
| 283 | right_voltage_components_offset); |
| 284 | trajectory_logging_builder.add_left_ff_voltage(last_U_ff_(0)); |
| 285 | trajectory_logging_builder.add_right_ff_voltage(last_U_ff_(1)); |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 286 | } |
James Kuszmaul | dc53443 | 2023-02-05 14:51:11 -0800 | [diff] [blame] | 287 | trajectory_logging_builder.add_is_executing(!IsAtEnd() && executing_spline_); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 288 | trajectory_logging_builder.add_is_executed(executing_spline_ && IsAtEnd()); |
| 289 | if (commanded_spline_) { |
| 290 | trajectory_logging_builder.add_goal_spline_handle(*commanded_spline_); |
| 291 | if (executing_spline_) { |
| 292 | trajectory_logging_builder.add_current_spline_idx(*commanded_spline_); |
| 293 | } |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 294 | } |
Austin Schuh | 6bdcc37 | 2024-06-27 14:49:11 -0700 | [diff] [blame] | 295 | if (executing_spline_) { |
| 296 | const FinishedTrajectory *const trajectory = current_trajectory(); |
| 297 | CHECK(trajectory != nullptr); |
| 298 | trajectory_logging_builder.add_distance_remaining(trajectory->length() - |
| 299 | current_xva_.x()); |
| 300 | } else { |
| 301 | trajectory_logging_builder.add_distance_remaining(0.0); |
| 302 | } |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 303 | trajectory_logging_builder.add_available_splines(handles_vector); |
Austin Schuh | 1a84377 | 2023-04-09 22:18:05 -0700 | [diff] [blame] | 304 | trajectory_logging_builder.add_distance_traveled( |
| 305 | executing_spline_ ? current_xva_.x() : 0.0); |
James Kuszmaul | 75a18c5 | 2021-03-10 22:02:07 -0800 | [diff] [blame] | 306 | |
Alex Perry | cb7da4b | 2019-08-28 19:35:56 -0700 | [diff] [blame] | 307 | return trajectory_logging_builder.Finish(); |
| 308 | } |
| 309 | |
| 310 | flatbuffers::Offset<TrajectoryLogging> SplineDrivetrain::MakeTrajectoryLogging( |
| 311 | aos::Sender<drivetrain::Status>::Builder *builder) const { |
| 312 | return MakeTrajectoryLogging(builder->fbb()); |
Alex Perry | e32eabc | 2019-02-08 19:51:19 -0800 | [diff] [blame] | 313 | } |
| 314 | |
Stephan Pleines | f63bde8 | 2024-01-13 15:59:33 -0800 | [diff] [blame] | 315 | } // namespace frc971::control_loops::drivetrain |