created a NetworkRobot class that sends messages successfully
diff --git a/frc971/crio/crio.gyp b/frc971/crio/crio.gyp
index 62d88bc..731743b 100644
--- a/frc971/crio/crio.gyp
+++ b/frc971/crio/crio.gyp
@@ -29,17 +29,35 @@
       ],
     },
     {
+      'target_name': 'dumb_main',
+      'type': 'static_library',
+      'sources': [
+        'dumb_main.cc',
+      ],
+      'dependencies': [
+        '<(EXTERNALS):WPILib',
+        '<(AOS)/common/common.gyp:common',
+      ],
+    },
+    {
       'target_name': 'FRC_UserProgram',
       'type': 'shared_library',
       'dependencies': [
-        'user_program'
+        'WPILib_changes',
+        'dumb_main',
+      ],
+    },
+    {
+      'target_name': 'FRC_UserProgram_old',
+      'type': 'shared_library',
+      'dependencies': [
+        'user_program',
       ],
     },
     {
       'target_name': 'FRC_UserProgram_WithTests',
       'type': 'shared_library',
       'dependencies': [
-        # For testing.
         '<(AOS)/build/aos_all.gyp:Crio',
       ],
     },
diff --git a/frc971/crio/dumb_main.cc b/frc971/crio/dumb_main.cc
new file mode 100644
index 0000000..ade0af1
--- /dev/null
+++ b/frc971/crio/dumb_main.cc
@@ -0,0 +1,16 @@
+#include "WPILib/NetworkRobot/NetworkRobot.h"
+#include "WPILib/RobotBase.h"
+#include "aos/common/Configuration.h"
+
+namespace frc971 {
+
+class MyRobot : public NetworkRobot {
+ public:
+  MyRobot() : NetworkRobot(static_cast<uint16_t>(::aos::NetworkPort::kMotors),
+                           ::aos::configuration::GetIPAddress(
+                               ::aos::configuration::NetworkDevice::kAtom)) {}
+};
+
+}  // namespace frc971
+
+START_ROBOT_CLASS(::frc971::MyRobot);
diff --git a/frc971/output/AtomMotorWriter.cc b/frc971/output/AtomMotorWriter.cc
index 8431fa7..3ba3593 100644
--- a/frc971/output/AtomMotorWriter.cc
+++ b/frc971/output/AtomMotorWriter.cc
@@ -2,14 +2,12 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "aos/aos_core.h"
-#include "aos/common/control_loop/Timing.h"
-#include "aos/common/messages/RobotState.q.h"
-#include "aos/atom_code/output/MotorOutput.h"
+#include "aos/atom_code/output/motor_output.h"
+#include "aos/common/logging/logging.h"
+#include "aos/atom_code/init.h"
 
 #include "frc971/queues/Piston.q.h"
 #include "frc971/control_loops/drivetrain/drivetrain.q.h"
-#include "frc971/constants.h"
 #include "frc971/control_loops/wrist/wrist_motor.q.h"
 #include "frc971/control_loops/shooter/shooter_motor.q.h"
 #include "frc971/control_loops/index/index_motor.q.h"
@@ -26,77 +24,84 @@
 namespace frc971 {
 namespace output {
 
-class MotorWriter : public aos::MotorOutput {
+class MotorWriter : public ::aos::MotorOutput {
   // Maximum age of an output packet before the motors get zeroed instead.
   static const int kOutputMaxAgeMS = 20;
   static const int kEnableDrivetrain = true;
 
-  void RunIteration() {
+  virtual void RunIteration() {
+    values_.digital_module = 0;
+    values_.pressure_switch_channel = 14;
+    values_.compressor_channel = 1;
+    values_.solenoid_module = 0;
+
     drivetrain.output.FetchLatest();
     if (drivetrain.output.IsNewerThanMS(kOutputMaxAgeMS) && kEnableDrivetrain) {
-      AddMotor(TALON, 2, drivetrain.output->right_voltage / 12.0);
-      AddMotor(TALON, 3, drivetrain.output->right_voltage / 12.0);
-      AddMotor(TALON, 5, -drivetrain.output->left_voltage / 12.0);
-      AddMotor(TALON, 6, -drivetrain.output->left_voltage / 12.0);
+      SetPWMOutput(2, drivetrain.output->right_voltage / 12.0, kTalonBounds);
+      SetPWMOutput(3, drivetrain.output->right_voltage / 12.0, kTalonBounds);
+      SetPWMOutput(5, -drivetrain.output->left_voltage / 12.0, kTalonBounds);
+      SetPWMOutput(6, -drivetrain.output->left_voltage / 12.0, kTalonBounds);
     } else {
-      AddMotor(TALON, 2, 0);
-      AddMotor(TALON, 3, 0);
-      AddMotor(TALON, 5, 0);
-      AddMotor(TALON, 6, 0);
+      DisablePWMOutput(2);
+      DisablePWMOutput(3);
+      DisablePWMOutput(5);
+      DisablePWMOutput(6);
       if (kEnableDrivetrain) {
         LOG(WARNING, "drivetrain not new enough\n");
       }
     }
     shifters.FetchLatest();
-    if (shifters.IsNewerThanMS(kOutputMaxAgeMS)) {
-      AddSolenoid(1, shifters->set);
-      AddSolenoid(2, !shifters->set);
+    if (shifters.get()) {
+      SetSolenoid(1, shifters->set);
+      SetSolenoid(2, !shifters->set);
     }
 
     wrist.output.FetchLatest();
     if (wrist.output.IsNewerThanMS(kOutputMaxAgeMS)) {
-      AddMotor(TALON, 10, wrist.output->voltage / 12.0);
+      SetPWMOutput(10, wrist.output->voltage / 12.0, kTalonBounds);
     } else {
-      AddMotor(TALON, 10, 0);
+      DisablePWMOutput(10);
       LOG(WARNING, "wrist not new enough\n");
     }
 
     shooter.output.FetchLatest();
     if (shooter.output.IsNewerThanMS(kOutputMaxAgeMS)) {
-      AddMotor(TALON, 4, shooter.output->voltage / 12.0);
+      SetPWMOutput(4, shooter.output->voltage / 12.0, kTalonBounds);
     } else {
-      AddMotor(TALON, 4, 0);
+      DisablePWMOutput(4);
       LOG(WARNING, "shooter not new enough\n");
     }
 
     angle_adjust.output.FetchLatest();
     if (angle_adjust.output.IsNewerThanMS(kOutputMaxAgeMS)) {
-      AddMotor(TALON, 1, -angle_adjust.output->voltage / 12.0);
+      SetPWMOutput(1, -angle_adjust.output->voltage / 12.0, kTalonBounds);
     } else {
-      AddMotor(TALON, 1, 0);
+      DisablePWMOutput(1);
       LOG(WARNING, "angle adjust is not new enough\n");
     }
 
     index_loop.output.FetchLatest();
+    if (index_loop.output.get()) {
+      SetSolenoid(7, index_loop.output->loader_up);
+      SetSolenoid(8, !index_loop.output->loader_up);
+      SetSolenoid(6, index_loop.output->disc_clamped);
+      SetSolenoid(3, index_loop.output->disc_ejected);
+    }
     if (index_loop.output.IsNewerThanMS(kOutputMaxAgeMS)) {
-      AddMotor(TALON, 8, index_loop.output->intake_voltage / 12.0);
-      AddMotor(TALON, 9, index_loop.output->transfer_voltage / 12.0);
-      AddMotor(TALON, 7, -index_loop.output->index_voltage / 12.0);
-      AddSolenoid(7, index_loop.output->loader_up);
-      AddSolenoid(8, !index_loop.output->loader_up);
-      AddSolenoid(6, index_loop.output->disc_clamped);
-      AddSolenoid(3, index_loop.output->disc_ejected);
+      SetPWMOutput(8, index_loop.output->intake_voltage / 12.0, kTalonBounds);
+      SetPWMOutput(9, index_loop.output->transfer_voltage / 12.0, kTalonBounds);
+      SetPWMOutput(7, -index_loop.output->index_voltage / 12.0, kTalonBounds);
     } else {
-      AddMotor(TALON, 8, 0);
-      AddMotor(TALON, 9, 0);
-      AddMotor(TALON, 7, 0);
+      DisablePWMOutput(8);
+      DisablePWMOutput(9);
+      DisablePWMOutput(7);
       LOG(WARNING, "index not new enough\n");
     }
 
     hangers.FetchLatest();
-    if (hangers.IsNewerThanMS(kOutputMaxAgeMS)) {
-      AddSolenoid(4, hangers->set);
-      AddSolenoid(5, hangers->set);
+    if (hangers.get()) {
+      SetSolenoid(4, hangers->set);
+      SetSolenoid(5, hangers->set);
     }
   }
 };
@@ -104,4 +109,9 @@
 }  // namespace output
 }  // namespace frc971
 
-AOS_RUN(frc971::output::MotorWriter)
+int main() {
+  ::aos::Init();
+  ::frc971::output::MotorWriter writer;
+  writer.Run();
+  ::aos::Cleanup();
+}
diff --git a/frc971/output/output.gyp b/frc971/output/output.gyp
index 4459984..b872713 100644
--- a/frc971/output/output.gyp
+++ b/frc971/output/output.gyp
@@ -29,8 +29,8 @@
             'sources': ['AtomMotorWriter.cc'],
             'dependencies': [
               '<(AOS)/atom_code/output/output.gyp:motor_output',
-              '<(AOS)/atom_code/messages/messages.gyp:messages',
               '<(AOS)/atom_code/atom_code.gyp:init',
+              '<(AOS)/build/aos.gyp:logging',
               '<(DEPTH)/frc971/control_loops/angle_adjust/angle_adjust.gyp:angle_adjust_loop',
               '<(DEPTH)/frc971/control_loops/wrist/wrist.gyp:wrist_loop',
               '<(DEPTH)/frc971/control_loops/index/index.gyp:index_loop',