blob: 2b0471ad8d0ef53129c5f9e26ea2f290e00a3991 [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
16namespace frc971 {
17namespace control_loops {
18namespace drivetrain {
19
James Kuszmaulc29f4572023-02-25 17:02:33 -080020// Configuration for line-following mode.
21struct LineFollowConfig {
22 // The line-following uses an LQR controller with states of [theta,
23 // linear_velocity, angular_velocity] and inputs of [left_voltage,
24 // right_voltage].
25 // These Q and R matrices are the costs for state and input respectively.
26 Eigen::Matrix3d Q =
27 Eigen::Matrix3d((::Eigen::DiagonalMatrix<double, 3>().diagonal()
28 << 1.0 / ::std::pow(0.1, 2),
29 1.0 / ::std::pow(1.0, 2), 1.0 / ::std::pow(1.0, 2))
30 .finished()
31 .asDiagonal());
32 Eigen::Matrix2d R =
33 Eigen::Matrix2d((::Eigen::DiagonalMatrix<double, 2>().diagonal()
34 << 1.0 / ::std::pow(12.0, 2),
35 1.0 / ::std::pow(12.0, 2))
36 .finished()
37 .asDiagonal());
38
39 // The driver can use their steering controller to adjust where we attempt to
40 // place things laterally. This specifies how much range on either side of
41 // zero we allow them, in meters.
42 double max_controllable_offset = 0.1;
James Kuszmaul68025332024-01-20 17:06:02 -080043
44 static LineFollowConfig FromFlatbuffer(const fbs::LineFollowConfig *fbs) {
45 if (fbs == nullptr) {
46 return {};
47 }
48 return LineFollowConfig{
49 .Q = ToEigenOrDie<3, 3>(*CHECK_NOTNULL(fbs->q())),
50 .R = ToEigenOrDie<2, 2>(*CHECK_NOTNULL(fbs->r())),
51 .max_controllable_offset = fbs->max_controllable_offset()};
52 }
James Kuszmaulc29f4572023-02-25 17:02:33 -080053};
54
Austin Schuhbcce26a2018-03-26 23:41:24 -070055template <typename Scalar = double>
Comran Morshed5323ecb2015-12-26 20:50:55 +000056struct DrivetrainConfig {
57 // Shifting method we are using.
58 ShifterType shifter_type;
59
Comran Morshed76ca8f52016-02-21 17:26:28 +000060 // Type of loop to use.
61 LoopType loop_type;
62
Campbell Crowley2527ed22017-02-17 21:10:02 -080063 // Type of gyro to use.
64 GyroType gyro_type;
65
Diana Burgessd0180f12018-03-21 21:24:17 -070066 // Type of IMU to use.
James Kuszmaul68025332024-01-20 17:06:02 -080067 ImuType imu_type;
Diana Burgessd0180f12018-03-21 21:24:17 -070068
Comran Morshed5323ecb2015-12-26 20:50:55 +000069 // Polydrivetrain functions returning various controller loops with plants.
Austin Schuhbcce26a2018-03-26 23:41:24 -070070 ::std::function<StateFeedbackLoop<4, 2, 2, Scalar>()> make_drivetrain_loop;
71 ::std::function<StateFeedbackLoop<2, 2, 2, Scalar>()> make_v_drivetrain_loop;
72 ::std::function<StateFeedbackLoop<7, 2, 4, Scalar>()> make_kf_drivetrain_loop;
Austin Schuha062edb2019-01-03 13:17:13 -080073#if defined(__linux__)
74 ::std::function<
75 StateFeedbackLoop<2, 2, 2, Scalar, StateFeedbackHybridPlant<2, 2, 2>,
76 HybridKalman<2, 2, 2>>()>
77 make_hybrid_drivetrain_velocity_loop;
78#endif
Comran Morshed5323ecb2015-12-26 20:50:55 +000079
Austin Schuhbb735b72019-01-03 12:58:41 -080080 ::std::chrono::nanoseconds dt; // Control loop time step.
81 Scalar robot_radius; // Robot radius, in meters.
82 Scalar wheel_radius; // Wheel radius, in meters.
83 Scalar v; // Motor velocity constant.
Comran Morshed5323ecb2015-12-26 20:50:55 +000084
Austin Schuh09fa9bb2016-02-16 11:47:40 -080085 // Gear ratios, from wheel to motor shaft.
Austin Schuhbcce26a2018-03-26 23:41:24 -070086 Scalar high_gear_ratio;
87 Scalar low_gear_ratio;
Comran Morshed5323ecb2015-12-26 20:50:55 +000088
Austin Schuhe6a9fdf2019-01-12 16:05:43 -080089 // Moment of inertia and mass.
90 Scalar J;
91 Scalar mass;
92
Comran Morshed5323ecb2015-12-26 20:50:55 +000093 // Hall effect constants. Unused if not applicable to shifter type.
James Kuszmaul68025332024-01-20 17:06:02 -080094 ShifterHallEffect left_drive;
95 ShifterHallEffect right_drive;
Adam Snaiderbc918b62016-02-27 21:03:39 -080096
97 // Variable that holds the default gear ratio. We use this in ZeroOutputs().
98 // (ie. true means high gear is default).
99 bool default_high_gear;
Austin Schuh889fee82016-04-13 22:16:36 -0700100
Austin Schuhbcce26a2018-03-26 23:41:24 -0700101 Scalar down_offset;
Adam Snaider94a52372016-10-19 20:06:01 -0700102
Austin Schuhbcce26a2018-03-26 23:41:24 -0700103 Scalar wheel_non_linearity;
Adam Snaider94a52372016-10-19 20:06:01 -0700104
Austin Schuhbcce26a2018-03-26 23:41:24 -0700105 Scalar quickturn_wheel_multiplier;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700106
Austin Schuhbcce26a2018-03-26 23:41:24 -0700107 Scalar wheel_multiplier;
Austin Schuhe8a54c02018-03-05 00:25:58 -0800108
James Kuszmaul8bad2412019-03-10 10:47:56 -0700109 // Whether the shift button on the pistol grip enables line following mode.
110 bool pistol_grip_shift_enables_line_follow = false;
111
James Kuszmaul2215d922020-02-11 17:17:26 -0800112 // Rotation matrix from the IMU's coordinate frame to the robot's coordinate
113 // frame.
114 // I.e., imu_transform * imu_readings will give the imu readings in the
115 // robot frame.
James Kuszmauld478f872020-03-16 20:54:27 -0700116 Eigen::Matrix<Scalar, 3, 3> imu_transform =
117 Eigen::Matrix<Scalar, 3, 3>::Identity();
James Kuszmaul2215d922020-02-11 17:17:26 -0800118
119 // True if we are running a simulated drivetrain.
120 bool is_simulated = false;
121
James Kuszmaul68025332024-01-20 17:06:02 -0800122 DownEstimatorConfigT down_estimator_config{};
James Kuszmaul207ae322022-02-25 21:15:31 -0800123
James Kuszmaulc29f4572023-02-25 17:02:33 -0800124 LineFollowConfig line_follow_config{};
125
Maxwell Henderson24f89f32023-03-25 15:55:46 -0700126 PistolTopButtonUse top_button_use = PistolTopButtonUse::kShift;
127 PistolSecondButtonUse second_button_use = PistolSecondButtonUse::kShiftLow;
128 PistolBottomButtonUse bottom_button_use = PistolBottomButtonUse::kSlowDown;
129
Austin Schuhd91c0d22016-10-15 21:24:28 -0700130 // Converts the robot state to a linear distance position, velocity.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700131 static Eigen::Matrix<Scalar, 2, 1> LeftRightToLinear(
132 const Eigen::Matrix<Scalar, 7, 1> &left_right) {
133 Eigen::Matrix<Scalar, 2, 1> linear;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700134 linear(0, 0) = (left_right(0, 0) + left_right(2, 0)) / 2.0;
135 linear(1, 0) = (left_right(1, 0) + left_right(3, 0)) / 2.0;
136 return linear;
137 }
138 // Converts the robot state to an anglular distance, velocity.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700139 Eigen::Matrix<Scalar, 2, 1> LeftRightToAngular(
140 const Eigen::Matrix<Scalar, 7, 1> &left_right) const {
141 Eigen::Matrix<Scalar, 2, 1> angular;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700142 angular(0, 0) =
143 (left_right(2, 0) - left_right(0, 0)) / (this->robot_radius * 2.0);
144 angular(1, 0) =
145 (left_right(3, 0) - left_right(1, 0)) / (this->robot_radius * 2.0);
146 return angular;
147 }
148
Alex Perrye32eabc2019-02-08 19:51:19 -0800149 Eigen::Matrix<Scalar, 2, 2> Tlr_to_la() const {
150 return (::Eigen::Matrix<Scalar, 2, 2>() << 0.5, 0.5,
Austin Schuhd749d932020-12-30 21:38:40 -0800151 -1.0 / (2 * robot_radius), 1.0 / (2 * robot_radius))
152 .finished();
Alex Perrye32eabc2019-02-08 19:51:19 -0800153 }
154
155 Eigen::Matrix<Scalar, 2, 2> Tla_to_lr() const {
156 return Tlr_to_la().inverse();
157 }
158
Austin Schuhd91c0d22016-10-15 21:24:28 -0700159 // Converts the linear and angular position, velocity to the top 4 states of
160 // the robot state.
Austin Schuhbcce26a2018-03-26 23:41:24 -0700161 Eigen::Matrix<Scalar, 4, 1> AngularLinearToLeftRight(
162 const Eigen::Matrix<Scalar, 2, 1> &linear,
163 const Eigen::Matrix<Scalar, 2, 1> &angular) const {
Austin Schuhd749d932020-12-30 21:38:40 -0800164 Eigen::Matrix<Scalar, 2, 1> scaled_angle = angular * this->robot_radius;
Austin Schuhbcce26a2018-03-26 23:41:24 -0700165 Eigen::Matrix<Scalar, 4, 1> state;
Austin Schuhd91c0d22016-10-15 21:24:28 -0700166 state(0, 0) = linear(0, 0) - scaled_angle(0, 0);
167 state(1, 0) = linear(1, 0) - scaled_angle(1, 0);
168 state(2, 0) = linear(0, 0) + scaled_angle(0, 0);
169 state(3, 0) = linear(1, 0) + scaled_angle(1, 0);
170 return state;
171 }
James Kuszmaul68025332024-01-20 17:06:02 -0800172
173 static DrivetrainConfig FromFlatbuffer(const fbs::DrivetrainConfig &fbs) {
174 std::shared_ptr<aos::FlatbufferDetachedBuffer<fbs::DrivetrainConfig>>
175 fbs_copy = std::make_shared<
176 aos::FlatbufferDetachedBuffer<fbs::DrivetrainConfig>>(
177 aos::RecursiveCopyFlatBuffer(&fbs));
178 return {
179#define ASSIGN(field) .field = fbs.field()
180 ASSIGN(shifter_type), ASSIGN(loop_type), ASSIGN(gyro_type),
181 ASSIGN(imu_type),
182 .make_drivetrain_loop =
183 [fbs_copy]() {
184 return MakeStateFeedbackLoop<4, 2, 2>(*CHECK_NOTNULL(
185 fbs_copy->message().loop_config()->drivetrain_loop()));
186 },
187 .make_v_drivetrain_loop =
188 [fbs_copy]() {
189 return MakeStateFeedbackLoop<2, 2, 2>(
190 *CHECK_NOTNULL(fbs_copy->message()
191 .loop_config()
192 ->velocity_drivetrain_loop()));
193 },
194 .make_kf_drivetrain_loop =
195 [fbs_copy]() {
196 return MakeStateFeedbackLoop<7, 2, 4>(
197 *CHECK_NOTNULL(fbs_copy->message()
198 .loop_config()
199 ->kalman_drivetrain_loop()));
200 },
201#if defined(__linux__)
202 .make_hybrid_drivetrain_velocity_loop =
203 [fbs_copy]() {
204 return MakeHybridStateFeedbackLoop<2, 2, 2>(
205 *CHECK_NOTNULL(fbs_copy->message()
206 .loop_config()
207 ->hybrid_velocity_drivetrain_loop()));
208 },
209#endif
210 .dt = std::chrono::nanoseconds(fbs.loop_config()->dt()),
211 .robot_radius = fbs.loop_config()->robot_radius(),
212 .wheel_radius = fbs.loop_config()->wheel_radius(),
213 .v = fbs.loop_config()->motor_kv(),
214 .high_gear_ratio = fbs.loop_config()->high_gear_ratio(),
215 .low_gear_ratio = fbs.loop_config()->low_gear_ratio(),
216 .J = fbs.loop_config()->moment_of_inertia(),
217 .mass = fbs.loop_config()->mass(), .left_drive = *fbs.left_drive(),
218 .right_drive = *fbs.right_drive(), ASSIGN(default_high_gear),
219 ASSIGN(down_offset), ASSIGN(wheel_non_linearity),
220 ASSIGN(quickturn_wheel_multiplier), ASSIGN(wheel_multiplier),
221 ASSIGN(pistol_grip_shift_enables_line_follow),
222 .imu_transform =
223 ToEigenOrDie<3, 3>(*CHECK_NOTNULL(fbs.imu_transform())),
224 ASSIGN(is_simulated),
225 .down_estimator_config =
226 aos::UnpackFlatbuffer(fbs.down_estimator_config()),
227 .line_follow_config =
228 LineFollowConfig::FromFlatbuffer(fbs.line_follow_config()),
229 ASSIGN(top_button_use), ASSIGN(second_button_use),
230 ASSIGN(bottom_button_use)
231#undef ASSIGN
232 };
233 }
Comran Morshed5323ecb2015-12-26 20:50:55 +0000234};
Comran Morshed5323ecb2015-12-26 20:50:55 +0000235} // namespace drivetrain
236} // namespace control_loops
237} // namespace frc971
238
239#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_CONSTANTS_H_