Merge "Send april corners for foxglove displaying"
diff --git a/frc971/analysis/foxglove.md b/frc971/analysis/foxglove.md
new file mode 100644
index 0000000..8276584
--- /dev/null
+++ b/frc971/analysis/foxglove.md
@@ -0,0 +1,36 @@
+We have some support for using [Foxglove Studio](https://studio.foxglove.dev)
+for visualizing robot data.
+
+# Accessing Foxglove
+
+You have three main options for using foxglove studio:
+1. Go to https://studio.foxglove.dev and use the most up-to-date studio. This
+   is convenient; it won't work when you do not have Internet access, and
+   has some limitations when it comes to accessing unsecured websockets.
+2. Download the foxglove desktop application.
+3. Run our local copy by running `bazel run //frc971/analysis:local_foxglove`
+   This will work offline, and serves foxglove at http://localhost:8000 by
+   default.
+
+# Log Visualization
+
+If looking at data from a log, you will first need to convert one of our AOS
+logs to MCAP so that it can be viewed in foxglove. In order to do so,
+run `bazel run -c opt //aos/util:log_to_mcap -- /path/to/log --output_path /tmp/log.mcap`.
+This will create an MCAP file at the specified path, which you can then open
+in any of the various foxglove options.
+
+# Live Visualization
+
+On the pis, we run a `foxglove_websocket` application by default. This exposes
+a websocket on the 8765 port. How you connect to this varies depending on
+what method you are using to create a foxglove instance.
+
+If using https://studio.foxglove.dev, you cannot directly access
+ws://10.9.71.10X:8765 due to security constraints. Instead, you will have to
+port forward by doing something like `ssh -L 8765:localhost:8765 pi@10.9.71.101`
+to expose the port locally, and then use the `ws://localhost:8765` websocket.
+
+If using the local foxglove, you can just use the pi IP address directly.
+
+I have not tried using the desktop Foxglove application for this.
diff --git a/y2023/control_loops/python/graph_edit.py b/y2023/control_loops/python/graph_edit.py
index b9e29d0..689401a 100644
--- a/y2023/control_loops/python/graph_edit.py
+++ b/y2023/control_loops/python/graph_edit.py
@@ -162,6 +162,8 @@
         self.ax = self.fig.add_subplot(111)
         plt.show(block=False)
 
+        self.index = 0
+
     def do_key_press(self, event):
         pass
 
@@ -330,8 +332,7 @@
 
         set_color(cr, Color(0.0, 0.5, 1.0))
         for segment in self.segments:
-            color = [0, random.random(), 1]
-            random.shuffle(color)
+            color = [0.2, random.random(), random.random()]
             set_color(cr, Color(color[0], color[1], color[2]))
             segment.DrawTo(cr, self.theta_version)
             with px(cr):
@@ -411,13 +412,16 @@
         elif keyval == Gdk.KEY_r:
             self.prev_segment_pt = self.now_segment_pt
 
+        elif keyval == Gdk.KEY_o:
+            # Only prints current segment
+            print(repr(self.segments[self.index]))
         elif keyval == Gdk.KEY_p:
             # Print out the segments.
             print(repr(self.segments))
         elif keyval == Gdk.KEY_g:
             # Generate theta points.
             if self.segments:
-                print(repr(self.segments[0].ToThetaPoints()))
+                print(repr(self.segments[self.index].ToThetaPoints()))
         elif keyval == Gdk.KEY_e:
             best_pt = self.now_segment_pt
             best_dist = 1e10
@@ -432,6 +436,10 @@
                     best_dist = d
             self.now_segment_pt = best_pt
 
+        elif keyval == Gdk.KEY_k:
+            self.index += 1
+            self.index = self.index % len(self.segments)
+
         elif keyval == Gdk.KEY_t:
             # Toggle between theta and xy renderings
             if self.theta_version:
@@ -449,9 +457,9 @@
         elif keyval == Gdk.KEY_z:
             self.edit_control1 = not self.edit_control1
             if self.edit_control1:
-                self.now_segment_pt = self.segments[0].control1
+                self.now_segment_pt = self.segments[self.index].control1
             else:
-                self.now_segment_pt = self.segments[0].control2
+                self.now_segment_pt = self.segments[self.index].control2
             if not self.theta_version:
                 data = to_xy(self.now_segment_pt[0], self.now_segment_pt[1])
                 self.last_pos = (data[0], data[1])
@@ -474,9 +482,9 @@
         self.now_segment_pt = np.array(shift_angles(pt_theta))
 
         if self.edit_control1:
-            self.segments[0].control1 = self.now_segment_pt
+            self.segments[self.index].control1 = self.now_segment_pt
         else:
-            self.segments[0].control2 = self.now_segment_pt
+            self.segments[self.index].control2 = self.now_segment_pt
 
         print('Clicked at theta: %s' % (repr(self.now_segment_pt, )))
         if not self.theta_version:
@@ -485,9 +493,11 @@
                    self.circular_index_select))
 
         print('c1: np.array([%f, %f])' %
-              (self.segments[0].control1[0], self.segments[0].control1[1]))
+              (self.segments[self.index].control1[0],
+               self.segments[self.index].control1[1]))
         print('c2: np.array([%f, %f])' %
-              (self.segments[0].control2[0], self.segments[0].control2[1]))
+              (self.segments[self.index].control2[0],
+               self.segments[self.index].control2[1]))
 
         self.redraw()
 
diff --git a/y2023/rockpi/BUILD b/y2023/rockpi/BUILD
index 91e8729..701383b 100644
--- a/y2023/rockpi/BUILD
+++ b/y2023/rockpi/BUILD
@@ -7,5 +7,6 @@
         "//aos:init",
         "//aos/events:shm_event_loop",
         "//frc971/imu_reader:imu",
+        "//y2023:constants",
     ],
 )
diff --git a/y2023/rockpi/imu_main.cc b/y2023/rockpi/imu_main.cc
index ac0c141..d53b3fb 100644
--- a/y2023/rockpi/imu_main.cc
+++ b/y2023/rockpi/imu_main.cc
@@ -2,6 +2,7 @@
 #include "aos/init.h"
 #include "aos/realtime.h"
 #include "frc971/imu_reader/imu.h"
+#include "y2023/constants.h"
 
 DEFINE_string(config, "aos_config.json", "Path to the config file to use.");
 
@@ -12,8 +13,8 @@
       aos::configuration::ReadConfig(FLAGS_config);
 
   aos::ShmEventLoop event_loop(&config.message());
-  // TODO(austin): Set the ratio...
-  frc971::imu::Imu imu(&event_loop, 1.0);
+  frc971::imu::Imu imu(&event_loop,
+                       y2023::constants::Values::DrivetrainEncoderToMeters(1));
 
   event_loop.SetRuntimeAffinity(aos::MakeCpusetFromCpus({0}));
   event_loop.SetRuntimeRealtimePriority(55);
diff --git a/y2023/y2023_logger.json b/y2023/y2023_logger.json
index 5386a1d..bb78bc5 100644
--- a/y2023/y2023_logger.json
+++ b/y2023/y2023_logger.json
@@ -460,6 +460,7 @@
     {
       "name": "logger_camera_reader",
       "executable_name": "camera_reader",
+      "user": "pi",
       "args": ["--enable_ftrace", "--send_downsized_images"],
       "nodes": [
         "logger"
@@ -469,6 +470,7 @@
       "name": "image_logger",
       "executable_name": "logger_main",
       "autostart": false,
+      "user": "pi",
       "args": [
         "--logging_folder",
         "",
@@ -485,6 +487,7 @@
       "name": "image_streamer",
       "executable_name": "image_streamer_start.sh",
       "autostart": true,
+      "user": "pi",
       "nodes": [
         "logger"
       ]
@@ -492,6 +495,7 @@
     {
       "name": "constants_sender",
       "autorestart": false,
+      "user": "pi",
       "nodes": [
         "logger"
       ]