Move some DrivetrainConfig types to flatbuffers

This makes it so that we can start to implement the DrivetrainConfig as
a flatbuffer.

Change-Id: I69b92fcc436e82662d01a329d048a80c67267267
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/frc971/BUILD b/frc971/BUILD
index dd1b367..5a357ab 100644
--- a/frc971/BUILD
+++ b/frc971/BUILD
@@ -9,6 +9,7 @@
     hdrs = [
         "shifter_hall_effect.h",
     ],
+    deps = ["//frc971/control_loops/drivetrain:drivetrain_config_fbs"],
 )
 
 cc_library(
diff --git a/frc971/control_loops/drivetrain/BUILD b/frc971/control_loops/drivetrain/BUILD
index 7a25bcd..4df6486 100644
--- a/frc971/control_loops/drivetrain/BUILD
+++ b/frc971/control_loops/drivetrain/BUILD
@@ -182,8 +182,13 @@
     deps = [
         "//frc971:shifter_hall_effect",
         "//frc971/control_loops:state_feedback_loop",
+        "//frc971/control_loops:state_feedback_loop_converters",
+        ":drivetrain_config_fbs",
     ] + select({
-        "@platforms//os:linux": ["//frc971/control_loops:hybrid_state_feedback_loop"],
+        "@platforms//os:linux": [
+            "//frc971/control_loops:hybrid_state_feedback_loop",
+            "//frc971/control_loops:hybrid_state_feedback_loop_converters",
+        ],
         "//conditions:default": [],
     }),
 )
@@ -838,3 +843,10 @@
         "//aos/network/www:proxy",
     ],
 )
+
+static_flatbuffer(
+    name = "drivetrain_config_fbs",
+    srcs = ["drivetrain_config.fbs"],
+    visibility = ["//visibility:public"],
+    deps = ["//frc971/control_loops:state_feedback_loop_fbs"],
+)
diff --git a/frc971/control_loops/drivetrain/drivetrain.cc b/frc971/control_loops/drivetrain/drivetrain.cc
index cdccd7d..2b84a9d 100644
--- a/frc971/control_loops/drivetrain/drivetrain.cc
+++ b/frc971/control_loops/drivetrain/drivetrain.cc
@@ -98,7 +98,7 @@
                                 const drivetrain::Position *position) {
   // TODO(austin): Put gear detection logic here.
   switch (dt_config_.shifter_type) {
-    case ShifterType::SIMPLE_SHIFTER:
+    case ShifterType::kSimpleShifter:
       // Force the right controller for simple shifters since we assume that
       // gear switching is instantaneous.
       if (left_high_requested_) {
@@ -112,13 +112,13 @@
         right_gear_ = Gear::LOW;
       }
       break;
-    case ShifterType::HALL_EFFECT_SHIFTER:
+    case ShifterType::kHallEffectShifter:
       left_gear_ = ComputeGear(position->left_shifter_position(),
                                dt_config_.left_drive, left_high_requested_);
       right_gear_ = ComputeGear(position->right_shifter_position(),
                                 dt_config_.right_drive, right_high_requested_);
       break;
-    case ShifterType::NO_SHIFTER:
+    case ShifterType::kNoShifter:
       break;
   }
 
@@ -151,16 +151,16 @@
       const IMUValues *value = imu_values_fetcher_->readings()->Get(
           imu_values_fetcher_->readings()->size() - 1);
       switch (dt_config_.imu_type) {
-        case IMUType::IMU_X:
+        case ImuType::kImuX:
           last_accel_ = -value->accelerometer_x();
           break;
-        case IMUType::IMU_FLIPPED_X:
+        case ImuType::kImuFlippedX:
           last_accel_ = value->accelerometer_x();
           break;
-        case IMUType::IMU_Y:
+        case ImuType::kImuY:
           last_accel_ = -value->accelerometer_y();
           break;
-        case IMUType::IMU_Z:
+        case ImuType::kImuZ:
           last_accel_ = value->accelerometer_z();
           break;
       }
@@ -171,37 +171,37 @@
   bool imu_zeroer_zeroed = imu_zeroer_.Zeroed();
 
   switch (dt_config_.gyro_type) {
-    case GyroType::IMU_X_GYRO:
+    case GyroType::kImuXGyro:
       if (got_imu_reading) {
         last_gyro_rate_ =
             imu_zeroer_zeroed ? imu_zeroer_.ZeroedGyro().value().x() : 0.0;
       }
       break;
-    case GyroType::IMU_Y_GYRO:
+    case GyroType::kImuYGyro:
       if (got_imu_reading) {
         last_gyro_rate_ =
             imu_zeroer_zeroed ? imu_zeroer_.ZeroedGyro().value().y() : 0.0;
       }
       break;
-    case GyroType::IMU_Z_GYRO:
+    case GyroType::kImuZGyro:
       if (got_imu_reading) {
         last_gyro_rate_ =
             imu_zeroer_zeroed ? imu_zeroer_.ZeroedGyro().value().z() : 0.0;
       }
       break;
-    case GyroType::FLIPPED_IMU_Z_GYRO:
+    case GyroType::kFlippedImuZGyro:
       if (got_imu_reading) {
         last_gyro_rate_ =
             imu_zeroer_zeroed ? -imu_zeroer_.ZeroedGyro().value().z() : 0.0;
       }
       break;
-    case GyroType::SPARTAN_GYRO:
+    case GyroType::kSpartanGyro:
       if (gyro_reading_fetcher_.Fetch()) {
         last_gyro_rate_ = gyro_reading_fetcher_->velocity();
         last_gyro_time_ = monotonic_now;
       }
       break;
-    case GyroType::FLIPPED_SPARTAN_GYRO:
+    case GyroType::kFlippedSpartanGyro:
       if (gyro_reading_fetcher_.Fetch()) {
         last_gyro_rate_ = -gyro_reading_fetcher_->velocity();
         last_gyro_time_ = monotonic_now;
@@ -213,8 +213,8 @@
   }
 
   switch (dt_config_.gyro_type) {
-    case GyroType::SPARTAN_GYRO:
-    case GyroType::FLIPPED_SPARTAN_GYRO:
+    case GyroType::kSpartanGyro:
+    case GyroType::kFlippedSpartanGyro:
       if (!yaw_gyro_zero_.has_value()) {
         yaw_gyro_zeroer_.AddData(last_gyro_rate_);
         if (yaw_gyro_zeroer_.full() &&
@@ -229,10 +229,10 @@
         last_gyro_rate_ = last_gyro_rate_ - yaw_gyro_zero_.value();
       }
       break;
-    case GyroType::IMU_X_GYRO:
-    case GyroType::IMU_Y_GYRO:
-    case GyroType::IMU_Z_GYRO:
-    case GyroType::FLIPPED_IMU_Z_GYRO:
+    case GyroType::kImuXGyro:
+    case GyroType::kImuYGyro:
+    case GyroType::kImuZGyro:
+    case GyroType::kFlippedImuZGyro:
       ready_ = imu_zeroer_.Zeroed();
       break;
   }
@@ -326,9 +326,9 @@
 Gear DrivetrainFilters::ComputeGear(
     double shifter_position, const constants::ShifterHallEffect &shifter_config,
     bool high_requested) const {
-  if (shifter_position < shifter_config.clear_low) {
+  if (shifter_position < shifter_config.clear_low()) {
     return Gear::LOW;
-  } else if (shifter_position > shifter_config.clear_high) {
+  } else if (shifter_position > shifter_config.clear_high()) {
     return Gear::HIGH;
   } else {
     if (high_requested) {
diff --git a/frc971/control_loops/drivetrain/drivetrain_config.fbs b/frc971/control_loops/drivetrain/drivetrain_config.fbs
new file mode 100644
index 0000000..645eeac
--- /dev/null
+++ b/frc971/control_loops/drivetrain/drivetrain_config.fbs
@@ -0,0 +1,141 @@
+include "frc971/control_loops/state_feedback_loop.fbs";
+include "frc971/math/matrix.fbs";
+
+namespace frc971.control_loops.drivetrain;
+
+// Contains the constants for mapping the analog voltages that the shifter
+// sensors return to the shifter position.  The code which uses this is trying
+// to sort out if we are in low gear, high gear, or neutral.
+// The hall-effect messages are structs in order to enable an easier transition
+// from existing code; we will deal with compatibility issues if we do end
+// up needing to repurpose this in the future.
+struct ShifterHallEffect {
+  // low_gear_low is the voltage that the shifter position sensor reads when it
+  // is all the way in low gear.  high_gear_high is the voltage that the shifter
+  // position sensor reads when it is all the way in high gear.  These two
+  // values are used to calculate a position from 0 to 1, where we get 0 when
+  // the shifter is in low gear, and 1 when it is high gear.
+  low_gear_low:double (id: 0);
+  high_gear_high:double (id: 1);
+
+  // The numbers for when the dog is clear of each gear.
+  // We are in low gear when the position is less than clear_low, and in high
+  // gear when the shifter position is greater than clear_high.
+  clear_low:double (id: 2);
+  clear_high:double (id: 3);
+}
+
+struct DualHallShifterHallEffect {
+  shifter_hall_effect:ShifterHallEffect (id: 0);
+  low_gear_middle:double (id: 1);
+  high_gear_middle:double (id: 2);
+}
+
+// What to use the top two buttons for on the pistol grip.
+enum PistolTopButtonUse : ubyte {
+  // Normal shifting.
+  kShift = 0,
+  // Line following (currently just uses top button).
+  kLineFollow = 1,
+  // Don't use the top button
+  kNone = 2,
+}
+
+enum PistolSecondButtonUse : ubyte {
+  kTurn1 = 0,
+  kShiftLow = 1,
+  kNone = 2,
+}
+
+enum PistolBottomButtonUse : ubyte {
+  kControlLoopDriving = 0,
+  kSlowDown = 1,
+  kNone = 2,
+}
+
+enum ShifterType : int32 {
+  kHallEffectShifter = 0,  // Detect when inbetween gears.
+  kSimpleShifter = 1,       // Switch gears without speedmatch logic.
+  kNoShifter = 2,           // Only one gear ratio.
+}
+
+enum LoopType : int32 {
+  kOpenLoop = 0,    // Only use open loop logic.
+  kClosedLoop = 1,  // Add in closed loop calculation.
+}
+
+enum GyroType : int32 {
+  kSpartanGyro = 0,          // Use the gyro on the spartan board.
+  kImuXGyro = 1,            // Use the x-axis of the gyro on the IMU.
+  kImuYGyro = 2,            // Use the y-axis of the gyro on the IMU.
+  kImuZGyro = 3,            // Use the z-axis of the gyro on the IMU.
+  kFlippedSpartanGyro = 4,  // Use the gyro on the spartan board.
+  kFlippedImuZGyro = 5,    // Use the flipped z-axis of the gyro on the IMU.
+}
+
+enum ImuType : int32 {
+  kImuX = 0,          // Use the x-axis of the IMU.
+  kImuY = 1,          // Use the y-axis of the IMU.
+  kImuFlippedX = 2,  // Use the flipped x-axis of the IMU.
+  kImuZ = 3,          // Use the z-axis of the IMU.
+}
+
+table DownEstimatorConfig {
+  gravity_threshold:double = 0.025 (id: 0);
+  do_accel_corrections:int = 50 (id: 1);
+}
+
+// The below tables shadow C++ classes.
+namespace frc971.control_loops.drivetrain.fbs;
+
+table LineFollowConfig {
+  // Q should be a 3x3 positive-definite matrix; it is used as the state cost
+  // of the LQR controller for the line-following mode.
+  q:frc971.fbs.Matrix (id: 0);
+  // R should be a 2x2 positive-definite matrix; it is used as the input cost
+  // of the LQR controller for the line-following mode.
+  r:frc971.fbs.Matrix (id: 1);
+  max_controllable_offset:double = 0.1 (id: 2);
+}
+
+// These constants are all specified by the drivetrain python code, and
+// so are separated out for easy codegen.
+table DrivetrainLoopConfig {
+  drivetrain_loop:[frc971.control_loops.fbs.StateFeedbackLoopCoefficients] (id: 0);
+  velocity_drivetrain_loop:[frc971.control_loops.fbs.StateFeedbackLoopCoefficients] (id: 1);
+  kalman_drivetrain_loop:[frc971.control_loops.fbs.StateFeedbackLoopCoefficients] (id: 2);
+  hybrid_velocity_drivetrain_loop:[frc971.control_loops.fbs.StateFeedbackHybridLoopCoefficients] (id: 3);
+  // Nanoseconds
+  dt:uint64 (id: 4);
+  // meters
+  robot_radius:double (id: 5);
+  wheel_radius:double (id: 6);
+  motor_kv:double (id: 7);
+  high_gear_ratio:double (id: 8);
+  low_gear_ratio:double (id: 9);
+  moment_of_inertia:double (id: 10);
+  mass:double (id: 11);
+}
+
+table DrivetrainConfig {
+  shifter_type:ShifterType (id: 0);
+  loop_type:LoopType (id: 1);
+  gyro_type:GyroType (id: 2);
+  imu_type:ImuType (id: 3);
+  loop_config:DrivetrainLoopConfig (id: 4);
+  left_drive:ShifterHallEffect (id: 5);
+  right_drive:ShifterHallEffect (id: 6);
+  default_high_gear:bool (id: 7);
+  down_offset:double (id: 8);
+  wheel_non_linearity:double (id: 9);
+  quickturn_wheel_multiplier:double (id: 10);
+  wheel_multiplier:double (id: 11);
+  pistol_grip_shift_enables_line_follow:bool = false (id: 12);
+  imu_transform:frc971.fbs.Matrix (id: 13);
+  is_simulated:bool = false (id: 14);
+  down_estimator_config:DownEstimatorConfig (id: 15);
+  line_follow_config:LineFollowConfig (id: 16);
+  top_button_use:PistolTopButtonUse = kShift (id: 17);
+  second_button_use:PistolSecondButtonUse = kShiftLow (id: 18);
+  bottom_button_use:PistolBottomButtonUse = kSlowDown (id: 19);
+}
diff --git a/frc971/control_loops/drivetrain/drivetrain_config.h b/frc971/control_loops/drivetrain/drivetrain_config.h
index 9c17fc8..2b0471a 100644
--- a/frc971/control_loops/drivetrain/drivetrain_config.h
+++ b/frc971/control_loops/drivetrain/drivetrain_config.h
@@ -3,74 +3,20 @@
 
 #include <functional>
 
+#include "aos/flatbuffer_merge.h"
 #if defined(__linux__)
 #include "frc971/control_loops/hybrid_state_feedback_loop.h"
+#include "frc971/control_loops/hybrid_state_feedback_loop_converters.h"
 #endif
+#include "frc971/control_loops/drivetrain/drivetrain_config_static.h"
 #include "frc971/control_loops/state_feedback_loop.h"
+#include "frc971/control_loops/state_feedback_loop_converters.h"
 #include "frc971/shifter_hall_effect.h"
 
 namespace frc971 {
 namespace control_loops {
 namespace drivetrain {
 
-// What to use the top two buttons for on the pistol grip.
-enum class PistolTopButtonUse {
-  // Normal shifting.
-  kShift,
-  // Line following (currently just uses top button).
-  kLineFollow,
-  // Don't use the top button
-  kNone,
-};
-
-enum class PistolSecondButtonUse {
-  kTurn1,
-  kShiftLow,
-  kNone,
-};
-
-enum class PistolBottomButtonUse {
-  kControlLoopDriving,
-  kSlowDown,
-  kNone,
-};
-
-enum class ShifterType : int32_t {
-  HALL_EFFECT_SHIFTER = 0,  // Detect when inbetween gears.
-  SIMPLE_SHIFTER = 1,       // Switch gears without speedmatch logic.
-  NO_SHIFTER = 2,           // Only one gear ratio.
-};
-
-enum class LoopType : int32_t {
-  OPEN_LOOP = 0,    // Only use open loop logic.
-  CLOSED_LOOP = 1,  // Add in closed loop calculation.
-};
-
-enum class GyroType : int32_t {
-  SPARTAN_GYRO = 0,          // Use the gyro on the spartan board.
-  IMU_X_GYRO = 1,            // Use the x-axis of the gyro on the IMU.
-  IMU_Y_GYRO = 2,            // Use the y-axis of the gyro on the IMU.
-  IMU_Z_GYRO = 3,            // Use the z-axis of the gyro on the IMU.
-  FLIPPED_SPARTAN_GYRO = 4,  // Use the gyro on the spartan board.
-  FLIPPED_IMU_Z_GYRO = 5,    // Use the flipped z-axis of the gyro on the IMU.
-};
-
-enum class IMUType : int32_t {
-  IMU_X = 0,          // Use the x-axis of the IMU.
-  IMU_Y = 1,          // Use the y-axis of the IMU.
-  IMU_FLIPPED_X = 2,  // Use the flipped x-axis of the IMU.
-  IMU_Z = 3,          // Use the z-axis of the IMU.
-};
-
-struct DownEstimatorConfig {
-  // Threshold, in g's, to use for detecting whether we are stopped in the down
-  // estimator.
-  double gravity_threshold = 0.025;
-  // Number of cycles of being still to require before taking accelerometer
-  // corrections.
-  int do_accel_corrections = 50;
-};
-
 // Configuration for line-following mode.
 struct LineFollowConfig {
   // The line-following uses an LQR controller with states of [theta,
@@ -94,6 +40,16 @@
   // place things laterally. This specifies how much range on either side of
   // zero we allow them, in meters.
   double max_controllable_offset = 0.1;
+
+  static LineFollowConfig FromFlatbuffer(const fbs::LineFollowConfig *fbs) {
+    if (fbs == nullptr) {
+      return {};
+    }
+    return LineFollowConfig{
+        .Q = ToEigenOrDie<3, 3>(*CHECK_NOTNULL(fbs->q())),
+        .R = ToEigenOrDie<2, 2>(*CHECK_NOTNULL(fbs->r())),
+        .max_controllable_offset = fbs->max_controllable_offset()};
+  }
 };
 
 template <typename Scalar = double>
@@ -108,7 +64,7 @@
   GyroType gyro_type;
 
   // Type of IMU to use.
-  IMUType imu_type;
+  ImuType imu_type;
 
   // Polydrivetrain functions returning various controller loops with plants.
   ::std::function<StateFeedbackLoop<4, 2, 2, Scalar>()> make_drivetrain_loop;
@@ -135,8 +91,8 @@
   Scalar mass;
 
   // Hall effect constants. Unused if not applicable to shifter type.
-  constants::ShifterHallEffect left_drive;
-  constants::ShifterHallEffect right_drive;
+  ShifterHallEffect left_drive;
+  ShifterHallEffect right_drive;
 
   // Variable that holds the default gear ratio. We use this in ZeroOutputs().
   // (ie. true means high gear is default).
@@ -163,7 +119,7 @@
   // True if we are running a simulated drivetrain.
   bool is_simulated = false;
 
-  DownEstimatorConfig down_estimator_config{};
+  DownEstimatorConfigT down_estimator_config{};
 
   LineFollowConfig line_follow_config{};
 
@@ -213,6 +169,68 @@
     state(3, 0) = linear(1, 0) + scaled_angle(1, 0);
     return state;
   }
+
+  static DrivetrainConfig FromFlatbuffer(const fbs::DrivetrainConfig &fbs) {
+    std::shared_ptr<aos::FlatbufferDetachedBuffer<fbs::DrivetrainConfig>>
+        fbs_copy = std::make_shared<
+            aos::FlatbufferDetachedBuffer<fbs::DrivetrainConfig>>(
+            aos::RecursiveCopyFlatBuffer(&fbs));
+    return {
+#define ASSIGN(field) .field = fbs.field()
+      ASSIGN(shifter_type), ASSIGN(loop_type), ASSIGN(gyro_type),
+          ASSIGN(imu_type),
+          .make_drivetrain_loop =
+              [fbs_copy]() {
+                return MakeStateFeedbackLoop<4, 2, 2>(*CHECK_NOTNULL(
+                    fbs_copy->message().loop_config()->drivetrain_loop()));
+              },
+          .make_v_drivetrain_loop =
+              [fbs_copy]() {
+                return MakeStateFeedbackLoop<2, 2, 2>(
+                    *CHECK_NOTNULL(fbs_copy->message()
+                                       .loop_config()
+                                       ->velocity_drivetrain_loop()));
+              },
+          .make_kf_drivetrain_loop =
+              [fbs_copy]() {
+                return MakeStateFeedbackLoop<7, 2, 4>(
+                    *CHECK_NOTNULL(fbs_copy->message()
+                                       .loop_config()
+                                       ->kalman_drivetrain_loop()));
+              },
+#if defined(__linux__)
+          .make_hybrid_drivetrain_velocity_loop =
+              [fbs_copy]() {
+                return MakeHybridStateFeedbackLoop<2, 2, 2>(
+                    *CHECK_NOTNULL(fbs_copy->message()
+                                       .loop_config()
+                                       ->hybrid_velocity_drivetrain_loop()));
+              },
+#endif
+          .dt = std::chrono::nanoseconds(fbs.loop_config()->dt()),
+          .robot_radius = fbs.loop_config()->robot_radius(),
+          .wheel_radius = fbs.loop_config()->wheel_radius(),
+          .v = fbs.loop_config()->motor_kv(),
+          .high_gear_ratio = fbs.loop_config()->high_gear_ratio(),
+          .low_gear_ratio = fbs.loop_config()->low_gear_ratio(),
+          .J = fbs.loop_config()->moment_of_inertia(),
+          .mass = fbs.loop_config()->mass(), .left_drive = *fbs.left_drive(),
+          .right_drive = *fbs.right_drive(), ASSIGN(default_high_gear),
+          ASSIGN(down_offset), ASSIGN(wheel_non_linearity),
+          ASSIGN(quickturn_wheel_multiplier), ASSIGN(wheel_multiplier),
+          ASSIGN(pistol_grip_shift_enables_line_follow),
+          .imu_transform =
+              ToEigenOrDie<3, 3>(*CHECK_NOTNULL(fbs.imu_transform())),
+          ASSIGN(is_simulated),
+          .down_estimator_config =
+              aos::UnpackFlatbuffer(fbs.down_estimator_config()),
+          .line_follow_config =
+              LineFollowConfig::FromFlatbuffer(fbs.line_follow_config()),
+          ASSIGN(top_button_use), ASSIGN(second_button_use),
+          ASSIGN(bottom_button_use)
+#undef ASSIGN
+    };
+  }
 };
 }  // namespace drivetrain
 }  // namespace control_loops
diff --git a/frc971/control_loops/drivetrain/drivetrain_test_lib.cc b/frc971/control_loops/drivetrain/drivetrain_test_lib.cc
index c8e4dee..394be07 100644
--- a/frc971/control_loops/drivetrain/drivetrain_test_lib.cc
+++ b/frc971/control_loops/drivetrain/drivetrain_test_lib.cc
@@ -48,10 +48,10 @@
 
 const DrivetrainConfig<double> &GetTestDrivetrainConfig() {
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::HALL_EFFECT_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::IMU_Z_GYRO,
-      IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kHallEffectShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kImuZGyro,
+      ImuType::kImuFlippedX,
       ::y2016::control_loops::drivetrain::MakeDrivetrainLoop,
       ::y2016::control_loops::drivetrain::MakeVelocityDrivetrainLoop,
       ::y2016::control_loops::drivetrain::MakeKFDrivetrainLoop,
diff --git a/frc971/control_loops/drivetrain/improved_down_estimator.h b/frc971/control_loops/drivetrain/improved_down_estimator.h
index 4e3227e..b5cc509 100644
--- a/frc971/control_loops/drivetrain/improved_down_estimator.h
+++ b/frc971/control_loops/drivetrain/improved_down_estimator.h
@@ -193,7 +193,7 @@
   // The transformation from the IMU's frame to the robot frame.
   Eigen::Matrix<double, 3, 3> imu_transform_;
 
-  const DownEstimatorConfig config_;
+  const DownEstimatorConfigT config_;
 
   bool assume_perfect_gravity_ = false;
 };
diff --git a/frc971/control_loops/drivetrain/polydrivetrain.h b/frc971/control_loops/drivetrain/polydrivetrain.h
index ecdf340..a9dea7e 100644
--- a/frc971/control_loops/drivetrain/polydrivetrain.h
+++ b/frc971/control_loops/drivetrain/polydrivetrain.h
@@ -150,10 +150,10 @@
       velocity /
       static_cast<Scalar>(dt_config_.low_gear_ratio / dt_config_.wheel_radius);
 
-  if (shifter_position < static_cast<Scalar>(hall_effect.clear_low)) {
+  if (shifter_position < static_cast<Scalar>(hall_effect.clear_low())) {
     // We're in low gear, so return speed for that gear.
     return low_gear_speed;
-  } else if (shifter_position > static_cast<Scalar>(hall_effect.clear_high)) {
+  } else if (shifter_position > static_cast<Scalar>(hall_effect.clear_high())) {
     // We're in high gear, so return speed for that gear.
     return high_gear_speed;
   }
@@ -175,11 +175,11 @@
 Gear PolyDrivetrain<Scalar>::UpdateSingleGear(Gear requested_gear,
                                               Gear current_gear) {
   const Gear shift_up =
-      (dt_config_.shifter_type == ShifterType::HALL_EFFECT_SHIFTER)
+      (dt_config_.shifter_type == ShifterType::kHallEffectShifter)
           ? Gear::SHIFTING_UP
           : Gear::HIGH;
   const Gear shift_down =
-      (dt_config_.shifter_type == ShifterType::HALL_EFFECT_SHIFTER)
+      (dt_config_.shifter_type == ShifterType::kHallEffectShifter)
           ? Gear::SHIFTING_DOWN
           : Gear::LOW;
   if (current_gear != requested_gear) {
@@ -294,7 +294,7 @@
 
 template <typename Scalar>
 void PolyDrivetrain<Scalar>::Update(Scalar voltage_battery) {
-  if (dt_config_.loop_type == LoopType::CLOSED_LOOP) {
+  if (dt_config_.loop_type == LoopType::kClosedLoop) {
     loop_->mutable_X_hat()(0, 0) = kf_->X_hat()(kLeftVelocity);
     loop_->mutable_X_hat()(1, 0) = kf_->X_hat()(kRightVelocity);
   }
@@ -362,7 +362,7 @@
       loop_->mutable_U()[i] = ::aos::Clip(U_ideal[i], -12, 12);
     }
 
-    if (dt_config_.loop_type == LoopType::OPEN_LOOP) {
+    if (dt_config_.loop_type == LoopType::kOpenLoop) {
       ff_volts_.setZero();
       loop_->mutable_X_hat() =
           loop_->plant().A() * loop_->X_hat() + loop_->plant().B() * loop_->U();
diff --git a/frc971/shifter_hall_effect.h b/frc971/shifter_hall_effect.h
index 4a0197c..7291ddd 100644
--- a/frc971/shifter_hall_effect.h
+++ b/frc971/shifter_hall_effect.h
@@ -1,31 +1,13 @@
 #ifndef FRC971_SHIFTER_HALL_EFFECT_H_
 #define FRC971_SHIFTER_HALL_EFFECT_H_
 
+#include "frc971/control_loops/drivetrain/drivetrain_config_generated.h"
+
 namespace frc971::constants {
 
-// Contains the constants for mapping the analog voltages that the shifter
-// sensors return to the shifter position.  The code which uses this is trying
-// to sort out if we are in low gear, high gear, or neutral.
-struct ShifterHallEffect {
-  // low_gear_low is the voltage that the shifter position sensor reads when it
-  // is all the way in low gear.  high_gear_high is the voltage that the shifter
-  // position sensor reads when it is all the way in high gear.  These two
-  // values are used to calculate a position from 0 to 1, where we get 0 when
-  // the shifter is in low gear, and 1 when it is high gear.
-  double low_gear_low;
-  double high_gear_high;
-
-  // The numbers for when the dog is clear of each gear.
-  // We are in low gear when the position is less than clear_low, and in high
-  // gear when the shifter position is greater than clear_high.
-  double clear_low, clear_high;
-};
-
-struct DualHallShifterHallEffect {
-  ShifterHallEffect shifter_hall_effect;
-  double low_gear_middle;
-  double high_gear_middle;
-};
+typedef frc971::control_loops::drivetrain::ShifterHallEffect ShifterHallEffect;
+typedef frc971::control_loops::drivetrain::DualHallShifterHallEffect
+    DualHallShifterHallEffect;
 
 }  // namespace frc971::constants
 
diff --git a/motors/simple_receiver.cc b/motors/simple_receiver.cc
index 2ae0c9b..cc1056c 100644
--- a/motors/simple_receiver.cc
+++ b/motors/simple_receiver.cc
@@ -56,14 +56,14 @@
   return r;
 }
 
-const ShifterHallEffect kThreeStateDriveShifter{0.0, 0.0, 0.25, 0.75};
+const ShifterHallEffect kThreeStateDriveShifter{{}, 0.0, 0.0, 0.25, 0.75};
 
 const DrivetrainConfig<float> &GetDrivetrainConfig() {
   static DrivetrainConfig<float> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::NO_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::OPEN_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kNoShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kOpenLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuX,
 
       ::motors::seems_reasonable::MakeDrivetrainLoop,
       ::motors::seems_reasonable::MakeVelocityDrivetrainLoop,
diff --git a/motors/simpler_receiver.cc b/motors/simpler_receiver.cc
index 7fad0b8..2724f3b 100644
--- a/motors/simpler_receiver.cc
+++ b/motors/simpler_receiver.cc
@@ -27,14 +27,14 @@
 
 namespace chrono = ::std::chrono;
 
-const ShifterHallEffect kThreeStateDriveShifter{0.0, 0.0, 0.25, 0.75};
+const ShifterHallEffect kThreeStateDriveShifter{{}, 0.0, 0.0, 0.25, 0.75};
 
 const DrivetrainConfig<float> &GetDrivetrainConfig() {
   static DrivetrainConfig<float> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::NO_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::OPEN_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kNoShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kOpenLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuX,
 
       ::motors::seems_reasonable::MakeDrivetrainLoop,
       ::motors::seems_reasonable::MakeVelocityDrivetrainLoop,
diff --git a/y2014/control_loops/drivetrain/drivetrain_base.cc b/y2014/control_loops/drivetrain/drivetrain_base.cc
index d9f396e..a8021fd 100644
--- a/y2014/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2014/control_loops/drivetrain/drivetrain_base.cc
@@ -18,10 +18,10 @@
 const DrivetrainConfig<double> &GetDrivetrainConfig() {
   // TODO(austin): Switch over to using the profile.
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::HALL_EFFECT_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kHallEffectShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
@@ -38,8 +38,8 @@
       constants::GetValues().low_gear_ratio,
       drivetrain::kJ,
       drivetrain::kMass,
-      constants::GetValues().left_drive.shifter_hall_effect,
-      constants::GetValues().right_drive.shifter_hall_effect,
+      constants::GetValues().left_drive.shifter_hall_effect(),
+      constants::GetValues().right_drive.shifter_hall_effect(),
       true /* default_high_gear */,
       0,
       0.25 /* wheel_non_linearity */,
diff --git a/y2014/wpilib_interface.cc b/y2014/wpilib_interface.cc
index 016b17a..fd5e70e 100644
--- a/y2014/wpilib_interface.cc
+++ b/y2014/wpilib_interface.cc
@@ -76,13 +76,14 @@
 float hall_translate(const constants::DualHallShifterHallEffect &k,
                      float in_low, float in_high) {
   const float low_ratio =
-      0.5 * (in_low - static_cast<float>(k.shifter_hall_effect.low_gear_low)) /
-      static_cast<float>(k.low_gear_middle -
-                         k.shifter_hall_effect.low_gear_low);
+      0.5 *
+      (in_low - static_cast<float>(k.shifter_hall_effect().low_gear_low())) /
+      static_cast<float>(k.low_gear_middle() -
+                         k.shifter_hall_effect().low_gear_low());
   const float high_ratio =
-      0.5 + 0.5 * (in_high - static_cast<float>(k.high_gear_middle)) /
-                static_cast<float>(k.shifter_hall_effect.high_gear_high -
-                                   k.high_gear_middle);
+      0.5 + 0.5 * (in_high - static_cast<float>(k.high_gear_middle())) /
+                static_cast<float>(k.shifter_hall_effect().high_gear_high() -
+                                   k.high_gear_middle());
 
   // Return low when we are below 1/2, and high when we are above 1/2.
   if (low_ratio + high_ratio < 1.0) {
diff --git a/y2014_bot3/control_loops/drivetrain/drivetrain_base.cc b/y2014_bot3/control_loops/drivetrain/drivetrain_base.cc
index ea6806f..c555f5a 100644
--- a/y2014_bot3/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2014_bot3/control_loops/drivetrain/drivetrain_base.cc
@@ -21,10 +21,10 @@
 
 const DrivetrainConfig<double> &GetDrivetrainConfig() {
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuX,
 
       ::y2014_bot3::control_loops::drivetrain::MakeDrivetrainLoop,
       ::y2014_bot3::control_loops::drivetrain::MakeVelocityDrivetrainLoop,
diff --git a/y2016/control_loops/drivetrain/drivetrain_base.cc b/y2016/control_loops/drivetrain/drivetrain_base.cc
index 208c843..978680c 100644
--- a/y2016/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2016/control_loops/drivetrain/drivetrain_base.cc
@@ -22,10 +22,10 @@
 
 const DrivetrainConfig<double> &GetDrivetrainConfig() {
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::HALL_EFFECT_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kHallEffectShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
diff --git a/y2017/control_loops/drivetrain/drivetrain_base.cc b/y2017/control_loops/drivetrain/drivetrain_base.cc
index 1569e34..2ed6981 100644
--- a/y2017/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2017/control_loops/drivetrain/drivetrain_base.cc
@@ -22,10 +22,10 @@
 
 const DrivetrainConfig<double> &GetDrivetrainConfig() {
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::NO_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::IMU_Z_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kNoShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kImuZGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
diff --git a/y2018/control_loops/drivetrain/drivetrain_base.cc b/y2018/control_loops/drivetrain/drivetrain_base.cc
index 92f460d..bf68e94 100644
--- a/y2018/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2018/control_loops/drivetrain/drivetrain_base.cc
@@ -21,10 +21,10 @@
 
 const DrivetrainConfig<double> &GetDrivetrainConfig() {
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::IMU_Z_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_Y,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kImuZGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuY,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
diff --git a/y2019/control_loops/drivetrain/drivetrain_base.cc b/y2019/control_loops/drivetrain/drivetrain_base.cc
index 77085a6..7a7534c 100644
--- a/y2019/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2019/control_loops/drivetrain/drivetrain_base.cc
@@ -21,10 +21,10 @@
 
 const DrivetrainConfig<double> &GetDrivetrainConfig() {
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::IMU_Z_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kImuZGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuFlippedX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
diff --git a/y2020/control_loops/drivetrain/drivetrain_base.cc b/y2020/control_loops/drivetrain/drivetrain_base.cc
index 3e05020..118450e 100644
--- a/y2020/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2020/control_loops/drivetrain/drivetrain_base.cc
@@ -23,10 +23,10 @@
 
 const DrivetrainConfig<double> &GetDrivetrainConfig() {
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::IMU_X_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_Z,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kImuXGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuZ,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
@@ -66,10 +66,10 @@
                                        0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
                                           .finished();
     kDrivetrainConfig.gyro_type =
-        ::frc971::control_loops::drivetrain::GyroType::IMU_Z_GYRO;
-    // TODO(james): CHECK IF THIS IS IMU_X or IMU_FLIPPED_X.
+        ::frc971::control_loops::drivetrain::GyroType::kImuZGyro;
+    // TODO(james): CHECK IF THIS IS kImuX or kImuFlippedX.
     kDrivetrainConfig.imu_type =
-        ::frc971::control_loops::drivetrain::IMUType::IMU_X;
+        ::frc971::control_loops::drivetrain::ImuType::kImuX;
   }
 
   return kDrivetrainConfig;
diff --git a/y2021_bot3/control_loops/drivetrain/drivetrain_base.cc b/y2021_bot3/control_loops/drivetrain/drivetrain_base.cc
index 42f0535..e894876 100644
--- a/y2021_bot3/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2021_bot3/control_loops/drivetrain/drivetrain_base.cc
@@ -21,10 +21,10 @@
 
 const DrivetrainConfig<double> &GetDrivetrainConfig() {
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::IMU_Z_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kImuZGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuFlippedX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
diff --git a/y2022/control_loops/drivetrain/drivetrain_base.cc b/y2022/control_loops/drivetrain/drivetrain_base.cc
index 551a5d5..52899ed 100644
--- a/y2022/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2022/control_loops/drivetrain/drivetrain_base.cc
@@ -9,7 +9,7 @@
 #include "y2022/control_loops/drivetrain/kalman_drivetrain_motor_plant.h"
 #include "y2022/control_loops/drivetrain/polydrivetrain_dog_motor_plant.h"
 
-using ::frc971::control_loops::drivetrain::DownEstimatorConfig;
+using ::frc971::control_loops::drivetrain::DownEstimatorConfigT;
 using ::frc971::control_loops::drivetrain::DrivetrainConfig;
 
 namespace chrono = ::std::chrono;
@@ -24,10 +24,10 @@
   // Yaw of the IMU relative to the robot frame.
   static constexpr double kImuYaw = 0.0;
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuFlippedX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
@@ -58,8 +58,7 @@
        0.0, std::sin(kImuYaw), std::cos(kImuYaw), 0.0, 0.0, 0.0, 1.0)
           .finished(),
       false /*is_simulated*/,
-      DownEstimatorConfig{.gravity_threshold = 0.015,
-                          .do_accel_corrections = 1000}};
+      DownEstimatorConfigT{{}, 0.015, 1000}};
 
   return kDrivetrainConfig;
 };
diff --git a/y2022_bot3/control_loops/drivetrain/drivetrain_base.cc b/y2022_bot3/control_loops/drivetrain/drivetrain_base.cc
index dc89588..3136fcf 100644
--- a/y2022_bot3/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2022_bot3/control_loops/drivetrain/drivetrain_base.cc
@@ -9,7 +9,7 @@
 #include "y2022_bot3/control_loops/drivetrain/kalman_drivetrain_motor_plant.h"
 #include "y2022_bot3/control_loops/drivetrain/polydrivetrain_dog_motor_plant.h"
 
-using ::frc971::control_loops::drivetrain::DownEstimatorConfig;
+using ::frc971::control_loops::drivetrain::DownEstimatorConfigT;
 using ::frc971::control_loops::drivetrain::DrivetrainConfig;
 
 namespace chrono = ::std::chrono;
@@ -24,10 +24,10 @@
   // Yaw of the IMU relative to the robot frame.
   static constexpr double kImuYaw = 0.0;
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuFlippedX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
@@ -58,8 +58,7 @@
        0.0, std::sin(kImuYaw), std::cos(kImuYaw), 0.0, 0.0, 0.0, 1.0)
           .finished(),
       false /*is_simulated*/,
-      DownEstimatorConfig{.gravity_threshold = 0.015,
-                          .do_accel_corrections = 1000}};
+      DownEstimatorConfigT{{}, 0.015, 1000}};
 
   return kDrivetrainConfig;
 };
diff --git a/y2023/control_loops/drivetrain/drivetrain_base.cc b/y2023/control_loops/drivetrain/drivetrain_base.cc
index 63e7904..49db14f 100644
--- a/y2023/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2023/control_loops/drivetrain/drivetrain_base.cc
@@ -9,7 +9,7 @@
 #include "y2023/control_loops/drivetrain/kalman_drivetrain_motor_plant.h"
 #include "y2023/control_loops/drivetrain/polydrivetrain_dog_motor_plant.h"
 
-using ::frc971::control_loops::drivetrain::DownEstimatorConfig;
+using ::frc971::control_loops::drivetrain::DownEstimatorConfigT;
 using ::frc971::control_loops::drivetrain::DrivetrainConfig;
 using ::frc971::control_loops::drivetrain::LineFollowConfig;
 
@@ -25,10 +25,10 @@
   // Yaw of the IMU relative to the robot frame.
   static constexpr double kImuYaw = 0.0;
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuFlippedX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
@@ -59,8 +59,7 @@
        0.0, std::sin(kImuYaw), std::cos(kImuYaw), 0.0, 0.0, 0.0, 1.0)
           .finished(),
       false /*is_simulated*/,
-      DownEstimatorConfig{.gravity_threshold = 0.015,
-                          .do_accel_corrections = 1000},
+      DownEstimatorConfigT{{}, 0.015, 1000},
       LineFollowConfig{
           .Q = Eigen::Matrix3d((::Eigen::DiagonalMatrix<double, 3>().diagonal()
                                     << 1.0 / ::std::pow(0.1, 2),
diff --git a/y2023_bot3/control_loops/drivetrain/drivetrain_base.cc b/y2023_bot3/control_loops/drivetrain/drivetrain_base.cc
index 481cab0..7269e74 100644
--- a/y2023_bot3/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2023_bot3/control_loops/drivetrain/drivetrain_base.cc
@@ -9,7 +9,7 @@
 #include "y2023_bot3/control_loops/drivetrain/kalman_drivetrain_motor_plant.h"
 #include "y2023_bot3/control_loops/drivetrain/polydrivetrain_dog_motor_plant.h"
 
-using ::frc971::control_loops::drivetrain::DownEstimatorConfig;
+using ::frc971::control_loops::drivetrain::DownEstimatorConfigT;
 using ::frc971::control_loops::drivetrain::DrivetrainConfig;
 using ::frc971::control_loops::drivetrain::LineFollowConfig;
 
@@ -25,10 +25,10 @@
   // Yaw of the IMU relative to the robot frame.
   static constexpr double kImuYaw = 0.0;
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuFlippedX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
@@ -59,8 +59,7 @@
        0.0, std::sin(kImuYaw), std::cos(kImuYaw), 0.0, 0.0, 0.0, 1.0)
           .finished(),
       false /*is_simulated*/,
-      DownEstimatorConfig{.gravity_threshold = 0.015,
-                          .do_accel_corrections = 1000},
+      DownEstimatorConfigT{{}, 0.015, 1000},
       LineFollowConfig{
           .Q = Eigen::Matrix3d((::Eigen::DiagonalMatrix<double, 3>().diagonal()
                                     << 1.0 / ::std::pow(0.1, 2),
diff --git a/y2024/control_loops/drivetrain/drivetrain_base.cc b/y2024/control_loops/drivetrain/drivetrain_base.cc
index 325dae8..ebb61ac 100644
--- a/y2024/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2024/control_loops/drivetrain/drivetrain_base.cc
@@ -9,7 +9,7 @@
 #include "y2024/control_loops/drivetrain/kalman_drivetrain_motor_plant.h"
 #include "y2024/control_loops/drivetrain/polydrivetrain_dog_motor_plant.h"
 
-using ::frc971::control_loops::drivetrain::DownEstimatorConfig;
+using ::frc971::control_loops::drivetrain::DownEstimatorConfigT;
 using ::frc971::control_loops::drivetrain::DrivetrainConfig;
 using ::frc971::control_loops::drivetrain::LineFollowConfig;
 
@@ -25,10 +25,10 @@
   // Yaw of the IMU relative to the robot frame.
   static constexpr double kImuYaw = 0.0;
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuFlippedX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
@@ -59,8 +59,7 @@
        0.0, std::sin(kImuYaw), std::cos(kImuYaw), 0.0, 0.0, 0.0, 1.0)
           .finished(),
       false /*is_simulated*/,
-      DownEstimatorConfig{.gravity_threshold = 0.015,
-                          .do_accel_corrections = 1000},
+      DownEstimatorConfigT{{}, 0.015, 1000},
       LineFollowConfig{
           .Q = Eigen::Matrix3d((::Eigen::DiagonalMatrix<double, 3>().diagonal()
                                     << 1.0 / ::std::pow(0.1, 2),
diff --git a/y2024_defense/control_loops/drivetrain/drivetrain_base.cc b/y2024_defense/control_loops/drivetrain/drivetrain_base.cc
index 2f33e35..b90897f 100644
--- a/y2024_defense/control_loops/drivetrain/drivetrain_base.cc
+++ b/y2024_defense/control_loops/drivetrain/drivetrain_base.cc
@@ -9,7 +9,7 @@
 #include "y2024_defense/control_loops/drivetrain/kalman_drivetrain_motor_plant.h"
 #include "y2024_defense/control_loops/drivetrain/polydrivetrain_dog_motor_plant.h"
 
-using ::frc971::control_loops::drivetrain::DownEstimatorConfig;
+using ::frc971::control_loops::drivetrain::DownEstimatorConfigT;
 using ::frc971::control_loops::drivetrain::DrivetrainConfig;
 using ::frc971::control_loops::drivetrain::LineFollowConfig;
 
@@ -25,10 +25,10 @@
   // Yaw of the IMU relative to the robot frame.
   static constexpr double kImuYaw = 0.0;
   static DrivetrainConfig<double> kDrivetrainConfig{
-      ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
-      ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
-      ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
-      ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+      ::frc971::control_loops::drivetrain::ShifterType::kSimpleShifter,
+      ::frc971::control_loops::drivetrain::LoopType::kClosedLoop,
+      ::frc971::control_loops::drivetrain::GyroType::kSpartanGyro,
+      ::frc971::control_loops::drivetrain::ImuType::kImuFlippedX,
 
       drivetrain::MakeDrivetrainLoop,
       drivetrain::MakeVelocityDrivetrainLoop,
@@ -59,8 +59,7 @@
        0.0, std::sin(kImuYaw), std::cos(kImuYaw), 0.0, 0.0, 0.0, 1.0)
           .finished(),
       false /*is_simulated*/,
-      DownEstimatorConfig{.gravity_threshold = 0.015,
-                          .do_accel_corrections = 1000},
+      DownEstimatorConfigT{{}, 0.015, 1000},
       LineFollowConfig{
           .Q = Eigen::Matrix3d((::Eigen::DiagonalMatrix<double, 3>().diagonal()
                                     << 1.0 / ::std::pow(0.1, 2),