Convert aos over to flatbuffers

Everything builds, and all the tests pass.  I suspect that some entries
are missing from the config files, but those will be found pretty
quickly on startup.

There is no logging or live introspection of queue messages.

Change-Id: I496ee01ed68f202c7851bed7e8786cee30df29f5
diff --git a/y2016/control_loops/shooter/BUILD b/y2016/control_loops/shooter/BUILD
index 8938a2b..794c4fc 100644
--- a/y2016/control_loops/shooter/BUILD
+++ b/y2016/control_loops/shooter/BUILD
@@ -1,16 +1,37 @@
 package(default_visibility = ["//visibility:public"])
 
-load("//aos/build:queues.bzl", "queue_library")
+load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
 
-queue_library(
-    name = "shooter_queue",
+flatbuffer_cc_library(
+    name = "shooter_goal_fbs",
     srcs = [
-        "shooter.q",
+        "shooter_goal.fbs",
     ],
-    deps = [
-        "//aos/controls:control_loop_queues",
-        "//frc971/control_loops:queues",
+    gen_reflections = 1,
+)
+
+flatbuffer_cc_library(
+    name = "shooter_position_fbs",
+    srcs = [
+        "shooter_position.fbs",
     ],
+    gen_reflections = 1,
+)
+
+flatbuffer_cc_library(
+    name = "shooter_output_fbs",
+    srcs = [
+        "shooter_output.fbs",
+    ],
+    gen_reflections = 1,
+)
+
+flatbuffer_cc_library(
+    name = "shooter_status_fbs",
+    srcs = [
+        "shooter_status.fbs",
+    ],
+    gen_reflections = 1,
 )
 
 genrule(
@@ -52,8 +73,11 @@
         "shooter.h",
     ],
     deps = [
+        ":shooter_goal_fbs",
+        ":shooter_output_fbs",
         ":shooter_plants",
-        ":shooter_queue",
+        ":shooter_position_fbs",
+        ":shooter_status_fbs",
         "//aos/controls:control_loop",
     ],
 )
@@ -63,10 +87,13 @@
     srcs = [
         "shooter_lib_test.cc",
     ],
+    data = ["//y2016:config.json"],
     deps = [
+        ":shooter_goal_fbs",
         ":shooter_lib",
-        ":shooter_queue",
-        "//aos:queues",
+        ":shooter_output_fbs",
+        ":shooter_position_fbs",
+        ":shooter_status_fbs",
         "//aos/controls:control_loop_test",
         "//aos/testing:googletest",
         "//frc971/control_loops:state_feedback_loop",
@@ -80,9 +107,12 @@
         "shooter_main.cc",
     ],
     deps = [
+        ":shooter_goal_fbs",
         ":shooter_lib",
-        ":shooter_queue",
+        ":shooter_output_fbs",
+        ":shooter_position_fbs",
+        ":shooter_status_fbs",
         "//aos:init",
-        "//aos/events:shm-event-loop",
+        "//aos/events:shm_event_loop",
     ],
 )
diff --git a/y2016/control_loops/shooter/shooter.cc b/y2016/control_loops/shooter/shooter.cc
index bf527ec..5156a61 100644
--- a/y2016/control_loops/shooter/shooter.cc
+++ b/y2016/control_loops/shooter/shooter.cc
@@ -2,10 +2,7 @@
 
 #include <chrono>
 
-#include "aos/controls/control_loops.q.h"
 #include "aos/logging/logging.h"
-#include "aos/logging/queue_logging.h"
-
 #include "y2016/control_loops/shooter/shooter_plant.h"
 
 namespace y2016 {
@@ -49,80 +46,99 @@
   loop_->Update(disabled);
 }
 
-void ShooterSide::SetStatus(ShooterSideStatus *status) {
+flatbuffers::Offset<ShooterSideStatus> ShooterSide::SetStatus(
+    flatbuffers::FlatBufferBuilder *fbb) {
+  ShooterSideStatus::Builder shooter_side_status_builder(*fbb);
   // Compute the oldest point in the history.
   const int oldest_history_position =
       ((history_position_ == 0) ? kHistoryLength : history_position_) - 1;
 
   // Compute the distance moved over that time period.
-  status->avg_angular_velocity =
+  const double avg_angular_velocity =
       (history_[oldest_history_position] - history_[history_position_]) /
       (::aos::time::DurationInSeconds(::aos::controls::kLoopFrequency) *
        static_cast<double>(kHistoryLength - 1));
+  shooter_side_status_builder.add_avg_angular_velocity(avg_angular_velocity);
 
-  status->angular_velocity = loop_->X_hat(1, 0);
+  shooter_side_status_builder.add_angular_velocity(loop_->X_hat(1, 0));
 
   // Ready if average angular velocity is close to the goal.
-  status->ready = (std::abs(loop_->next_R(1, 0) -
-                            status->avg_angular_velocity) < kTolerance &&
-                   loop_->next_R(1, 0) > 1.0);
+  shooter_side_status_builder.add_ready(
+      (std::abs(loop_->next_R(1, 0) - avg_angular_velocity) < kTolerance &&
+       loop_->next_R(1, 0) > 1.0));
+
+  return shooter_side_status_builder.Finish();
 }
 
 Shooter::Shooter(::aos::EventLoop *event_loop, const ::std::string &name)
-    : aos::controls::ControlLoop<ShooterQueue>(event_loop, name),
+    : aos::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
+                                                                 name),
       shots_(0),
       last_pre_shot_timeout_(::aos::monotonic_clock::min_time) {}
 
-void Shooter::RunIteration(const ShooterQueue::Goal *goal,
-                           const ShooterQueue::Position *position,
-                           ShooterQueue::Output *output,
-                           ShooterQueue::Status *status) {
+void Shooter::RunIteration(const Goal *goal, const Position *position,
+                           aos::Sender<Output>::Builder *output,
+                           aos::Sender<Status>::Builder *status) {
   const ::aos::monotonic_clock::time_point monotonic_now =
       event_loop()->monotonic_now();
   if (goal) {
     // Update position/goal for our two shooter sides.
-    left_.set_goal(goal->angular_velocity);
-    right_.set_goal(goal->angular_velocity);
-
-    // Turn the lights on if we are supposed to spin.
-    if (output) {
-      if (::std::abs(goal->angular_velocity) > 0.0) {
-        output->lights_on = true;
-        if (goal->shooting_forwards) {
-          output->forwards_flashlight = true;
-          output->backwards_flashlight = false;
-        } else {
-          output->forwards_flashlight = false;
-          output->backwards_flashlight = true;
-        }
-      }
-      if (goal->force_lights_on) {
-        output->lights_on = true;
-      }
-    }
+    left_.set_goal(goal->angular_velocity());
+    right_.set_goal(goal->angular_velocity());
   }
 
-  left_.set_position(position->theta_left);
-  right_.set_position(position->theta_right);
+  left_.set_position(position->theta_left());
+  right_.set_position(position->theta_right());
 
   left_.Update(output == nullptr);
   right_.Update(output == nullptr);
 
-  left_.SetStatus(&status->left);
-  right_.SetStatus(&status->right);
-  status->ready = (status->left.ready && status->right.ready);
+  flatbuffers::Offset<ShooterSideStatus> left_status_offset =
+      left_.SetStatus(status->fbb());
+  flatbuffers::Offset<ShooterSideStatus> right_status_offset =
+      right_.SetStatus(status->fbb());
+
+  ShooterSideStatus *left_status =
+      GetMutableTemporaryPointer(*status->fbb(), left_status_offset);
+  ShooterSideStatus *right_status =
+      GetMutableTemporaryPointer(*status->fbb(), right_status_offset);
+
+  const bool ready = (left_status->ready() && right_status->ready());
+
+  Status::Builder status_builder = status->MakeBuilder<Status>();
+  status_builder.add_ready((left_status->ready() && right_status->ready()));
+  status_builder.add_left(left_status_offset);
+  status_builder.add_right(right_status_offset);
 
   if (output) {
-    output->voltage_left = left_.voltage();
-    output->voltage_right = right_.voltage();
+    Output::Builder output_builder = output->MakeBuilder<Output>();
 
+    output_builder.add_voltage_left(left_.voltage());
+    output_builder.add_voltage_right(right_.voltage());
+    // Turn the lights on if we are supposed to spin.
     if (goal) {
+      bool lights_on = false;
+      if (::std::abs(goal->angular_velocity()) > 0.0) {
+        lights_on = true;
+        if (goal->shooting_forwards()) {
+          output_builder.add_forwards_flashlight(true);
+          output_builder.add_backwards_flashlight(false);
+        } else {
+          output_builder.add_forwards_flashlight(false);
+          output_builder.add_backwards_flashlight(true);
+        }
+      }
+      if (goal->force_lights_on()) {
+        lights_on = true;
+      }
+      output_builder.add_lights_on(lights_on);
+
       bool shoot = false;
       switch (state_) {
         case ShooterLatchState::PASS_THROUGH:
-          if (goal->push_to_shooter) {
-            if (::std::abs(goal->angular_velocity) > 10) {
-              if (status->ready) {
+          if (goal->push_to_shooter()) {
+            if (::std::abs(goal->angular_velocity()) > 10) {
+              if (ready) {
                 state_ = ShooterLatchState::WAITING_FOR_SPINDOWN;
                 shoot = true;
               }
@@ -134,22 +150,22 @@
           break;
         case ShooterLatchState::WAITING_FOR_SPINDOWN:
           shoot = true;
-          if (left_.velocity() < goal->angular_velocity * 0.9 ||
-              right_.velocity() < goal->angular_velocity * 0.9) {
+          if (left_.velocity() < goal->angular_velocity() * 0.9 ||
+              right_.velocity() < goal->angular_velocity() * 0.9) {
             state_ = ShooterLatchState::WAITING_FOR_SPINUP;
           }
-          if (::std::abs(goal->angular_velocity) < 10 ||
+          if (::std::abs(goal->angular_velocity()) < 10 ||
               last_pre_shot_timeout_ < monotonic_now) {
             state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
           }
           break;
         case ShooterLatchState::WAITING_FOR_SPINUP:
           shoot = true;
-          if (left_.velocity() > goal->angular_velocity * 0.95 &&
-              right_.velocity() > goal->angular_velocity * 0.95) {
+          if (left_.velocity() > goal->angular_velocity() * 0.95 &&
+              right_.velocity() > goal->angular_velocity() * 0.95) {
             state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
           }
-          if (::std::abs(goal->angular_velocity) < 10 ||
+          if (::std::abs(goal->angular_velocity()) < 10 ||
               last_pre_shot_timeout_ < monotonic_now) {
             state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
           }
@@ -160,18 +176,22 @@
           break;
         case ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE:
           shoot = true;
-          if (!goal->push_to_shooter) {
+          if (!goal->push_to_shooter()) {
             state_ = ShooterLatchState::PASS_THROUGH;
           }
           break;
       }
 
-      output->clamp_open = goal->clamp_open;
-      output->push_to_shooter = shoot;
+      output_builder.add_clamp_open(goal->clamp_open());
+      output_builder.add_push_to_shooter(shoot);
     }
+
+    output->Send(output_builder.Finish());
   }
 
-  status->shots = shots_;
+  status_builder.add_shots(shots_);
+
+  status->Send(status_builder.Finish());
 }
 
 }  // namespace shooter
diff --git a/y2016/control_loops/shooter/shooter.h b/y2016/control_loops/shooter/shooter.h
index 9e6968f..07fee84 100644
--- a/y2016/control_loops/shooter/shooter.h
+++ b/y2016/control_loops/shooter/shooter.h
@@ -4,11 +4,14 @@
 #include <memory>
 
 #include "aos/controls/control_loop.h"
-#include "aos/events/event-loop.h"
+#include "aos/events/event_loop.h"
 #include "aos/time/time.h"
 #include "frc971/control_loops/state_feedback_loop.h"
-#include "y2016/control_loops/shooter/shooter.q.h"
+#include "y2016/control_loops/shooter/shooter_goal_generated.h"
 #include "y2016/control_loops/shooter/shooter_integral_plant.h"
+#include "y2016/control_loops/shooter/shooter_output_generated.h"
+#include "y2016/control_loops/shooter/shooter_position_generated.h"
+#include "y2016/control_loops/shooter/shooter_status_generated.h"
 
 namespace y2016 {
 namespace control_loops {
@@ -28,7 +31,8 @@
   void set_position(double current_position);
 
   // Populates the status structure.
-  void SetStatus(ShooterSideStatus *status);
+  flatbuffers::Offset<ShooterSideStatus> SetStatus(
+      flatbuffers::FlatBufferBuilder *fbb);
 
   // Returns the control loop calculated voltage.
   double voltage() const;
@@ -53,11 +57,11 @@
   DISALLOW_COPY_AND_ASSIGN(ShooterSide);
 };
 
-class Shooter : public ::aos::controls::ControlLoop<ShooterQueue> {
+class Shooter
+    : public ::aos::controls::ControlLoop<Goal, Position, Status, Output> {
  public:
-  explicit Shooter(
-      ::aos::EventLoop *event_loop,
-      const ::std::string &name = ".y2016.control_loops.shooter.shooter_queue");
+  explicit Shooter(::aos::EventLoop *event_loop,
+                   const ::std::string &name = "/shooter");
 
   enum class ShooterLatchState {
     // Any shoot commands will be passed through without modification.
@@ -73,10 +77,9 @@
   };
 
  protected:
-  void RunIteration(const ShooterQueue::Goal *goal,
-                    const ShooterQueue::Position *position,
-                    ShooterQueue::Output *output,
-                    ShooterQueue::Status *status) override;
+  void RunIteration(const Goal *goal, const Position *position,
+                    aos::Sender<Output>::Builder *output,
+                    aos::Sender<Status>::Builder *status) override;
 
  private:
   ShooterSide left_, right_;
diff --git a/y2016/control_loops/shooter/shooter.q b/y2016/control_loops/shooter/shooter.q
deleted file mode 100644
index 583b762..0000000
--- a/y2016/control_loops/shooter/shooter.q
+++ /dev/null
@@ -1,81 +0,0 @@
-package y2016.control_loops.shooter;
-
-import "aos/controls/control_loops.q";
-import "frc971/control_loops/control_loops.q";
-
-struct ShooterSideStatus {
-  // True if the shooter side is up to speed and stable.
-  bool ready;
-  // The current average velocity in radians/second.
-  double avg_angular_velocity;
-  // The current instantaneous filtered velocity in radians/second.
-  double angular_velocity;
-};
-
-// Published on ".y2016.control_loops.shooter.shooter_queue"
-queue_group ShooterQueue {
-  implements aos.control_loops.ControlLoop;
-
-  // All angles are in radians, and angular velocities are in radians/second.
-  // For all angular velocities, positive is shooting the ball out of the robot.
-
-  message Goal {
-    // Angular velocity goals in radians/second.
-    double angular_velocity;
-
-    bool clamp_open; // True to release our clamp on the ball.
-    // True to push the ball into the shooter.
-    // If we are in the act of shooting with a goal velocity != 0, wait until it
-    // is up to speed, push the ball into the shooter, and then wait until it
-    // spins up and down before letting the piston be released.
-    bool push_to_shooter;
-
-    // Forces the lights on.
-    bool force_lights_on;
-
-    // If true, the robot is shooting forwards.
-    bool shooting_forwards;
-  };
-
-  message Position {
-    // Wheel angle in radians/second.
-    double theta_left;
-    double theta_right;
-  };
-
-  message Status {
-    // Left side status.
-    ShooterSideStatus left;
-    // Right side status.
-    ShooterSideStatus right;
-
-    // True if the shooter is ready.  It is better to compare the velocities
-    // directly so there isn't confusion on if the goal is up to date.
-    bool ready;
-
-    // The number of shots that have been fired since the start of the shooter
-    // control loop.
-    uint32_t shots;
-  };
-
-  message Output {
-    // Voltage in volts of the left and right shooter motors.
-    double voltage_left;
-    double voltage_right;
-
-    // See comments on the identical fields in Goal for details.
-    bool clamp_open;
-    bool push_to_shooter;
-
-    // If true, the lights are on.
-    bool lights_on;
-
-    bool forwards_flashlight;
-    bool backwards_flashlight;
-  };
-
-  queue Goal goal;
-  queue Position position;
-  queue Output output;
-  queue Status status;
-};
diff --git a/y2016/control_loops/shooter/shooter_goal.fbs b/y2016/control_loops/shooter/shooter_goal.fbs
new file mode 100644
index 0000000..f041503
--- /dev/null
+++ b/y2016/control_loops/shooter/shooter_goal.fbs
@@ -0,0 +1,23 @@
+namespace y2016.control_loops.shooter;
+
+// All angles are in radians, and angular velocities are in radians/second.
+// For all angular velocities, positive is shooting the ball out of the robot.
+table Goal {
+  // Angular velocity goals in radians/second.
+  angular_velocity:double;
+
+  clamp_open:bool; // True to release our clamp on the ball.
+  // True to push the ball into the shooter.
+  // If we are in the act of shooting with a goal velocity != 0, wait until it
+  // is up to speed, push the ball into the shooter, and then wait until it
+  // spins up and down before letting the piston be released.
+  push_to_shooter:bool;
+
+  // Forces the lights on.
+  force_lights_on:bool;
+
+  // If true, the robot is shooting forwards.
+  shooting_forwards:bool;
+}
+
+root_type Goal;
diff --git a/y2016/control_loops/shooter/shooter_lib_test.cc b/y2016/control_loops/shooter/shooter_lib_test.cc
index 30b5166..b432049 100644
--- a/y2016/control_loops/shooter/shooter_lib_test.cc
+++ b/y2016/control_loops/shooter/shooter_lib_test.cc
@@ -5,13 +5,15 @@
 #include <chrono>
 #include <memory>
 
-#include "gtest/gtest.h"
-#include "aos/queue.h"
 #include "aos/controls/control_loop_test.h"
 #include "frc971/control_loops/team_number_test_environment.h"
-#include "y2016/control_loops/shooter/shooter.q.h"
+#include "gtest/gtest.h"
 #include "y2016/control_loops/shooter/shooter.h"
+#include "y2016/control_loops/shooter/shooter_goal_generated.h"
+#include "y2016/control_loops/shooter/shooter_output_generated.h"
 #include "y2016/control_loops/shooter/shooter_plant.h"
+#include "y2016/control_loops/shooter/shooter_position_generated.h"
+#include "y2016/control_loops/shooter/shooter_status_generated.h"
 
 using ::frc971::control_loops::testing::kTeamNumber;
 
@@ -50,11 +52,8 @@
   // Constructs a shooter simulation.
   ShooterSimulation(::aos::EventLoop *event_loop, chrono::nanoseconds dt)
       : event_loop_(event_loop),
-        shooter_position_sender_(
-            event_loop_->MakeSender<ShooterQueue::Position>(
-                ".y2016.control_loops.shooter.shooter_queue.position")),
-        shooter_output_fetcher_(event_loop_->MakeFetcher<ShooterQueue::Output>(
-            ".y2016.control_loops.shooter.shooter_queue.output")),
+        shooter_position_sender_(event_loop_->MakeSender<Position>("/shooter")),
+        shooter_output_fetcher_(event_loop_->MakeFetcher<Output>("/shooter")),
         shooter_plant_left_(new ShooterPlant(
             ::y2016::control_loops::shooter::MakeShooterPlant())),
         shooter_plant_right_(new ShooterPlant(
@@ -73,12 +72,14 @@
 
   // Sends a queue message with the position of the shooter.
   void SendPositionMessage() {
-    ::aos::Sender<ShooterQueue::Position>::Message position =
-        shooter_position_sender_.MakeMessage();
+    ::aos::Sender<Position>::Builder builder =
+        shooter_position_sender_.MakeBuilder();
 
-    position->theta_left = shooter_plant_left_->Y(0, 0);
-    position->theta_right = shooter_plant_right_->Y(0, 0);
-    position.Send();
+    Position::Builder position_builder = builder.MakeBuilder<Position>();
+
+    position_builder.add_theta_left(shooter_plant_left_->Y(0, 0));
+    position_builder.add_theta_right(shooter_plant_right_->Y(0, 0));
+    builder.Send(position_builder.Finish());
   }
 
   void set_left_voltage_offset(double voltage_offset) {
@@ -95,9 +96,9 @@
 
     ::Eigen::Matrix<double, 1, 1> U_left;
     ::Eigen::Matrix<double, 1, 1> U_right;
-    U_left(0, 0) = shooter_output_fetcher_->voltage_left +
+    U_left(0, 0) = shooter_output_fetcher_->voltage_left() +
                    shooter_plant_left_->voltage_offset();
-    U_right(0, 0) = shooter_output_fetcher_->voltage_right +
+    U_right(0, 0) = shooter_output_fetcher_->voltage_right() +
                     shooter_plant_right_->voltage_offset();
 
     shooter_plant_left_->Update(U_left);
@@ -107,8 +108,8 @@
  private:
   ::aos::EventLoop *event_loop_;
 
-  ::aos::Sender<ShooterQueue::Position> shooter_position_sender_;
-  ::aos::Fetcher<ShooterQueue::Output> shooter_output_fetcher_;
+  ::aos::Sender<Position> shooter_position_sender_;
+  ::aos::Fetcher<Output> shooter_output_fetcher_;
 
   ::std::unique_ptr<ShooterPlant> shooter_plant_left_, shooter_plant_right_;
 
@@ -118,18 +119,16 @@
 class ShooterTest : public ::aos::testing::ControlLoopTest {
  protected:
   ShooterTest()
-      : ::aos::testing::ControlLoopTest(chrono::microseconds(5000)),
+      : ::aos::testing::ControlLoopTest(
+            aos::configuration::ReadConfig("y2016/config.json"),
+            chrono::microseconds(5000)),
         test_event_loop_(MakeEventLoop()),
-        shooter_goal_fetcher_(test_event_loop_->MakeFetcher<ShooterQueue::Goal>(
-            ".y2016.control_loops.shooter.shooter_queue.goal")),
-        shooter_goal_sender_(test_event_loop_->MakeSender<ShooterQueue::Goal>(
-            ".y2016.control_loops.shooter.shooter_queue.goal")),
+        shooter_goal_fetcher_(test_event_loop_->MakeFetcher<Goal>("/shooter")),
+        shooter_goal_sender_(test_event_loop_->MakeSender<Goal>("/shooter")),
         shooter_status_fetcher_(
-            test_event_loop_->MakeFetcher<ShooterQueue::Status>(
-                ".y2016.control_loops.shooter.shooter_queue.status")),
+            test_event_loop_->MakeFetcher<Status>("/shooter")),
         shooter_output_fetcher_(
-            test_event_loop_->MakeFetcher<ShooterQueue::Output>(
-                ".y2016.control_loops.shooter.shooter_queue.output")),
+            test_event_loop_->MakeFetcher<Output>("/shooter")),
         shooter_event_loop_(MakeEventLoop()),
         shooter_(shooter_event_loop_.get()),
         shooter_plant_event_loop_(MakeEventLoop()),
@@ -144,22 +143,22 @@
     EXPECT_TRUE(shooter_goal_fetcher_.get() != nullptr);
     EXPECT_TRUE(shooter_status_fetcher_.get() != nullptr);
 
-    EXPECT_NEAR(shooter_goal_fetcher_->angular_velocity,
-                shooter_status_fetcher_->left.angular_velocity, 10.0);
-    EXPECT_NEAR(shooter_goal_fetcher_->angular_velocity,
-                shooter_status_fetcher_->right.angular_velocity, 10.0);
+    EXPECT_NEAR(shooter_goal_fetcher_->angular_velocity(),
+                shooter_status_fetcher_->left()->angular_velocity(), 10.0);
+    EXPECT_NEAR(shooter_goal_fetcher_->angular_velocity(),
+                shooter_status_fetcher_->right()->angular_velocity(), 10.0);
 
-    EXPECT_NEAR(shooter_goal_fetcher_->angular_velocity,
-                shooter_status_fetcher_->left.avg_angular_velocity, 10.0);
-    EXPECT_NEAR(shooter_goal_fetcher_->angular_velocity,
-                shooter_status_fetcher_->right.avg_angular_velocity, 10.0);
+    EXPECT_NEAR(shooter_goal_fetcher_->angular_velocity(),
+                shooter_status_fetcher_->left()->avg_angular_velocity(), 10.0);
+    EXPECT_NEAR(shooter_goal_fetcher_->angular_velocity(),
+                shooter_status_fetcher_->right()->avg_angular_velocity(), 10.0);
   }
 
   ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
-  ::aos::Fetcher<ShooterQueue::Goal> shooter_goal_fetcher_;
-  ::aos::Sender<ShooterQueue::Goal> shooter_goal_sender_;
-  ::aos::Fetcher<ShooterQueue::Status> shooter_status_fetcher_;
-  ::aos::Fetcher<ShooterQueue::Output> shooter_output_fetcher_;
+  ::aos::Fetcher<Goal> shooter_goal_fetcher_;
+  ::aos::Sender<Goal> shooter_goal_sender_;
+  ::aos::Fetcher<Status> shooter_status_fetcher_;
+  ::aos::Fetcher<Output> shooter_output_fetcher_;
 
   // Create a control loop and simulation.
   ::std::unique_ptr<::aos::EventLoop> shooter_event_loop_;
@@ -173,9 +172,10 @@
 TEST_F(ShooterTest, DoesNothing) {
   SetEnabled(true);
   {
-    auto message = shooter_goal_sender_.MakeMessage();
-    message->angular_velocity = 0.0;
-    EXPECT_TRUE(message.Send());
+    auto builder = shooter_goal_sender_.MakeBuilder();
+    Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+    goal_builder.add_angular_velocity(0.0);
+    EXPECT_TRUE(builder.Send(goal_builder.Finish()));
   }
 
   RunFor(dt());
@@ -183,8 +183,8 @@
   VerifyNearGoal();
 
   EXPECT_TRUE(shooter_output_fetcher_.Fetch());
-  EXPECT_EQ(shooter_output_fetcher_->voltage_left, 0.0);
-  EXPECT_EQ(shooter_output_fetcher_->voltage_right, 0.0);
+  EXPECT_EQ(shooter_output_fetcher_->voltage_left(), 0.0);
+  EXPECT_EQ(shooter_output_fetcher_->voltage_right(), 0.0);
 }
 
 // Tests that the shooter spins up to speed and that it then spins down
@@ -193,32 +193,34 @@
   SetEnabled(true);
   // Spin up.
   {
-    auto message = shooter_goal_sender_.MakeMessage();
-    message->angular_velocity = 450.0;
-    EXPECT_TRUE(message.Send());
+    auto builder = shooter_goal_sender_.MakeBuilder();
+    Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+    goal_builder.add_angular_velocity(450.0);
+    EXPECT_TRUE(builder.Send(goal_builder.Finish()));
   }
 
   RunFor(chrono::seconds(1));
   VerifyNearGoal();
   shooter_status_fetcher_.Fetch();
-  EXPECT_TRUE(shooter_status_fetcher_->ready);
+  EXPECT_TRUE(shooter_status_fetcher_->ready());
   {
-    auto message = shooter_goal_sender_.MakeMessage();
-    message->angular_velocity = 0.0;
-    EXPECT_TRUE(message.Send());
+    auto builder = shooter_goal_sender_.MakeBuilder();
+    Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+    goal_builder.add_angular_velocity(0.0);
+    EXPECT_TRUE(builder.Send(goal_builder.Finish()));
   }
 
   // Make sure we don't apply voltage on spin-down.
   RunFor(dt());
   EXPECT_TRUE(shooter_output_fetcher_.Fetch());
-  EXPECT_EQ(0.0, shooter_output_fetcher_->voltage_left);
-  EXPECT_EQ(0.0, shooter_output_fetcher_->voltage_right);
+  EXPECT_EQ(0.0, shooter_output_fetcher_->voltage_left());
+  EXPECT_EQ(0.0, shooter_output_fetcher_->voltage_right());
 
   // Continue to stop.
   RunFor(chrono::seconds(5));
   EXPECT_TRUE(shooter_output_fetcher_.Fetch());
-  EXPECT_EQ(0.0, shooter_output_fetcher_->voltage_left);
-  EXPECT_EQ(0.0, shooter_output_fetcher_->voltage_right);
+  EXPECT_EQ(0.0, shooter_output_fetcher_->voltage_left());
+  EXPECT_EQ(0.0, shooter_output_fetcher_->voltage_right());
 }
 
 // Tests that the shooter doesn't say it is ready if one side isn't up to speed.
@@ -228,9 +230,10 @@
   SetEnabled(true);
   // Spin up.
   {
-    auto message = shooter_goal_sender_.MakeMessage();
-    message->angular_velocity = 20.0;
-    EXPECT_TRUE(message.Send());
+    auto builder = shooter_goal_sender_.MakeBuilder();
+    Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+    goal_builder.add_angular_velocity(20.0);
+    EXPECT_TRUE(builder.Send(goal_builder.Finish()));
   }
   // Cause problems by adding a voltage error on one side.
   shooter_plant_.set_right_voltage_offset(-4.0);
@@ -243,9 +246,9 @@
   EXPECT_TRUE(shooter_status_fetcher_.get() != nullptr);
 
   // Left should be up to speed, right shouldn't.
-  EXPECT_TRUE(shooter_status_fetcher_->left.ready);
-  EXPECT_FALSE(shooter_status_fetcher_->right.ready);
-  EXPECT_FALSE(shooter_status_fetcher_->ready);
+  EXPECT_TRUE(shooter_status_fetcher_->left()->ready());
+  EXPECT_FALSE(shooter_status_fetcher_->right()->ready());
+  EXPECT_FALSE(shooter_status_fetcher_->ready());
 
   RunFor(chrono::seconds(5));
 
@@ -256,22 +259,23 @@
   EXPECT_TRUE(shooter_status_fetcher_.get() != nullptr);
 
   // Both should be up to speed.
-  EXPECT_TRUE(shooter_status_fetcher_->left.ready);
-  EXPECT_TRUE(shooter_status_fetcher_->right.ready);
-  EXPECT_TRUE(shooter_status_fetcher_->ready);
+  EXPECT_TRUE(shooter_status_fetcher_->left()->ready());
+  EXPECT_TRUE(shooter_status_fetcher_->right()->ready());
+  EXPECT_TRUE(shooter_status_fetcher_->ready());
 }
 
 // Tests that the shooter can spin up nicely after being disabled for a while.
 TEST_F(ShooterTest, Disabled) {
   {
-    auto message = shooter_goal_sender_.MakeMessage();
-    message->angular_velocity = 200.0;
-    EXPECT_TRUE(message.Send());
+    auto builder = shooter_goal_sender_.MakeBuilder();
+    Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+    goal_builder.add_angular_velocity(200.0);
+    EXPECT_TRUE(builder.Send(goal_builder.Finish()));
   }
   RunFor(chrono::seconds(5));
   EXPECT_TRUE(shooter_output_fetcher_.Fetch());
-  EXPECT_EQ(shooter_output_fetcher_->voltage_left, 0.0);
-  EXPECT_EQ(shooter_output_fetcher_->voltage_right, 0.0);
+  EXPECT_EQ(shooter_output_fetcher_->voltage_left(), 0.0);
+  EXPECT_EQ(shooter_output_fetcher_->voltage_right(), 0.0);
 
   SetEnabled(true);
   RunFor(chrono::seconds(5));
diff --git a/y2016/control_loops/shooter/shooter_main.cc b/y2016/control_loops/shooter/shooter_main.cc
index b9737fd..6e46114 100644
--- a/y2016/control_loops/shooter/shooter_main.cc
+++ b/y2016/control_loops/shooter/shooter_main.cc
@@ -1,12 +1,15 @@
 #include "y2016/control_loops/shooter/shooter.h"
 
-#include "aos/events/shm-event-loop.h"
+#include "aos/events/shm_event_loop.h"
 #include "aos/init.h"
 
 int main() {
   ::aos::InitNRT(true);
 
-  ::aos::ShmEventLoop event_loop;
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig("config.json");
+
+  ::aos::ShmEventLoop event_loop(&config.message());
   ::y2016::control_loops::shooter::Shooter shooter(&event_loop);
 
   event_loop.Run();
diff --git a/y2016/control_loops/shooter/shooter_output.fbs b/y2016/control_loops/shooter/shooter_output.fbs
new file mode 100644
index 0000000..6d7fcdf
--- /dev/null
+++ b/y2016/control_loops/shooter/shooter_output.fbs
@@ -0,0 +1,19 @@
+namespace y2016.control_loops.shooter;
+
+table Output {
+  // Voltage in volts of the left and right shooter motors.
+  voltage_left:double;
+  voltage_right:double;
+
+  // See comments on the identical fields in Goal for details.
+  clamp_open:bool;
+  push_to_shooter:bool;
+
+  // If true, the lights are on.
+  lights_on:bool;
+
+  forwards_flashlight:bool;
+  backwards_flashlight:bool;
+}
+
+root_type Output;
diff --git a/y2016/control_loops/shooter/shooter_position.fbs b/y2016/control_loops/shooter/shooter_position.fbs
new file mode 100644
index 0000000..d97268c
--- /dev/null
+++ b/y2016/control_loops/shooter/shooter_position.fbs
@@ -0,0 +1,11 @@
+namespace y2016.control_loops.shooter;
+
+// All angles are in radians, and angular velocities are in radians/second.
+// For all angular velocities, positive is shooting the ball out of the robot.
+table Position {
+  // Wheel angle in radians/second.
+  theta_left:double;
+  theta_right:double;
+}
+
+root_type Position;
diff --git a/y2016/control_loops/shooter/shooter_status.fbs b/y2016/control_loops/shooter/shooter_status.fbs
new file mode 100644
index 0000000..6f6262b
--- /dev/null
+++ b/y2016/control_loops/shooter/shooter_status.fbs
@@ -0,0 +1,27 @@
+namespace y2016.control_loops.shooter;
+
+table ShooterSideStatus {
+  // True if the shooter side is up to speed and stable.
+  ready:bool;
+  // The current average velocity in radians/second.
+  avg_angular_velocity:double;
+  // The current instantaneous filtered velocity in radians/second.
+  angular_velocity:double;
+}
+
+table Status {
+  // Left side status.
+  left:ShooterSideStatus;
+  // Right side status.
+  right:ShooterSideStatus;
+
+  // True if the shooter is ready.  It is better to compare the velocities
+  // directly so there isn't confusion on if the goal is up to date.
+  ready:bool;
+
+  // The number of shots that have been fired since the start of the shooter
+  // control loop.
+  shots:uint;
+}
+
+root_type Status;