blob: 4c35b6a18a6f44c74c39f9a598c0dfc837a85360 [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 }
46 return LineFollowConfig{
47 .Q = ToEigenOrDie<3, 3>(*CHECK_NOTNULL(fbs->q())),
48 .R = ToEigenOrDie<2, 2>(*CHECK_NOTNULL(fbs->r())),
49 .max_controllable_offset = fbs->max_controllable_offset()};
50 }
James Kuszmaulc29f4572023-02-25 17:02:33 -080051};
52
James Kuszmaul6e5f8252024-03-17 21:00:08 -070053struct SplineFollowerConfig {
54 // The line-following uses an LQR controller with states of
55 // [longitudinal_position, lateral_positoin, theta, left_velocity,
56 // right_velocity] and inputs of [left_voltage, right_voltage]. These Q and R
57 // matrices are the costs for state and input respectively.
58 Eigen::Matrix<double, 5, 5> Q = Eigen::Matrix<double, 5, 5>(
59 (::Eigen::DiagonalMatrix<double, 5>().diagonal() << ::std::pow(60.0, 2.0),
60 ::std::pow(60.0, 2.0), ::std::pow(40.0, 2.0), ::std::pow(30.0, 2.0),
61 ::std::pow(30.0, 2.0))
62 .finished()
63 .asDiagonal());
64 Eigen::Matrix2d R = Eigen::Matrix2d(
65 (::Eigen::DiagonalMatrix<double, 2>().diagonal() << 5.0, 5.0)
66 .finished()
67 .asDiagonal());
68
69 static SplineFollowerConfig FromFlatbuffer(
70 const fbs::SplineFollowerConfig *fbs) {
71 if (fbs == nullptr) {
72 return {};
73 }
74 return SplineFollowerConfig{
75 .Q = ToEigenOrDie<5, 5>(*CHECK_NOTNULL(fbs->q())),
76 .R = ToEigenOrDie<2, 2>(*CHECK_NOTNULL(fbs->r()))};
77 }
78};
79
Austin Schuhbcce26a2018-03-26 23:41:24 -070080template <typename Scalar = double>
Comran Morshed5323ecb2015-12-26 20:50:55 +000081struct DrivetrainConfig {
82 // Shifting method we are using.
83 ShifterType shifter_type;
84
Comran Morshed76ca8f52016-02-21 17:26:28 +000085 // Type of loop to use.
86 LoopType loop_type;
87
Campbell Crowley2527ed22017-02-17 21:10:02 -080088 // Type of gyro to use.
89 GyroType gyro_type;
90
Diana Burgessd0180f12018-03-21 21:24:17 -070091 // Type of IMU to use.
James Kuszmaul68025332024-01-20 17:06:02 -080092 ImuType imu_type;
Diana Burgessd0180f12018-03-21 21:24:17 -070093
Comran Morshed5323ecb2015-12-26 20:50:55 +000094 // Polydrivetrain functions returning various controller loops with plants.
Austin Schuhbcce26a2018-03-26 23:41:24 -070095 ::std::function<StateFeedbackLoop<4, 2, 2, Scalar>()> make_drivetrain_loop;
96 ::std::function<StateFeedbackLoop<2, 2, 2, Scalar>()> make_v_drivetrain_loop;
97 ::std::function<StateFeedbackLoop<7, 2, 4, Scalar>()> make_kf_drivetrain_loop;
Austin Schuha062edb2019-01-03 13:17:13 -080098#if defined(__linux__)
99 ::std::function<
100 StateFeedbackLoop<2, 2, 2, Scalar, StateFeedbackHybridPlant<2, 2, 2>,
101 HybridKalman<2, 2, 2>>()>
102 make_hybrid_drivetrain_velocity_loop;
103#endif
Comran Morshed5323ecb2015-12-26 20:50:55 +0000104
Austin Schuhbb735b72019-01-03 12:58:41 -0800105 ::std::chrono::nanoseconds dt; // Control loop time step.
106 Scalar robot_radius; // Robot radius, in meters.
107 Scalar wheel_radius; // Wheel radius, in meters.
108 Scalar v; // Motor velocity constant.
Comran Morshed5323ecb2015-12-26 20:50:55 +0000109
Austin Schuh09fa9bb2016-02-16 11:47:40 -0800110 // Gear ratios, from wheel to motor shaft.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700111 Scalar high_gear_ratio;
112 Scalar low_gear_ratio;
Comran Morshed5323ecb2015-12-26 20:50:55 +0000113
Austin Schuhe6a9fdf2019-01-12 16:05:43 -0800114 // Moment of inertia and mass.
115 Scalar J;
116 Scalar mass;
117
Comran Morshed5323ecb2015-12-26 20:50:55 +0000118 // Hall effect constants. Unused if not applicable to shifter type.
James Kuszmaul68025332024-01-20 17:06:02 -0800119 ShifterHallEffect left_drive;
120 ShifterHallEffect right_drive;
Adam Snaiderbc918b62016-02-27 21:03:39 -0800121
122 // Variable that holds the default gear ratio. We use this in ZeroOutputs().
123 // (ie. true means high gear is default).
124 bool default_high_gear;
Austin Schuh889fee82016-04-13 22:16:36 -0700125
Austin Schuhbcce26a2018-03-26 23:41:24 -0700126 Scalar down_offset;
Adam Snaider94a52372016-10-19 20:06:01 -0700127
Austin Schuhbcce26a2018-03-26 23:41:24 -0700128 Scalar wheel_non_linearity;
Adam Snaider94a52372016-10-19 20:06:01 -0700129
Austin Schuhbcce26a2018-03-26 23:41:24 -0700130 Scalar quickturn_wheel_multiplier;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700131
Austin Schuhbcce26a2018-03-26 23:41:24 -0700132 Scalar wheel_multiplier;
Austin Schuhe8a54c02018-03-05 00:25:58 -0800133
James Kuszmaul8bad2412019-03-10 10:47:56 -0700134 // Whether the shift button on the pistol grip enables line following mode.
135 bool pistol_grip_shift_enables_line_follow = false;
136
James Kuszmaul2215d922020-02-11 17:17:26 -0800137 // Rotation matrix from the IMU's coordinate frame to the robot's coordinate
138 // frame.
139 // I.e., imu_transform * imu_readings will give the imu readings in the
140 // robot frame.
James Kuszmauld478f872020-03-16 20:54:27 -0700141 Eigen::Matrix<Scalar, 3, 3> imu_transform =
142 Eigen::Matrix<Scalar, 3, 3>::Identity();
James Kuszmaul2215d922020-02-11 17:17:26 -0800143
144 // True if we are running a simulated drivetrain.
145 bool is_simulated = false;
146
James Kuszmaul68025332024-01-20 17:06:02 -0800147 DownEstimatorConfigT down_estimator_config{};
James Kuszmaul207ae322022-02-25 21:15:31 -0800148
James Kuszmaulc29f4572023-02-25 17:02:33 -0800149 LineFollowConfig line_follow_config{};
150
Maxwell Henderson24f89f32023-03-25 15:55:46 -0700151 PistolTopButtonUse top_button_use = PistolTopButtonUse::kShift;
152 PistolSecondButtonUse second_button_use = PistolSecondButtonUse::kShiftLow;
153 PistolBottomButtonUse bottom_button_use = PistolBottomButtonUse::kSlowDown;
154
James Kuszmaul6e5f8252024-03-17 21:00:08 -0700155 SplineFollowerConfig spline_follower_config{};
156
James Kuszmaul88e94412024-04-04 21:23:01 -0700157 // If set, then the IMU must be zeroed before we will send any outputs.
158 bool require_imu_for_output = true;
159
Austin Schuhd91c0d22016-10-15 21:24:28 -0700160 // Converts the robot state to a linear distance position, velocity.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700161 static Eigen::Matrix<Scalar, 2, 1> LeftRightToLinear(
162 const Eigen::Matrix<Scalar, 7, 1> &left_right) {
163 Eigen::Matrix<Scalar, 2, 1> linear;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700164 linear(0, 0) = (left_right(0, 0) + left_right(2, 0)) / 2.0;
165 linear(1, 0) = (left_right(1, 0) + left_right(3, 0)) / 2.0;
166 return linear;
167 }
168 // Converts the robot state to an anglular distance, velocity.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700169 Eigen::Matrix<Scalar, 2, 1> LeftRightToAngular(
170 const Eigen::Matrix<Scalar, 7, 1> &left_right) const {
171 Eigen::Matrix<Scalar, 2, 1> angular;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700172 angular(0, 0) =
173 (left_right(2, 0) - left_right(0, 0)) / (this->robot_radius * 2.0);
174 angular(1, 0) =
175 (left_right(3, 0) - left_right(1, 0)) / (this->robot_radius * 2.0);
176 return angular;
177 }
178
Alex Perrye32eabc2019-02-08 19:51:19 -0800179 Eigen::Matrix<Scalar, 2, 2> Tlr_to_la() const {
180 return (::Eigen::Matrix<Scalar, 2, 2>() << 0.5, 0.5,
Austin Schuhd749d932020-12-30 21:38:40 -0800181 -1.0 / (2 * robot_radius), 1.0 / (2 * robot_radius))
182 .finished();
Alex Perrye32eabc2019-02-08 19:51:19 -0800183 }
184
185 Eigen::Matrix<Scalar, 2, 2> Tla_to_lr() const {
186 return Tlr_to_la().inverse();
187 }
188
Austin Schuhd91c0d22016-10-15 21:24:28 -0700189 // Converts the linear and angular position, velocity to the top 4 states of
190 // the robot state.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700191 Eigen::Matrix<Scalar, 4, 1> AngularLinearToLeftRight(
192 const Eigen::Matrix<Scalar, 2, 1> &linear,
193 const Eigen::Matrix<Scalar, 2, 1> &angular) const {
Austin Schuhd749d932020-12-30 21:38:40 -0800194 Eigen::Matrix<Scalar, 2, 1> scaled_angle = angular * this->robot_radius;
Austin Schuhbcce26a2018-03-26 23:41:24 -0700195 Eigen::Matrix<Scalar, 4, 1> state;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700196 state(0, 0) = linear(0, 0) - scaled_angle(0, 0);
197 state(1, 0) = linear(1, 0) - scaled_angle(1, 0);
198 state(2, 0) = linear(0, 0) + scaled_angle(0, 0);
199 state(3, 0) = linear(1, 0) + scaled_angle(1, 0);
200 return state;
201 }
James Kuszmaul68025332024-01-20 17:06:02 -0800202
203 static DrivetrainConfig FromFlatbuffer(const fbs::DrivetrainConfig &fbs) {
204 std::shared_ptr<aos::FlatbufferDetachedBuffer<fbs::DrivetrainConfig>>
205 fbs_copy = std::make_shared<
206 aos::FlatbufferDetachedBuffer<fbs::DrivetrainConfig>>(
207 aos::RecursiveCopyFlatBuffer(&fbs));
208 return {
209#define ASSIGN(field) .field = fbs.field()
210 ASSIGN(shifter_type), ASSIGN(loop_type), ASSIGN(gyro_type),
211 ASSIGN(imu_type),
212 .make_drivetrain_loop =
213 [fbs_copy]() {
214 return MakeStateFeedbackLoop<4, 2, 2>(*CHECK_NOTNULL(
215 fbs_copy->message().loop_config()->drivetrain_loop()));
216 },
217 .make_v_drivetrain_loop =
218 [fbs_copy]() {
219 return MakeStateFeedbackLoop<2, 2, 2>(
220 *CHECK_NOTNULL(fbs_copy->message()
221 .loop_config()
222 ->velocity_drivetrain_loop()));
223 },
224 .make_kf_drivetrain_loop =
225 [fbs_copy]() {
226 return MakeStateFeedbackLoop<7, 2, 4>(
227 *CHECK_NOTNULL(fbs_copy->message()
228 .loop_config()
229 ->kalman_drivetrain_loop()));
230 },
231#if defined(__linux__)
232 .make_hybrid_drivetrain_velocity_loop =
233 [fbs_copy]() {
234 return MakeHybridStateFeedbackLoop<2, 2, 2>(
235 *CHECK_NOTNULL(fbs_copy->message()
236 .loop_config()
237 ->hybrid_velocity_drivetrain_loop()));
238 },
239#endif
240 .dt = std::chrono::nanoseconds(fbs.loop_config()->dt()),
241 .robot_radius = fbs.loop_config()->robot_radius(),
242 .wheel_radius = fbs.loop_config()->wheel_radius(),
243 .v = fbs.loop_config()->motor_kv(),
244 .high_gear_ratio = fbs.loop_config()->high_gear_ratio(),
245 .low_gear_ratio = fbs.loop_config()->low_gear_ratio(),
246 .J = fbs.loop_config()->moment_of_inertia(),
James Kuszmaul2549e752024-01-20 17:42:51 -0800247 .mass = fbs.loop_config()->mass(),
248 .left_drive =
249 fbs.has_left_drive() ? *fbs.left_drive() : ShifterHallEffect{},
250 .right_drive =
251 fbs.has_right_drive() ? *fbs.right_drive() : ShifterHallEffect{},
252 ASSIGN(default_high_gear), ASSIGN(down_offset),
253 ASSIGN(wheel_non_linearity), ASSIGN(quickturn_wheel_multiplier),
254 ASSIGN(wheel_multiplier),
James Kuszmaul68025332024-01-20 17:06:02 -0800255 ASSIGN(pistol_grip_shift_enables_line_follow),
256 .imu_transform =
257 ToEigenOrDie<3, 3>(*CHECK_NOTNULL(fbs.imu_transform())),
258 ASSIGN(is_simulated),
259 .down_estimator_config =
260 aos::UnpackFlatbuffer(fbs.down_estimator_config()),
261 .line_follow_config =
262 LineFollowConfig::FromFlatbuffer(fbs.line_follow_config()),
263 ASSIGN(top_button_use), ASSIGN(second_button_use),
James Kuszmaul6e5f8252024-03-17 21:00:08 -0700264 ASSIGN(bottom_button_use),
265 .spline_follower_config = SplineFollowerConfig::FromFlatbuffer(
266 fbs.spline_follower_config()),
James Kuszmaul88e94412024-04-04 21:23:01 -0700267 ASSIGN(require_imu_for_output),
James Kuszmaul68025332024-01-20 17:06:02 -0800268#undef ASSIGN
269 };
270 }
Comran Morshed5323ecb2015-12-26 20:50:55 +0000271};
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800272} // namespace frc971::control_loops::drivetrain
Comran Morshed5323ecb2015-12-26 20:50:55 +0000273
274#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_CONSTANTS_H_