Allow constructing control loops from flatbuffers

The core changes here are to:
* Allow constructing StateFeedbackLoop's from flatbuffers using the
  code in *state_feedback_loop_converters.*
* Add constructors to the single-dof subsystem class to make use of
  this.
* Add code to control_loops.py to generate JSON files with the requisite
  constants (these end up containing identical information to the
  generated .cc files).
* Add interfaces to actually support the new JSON codegen to single-dof
  subsystem classes.
* Convert all of the drivetrains over to generating these. This I mostly
  do so that I can write a test where Iconfirm that the .cc files and
  the JSON files generate exactly the same content.

Change-Id: Iceac48f25ecac96200b7bf992c8f34a15fe6800c
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/motors/seems_reasonable/BUILD b/motors/seems_reasonable/BUILD
index b899ffb..63fea8a 100644
--- a/motors/seems_reasonable/BUILD
+++ b/motors/seems_reasonable/BUILD
@@ -34,8 +34,10 @@
     outs = [
         "drivetrain_dog_motor_plant.h",
         "drivetrain_dog_motor_plant.cc",
+        "drivetrain_dog_motor_plant.json",
         "kalman_drivetrain_motor_plant.h",
         "kalman_drivetrain_motor_plant.cc",
+        "kalman_drivetrain_motor_plant.json",
     ],
     cmd = "$(location :drivetrain) $(OUTS)",
     target_compatible_with = ["@platforms//os:none"],
@@ -49,10 +51,13 @@
     outs = [
         "polydrivetrain_dog_motor_plant.h",
         "polydrivetrain_dog_motor_plant.cc",
+        "polydrivetrain_dog_motor_plant.json",
         "polydrivetrain_cim_plant.h",
         "polydrivetrain_cim_plant.cc",
+        "polydrivetrain_cim_plant.json",
         "hybrid_velocity_drivetrain.h",
         "hybrid_velocity_drivetrain.cc",
+        "hybrid_velocity_drivetrain.json",
     ],
     cmd = "$(location :polydrivetrain) $(OUTS)",
     target_compatible_with = ["@platforms//os:none"],
diff --git a/motors/seems_reasonable/drivetrain.py b/motors/seems_reasonable/drivetrain.py
index ad3d92a..1eeeb42 100644
--- a/motors/seems_reasonable/drivetrain.py
+++ b/motors/seems_reasonable/drivetrain.py
@@ -26,12 +26,12 @@
     argv = FLAGS(argv)
     glog.init()
 
-    if len(argv) != 5:
-        glog.error("Expected .h file name and .cc file name")
+    if len(argv) != 7:
+        glog.error("Expected .h, .cc, and .json filenames")
     else:
         # Write the generated constants out to a file.
-        drivetrain.WriteDrivetrain(argv[1:3],
-                                   argv[3:5], ['motors', 'seems_reasonable'],
+        drivetrain.WriteDrivetrain(argv[1:4],
+                                   argv[4:7], ['motors', 'seems_reasonable'],
                                    kDrivetrain,
                                    scalar_type='float')
 
diff --git a/motors/seems_reasonable/polydrivetrain.py b/motors/seems_reasonable/polydrivetrain.py
index 665739f..505ed38 100644
--- a/motors/seems_reasonable/polydrivetrain.py
+++ b/motors/seems_reasonable/polydrivetrain.py
@@ -20,12 +20,12 @@
 def main(argv):
     if FLAGS.plot:
         polydrivetrain.PlotPolyDrivetrainMotions(drivetrain.kDrivetrain)
-    elif len(argv) != 7:
-        glog.fatal('Expected .h file name and .cc file name')
+    elif len(argv) != 10:
+        glog.fatal('Expected .h, .cc, and .json filenames')
     else:
-        polydrivetrain.WritePolyDrivetrain(argv[1:3],
-                                           argv[3:5],
-                                           argv[5:7],
+        polydrivetrain.WritePolyDrivetrain(argv[1:4],
+                                           argv[4:7],
+                                           argv[7:10],
                                            ['motors', 'seems_reasonable'],
                                            drivetrain.kDrivetrain,
                                            scalar_type='float')