Convert control loop tests over to simulated event loop

This makes it so that we properly only use ShmEventLoop for running in
realtime on a robot.  Very nice.

Change-Id: I46b770b336f59e08cfaf28511b3bd5689f72fff1
diff --git a/y2018/control_loops/drivetrain/drivetrain_main.cc b/y2018/control_loops/drivetrain/drivetrain_main.cc
index 038497a..1bb1dc0 100644
--- a/y2018/control_loops/drivetrain/drivetrain_main.cc
+++ b/y2018/control_loops/drivetrain/drivetrain_main.cc
@@ -7,14 +7,17 @@
 using ::frc971::control_loops::drivetrain::DrivetrainLoop;
 
 int main() {
-  ::aos::Init();
+  ::aos::InitNRT(true);
+
   ::aos::ShmEventLoop event_loop;
   ::frc971::control_loops::drivetrain::DeadReckonEkf localizer(
-      ::y2018::control_loops::drivetrain::GetDrivetrainConfig());
+      &event_loop, ::y2018::control_loops::drivetrain::GetDrivetrainConfig());
   DrivetrainLoop drivetrain(
       ::y2018::control_loops::drivetrain::GetDrivetrainConfig(), &event_loop,
       &localizer);
-  drivetrain.Run();
+
+  event_loop.Run();
+
   ::aos::Cleanup();
   return 0;
 }
diff --git a/y2018/control_loops/superstructure/BUILD b/y2018/control_loops/superstructure/BUILD
index 1a2aa5e..5dabd1b 100644
--- a/y2018/control_loops/superstructure/BUILD
+++ b/y2018/control_loops/superstructure/BUILD
@@ -41,6 +41,7 @@
     srcs = [
         "superstructure_lib_test.cc",
     ],
+    shard_count = 5,
     deps = [
         ":superstructure_lib",
         ":superstructure_queue",
diff --git a/y2018/control_loops/superstructure/superstructure_lib_test.cc b/y2018/control_loops/superstructure/superstructure_lib_test.cc
index 202c428..1d4cf5d 100644
--- a/y2018/control_loops/superstructure/superstructure_lib_test.cc
+++ b/y2018/control_loops/superstructure/superstructure_lib_test.cc
@@ -187,8 +187,9 @@
 
 class SuperstructureSimulation {
  public:
-  SuperstructureSimulation()
-      : left_intake_(::y2018::control_loops::superstructure::intake::
+  SuperstructureSimulation(::aos::EventLoop *event_loop)
+      : event_loop_(event_loop),
+        left_intake_(::y2018::control_loops::superstructure::intake::
                          MakeDelayedIntakePlant(),
                      constants::GetValues().left_intake.zeroing),
         right_intake_(::y2018::control_loops::superstructure::intake::
@@ -196,17 +197,32 @@
                       constants::GetValues().right_intake.zeroing),
         arm_(constants::GetValues().arm_proximal.zeroing,
              constants::GetValues().arm_distal.zeroing),
-        superstructure_queue_(".y2018.control_loops.superstructure",
-                              ".y2018.control_loops.superstructure.goal",
-                              ".y2018.control_loops.superstructure.output",
-                              ".y2018.control_loops.superstructure.status",
-                              ".y2018.control_loops.superstructure.position") {
+        superstructure_position_sender_(
+            event_loop_->MakeSender<SuperstructureQueue::Position>(
+                ".y2018.control_loops.superstructure.position")),
+        superstructure_status_fetcher_(
+            event_loop_->MakeFetcher<SuperstructureQueue::Status>(
+                ".y2018.control_loops.superstructure.status")),
+        superstructure_output_fetcher_(
+            event_loop_->MakeFetcher<SuperstructureQueue::Output>(
+                ".y2018.control_loops.superstructure.output")) {
     // Start the intake out in the middle by default.
     InitializeIntakePosition((constants::Values::kIntakeRange().lower +
                               constants::Values::kIntakeRange().upper) /
                              2.0);
 
     InitializeArmPosition(arm::UpPoint());
+
+    phased_loop_handle_ = event_loop_->AddPhasedLoop(
+        [this](int) {
+          // Skip this the first time.
+          if (!first_) {
+            Simulate();
+          }
+          first_ = false;
+          SendPositionMessage();
+        },
+        ::std::chrono::microseconds(5050));
   }
 
   void InitializeIntakePosition(double start_pos) {
@@ -219,8 +235,7 @@
   }
 
   void SendPositionMessage() {
-    ::aos::ScopedMessagePtr<SuperstructureQueue::Position> position =
-        superstructure_queue_.position.MakeMessage();
+    auto position = superstructure_position_sender_.MakeMessage();
 
     left_intake_.GetSensorValues(&position->left_intake);
     right_intake_.GetSensorValues(&position->right_intake);
@@ -245,110 +260,116 @@
 
   // Simulates the intake for a single timestep.
   void Simulate() {
-    ASSERT_TRUE(superstructure_queue_.output.FetchLatest());
-    ASSERT_TRUE(superstructure_queue_.status.FetchLatest());
+    ASSERT_TRUE(superstructure_output_fetcher_.Fetch());
+    ASSERT_TRUE(superstructure_status_fetcher_.Fetch());
 
-    left_intake_.Simulate(superstructure_queue_.output->left_intake);
-    right_intake_.Simulate(superstructure_queue_.output->right_intake);
+    left_intake_.Simulate(superstructure_output_fetcher_->left_intake);
+    right_intake_.Simulate(superstructure_output_fetcher_->right_intake);
     arm_.Simulate((::Eigen::Matrix<double, 2, 1>()
-                       << superstructure_queue_.output->voltage_proximal,
-                   superstructure_queue_.output->voltage_distal)
+                       << superstructure_output_fetcher_->voltage_proximal,
+                   superstructure_output_fetcher_->voltage_distal)
                       .finished(),
-                  superstructure_queue_.output->release_arm_brake);
+                  superstructure_output_fetcher_->release_arm_brake);
   }
 
  private:
+  ::aos::EventLoop *event_loop_;
+  ::aos::PhasedLoopHandler *phased_loop_handle_ = nullptr;
+
   IntakeSideSimulation left_intake_;
   IntakeSideSimulation right_intake_;
   ArmSimulation arm_;
 
-  SuperstructureQueue superstructure_queue_;
+  ::aos::Sender<SuperstructureQueue::Position> superstructure_position_sender_;
+  ::aos::Fetcher<SuperstructureQueue::Status> superstructure_status_fetcher_;
+  ::aos::Fetcher<SuperstructureQueue::Output> superstructure_output_fetcher_;
+
+  bool first_ = true;
 };
 
 class SuperstructureTest : public ::aos::testing::ControlLoopTest {
  protected:
   SuperstructureTest()
-      : superstructure_queue_(".y2018.control_loops.superstructure",
-                              ".y2018.control_loops.superstructure.goal",
-                              ".y2018.control_loops.superstructure.output",
-                              ".y2018.control_loops.superstructure.status",
-                              ".y2018.control_loops.superstructure.position"),
-        superstructure_(&event_loop_, ".y2018.control_loops.superstructure") {
+      : ::aos::testing::ControlLoopTest(::std::chrono::microseconds(5050)),
+        test_event_loop_(MakeEventLoop()),
+        superstructure_goal_fetcher_(
+            test_event_loop_->MakeFetcher<SuperstructureQueue::Goal>(
+                ".y2018.control_loops.superstructure.goal")),
+        superstructure_goal_sender_(
+            test_event_loop_->MakeSender<SuperstructureQueue::Goal>(
+                ".y2018.control_loops.superstructure.goal")),
+        superstructure_status_fetcher_(
+            test_event_loop_->MakeFetcher<SuperstructureQueue::Status>(
+                ".y2018.control_loops.superstructure.status")),
+        superstructure_output_fetcher_(
+            test_event_loop_->MakeFetcher<SuperstructureQueue::Output>(
+                ".y2018.control_loops.superstructure.output")),
+        superstructure_event_loop_(MakeEventLoop()),
+        superstructure_(superstructure_event_loop_.get(),
+                        ".y2018.control_loops.superstructure"),
+        superstructure_plant_event_loop_(MakeEventLoop()),
+        superstructure_plant_(superstructure_plant_event_loop_.get()) {
     set_team_id(::frc971::control_loops::testing::kTeamNumber);
   }
 
   void VerifyNearGoal() {
-    superstructure_queue_.goal.FetchLatest();
-    superstructure_queue_.status.FetchLatest();
+    superstructure_goal_fetcher_.Fetch();
+    superstructure_status_fetcher_.Fetch();
 
-    ASSERT_TRUE(superstructure_queue_.goal.get() != nullptr) << ": No goal";
-    ASSERT_TRUE(superstructure_queue_.status.get() != nullptr);
+    ASSERT_TRUE(superstructure_goal_fetcher_.get() != nullptr) << ": No goal";
+    ASSERT_TRUE(superstructure_status_fetcher_.get() != nullptr);
     // Left side test.
-    EXPECT_NEAR(superstructure_queue_.goal->intake.left_intake_angle,
-                superstructure_queue_.status->left_intake.spring_position +
-                    superstructure_queue_.status->left_intake.motor_position,
+    EXPECT_NEAR(superstructure_goal_fetcher_->intake.left_intake_angle,
+                superstructure_status_fetcher_->left_intake.spring_position +
+                    superstructure_status_fetcher_->left_intake.motor_position,
                 0.001);
-    EXPECT_NEAR(superstructure_queue_.goal->intake.left_intake_angle,
+    EXPECT_NEAR(superstructure_goal_fetcher_->intake.left_intake_angle,
                 superstructure_plant_.left_intake().spring_position(), 0.001);
 
     // Right side test.
-    EXPECT_NEAR(superstructure_queue_.goal->intake.right_intake_angle,
-                superstructure_queue_.status->right_intake.spring_position +
-                    superstructure_queue_.status->right_intake.motor_position,
+    EXPECT_NEAR(superstructure_goal_fetcher_->intake.right_intake_angle,
+                superstructure_status_fetcher_->right_intake.spring_position +
+                    superstructure_status_fetcher_->right_intake.motor_position,
                 0.001);
-    EXPECT_NEAR(superstructure_queue_.goal->intake.right_intake_angle,
+    EXPECT_NEAR(superstructure_goal_fetcher_->intake.right_intake_angle,
                 superstructure_plant_.right_intake().spring_position(), 0.001);
   }
 
-  // Runs one iteration of the whole simulation.
-  void RunIteration(bool enabled = true) {
-    SendMessages(enabled);
+  ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
 
-    superstructure_plant_.SendPositionMessage();
-    superstructure_.Iterate();
-    superstructure_plant_.Simulate();
-
-    TickTime(::std::chrono::microseconds(5050));
-  }
-
-  // Runs iterations until the specified amount of simulated time has elapsed.
-  void RunForTime(const monotonic_clock::duration run_for,
-                  bool enabled = true) {
-    const auto end_time = monotonic_clock::now() + run_for;
-    while (monotonic_clock::now() < end_time) {
-      RunIteration(enabled);
-    }
-  }
-
-  ::aos::ShmEventLoop event_loop_;
-  // Create a new instance of the test queue so that it invalidates the queue
-  // that it points to.  Otherwise, we will have a pointer to shared memory
-  // that is no longer valid.
-  SuperstructureQueue superstructure_queue_;
+  ::aos::Fetcher<SuperstructureQueue::Goal> superstructure_goal_fetcher_;
+  ::aos::Sender<SuperstructureQueue::Goal> superstructure_goal_sender_;
+  ::aos::Fetcher<SuperstructureQueue::Status> superstructure_status_fetcher_;
+  ::aos::Fetcher<SuperstructureQueue::Output> superstructure_output_fetcher_;
 
   // Create a control loop and simulation.
+  ::std::unique_ptr<::aos::EventLoop> superstructure_event_loop_;
   Superstructure superstructure_;
+
+  ::std::unique_ptr<::aos::EventLoop> superstructure_plant_event_loop_;
   SuperstructureSimulation superstructure_plant_;
 };
 
 // Tests that the loop zeroes when run for a while without a goal.
 TEST_F(SuperstructureTest, ZeroNoGoalAndDoesNothing) {
-  RunForTime(chrono::seconds(2));
-  superstructure_queue_.output.FetchLatest();
+  SetEnabled(true);
+  RunFor(chrono::seconds(2));
+  superstructure_output_fetcher_.Fetch();
 
   EXPECT_EQ(intake::IntakeSide::State::RUNNING,
             superstructure_.intake_left().state());
   EXPECT_EQ(intake::IntakeSide::State::RUNNING,
             superstructure_.intake_right().state());
-  EXPECT_EQ(superstructure_queue_.output->left_intake.voltage_elastic, 0.0);
-  EXPECT_EQ(superstructure_queue_.output->right_intake.voltage_elastic, 0.0);
+  EXPECT_EQ(superstructure_output_fetcher_->left_intake.voltage_elastic, 0.0);
+  EXPECT_EQ(superstructure_output_fetcher_->right_intake.voltage_elastic, 0.0);
 }
 
 // Tests that the intake loop can reach a goal.
 TEST_F(SuperstructureTest, ReachesGoal) {
+  SetEnabled(true);
   // Set a reasonable goal.
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
 
     goal->intake.left_intake_angle = 0.1;
     goal->intake.right_intake_angle = 0.2;
@@ -359,7 +380,7 @@
   }
 
   // Give it a lot of time to get there.
-  RunForTime(chrono::seconds(8));
+  RunFor(chrono::seconds(8));
 
   VerifyNearGoal();
 }
@@ -367,11 +388,12 @@
 // Tests that the intake loop can reach a goal after starting at a non-zero
 // position.
 TEST_F(SuperstructureTest, OffsetStartReachesGoal) {
+  SetEnabled(true);
   superstructure_plant_.InitializeIntakePosition(0.5);
 
   // Set a reasonable goal.
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
 
     goal->intake.left_intake_angle = 0.1;
     goal->intake.right_intake_angle = 0.2;
@@ -382,7 +404,7 @@
   }
 
   // Give it a lot of time to get there.
-  RunForTime(chrono::seconds(8));
+  RunFor(chrono::seconds(8));
 
   VerifyNearGoal();
 }
@@ -390,9 +412,10 @@
 // Tests that the intake loops doesn't try and go beyond the
 // physical range of the mechanisms.
 TEST_F(SuperstructureTest, RespectsRange) {
+  SetEnabled(true);
   // Set some ridiculous goals to test upper limits.
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
 
     goal->intake.left_intake_angle = 5.0 * M_PI;
     goal->intake.right_intake_angle = 5.0 * M_PI;
@@ -401,27 +424,27 @@
 
     ASSERT_TRUE(goal.Send());
   }
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
 
   // Check that we are near our soft limit.
-  superstructure_queue_.status.FetchLatest();
+  superstructure_status_fetcher_.Fetch();
 
-  EXPECT_NEAR(0.0, superstructure_queue_.status->left_intake.spring_position,
+  EXPECT_NEAR(0.0, superstructure_status_fetcher_->left_intake.spring_position,
               0.001);
   EXPECT_NEAR(constants::Values::kIntakeRange().upper,
-              superstructure_queue_.status->left_intake.spring_position +
-                  superstructure_queue_.status->left_intake.motor_position,
+              superstructure_status_fetcher_->left_intake.spring_position +
+                  superstructure_status_fetcher_->left_intake.motor_position,
               0.001);
 
-  EXPECT_NEAR(0.0, superstructure_queue_.status->right_intake.spring_position,
+  EXPECT_NEAR(0.0, superstructure_status_fetcher_->right_intake.spring_position,
               0.001);
   EXPECT_NEAR(constants::Values::kIntakeRange().upper,
-                  superstructure_queue_.status->right_intake.motor_position,
+                  superstructure_status_fetcher_->right_intake.motor_position,
               0.001);
 
   // Set some ridiculous goals to test lower limits.
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
 
     goal->intake.left_intake_angle = -5.0 * M_PI;
     goal->intake.right_intake_angle = -5.0 * M_PI;
@@ -431,67 +454,70 @@
     ASSERT_TRUE(goal.Send());
   }
 
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
 
   // Check that we are near our soft limit.
-  superstructure_queue_.status.FetchLatest();
+  superstructure_status_fetcher_.Fetch();
 
   EXPECT_NEAR(constants::Values::kIntakeRange().lower,
-              superstructure_queue_.status->left_intake.motor_position, 0.001);
-  EXPECT_NEAR(0.0, superstructure_queue_.status->left_intake.spring_position,
+              superstructure_status_fetcher_->left_intake.motor_position, 0.001);
+  EXPECT_NEAR(0.0, superstructure_status_fetcher_->left_intake.spring_position,
               0.001);
 
   EXPECT_NEAR(constants::Values::kIntakeRange().lower,
-              superstructure_queue_.status->right_intake.motor_position, 0.001);
-  EXPECT_NEAR(0.0, superstructure_queue_.status->right_intake.spring_position,
+              superstructure_status_fetcher_->right_intake.motor_position, 0.001);
+  EXPECT_NEAR(0.0, superstructure_status_fetcher_->right_intake.spring_position,
               0.001);
 }
 
 TEST_F(SuperstructureTest, DISABLED_LowerHardstopStartup) {
+  SetEnabled(true);
   superstructure_plant_.InitializeIntakePosition(
       constants::Values::kIntakeRange().lower_hard);
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
     goal->intake.left_intake_angle = constants::Values::kIntakeRange().lower;
     goal->intake.right_intake_angle = constants::Values::kIntakeRange().lower;
     goal->arm_goal_position = arm::UpIndex();
     goal->open_claw = true;
     ASSERT_TRUE(goal.Send());
   }
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
     goal->intake.left_intake_angle = 1.0;
     goal->intake.right_intake_angle = 1.0;
     ASSERT_TRUE(goal.Send());
   }
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
   VerifyNearGoal();
 }
 
 // Tests that starting at the upper hardstops doesn't cause an abort.
 TEST_F(SuperstructureTest, DISABLED_UpperHardstopStartup) {
+  SetEnabled(true);
   superstructure_plant_.InitializeIntakePosition(
       constants::Values::kIntakeRange().upper_hard);
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
     goal->intake.left_intake_angle = constants::Values::kIntakeRange().upper;
     goal->intake.right_intake_angle = constants::Values::kIntakeRange().upper;
     goal->arm_goal_position = arm::UpIndex();
     goal->open_claw = true;
     ASSERT_TRUE(goal.Send());
   }
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
 
   VerifyNearGoal();
 }
 
 // Tests that resetting WPILib results in a rezero.
 TEST_F(SuperstructureTest, ResetTest) {
+  SetEnabled(true);
   superstructure_plant_.InitializeIntakePosition(
       constants::Values::kIntakeRange().upper);
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
     goal->intake.left_intake_angle =
         constants::Values::kIntakeRange().upper - 0.1;
     goal->intake.right_intake_angle =
@@ -500,7 +526,7 @@
     goal->open_claw = true;
     ASSERT_TRUE(goal.Send());
   }
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
 
   EXPECT_EQ(intake::IntakeSide::State::RUNNING,
             superstructure_.intake_left().state());
@@ -509,14 +535,14 @@
 
   VerifyNearGoal();
   SimulateSensorReset();
-  RunForTime(chrono::milliseconds(100));
+  RunFor(chrono::milliseconds(100));
 
   EXPECT_EQ(intake::IntakeSide::State::ZEROING,
             superstructure_.intake_left().state());
   EXPECT_EQ(intake::IntakeSide::State::ZEROING,
             superstructure_.intake_right().state());
 
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
 
   EXPECT_EQ(intake::IntakeSide::State::RUNNING,
             superstructure_.intake_left().state());
@@ -528,10 +554,11 @@
 
 // Tests that we don't freak out without a goal.
 TEST_F(SuperstructureTest, ArmSimpleGoal) {
-  RunForTime(chrono::seconds(5));
+  SetEnabled(true);
+  RunFor(chrono::seconds(5));
 
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
     goal->intake.left_intake_angle = -0.8;
     goal->intake.right_intake_angle = -0.8;
     goal->arm_goal_position = arm::FrontHighBoxIndex();
@@ -544,20 +571,22 @@
 
 // Tests that we can can execute a move.
 TEST_F(SuperstructureTest, ArmMoveAndMoveBack) {
+  SetEnabled(true);
+  {
+    auto goal = superstructure_goal_sender_.MakeMessage();
+    goal->intake.left_intake_angle = 0.0;
+    goal->intake.right_intake_angle = 0.0;
+    goal->arm_goal_position = arm::FrontHighBoxIndex();
+    goal->open_claw = true;
+    ASSERT_TRUE(goal.Send());
+  }
 
-  auto goal = superstructure_queue_.goal.MakeMessage();
-  goal->intake.left_intake_angle = 0.0;
-  goal->intake.right_intake_angle = 0.0;
-  goal->arm_goal_position = arm::FrontHighBoxIndex();
-  goal->open_claw = true;
-  ASSERT_TRUE(goal.Send());
-
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
 
   VerifyNearGoal();
 
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
     goal->intake.left_intake_angle = 0.0;
     goal->intake.right_intake_angle = 0.0;
     goal->arm_goal_position = arm::ReadyAboveBoxIndex();
@@ -565,27 +594,30 @@
     ASSERT_TRUE(goal.Send());
   }
 
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
   VerifyNearGoal();
 }
 
 // Tests that we can can execute a move which moves through multiple nodes.
 TEST_F(SuperstructureTest, ArmMultistepMove) {
+  SetEnabled(true);
   superstructure_plant_.InitializeArmPosition(arm::ReadyAboveBoxPoint());
 
-  auto goal = superstructure_queue_.goal.MakeMessage();
-  goal->intake.left_intake_angle = 0.0;
-  goal->intake.right_intake_angle = 0.0;
-  goal->arm_goal_position = arm::BackLowBoxIndex();
-  goal->open_claw = true;
-  ASSERT_TRUE(goal.Send());
+  {
+    auto goal = superstructure_goal_sender_.MakeMessage();
+    goal->intake.left_intake_angle = 0.0;
+    goal->intake.right_intake_angle = 0.0;
+    goal->arm_goal_position = arm::BackLowBoxIndex();
+    goal->open_claw = true;
+    ASSERT_TRUE(goal.Send());
+  }
 
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
 
   VerifyNearGoal();
 
   {
-    auto goal = superstructure_queue_.goal.MakeMessage();
+    auto goal = superstructure_goal_sender_.MakeMessage();
     goal->intake.left_intake_angle = 0.0;
     goal->intake.right_intake_angle = 0.0;
     goal->arm_goal_position = arm::ReadyAboveBoxIndex();
@@ -593,7 +625,7 @@
     ASSERT_TRUE(goal.Send());
   }
 
-  RunForTime(chrono::seconds(10));
+  RunFor(chrono::seconds(10));
   VerifyNearGoal();
 }
 
diff --git a/y2018/control_loops/superstructure/superstructure_main.cc b/y2018/control_loops/superstructure/superstructure_main.cc
index f5b026c..789f13f 100644
--- a/y2018/control_loops/superstructure/superstructure_main.cc
+++ b/y2018/control_loops/superstructure/superstructure_main.cc
@@ -5,11 +5,13 @@
 
 int main() {
   ::aos::InitNRT(true);
+
   ::aos::ShmEventLoop event_loop;
   ::y2018::control_loops::superstructure::Superstructure superstructure(
       &event_loop);
-  ::aos::GoRT();
-  superstructure.Run();
+
+  event_loop.Run();
+
   ::aos::Cleanup();
   return 0;
 }
diff --git a/y2018/joystick_reader.cc b/y2018/joystick_reader.cc
index d819c6f..b4c4efa 100644
--- a/y2018/joystick_reader.cc
+++ b/y2018/joystick_reader.cc
@@ -373,9 +373,12 @@
 }  // namespace y2018
 
 int main() {
-  ::aos::Init(-1);
+  ::aos::InitNRT(true);
+
   ::aos::ShmEventLoop event_loop;
   ::y2018::input::joysticks::Reader reader(&event_loop);
-  reader.Run();
+
+  event_loop.Run();
+
   ::aos::Cleanup();
 }