blob: ae1a31a4a1ef3144b0495bdec1d39629dab49bfc [file] [log] [blame]
Comran Morshed5323ecb2015-12-26 20:50:55 +00001#ifndef FRC971_CONTROL_LOOPS_DRIVETRAIN_CONSTANTS_H_
2#define FRC971_CONTROL_LOOPS_DRIVETRAIN_CONSTANTS_H_
3
4#include <functional>
5
James Kuszmaul68025332024-01-20 17:06:02 -08006#include "aos/flatbuffer_merge.h"
Austin Schuha062edb2019-01-03 13:17:13 -08007#if defined(__linux__)
8#include "frc971/control_loops/hybrid_state_feedback_loop.h"
James Kuszmaul68025332024-01-20 17:06:02 -08009#include "frc971/control_loops/hybrid_state_feedback_loop_converters.h"
Austin Schuha062edb2019-01-03 13:17:13 -080010#endif
James Kuszmaul68025332024-01-20 17:06:02 -080011#include "frc971/control_loops/drivetrain/drivetrain_config_static.h"
Comran Morshed5323ecb2015-12-26 20:50:55 +000012#include "frc971/control_loops/state_feedback_loop.h"
James Kuszmaul68025332024-01-20 17:06:02 -080013#include "frc971/control_loops/state_feedback_loop_converters.h"
Austin Schuha062edb2019-01-03 13:17:13 -080014#include "frc971/shifter_hall_effect.h"
Comran Morshed5323ecb2015-12-26 20:50:55 +000015
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080016namespace frc971::control_loops::drivetrain {
Comran Morshed5323ecb2015-12-26 20:50:55 +000017
James Kuszmaulc29f4572023-02-25 17:02:33 -080018// Configuration for line-following mode.
19struct LineFollowConfig {
20 // The line-following uses an LQR controller with states of [theta,
21 // linear_velocity, angular_velocity] and inputs of [left_voltage,
22 // right_voltage].
23 // These Q and R matrices are the costs for state and input respectively.
24 Eigen::Matrix3d Q =
25 Eigen::Matrix3d((::Eigen::DiagonalMatrix<double, 3>().diagonal()
26 << 1.0 / ::std::pow(0.1, 2),
27 1.0 / ::std::pow(1.0, 2), 1.0 / ::std::pow(1.0, 2))
28 .finished()
29 .asDiagonal());
30 Eigen::Matrix2d R =
31 Eigen::Matrix2d((::Eigen::DiagonalMatrix<double, 2>().diagonal()
32 << 1.0 / ::std::pow(12.0, 2),
33 1.0 / ::std::pow(12.0, 2))
34 .finished()
35 .asDiagonal());
36
37 // The driver can use their steering controller to adjust where we attempt to
38 // place things laterally. This specifies how much range on either side of
39 // zero we allow them, in meters.
40 double max_controllable_offset = 0.1;
James Kuszmaul68025332024-01-20 17:06:02 -080041
42 static LineFollowConfig FromFlatbuffer(const fbs::LineFollowConfig *fbs) {
43 if (fbs == nullptr) {
44 return {};
45 }
Austin Schuh6bdcc372024-06-27 14:49:11 -070046 CHECK(fbs->q() != nullptr);
47 CHECK(fbs->r() != nullptr);
James Kuszmaul68025332024-01-20 17:06:02 -080048 return LineFollowConfig{
Austin Schuh6bdcc372024-06-27 14:49:11 -070049 .Q = ToEigenOrDie<3, 3>(*fbs->q()),
50 .R = ToEigenOrDie<2, 2>(*fbs->r()),
James Kuszmaul68025332024-01-20 17:06:02 -080051 .max_controllable_offset = fbs->max_controllable_offset()};
52 }
James Kuszmaulc29f4572023-02-25 17:02:33 -080053};
54
James Kuszmaul6e5f8252024-03-17 21:00:08 -070055struct SplineFollowerConfig {
56 // The line-following uses an LQR controller with states of
57 // [longitudinal_position, lateral_positoin, theta, left_velocity,
58 // right_velocity] and inputs of [left_voltage, right_voltage]. These Q and R
59 // matrices are the costs for state and input respectively.
60 Eigen::Matrix<double, 5, 5> Q = Eigen::Matrix<double, 5, 5>(
61 (::Eigen::DiagonalMatrix<double, 5>().diagonal() << ::std::pow(60.0, 2.0),
62 ::std::pow(60.0, 2.0), ::std::pow(40.0, 2.0), ::std::pow(30.0, 2.0),
63 ::std::pow(30.0, 2.0))
64 .finished()
65 .asDiagonal());
66 Eigen::Matrix2d R = Eigen::Matrix2d(
67 (::Eigen::DiagonalMatrix<double, 2>().diagonal() << 5.0, 5.0)
68 .finished()
69 .asDiagonal());
70
71 static SplineFollowerConfig FromFlatbuffer(
72 const fbs::SplineFollowerConfig *fbs) {
73 if (fbs == nullptr) {
74 return {};
75 }
Austin Schuh6bdcc372024-06-27 14:49:11 -070076 CHECK(fbs->q() != nullptr);
77 CHECK(fbs->r() != nullptr);
78 return SplineFollowerConfig{.Q = ToEigenOrDie<5, 5>(*fbs->q()),
79 .R = ToEigenOrDie<2, 2>(*fbs->r())};
James Kuszmaul6e5f8252024-03-17 21:00:08 -070080 }
81};
82
Austin Schuhbcce26a2018-03-26 23:41:24 -070083template <typename Scalar = double>
Comran Morshed5323ecb2015-12-26 20:50:55 +000084struct DrivetrainConfig {
85 // Shifting method we are using.
86 ShifterType shifter_type;
87
Comran Morshed76ca8f52016-02-21 17:26:28 +000088 // Type of loop to use.
89 LoopType loop_type;
90
Campbell Crowley2527ed22017-02-17 21:10:02 -080091 // Type of gyro to use.
92 GyroType gyro_type;
93
Diana Burgessd0180f12018-03-21 21:24:17 -070094 // Type of IMU to use.
James Kuszmaul68025332024-01-20 17:06:02 -080095 ImuType imu_type;
Diana Burgessd0180f12018-03-21 21:24:17 -070096
Comran Morshed5323ecb2015-12-26 20:50:55 +000097 // Polydrivetrain functions returning various controller loops with plants.
Austin Schuhbcce26a2018-03-26 23:41:24 -070098 ::std::function<StateFeedbackLoop<4, 2, 2, Scalar>()> make_drivetrain_loop;
99 ::std::function<StateFeedbackLoop<2, 2, 2, Scalar>()> make_v_drivetrain_loop;
100 ::std::function<StateFeedbackLoop<7, 2, 4, Scalar>()> make_kf_drivetrain_loop;
Austin Schuha062edb2019-01-03 13:17:13 -0800101#if defined(__linux__)
102 ::std::function<
103 StateFeedbackLoop<2, 2, 2, Scalar, StateFeedbackHybridPlant<2, 2, 2>,
104 HybridKalman<2, 2, 2>>()>
105 make_hybrid_drivetrain_velocity_loop;
106#endif
Comran Morshed5323ecb2015-12-26 20:50:55 +0000107
Austin Schuhbb735b72019-01-03 12:58:41 -0800108 ::std::chrono::nanoseconds dt; // Control loop time step.
109 Scalar robot_radius; // Robot radius, in meters.
110 Scalar wheel_radius; // Wheel radius, in meters.
111 Scalar v; // Motor velocity constant.
Comran Morshed5323ecb2015-12-26 20:50:55 +0000112
Austin Schuh09fa9bb2016-02-16 11:47:40 -0800113 // Gear ratios, from wheel to motor shaft.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700114 Scalar high_gear_ratio;
115 Scalar low_gear_ratio;
Comran Morshed5323ecb2015-12-26 20:50:55 +0000116
Austin Schuhe6a9fdf2019-01-12 16:05:43 -0800117 // Moment of inertia and mass.
118 Scalar J;
119 Scalar mass;
120
Comran Morshed5323ecb2015-12-26 20:50:55 +0000121 // Hall effect constants. Unused if not applicable to shifter type.
James Kuszmaul68025332024-01-20 17:06:02 -0800122 ShifterHallEffect left_drive;
123 ShifterHallEffect right_drive;
Adam Snaiderbc918b62016-02-27 21:03:39 -0800124
125 // Variable that holds the default gear ratio. We use this in ZeroOutputs().
126 // (ie. true means high gear is default).
127 bool default_high_gear;
Austin Schuh889fee82016-04-13 22:16:36 -0700128
Austin Schuhbcce26a2018-03-26 23:41:24 -0700129 Scalar down_offset;
Adam Snaider94a52372016-10-19 20:06:01 -0700130
Austin Schuhbcce26a2018-03-26 23:41:24 -0700131 Scalar wheel_non_linearity;
Adam Snaider94a52372016-10-19 20:06:01 -0700132
Austin Schuhbcce26a2018-03-26 23:41:24 -0700133 Scalar quickturn_wheel_multiplier;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700134
Austin Schuhbcce26a2018-03-26 23:41:24 -0700135 Scalar wheel_multiplier;
Austin Schuhe8a54c02018-03-05 00:25:58 -0800136
James Kuszmaul8bad2412019-03-10 10:47:56 -0700137 // Whether the shift button on the pistol grip enables line following mode.
138 bool pistol_grip_shift_enables_line_follow = false;
139
James Kuszmaul2215d922020-02-11 17:17:26 -0800140 // Rotation matrix from the IMU's coordinate frame to the robot's coordinate
141 // frame.
142 // I.e., imu_transform * imu_readings will give the imu readings in the
143 // robot frame.
James Kuszmauld478f872020-03-16 20:54:27 -0700144 Eigen::Matrix<Scalar, 3, 3> imu_transform =
145 Eigen::Matrix<Scalar, 3, 3>::Identity();
James Kuszmaul2215d922020-02-11 17:17:26 -0800146
147 // True if we are running a simulated drivetrain.
148 bool is_simulated = false;
149
James Kuszmaul68025332024-01-20 17:06:02 -0800150 DownEstimatorConfigT down_estimator_config{};
James Kuszmaul207ae322022-02-25 21:15:31 -0800151
James Kuszmaulc29f4572023-02-25 17:02:33 -0800152 LineFollowConfig line_follow_config{};
153
Maxwell Henderson24f89f32023-03-25 15:55:46 -0700154 PistolTopButtonUse top_button_use = PistolTopButtonUse::kShift;
155 PistolSecondButtonUse second_button_use = PistolSecondButtonUse::kShiftLow;
156 PistolBottomButtonUse bottom_button_use = PistolBottomButtonUse::kSlowDown;
157
James Kuszmaul6e5f8252024-03-17 21:00:08 -0700158 SplineFollowerConfig spline_follower_config{};
159
James Kuszmaul88e94412024-04-04 21:23:01 -0700160 // If set, then the IMU must be zeroed before we will send any outputs.
161 bool require_imu_for_output = true;
162
Austin Schuhd91c0d22016-10-15 21:24:28 -0700163 // Converts the robot state to a linear distance position, velocity.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700164 static Eigen::Matrix<Scalar, 2, 1> LeftRightToLinear(
165 const Eigen::Matrix<Scalar, 7, 1> &left_right) {
166 Eigen::Matrix<Scalar, 2, 1> linear;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700167 linear(0, 0) = (left_right(0, 0) + left_right(2, 0)) / 2.0;
168 linear(1, 0) = (left_right(1, 0) + left_right(3, 0)) / 2.0;
169 return linear;
170 }
171 // Converts the robot state to an anglular distance, velocity.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700172 Eigen::Matrix<Scalar, 2, 1> LeftRightToAngular(
173 const Eigen::Matrix<Scalar, 7, 1> &left_right) const {
174 Eigen::Matrix<Scalar, 2, 1> angular;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700175 angular(0, 0) =
176 (left_right(2, 0) - left_right(0, 0)) / (this->robot_radius * 2.0);
177 angular(1, 0) =
178 (left_right(3, 0) - left_right(1, 0)) / (this->robot_radius * 2.0);
179 return angular;
180 }
181
Alex Perrye32eabc2019-02-08 19:51:19 -0800182 Eigen::Matrix<Scalar, 2, 2> Tlr_to_la() const {
183 return (::Eigen::Matrix<Scalar, 2, 2>() << 0.5, 0.5,
Austin Schuhd749d932020-12-30 21:38:40 -0800184 -1.0 / (2 * robot_radius), 1.0 / (2 * robot_radius))
185 .finished();
Alex Perrye32eabc2019-02-08 19:51:19 -0800186 }
187
188 Eigen::Matrix<Scalar, 2, 2> Tla_to_lr() const {
189 return Tlr_to_la().inverse();
190 }
191
Austin Schuhd91c0d22016-10-15 21:24:28 -0700192 // Converts the linear and angular position, velocity to the top 4 states of
193 // the robot state.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700194 Eigen::Matrix<Scalar, 4, 1> AngularLinearToLeftRight(
195 const Eigen::Matrix<Scalar, 2, 1> &linear,
196 const Eigen::Matrix<Scalar, 2, 1> &angular) const {
Austin Schuhd749d932020-12-30 21:38:40 -0800197 Eigen::Matrix<Scalar, 2, 1> scaled_angle = angular * this->robot_radius;
Austin Schuhbcce26a2018-03-26 23:41:24 -0700198 Eigen::Matrix<Scalar, 4, 1> state;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700199 state(0, 0) = linear(0, 0) - scaled_angle(0, 0);
200 state(1, 0) = linear(1, 0) - scaled_angle(1, 0);
201 state(2, 0) = linear(0, 0) + scaled_angle(0, 0);
202 state(3, 0) = linear(1, 0) + scaled_angle(1, 0);
203 return state;
204 }
James Kuszmaul68025332024-01-20 17:06:02 -0800205
206 static DrivetrainConfig FromFlatbuffer(const fbs::DrivetrainConfig &fbs) {
207 std::shared_ptr<aos::FlatbufferDetachedBuffer<fbs::DrivetrainConfig>>
208 fbs_copy = std::make_shared<
209 aos::FlatbufferDetachedBuffer<fbs::DrivetrainConfig>>(
210 aos::RecursiveCopyFlatBuffer(&fbs));
Austin Schuh6bdcc372024-06-27 14:49:11 -0700211 CHECK(fbs_copy->message().loop_config()->drivetrain_loop() != nullptr);
212 CHECK(fbs_copy->message().loop_config()->velocity_drivetrain_loop() !=
213 nullptr);
214 CHECK(fbs_copy->message().loop_config()->kalman_drivetrain_loop() !=
215 nullptr);
216 CHECK(
217 fbs_copy->message().loop_config()->hybrid_velocity_drivetrain_loop() !=
218 nullptr);
219 CHECK(fbs.imu_transform() != nullptr);
James Kuszmaul68025332024-01-20 17:06:02 -0800220 return {
221#define ASSIGN(field) .field = fbs.field()
222 ASSIGN(shifter_type), ASSIGN(loop_type), ASSIGN(gyro_type),
223 ASSIGN(imu_type),
224 .make_drivetrain_loop =
225 [fbs_copy]() {
Austin Schuh6bdcc372024-06-27 14:49:11 -0700226 return MakeStateFeedbackLoop<4, 2, 2>(
227 *fbs_copy->message().loop_config()->drivetrain_loop());
James Kuszmaul68025332024-01-20 17:06:02 -0800228 },
229 .make_v_drivetrain_loop =
230 [fbs_copy]() {
231 return MakeStateFeedbackLoop<2, 2, 2>(
Austin Schuh6bdcc372024-06-27 14:49:11 -0700232 *fbs_copy->message()
233 .loop_config()
234 ->velocity_drivetrain_loop());
James Kuszmaul68025332024-01-20 17:06:02 -0800235 },
236 .make_kf_drivetrain_loop =
237 [fbs_copy]() {
238 return MakeStateFeedbackLoop<7, 2, 4>(
Austin Schuh6bdcc372024-06-27 14:49:11 -0700239 *fbs_copy->message()
240 .loop_config()
241 ->kalman_drivetrain_loop());
James Kuszmaul68025332024-01-20 17:06:02 -0800242 },
243#if defined(__linux__)
244 .make_hybrid_drivetrain_velocity_loop =
245 [fbs_copy]() {
246 return MakeHybridStateFeedbackLoop<2, 2, 2>(
Austin Schuh6bdcc372024-06-27 14:49:11 -0700247 *fbs_copy->message()
248 .loop_config()
249 ->hybrid_velocity_drivetrain_loop());
James Kuszmaul68025332024-01-20 17:06:02 -0800250 },
251#endif
252 .dt = std::chrono::nanoseconds(fbs.loop_config()->dt()),
253 .robot_radius = fbs.loop_config()->robot_radius(),
254 .wheel_radius = fbs.loop_config()->wheel_radius(),
255 .v = fbs.loop_config()->motor_kv(),
256 .high_gear_ratio = fbs.loop_config()->high_gear_ratio(),
257 .low_gear_ratio = fbs.loop_config()->low_gear_ratio(),
258 .J = fbs.loop_config()->moment_of_inertia(),
James Kuszmaul2549e752024-01-20 17:42:51 -0800259 .mass = fbs.loop_config()->mass(),
260 .left_drive =
261 fbs.has_left_drive() ? *fbs.left_drive() : ShifterHallEffect{},
262 .right_drive =
263 fbs.has_right_drive() ? *fbs.right_drive() : ShifterHallEffect{},
264 ASSIGN(default_high_gear), ASSIGN(down_offset),
265 ASSIGN(wheel_non_linearity), ASSIGN(quickturn_wheel_multiplier),
266 ASSIGN(wheel_multiplier),
James Kuszmaul68025332024-01-20 17:06:02 -0800267 ASSIGN(pistol_grip_shift_enables_line_follow),
Austin Schuh6bdcc372024-06-27 14:49:11 -0700268 .imu_transform = ToEigenOrDie<3, 3>(*fbs.imu_transform()),
James Kuszmaul68025332024-01-20 17:06:02 -0800269 ASSIGN(is_simulated),
270 .down_estimator_config =
271 aos::UnpackFlatbuffer(fbs.down_estimator_config()),
272 .line_follow_config =
273 LineFollowConfig::FromFlatbuffer(fbs.line_follow_config()),
274 ASSIGN(top_button_use), ASSIGN(second_button_use),
James Kuszmaul6e5f8252024-03-17 21:00:08 -0700275 ASSIGN(bottom_button_use),
276 .spline_follower_config = SplineFollowerConfig::FromFlatbuffer(
277 fbs.spline_follower_config()),
James Kuszmaul88e94412024-04-04 21:23:01 -0700278 ASSIGN(require_imu_for_output),
James Kuszmaul68025332024-01-20 17:06:02 -0800279#undef ASSIGN
280 };
281 }
Comran Morshed5323ecb2015-12-26 20:50:55 +0000282};
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800283} // namespace frc971::control_loops::drivetrain
Comran Morshed5323ecb2015-12-26 20:50:55 +0000284
285#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_CONSTANTS_H_