ソースを参照

added comments

subDesTagesMitExtraKaese 3 年 前
コミット
58b960a7cb

+ 0 - 3
raspberry-pi/config.ini

@@ -8,9 +8,6 @@
 
 # acoustic sensor config
 [ac_sensor]
-  # distancce between receivers in mm
-  sensor_distance = 450
-
   # distance of the sensors in front of y=0 in mm
   y_offset = 10
 

+ 16 - 8
raspberry-pi/gui/graph.py

@@ -1,32 +1,37 @@
-import tkinter as tk
 import time, math
+
+import tkinter as tk
 from PIL import Image, ImageDraw, ImageTk, ImageFont
 
+
 class Graph(tk.Canvas):
   def __init__(self, root, scale=(-100, 550), **kwargs):
     self.root = root
     tk.Canvas.__init__(self, root, **kwargs)
+    self.image = self.create_image(0, 0, image=None, anchor='nw')
     self.height = self.winfo_reqheight()
     self.width = self.winfo_reqwidth()
+    # store last point of plot to connect the lines
     self.lastPoints = [(0, 0)] * 3
+    # scale contains the (min, max) values of both axes
     self.scale = scale
+    # appearance of the plots
     self.colors = [(100, 255, 100, 255), (255, 100, 100, 255) ,(100, 100, 255, 255)]
     self.font = ImageFont.truetype("gui/SourceSansPro-Semibold.otf", 12)
     self.lineWidth = 1
     
+    # the background contains all static elements
     self.drawBackground()
+    # the plots will be drawn on a separate canvas
     self.canvas = self.bg.copy()
-    self.image = self.create_image(0, 0, image=None, anchor='nw')
 
     self.bind("<Configure>", self.on_resize)
 
   def drawBackground(self):
     self.bg = Image.new('RGB', (self.width, self.height), (0,20,0))
     draw = ImageDraw.Draw(self.bg)
-
-    axes = self.pointToCoord((0, 0))
-
     # draw x and y axis
+    axes = self.pointToCoord((0, 0))
     draw.line([(0, axes[1]), (self.width, axes[1])], (60,127,127), self.lineWidth)
     draw.line([(axes[0], 0), (axes[0], self.height)], (60,127,127), self.lineWidth)
 
@@ -36,7 +41,7 @@ class Graph(tk.Canvas):
       tickPosY = self.pointToCoord((0, p))
       draw.line([(tickPosX[0], tickPosX[1]+self.lineWidth*3), (tickPosX[0], tickPosX[1]-self.lineWidth*3)], (60,127,127), int(self.lineWidth/2))
       draw.line([(tickPosY[0]+self.lineWidth*3, tickPosY[1]), (tickPosY[0]-self.lineWidth*3, tickPosY[1])], (60,127,127), int(self.lineWidth/2))
-
+      # draw tick labels
       draw.text((tickPosX[0]+3, tickPosX[1]+self.lineWidth*4), str(p) + " mm", font=self.font)
       if p != 0:
         draw.text((tickPosY[0]-self.lineWidth*4-35, tickPosY[1]), str(p) + " mm", font=self.font)
@@ -50,24 +55,27 @@ class Graph(tk.Canvas):
     self.drawBackground()
     self.canvas = Image.blend(self.canvas, self.bg, 1)
 
+  # convert physical space to screen space
   def pointToCoord(self, point):
     return ((point[0] - self.scale[0]) / (self.scale[1]-self.scale[0]) * self.width, 
       self.height - (point[1] - self.scale[0]) / (self.scale[1]-self.scale[0]) * self.height - 1)
 
   def update(self, data):
+    # load first point of line
     coord = [[self.pointToCoord(p)] for p in self.lastPoints]
-
+    # append new points
     for i in range(len(data)):
       for point in data[i]:
         coord[i].append(self.pointToCoord(point))
 
     self.lastPoints = [line[-1] for line in data]
-
+    #fade out old lines by mixing with background
     self.canvas = Image.blend(self.canvas, self.bg, 1/100)
     draw = ImageDraw.Draw(self.canvas)
     for i in range(len(coord)):
       draw.line(coord[i], fill=self.colors[i], width=self.lineWidth+2, joint='curve')
 
+    # draw to tk.Canvas
     self.photo = ImageTk.PhotoImage(self.canvas)
     self.itemconfig(self.image, image=self.photo)
 

+ 11 - 17
raspberry-pi/gui/mainWindow.py

@@ -1,11 +1,13 @@
-import tkinter as tk
 import time
 import queue
+
+import tkinter as tk
 import numpy as np
 
 from gui.popup import CalibrationPopUp
 from gui.graph import Graph
 
+
 class MainWindow(tk.Frame):
   def __init__(self, root, ac_sensor, ac_queue, ac_cal_state):
     self.root = root
@@ -14,10 +16,10 @@ class MainWindow(tk.Frame):
     self.ac_sensor = ac_sensor
     self.ac_queue = ac_queue
     tk.Frame.__init__(self, root)
-
+    # data plot at left side
     self.graph = Graph(self)
     self.graph.pack(fill=tk.BOTH, side=tk.LEFT, expand=True)
-
+    # frame at right side
     self.controls = tk.Frame(self, borderwidth=4)
     self.controls.pack(fill=tk.BOTH, side=tk.RIGHT)
     self.controlsUpdateTime = 0
@@ -45,19 +47,22 @@ class MainWindow(tk.Frame):
       return
 
     ac_positions = []
-
+    # aggregate measurements
     while self.ac_queue.qsize() > 0:
       name, data = self.ac_queue.get()
       if name == "data":
         ac_positions.append(data[0:2])
         self.ac_dro_val_sums += data
         self.ac_dro_val_count += 1
-
+    
+    # graph shows all values as a line
     if len(ac_positions) > 0:
       self.graph.update([ac_positions])
 
+      # readouts will only be updated so often
       if self.controlsUpdateTime + 0.4 < time.time():
         self.controlsUpdateTime = time.time()
+        # they display the average of all values
         if self.ac_dro_val_count > 0:
           self.ac_dro_val_sums /= self.ac_dro_val_count
         else:
@@ -83,23 +88,12 @@ class MainWindow(tk.Frame):
       self.pu_root = tk.Toplevel(self.root)
       self.pu_root.wm_transient(self.root)
       self.pu_root.wm_title("Calibration")
-
       # make it centered
       x = (self.pu_root.winfo_screenwidth()  - 500) / 2
       y = (self.pu_root.winfo_screenheight() - 200) / 2
       self.pu_root.geometry(f'500x200+{int(x)}+{int(y)}')
-
       # deactivate mainWindow
       self.pu_root.grab_set()
       self.popup = CalibrationPopUp(self.pu_root, self.ac_cal_state)
       self.popup.pack(side="top", fill="both", expand=True)
-    
-if __name__ == "__main__":
-  root = tk.Tk()
-  up_queue = queue.Queue()
-  down_queue = queue.Queue()
-  root.title("Tracking System")
-  view = MainWindow(root,up_queue,down_queue,list())
-  view.pack(side="top", fill="both", expand=True)
-  view.update()
-  root.mainloop()
+

+ 5 - 4
raspberry-pi/gui/popup.py

@@ -20,17 +20,18 @@ class CalibrationPopUp(tk.Frame):
   def update(self):
     if not self.root.winfo_exists():
       return
-
+    # display captured value count as progress
     self.cs['value'] = self.calibration_state.progress
+    # read state from state machine
     if self.calibration_state.get_state() == self.calibration_state.WAITING_POS_1:
       self.instruction["text"] = "Move gondola to far left corner!"
     elif self.calibration_state.get_state() == self.calibration_state.WAITING_POS_2:
       self.instruction["text"] = "Move gondola to far right corner!"
-    elif self.calibration_state.get_state() == self.calibration_state.CALIBRATION_DONE and not self.pendingClose:
-      self.pendingClose = True
-      self.root.after(1500, self.close)
     elif self.calibration_state.get_state() == self.calibration_state.CALIBRATION_DONE:
       self.instruction["text"] = "Calibration Done!"
+      if not self.pendingClose:
+        self.pendingClose = True
+        self.root.after(1500, self.close)
     else:
       self.instruction["text"] = "Processing..."
 

+ 27 - 16
raspberry-pi/sensors/acusticSensor.py

@@ -1,4 +1,3 @@
-from sensors.connection import globalArduinoSlave
 import time
 import statistics
 import math
@@ -6,22 +5,26 @@ import threading
 import random
 import traceback
 
+from sensors.connection import globalArduinoSlave
+
 conn = globalArduinoSlave()
 
+
 class AcusticSensor:
   def __init__(self, conf, ac_queue, calibration_state):
     self.ac_queue               = ac_queue
     self.calibration_state      = calibration_state
     self.field_height           = float(conf["field"]["y"])
-    self.field_length           = float(conf["field"]["x"])
-    self.sensor_distance        = float(conf["ac_sensor"]["sensor_distance"])
+    self.field_width           = float(conf["field"]["x"])
     self.sensor_y_offset        = float(conf["ac_sensor"]["y_offset"])
     self.left_sensor_x_offset   = float(conf["ac_sensor"]["left_x_offset"])
     self.right_sensor_x_offset  = float(conf["ac_sensor"]["right_x_offset"])
+    self.sensor_distance        = self.field_width - self.left_sensor_x_offset + self.right_sensor_x_offset
     self.sonic_speed            = float(conf["ac_sensor"]["sonicspeed"])
     self.overhead_left          = float(conf["ac_sensor"]["overhead_left"])
     self.overhead_right         = float(conf["ac_sensor"]["overhead_right"])
 
+    # temporary calibration variables
     self.time_vals = [[],[]]
     self.cal_values = {
       "left": [0, 0],
@@ -30,10 +33,11 @@ class AcusticSensor:
     self.n = 0
 
   def start(self):
-    self.dummyActive = True
     if not conn.isConnected():
       conn.open()
     conn.addRecvCallback(self._readCb)
+    # generate dummy values until arduino is ready
+    self.dummyActive = True
     dummyThread = threading.Thread(target=self._readCb_dummy)
     dummyThread.start()
     
@@ -64,17 +68,14 @@ class AcusticSensor:
       time.sleep(0.01)
 
   def _readCb(self, raw):
+    self.dummyActive = False
     value = conn.getAcusticRTTs()
-
-    if self.dummyActive:
-      self.dummyActive = False
-
+    # partially missing values will be ignored
     if value[0] >= 0 and value[1] >= 0:
       self.calibrate(value)
       self.pass_to_gui(self.calculate_position(value) + value)
 
   def calibrate(self, value):
-
     if self.calibration_state.get_state() == self.calibration_state.ACCUMULATING_1:
       self.time_vals[0].append(value[0])
       self.time_vals[1].append(value[1])
@@ -94,23 +95,32 @@ class AcusticSensor:
         self.cal_values["right"][0] = statistics.mean(self.time_vals[1])
 
         # all values have been captured
-        print(self.cal_values)
+        print("calibration measurements:", self.cal_values)
         
-        # calculate calibration results
-        timedif = self.cal_values["left"][1] - self.cal_values["left"][0]
+        # calculate distances from config
+        #          /|                               _.-|
+        #      d1 / |                       d2  _.-`   |
+        #        /  | y_off + height        _.-`       | y_off + height
+        #       /___|                     -____________|
+        #       x_off                     x_off + width
         distance_1 = math.sqrt(self.left_sensor_x_offset**2 + (self.sensor_y_offset + self.field_height)**2 )
-        distance_2 = math.sqrt((self.left_sensor_x_offset + self.field_length)**2 + (self.sensor_y_offset + self.field_height)**2 )
+        distance_2 = math.sqrt((self.left_sensor_x_offset + self.field_width)**2 + (self.sensor_y_offset + self.field_height)**2 )
         distancedif = distance_2 - distance_1
+        timedif = self.cal_values["left"][1] - self.cal_values["left"][0]
+        # speed of sound in mm/us
         sonicspeed_1 = distancedif / timedif
+        # processing time overhead in us
         overhead_1 = statistics.mean((self.cal_values["left"][1] - distance_1/sonicspeed_1, self.cal_values["left"][0] - distance_2/sonicspeed_1))
 
-        timedif = self.cal_values["right"][1] - self.cal_values["right"][0]
+        # same for the second set of values
         distance_1 = math.sqrt(self.right_sensor_x_offset**2 + (self.sensor_y_offset + self.field_height)**2 )
-        distance_2 = math.sqrt((self.right_sensor_x_offset + self.field_length)**2 + (self.sensor_y_offset + self.field_height)**2 )
+        distance_2 = math.sqrt((self.right_sensor_x_offset + self.field_width)**2 + (self.sensor_y_offset + self.field_height)**2 )
         distancedif = distance_2 - distance_1
+        timedif = self.cal_values["right"][1] - self.cal_values["right"][0]
         sonicspeed_2 = distancedif / timedif
         overhead_2 = statistics.mean((self.cal_values["right"][0] - distance_1/sonicspeed_2, self.cal_values["right"][1] - distance_2/sonicspeed_2))
 
+        # calculate calibration results
         self.sonic_speed = statistics.mean((sonicspeed_1,sonicspeed_2))
         self.overhead_left  = overhead_1
         self.overhead_right = overhead_2
@@ -131,9 +141,10 @@ class AcusticSensor:
       val2 -= self.overhead_right
       distance_left = val1 * self.sonic_speed
       distance_right = val2 * self.sonic_speed
+      # compute intersection of distance circles
       x = (self.sensor_distance**2 - distance_right**2 + distance_left**2) / (2*self.sensor_distance) + self.left_sensor_x_offset
       y = math.sqrt(max(distance_left**2 - x**2, 0)) - self.sensor_y_offset
-      return(x,y)
+      return (x, y)
     except Exception as e:
       print(values)
       traceback.print_exc()

+ 8 - 2
raspberry-pi/sensors/connection.py

@@ -1,10 +1,15 @@
-import threading, time, serial
+import threading
+import time
+
+import serial
+
 
 class SerialConnection:
   def __init__(self):
     self._ser = None
     self.port = None
-    
+  
+  # try connecting to an available port
   def open(self, port = None, baudrate = 1000000):
     self.port = port
 
@@ -146,6 +151,7 @@ class ArduinoSlave(SerialConnection):
         else:
           print("SERIAL: ", data[:-2])
 
+# this allows the usage of a single instance of ArduinoSlave
 _conn = None
 def globalArduinoSlave():
   global _conn

+ 3 - 1
raspberry-pi/sensors/magneticSensor.py

@@ -1,8 +1,10 @@
-from sensors.connection import globalArduinoSlave
 import time
 
+from sensors.connection import globalArduinoSlave
+
 conn = globalArduinoSlave()
 
+
 class MagneticSensor:
   def __init__(self):
     pass

+ 6 - 0
raspberry-pi/sensors/opticalSensor.py

@@ -3,12 +3,14 @@
 import time
 import threading
 import traceback
+
 import numpy as np
 import cv2
 import cv2.aruco as aruco
 
 aruco_dict = aruco.Dictionary_get(aruco.DICT_4X4_50)
 
+
 def saveMarkers():
   image = np.zeros((400,400), np.uint8)
   image[:,:] = (255)
@@ -22,6 +24,7 @@ def saveMarkers():
 
 parameters =  aruco.DetectorParameters_create()
 
+
 def find_marker(image):
     # Our operations on the frame come here
   gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
@@ -50,6 +53,7 @@ def find_marker(image):
 
   return markers
 
+
 def measureDistances(image):
     markers = find_marker(image)
 
@@ -64,6 +68,7 @@ def measureDistances(image):
     else:
       return None
 
+
 class OpticalSensor():
   def __init__(self):
     self.cap = cv2.VideoCapture(0)
@@ -89,6 +94,7 @@ class OpticalSensor():
   def read(self):
     return self.values
 
+
 if __name__ == "__main__":
   # opt = OpticalSensor()
   # opt.start()