Merge changes Ic18aba9d,Ibd51310f

* changes:
  Add spline debug plot
  Better handle high-precision numbers in plotter
diff --git a/aos/aos_dump.cc b/aos/aos_dump.cc
index 78df645..45168b2 100644
--- a/aos/aos_dump.cc
+++ b/aos/aos_dump.cc
@@ -95,6 +95,9 @@
         [channel, &str_builder, &cli_info, &message_count, &next_send_time](
             const aos::Context &context, const void * /*message*/) {
           if (context.monotonic_event_time > next_send_time) {
+            if (FLAGS_count > 0 && message_count >= FLAGS_count) {
+              return;
+            }
             PrintMessage(channel, context, &str_builder);
             ++message_count;
             next_send_time = context.monotonic_event_time +
diff --git a/aos/events/event_loop.h b/aos/events/event_loop.h
index cc5a356..d23314e 100644
--- a/aos/events/event_loop.h
+++ b/aos/events/event_loop.h
@@ -269,7 +269,7 @@
   const T *operator->() const { return get(); }
 
   // Returns true if this fetcher is valid and connected to a channel.
-  operator bool() const { return static_cast<bool>(fetcher_); }
+  bool valid() const { return static_cast<bool>(fetcher_); }
 
   // Copies the current flatbuffer into a FlatbufferVector.
   FlatbufferVector<T> CopyFlatBuffer() const {
diff --git a/aos/starter/starter_rpc_lib.cc b/aos/starter/starter_rpc_lib.cc
index 67b3fb2..7b86c0a 100644
--- a/aos/starter/starter_rpc_lib.cc
+++ b/aos/starter/starter_rpc_lib.cc
@@ -30,7 +30,7 @@
                                  const aos::Configuration *config) {
   std::string_view app_name = name;
   for (const auto app : *config->applications()) {
-    if (app->executable_name() != nullptr &&
+    if (app->has_executable_name() &&
         app->executable_name()->string_view() == name) {
       app_name = app->name()->string_view();
       break;
@@ -74,7 +74,7 @@
       event_loop.MakeFetcher<aos::starter::Status>("/aos");
   initial_status_fetcher.Fetch();
   auto initial_status =
-      initial_status_fetcher
+      initial_status_fetcher.get()
           ? FindApplicationStatus(*initial_status_fetcher, name)
           : nullptr;
 
@@ -133,8 +133,9 @@
 
   auto status_fetcher = event_loop.MakeFetcher<aos::starter::Status>("/aos");
   status_fetcher.Fetch();
-  auto status =
-      status_fetcher ? FindApplicationStatus(*status_fetcher, name) : nullptr;
+  auto status = status_fetcher.get()
+                    ? FindApplicationStatus(*status_fetcher, name)
+                    : nullptr;
   return status ? aos::CopyFlatBuffer(status)
                 : FlatbufferDetachedBuffer<
                       aos::starter::ApplicationStatus>::Empty();
@@ -147,8 +148,9 @@
 
   auto status_fetcher = event_loop.MakeFetcher<aos::starter::Status>("/aos");
   status_fetcher.Fetch();
-  return (status_fetcher ? std::make_optional(status_fetcher.CopyFlatBuffer())
-                         : std::nullopt);
+  return (status_fetcher.get()
+              ? std::make_optional(status_fetcher.CopyFlatBuffer())
+              : std::nullopt);
 }
 
 }  // namespace starter
diff --git a/frc971/wpilib/ADIS16470.cc b/frc971/wpilib/ADIS16470.cc
index ec2ee9e..8a56d96 100644
--- a/frc971/wpilib/ADIS16470.cc
+++ b/frc971/wpilib/ADIS16470.cc
@@ -11,6 +11,7 @@
 namespace frc971 {
 namespace wpilib {
 namespace {
+namespace chrono = std::chrono;
 namespace registers {
 
 // Flash memory write count
@@ -262,14 +263,14 @@
       reset_->Set(false);
       // Datasheet says it needs a 1 us pulse, so make sure we do something in
       // between asserting and deasserting.
-      std::this_thread::sleep_for(::std::chrono::milliseconds(1));
+      std::this_thread::sleep_for(chrono::milliseconds(1));
       reset_->Set(true);
 
       state_ = State::kWaitForReset;
       // Datasheet says it takes 193 ms to come out of reset, so give it some
       // margin on top of that.
       initialize_timer_->Setup(event_loop_->monotonic_now() +
-                               std::chrono::milliseconds(250));
+                               chrono::milliseconds(250));
     }
     break;
 
@@ -303,7 +304,7 @@
           // Start a sensor self test.
           WriteRegister(registers::GLOB_CMD, 1 << 2);
           // Datasheet says it takes 14ms, so give it some margin.
-          std::this_thread::sleep_for(std::chrono::milliseconds(25));
+          std::this_thread::sleep_for(chrono::milliseconds(25));
           // Read DIAG_STAT again, and queue up a read of the first part of the
           // autospi data packet.
           const uint16_t self_test_diag_stat_value =
@@ -335,6 +336,21 @@
 
             // Finally, enable automatic mode so it starts reading data.
             spi_->StartAutoTrigger(*data_ready_, true, false);
+
+            // We need a bit of time for the auto trigger to start up so we have
+            // something to throw out.  1 khz trigger, so 2 ms gives us 2 cycles
+            // to hit it worst case.
+            std::this_thread::sleep_for(chrono::milliseconds(2));
+
+            // Throw out the first sample.  It is almost always faulted due to
+            // how we start up, and it isn't worth tracking for downstream users
+            // to look at.
+            to_read_ = absl::MakeSpan(read_data_);
+            CHECK_EQ(spi_->ReadAutoReceivedData(
+                         to_read_.data(), to_read_.size(),
+                         1000.0 /* block for up to 1 second */),
+                     static_cast<int>(to_read_.size()))
+                << ": Failed to read first sample.";
             success = true;
           }
         }
diff --git a/y2020/control_loops/superstructure/shooter/flywheel_controller.h b/y2020/control_loops/superstructure/shooter/flywheel_controller.h
index 5fdac39..4eafe47 100644
--- a/y2020/control_loops/superstructure/shooter/flywheel_controller.h
+++ b/y2020/control_loops/superstructure/shooter/flywheel_controller.h
@@ -29,6 +29,7 @@
 
   // Sets the velocity goal in radians/sec
   void set_goal(double angular_velocity_goal);
+  double goal() const { return last_goal_; }
   // Sets the current encoder position in radians
   void set_position(double current_position,
                     const aos::monotonic_clock::time_point position_timestamp);
diff --git a/y2020/control_loops/superstructure/shooter/shooter.h b/y2020/control_loops/superstructure/shooter/shooter.h
index f72eeeb..1a46949 100644
--- a/y2020/control_loops/superstructure/shooter/shooter.h
+++ b/y2020/control_loops/superstructure/shooter/shooter.h
@@ -26,6 +26,9 @@
 
   bool ready() { return ready_; }
 
+  float finisher_goal() const { return finisher_.goal(); }
+  float accelerator_goal() const { return accelerator_left_.goal(); }
+
  private:
   FlywheelController finisher_, accelerator_left_, accelerator_right_;
 
diff --git a/y2020/control_loops/superstructure/superstructure.cc b/y2020/control_loops/superstructure/superstructure.cc
index 91e782e..9a48095 100644
--- a/y2020/control_loops/superstructure/superstructure.cc
+++ b/y2020/control_loops/superstructure/superstructure.cc
@@ -204,9 +204,8 @@
     if (unsafe_goal) {
       output_struct.washing_machine_spinner_voltage = 0.0;
       if (unsafe_goal->shooting()) {
-        if (shooter_.ready() &&
-            unsafe_goal->shooter()->velocity_accelerator() > 10.0 &&
-            unsafe_goal->shooter()->velocity_finisher() > 10.0) {
+        if (shooter_.ready() && shooter_.finisher_goal() > 10.0 &&
+            shooter_.accelerator_goal() > 10.0) {
           output_struct.feeder_voltage = 12.0;
         } else {
           output_struct.feeder_voltage = 0.0;