diff --git a/Code/Control/Laptop_Code/ESP32_AT/imageTread_AT.py b/Code/Control/Laptop_Code/ESP32_AT/imageTread_AT.py
index 4fdade85df85c73c0641473b3dea9062fe91e1a8..0c8ef6bdcc136bbe18da1ef89a356d6402391cfe 100644
--- a/Code/Control/Laptop_Code/ESP32_AT/imageTread_AT.py
+++ b/Code/Control/Laptop_Code/ESP32_AT/imageTread_AT.py
@@ -3,7 +3,9 @@ from urllib.request import urlopen, Request
 import numpy as np
 import time
 import math
+from math import sin,atan2,cos,pi,atan,sqrt
 # import apriltag
+import sys
 from pupil_apriltags import Detector
 def nothing(x):
     pass
@@ -18,6 +20,7 @@ def get_AT_6DOF_info(url):
     rx = [0.0,0.0,0.0]
     ry = [0.0, 0.0, 0.0]
     rz = [0.0, 0.0, 0.0]
+    pose_r = np.array([[0,0,0],[0,0,0],[0,0,0]])
     header = {
         "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36."}
     req = Request(url, headers=header)
@@ -36,7 +39,8 @@ def get_AT_6DOF_info(url):
     fy = 600
     cx = 400
     cy = 300
-    AT_size = 0.16
+    #AT_size = 0.16
+    AT_size = 0.74
     results = detector.detect(gray_image, estimate_tag_pose=True, camera_params=[fx, fy, cx, cy], tag_size=AT_size)
     debug_print = 0
     for r in results:
@@ -49,6 +53,7 @@ def get_AT_6DOF_info(url):
         ptA = (int(ptA[0]), int(ptA[1]))
         tx, ty, tz = r.pose_t # in meters
         rx,ry,rz = r.pose_R
+        pose_r = r.pose_R
         tid = r.tag_id
 
         # draw the bounding box of the AprilTag detection
@@ -81,15 +86,159 @@ def get_AT_6DOF_info(url):
 
     return tid,tx,ty,tz,rx,ry,rz
 
+def get_AT_6DOF_info_posR(url):
+    tid,tx,ty,tz= 0,100000,100000,0
+    rx = [0.0,0.0,0.0]
+    ry = [0.0, 0.0, 0.0]
+    rz = [0.0, 0.0, 0.0]
+    pose_r = np.array([[0,0,0],[0,0,0],[0,0,0]])
+    header = {
+        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36."}
+    req = Request(url, headers=header)
+    img_resp = urlopen(req, timeout=60)
+    imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8)
+    frame = cv2.imdecode(imgnp, -1)
+
+    # ret,frame = cap.read()
+    gray_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+
+    h, w, _ = frame.shape
+    # put a dot in center of the frame
+    cv2.circle(frame, (w // 2, h // 2), 7, (255, 0, 0), -1)
+    # set camera parameters
+    fx = 800
+    fy = 600
+    cx = 400
+    cy = 300
+    #AT_size = 0.16
+    AT_size = 0.74
+    results = detector.detect(gray_image, estimate_tag_pose=True, camera_params=[fx, fy, cx, cy], tag_size=AT_size)
+    debug_print = 0
+    for r in results:
+        # extract the bounding box (x, y)-coordinates for the AprilTag
+        # and convert each of the (x, y)-coordinate pairs to integers
+        (ptA, ptB, ptC, ptD) = r.corners
+        ptB = (int(ptB[0]), int(ptB[1]))
+        ptC = (int(ptC[0]), int(ptC[1]))
+        ptD = (int(ptD[0]), int(ptD[1]))
+        ptA = (int(ptA[0]), int(ptA[1]))
+        tx, ty, tz = r.pose_t # in meters
+        rx,ry,rz = r.pose_R
+        pose_r = r.pose_R
+        tid = r.tag_id
+
+        # draw the bounding box of the AprilTag detection
+        cv2.line(frame, ptA, ptB, (0, 255, 0), 5)
+        cv2.line(frame, ptB, ptC, (0, 255, 0), 5)
+        cv2.line(frame, ptC, ptD, (0, 255, 0), 5)
+        cv2.line(frame, ptD, ptA, (0, 255, 0), 5)
+        # draw the center (x, y)-coordinates of the AprilTag
+        (cX, cY) = (int(r.center[0]), int(r.center[1]))
+        cv2.circle(frame, (cX, cY), 5, (0, 0, 255), -1)
+
+        # draw the tag family on the image
+
+
+        tagFamily = r.tag_family.decode("utf-8")
 
-def rotationMatrixToEulerAngles(rx,ry,rz) :
 
-    sy = math.sqrt(rx[0] * rx[0] + ry[0] * ry[0])
-    roll = math.atan2(rz[1] , rz[2])
-    pitch = math.atan2(-rz[0], sy)
-    yaw = math.atan2(ry[0], rx[0])
+        cv2.putText(frame, tagFamily, (ptA[0], ptA[1] - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
+
+        cv2.putText(frame, "tx: {:.2f}  ty: {:.2f}  tz:{:.2f}".format(tx[0], ty[0], tz[0]), (ptA[0], ptA[1] + 30),
+                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
+
+        if debug_print == 1:
+            print("tx,ty,tz:{},{},{}".format(tx, ty, tz))
+            print("cX,cY:{},{}".format(cX, cY))
+            print("[INFO] tag id: {}".format(tid))
+
+    # show the output image after AprilTag detection
+    cv2.imshow("Image", frame)
+
+    return tid,tx,ty,tz,rx,ry,rz,pose_r
+
+
+def rotationM2Euler(rx,ry,rz) :
+    R_00 = rx[0]
+    R_01 = rx[1]
+    R_02 = rx[2]
+    R_10 = ry[0]
+    R_11 = ry[1]
+    R_12 = ry[2]
+    R_20 = rz[0]
+    R_21 = rz[1]
+    R_22 = rz[2]
+
+    sy = math.sqrt(R_00 * R_00 + R_10 * R_10)
+    singular = sy < 1e-6
+    if not singular:
+        x = math.atan2(R_21, R_22)
+        y = math.atan2(-R_20, sy)
+        z = math.atan2(R_10, R_00)
+    else:
+        x = math.atan2(-R_12, R_11)
+        y = math.atan2(-R_20, sy)
+        z = 0
+
+    print("phi =", np.rad2deg(x))
+    print("theta  =", np.rad2deg(y))
+    print("psi =", np.rad2deg(z))
+
+    """
+    tol = sys.float_info.epsilon * 10
+
+    if abs(R_00) < tol and abs(R_10) < tol:
+        eul1 = 0
+        eul2 = atan2(-R_20, R_00)
+        eul3 = atan2(-R_12, R_11)
+    else:
+        eul1 = atan2(R_10, R_00)
+        sp = sin(eul1)
+        cp = cos(eul1)
+        eul2 = atan2(-R_20, cp * R_00 + sp * R_10)
+        eul3 = atan2(sp * R_02 - cp * R_12, cp * R_11 - sp * R_01)
+
+    print("phi =", np.rad2deg(eul1))
+    print("theta  =", np.rad2deg(eul2))
+    print("psi =", np.rad2deg(eul3))
+    """
+
+
+def rotationMatrixToEulerAngles(R) :
+    assert(isRotationMatrix(R))
+    sy = math.sqrt(R[0,0] * R[0,0] +  R[1,0] * R[1,0])
+    singular = sy < 1e-6
+    if  not singular :
+        x = math.atan2(R[2,1] , R[2,2])
+        y = math.atan2(-R[2,0], sy)
+        z = math.atan2(R[1,0], R[0,0])
+    else :
+        x = math.atan2(-R[1,2], R[1,1])
+        y = math.atan2(-R[2,0], sy)
+        z = 0
+    print("R_phi =", np.rad2deg(x))
+    print("R_theta  =", np.rad2deg(y))
+    print("R_psi =", np.rad2deg(z))
+
+def R2EA(pose_r):
+    r11 = pose_r[0][0]
+    r12 = pose_r[0][1]
+    r13 = pose_r[0][2]
+    r21 = pose_r[1][0]
+    r22 = pose_r[1][1]
+    r23 = pose_r[1][2]
+    r31 = pose_r[2][0]
+    r32 = pose_r[2][1]
+    r33 = pose_r[2][2]
+
+    AprilTagPitch = round(np.degrees(atan(-r31 / sqrt((r32 * r32) + (r33 * r33)))), 3)
+    AprilTagRoll = round(np.degrees(atan(-r32 / r33)), 3)
+    ApriTagYaw = round(np.degrees(atan(r21 / r11)), 3)
+
+    print("pitch =", AprilTagPitch)
+    print("roll  =", AprilTagRoll)
+    print("yaw =", ApriTagYaw )
 
-    return np.array([roll, pitch, yaw])
 if __name__ == "__main__":
     #change the IP address below according to the
     #IP shown in the Serial monitor of Arduino code
@@ -97,6 +246,10 @@ if __name__ == "__main__":
     # url='http://192.168.1.107/cam-hi.jpg'
     url='http://192.168.4.1/cam-hi.jpg'
     url = 'http://192.168.1.118/cam-hi.jpg'
+    url = 'http://10.0.0.3/cam-hi.jpg'  #03
+    url = 'http://10.0.0.5/cam-hi.jpg'  #01
+    url = 'http://10.0.0.6/cam-hi.jpg'  #02
+    url = 'http://10.0.0.9/cam-hi.jpg'  # 6
 
 
     # cv2.namedWindow("live transmission", cv2.WINDOW_AUTOSIZE)
@@ -109,94 +262,30 @@ if __name__ == "__main__":
     if test_webcam == 1:
         cap = cv2.VideoCapture(0)
     while True:
-        """
-        header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36."}
-        req = Request(url, headers=header)
-        img_resp = urlopen(req, timeout=60)
-        imgnp=np.array(bytearray(img_resp.read()),dtype=np.uint8)
-        frame=cv2.imdecode(imgnp,-1)
-
-        gray_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
-        #print(len(gray_image.shape))
-        h,w,_ = frame.shape
-
-        # put a dot in center of the frame
-        cv2.circle(frame, (w//2, h//2), 7, (255, 0, 0), -1)
-        """
-        """
-        If you also want to extract the tag pose, estimate_tag_pose should be set to True
-        and camera_params ([fx, fy, cx, cy])
-        and tag_size (in meters) should be supplied.
-        The detect method returns a list of Detection objects each having
-        the following attributes
-        (note that the ones with an asterisks are computed only if estimate_tag_pose=True):
-        """
 
-        """
-        So fx and fy are the focal lengths expressed in pixels.
-        Cx and Cy describe the coordinates of the so called principal
-        point that should be in the center of the image.
-        It is e.g. not in the center of the image if you cropped the image,
-        what you should never do when calibrating.
-
-        fx, fy, cx, cy are given in Pixels in Computer Vision ( and openCV)
-        but e.g. in Photogrammetry you often use mm
-        """
-        """
-        fx = 800
-        fy = 600
-        cx = 400
-        cy = 300
-        results = detector.detect(gray_image,estimate_tag_pose=True, camera_params=[fx, fy, cx, cy], tag_size=0.16)
-
-        # loop over the AprilTag detection results
-        for r in results:
-            # extract the bounding box (x, y)-coordinates for the AprilTag
-            # and convert each of the (x, y)-coordinate pairs to integers
-            (ptA, ptB, ptC, ptD) = r.corners
-            ptB = (int(ptB[0]), int(ptB[1]))
-            ptC = (int(ptC[0]), int(ptC[1]))
-            ptD = (int(ptD[0]), int(ptD[1]))
-            ptA = (int(ptA[0]), int(ptA[1]))
-            tx,ty,tz = r.pose_t
-            print("tx,ty,tz:{},{},{}".format(tx,ty,tz))
-            # draw the bounding box of the AprilTag detection
-            cv2.line(frame, ptA, ptB, (0, 255, 0), 5)
-            cv2.line(frame, ptB, ptC, (0, 255, 0), 5)
-            cv2.line(frame, ptC, ptD, (0, 255, 0), 5)
-            cv2.line(frame, ptD, ptA, (0, 255, 0), 5)
-            # draw the center (x, y)-coordinates of the AprilTag
-            (cX, cY) = (int(r.center[0]), int(r.center[1]))
-            cv2.circle(frame, (cX, cY), 5, (0, 0, 255), -1)
-            # draw the tag family on the image
-            print("cX,cY:{},{}".format(cX,cY))
-
-
-            tagFamily = r.tag_family.decode("utf-8")
-            tid = r.tag_id
-            cv2.putText(frame, tagFamily, (ptA[0], ptA[1] - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
-
-            cv2.putText(frame, "tx: {:.2f}  ty: {:.2f}  tz:{:.2f}".format(tx[0],ty[0],tz[0]), (ptA[0], ptA[1] + 30), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
-
-            print("[INFO] tag id: {}".format(tid))
-
-        # show the output image after AprilTag detection
-        cv2.imshow("Image", frame)
-        """
-        tid,tx,ty,tz,rx,ry,rz = get_AT_6DOF_info(url)
+        tid,tx,ty,tz,rx,ry,rz,R = get_AT_6DOF_info(url)
 
         print("testing new function")
         print("-----------------------")
+
         print("tid:{}".format(tid))
         print("tx,ty,tz:{},{},{}".format(tx,ty,tz))
         print("rx,ry,rz:{},{},{}".format(rx,ry,rz))
 
-        # R = np.array([rx,ry,rz])
+
+        print("rotation matrix:{}".format(R))
+        R2EA(R)
+
+        # print("R00,R10,R20:{},{},{}".format(rx[0], ry[0], rz[0]))
+        # rotationM2Euler(rx, ry, rz)
+        """
         roll,pitch, yaw = rotationMatrixToEulerAngles(rx,ry,rz)
         roll = roll * 180 /math.pi
         pitch = pitch * 180 / math.pi
         yaw = yaw * 180 / math.pi
         print("roll,pitch,yaw:{},{},{}".format(roll, pitch, yaw))
+        """
+        # rotationMatrixToEulerAngles(R)
 
         key=cv2.waitKey(5)
         if key==ord('q'):
diff --git a/Code/Control/Laptop_Code/ESP32_slave/ESP32_slave.ino b/Code/Control/Laptop_Code/ESP32_slave/ESP32_slave.ino
index c32e3b41b30ed8d5dc0e58491546bf190020a22c..ccf46dc1f3fe91a849c426a2c652c46a6bc63d23 100644
--- a/Code/Control/Laptop_Code/ESP32_slave/ESP32_slave.ino
+++ b/Code/Control/Laptop_Code/ESP32_slave/ESP32_slave.ino
@@ -1,12 +1,19 @@
 #include <esp_now.h> 
 #include <WiFi.h> 
 #include <Wire.h> 
-#include <SparkFun_VL53L1X.h> 
+#include <VL53L1X.h>
 #include <Arduino.h> 
  
 #include "Camera.h" 
 #include "utilities.h" 
 #include <Adafruit_MotorShield.h> 
+
+// For LIDAR 1 and 2
+#define XSHUT_pin1 A7
+#define XSHUT_pin2 A6
+
+#define Sensor1_newAddress 43 
+#define Sensor2_newAddress 45
  
 // REPLACE WITH THE MAC Address of your receiver (MASTER) 
 // Slave: 40:F5:20:44:B6:4C 
@@ -35,9 +42,10 @@ String Rec_dir4;
 int count = 0; 
 int count_var = 0; 
 int print_count = 0; 
-int change_count =0; 
-int Lidar_flag = 0; 
- 
+int change_count =0;  
+int Lidar1_flag = 0; 
+int Lidar2_flag = 0; 
+
 // Define variables to be sent; 
 int Sent_tx = 0; 
 int Sent_ty = 0; 
@@ -46,12 +54,17 @@ int Sent_rx = 0;
 int Sent_ry = 0; 
 int Sent_rz = 0; 
 int Sent_dist = 0; 
+int Sent_dist1 = 0; 
+int Sent_dist2 = 0; 
  
 int8_t g1 = 0,g2=1,g3=2; 
 int8_t goal_id[3] = {g1, g2, g3}; 
  
 // Define Lidar variables 
-SFEVL53L1X distanceSensor; 
+// Define Lidar variables 
+VL53L1X Sensor1;
+VL53L1X Sensor2;
+
 int budgetIndex = 4; 
 int budgetValue[7] = {15, 20, 33, 50, 100, 200, 500}; 
  
@@ -68,7 +81,8 @@ typedef struct struct_message {
   int Rrx; 
   int Rry; 
   int Rrz; 
-  int Rdist; 
+  int Rdist1;
+  int Rdist2; 
   String DebugM; 
   int Spwm1; 
   int Spwm2; 
@@ -119,9 +133,9 @@ void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  
 // =============================== All the setup =========================================== 
 //Create the interface that will be used by the camera 
-openmv::rpc_scratch_buffer<256> scratch_buffer; // All RPC objects share this buffer. 
-openmv::rpc_i2c_master interface(0x12, 100000); //to make this more robust, consider making address and rate as constructor argument 
-Camera cam(&interface); 
+// openmv::rpc_scratch_buffer<256> scratch_buffer; // All RPC objects share this buffer. 
+// openmv::rpc_i2c_master interface(0x12, 100000); //to make this more robust, consider making address and rate as constructor argument 
+//Camera cam(&interface); 
 // ========================== Motor part ==================================== 
 // Create the motor shield object with the default I2C address 
 Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
@@ -135,23 +149,46 @@ void setup() {
   // Init Serial Monitor 
   Serial.begin(115200); 
   Wire.begin(); 
-  interface.begin(); //communication between ESP and OpenMV 
+  // interface.begin(); //communication between ESP and OpenMV 
   AFMS.begin();  // create with the default frequency 1.6KHz 
   // -------------- LED part -------------------- 
   pinMode(LED, OUTPUT); 
   digitalWrite(LED, HIGH); 
   digitalWrite(LED, LOW); 
-   
-  // -------------- lidar part -------------------- 
-  if (distanceSensor.begin() == 0){ 
-    Serial.println("Sensor online!"); 
-    Lidar_flag = 1; 
-  }else { 
-    Lidar_flag = 0; 
-  } 
-      
-  distanceSensor.startRanging(); 
-  distanceSensor.setIntermeasurementPeriod(budgetValue[budgetIndex]); 
+  
+ // -------------- lidar part -------------------- 
+  pinMode(XSHUT_pin1, OUTPUT);
+  pinMode(XSHUT_pin2, OUTPUT);
+  
+  Wire.setClock(100000); 
+
+  pinMode(XSHUT_pin1, INPUT);
+  if (!Sensor1.init()){
+    Serial.println("Failed to detect and initialize sensor1!");
+    Lidar1_flag = 0; 
+  } else {
+    Lidar1_flag = 1; 
+      delay(10);
+  Sensor1.setAddress(Sensor1_newAddress);
+  Sensor1.setTimeout(500);
+    Sensor1.setDistanceMode(VL53L1X::Medium);
+  Sensor1.setMeasurementTimingBudget(33000);
+  }
+
+
+  pinMode(XSHUT_pin2, INPUT);
+  if (!Sensor2.init())
+  {
+    Serial.println("Failed to detect and initialize sensor2!");
+    Lidar2_flag = 0; 
+  } else {
+    Lidar2_flag = 1; 
+  delay(10);
+  Sensor2.setAddress(Sensor2_newAddress);
+  Sensor2.setTimeout(500);
+  Sensor2.setDistanceMode(VL53L1X::Medium);
+  Sensor2.setMeasurementTimingBudget(33000);
+  }
    
  // --------------------------- esp now --------------------------- 
   // Set device as a Wi-Fi Station 
@@ -195,7 +232,7 @@ void loop()
   int y = 0;  
   bool goalfind_flag = 0; 
    
-  goalfind_flag = cam.exe_goalfinder(goal_id[0],goal_id[1],goal_id[2], id, tx, ty, tz, rx, ry, rz); 
+//  goalfind_flag = cam.exe_goalfinder(goal_id[0],goal_id[1],goal_id[2], id, tx, ty, tz, rx, ry, rz); 
   if (goalfind_flag){ 
       Sent_tx = tx; 
       Sent_ty = ty; 
@@ -211,11 +248,22 @@ void loop()
       Sent_ry = 0; 
       Sent_rz = 0;  
   } 
-  if (Lidar_flag == 1){ 
-    Sent_dist = distanceSensor.getDistance(); // Lidar distance (use the real Lidar data) 
+  if (Lidar1_flag == 1){ 
+    Sensor1.startContinuous(50);
+    Sensor1.read();
+    Sensor1.stopContinuous();
+    Sent_dist1 = Sensor1.ranging_data.range_mm; // Lidar distance (use the real Lidar data) 
   }else { 
-    Sent_dist = 0; 
-  } 
+    Sent_dist1 = 0; 
+  }
+  if (Lidar2_flag == 1){ 
+    Sensor2.startContinuous(50);
+    Sensor2.read();
+    Sensor2.stopContinuous();
+    Sent_dist2 = Sensor2.ranging_data.range_mm; // Lidar distance (use the real Lidar data) 
+  }else { 
+    Sent_dist2 = 0; 
+  }  
   // ========== lidar state info ========= 
   if (Sent_dist < 300 && Sent_dist > 0){ 
     receivedData.DebugM = "found b"; 
@@ -229,7 +277,8 @@ void loop()
   receivedData.Rrx = Sent_rx;   
   receivedData.Rry = Sent_ry;  
   receivedData.Rrz = Sent_rz; 
-  receivedData.Rdist = Sent_dist; 
+  receivedData.Rdist1 = Sent_dist1;
+  receivedData.Rdist2 = Sent_dist2;
   send_var_once(); 
   print_received_Data(); 
    
diff --git a/Code/Control/Laptop_Code/ball_detection/ball_detection.py b/Code/Control/Laptop_Code/ball_detection/ball_detection.py
index f35e2f847384cd7b5e0a62e0d75132a9a210d627..ee6c9873287cb955a844ee1f5fb9dfba5d47c564 100644
--- a/Code/Control/Laptop_Code/ball_detection/ball_detection.py
+++ b/Code/Control/Laptop_Code/ball_detection/ball_detection.py
@@ -23,9 +23,9 @@ distanceDetect = __import__('ball_detection.distance-detection-torch.distance-de
 
 # change the IP address below according to the IP shown in the Serial monitor of Arduino code
 # url='http://192.168.1.107/cam-lo.jpg'
-url='http://192.168.4.1/cam-hi.jpg'
+# url='http://192.168.4.1/cam-hi.jpg'
 # url='http://192.168.1.107/cam-mid.jpg'
-url='http://192.168.0.204/cam-hi.jpg' # url2
+# url='http://192.168.0.204/cam-hi.jpg' # url2
 
 #### Modify Detecto Core to include possibility of other base models
 def modifyCore():
@@ -33,10 +33,10 @@ def modifyCore():
   cAddLineNums = [254, 256, 257, 258, 259]
 
   # REPLACABLE LINE FOR DIFFERENT LOCAL COMPUTER DEVICES
-  coreFile     = 'C:\\Users\\uclal\\.conda\\envs\\foray2\\Lib\\site-packages\\detecto\\core.py'
+  coreFile     = 'C:\\Users\\aaronjs\\.conda\\envs\\FORAYenv\\Lib\\site-packages\\detecto\\core.py'
 
   cModLineVals = ["    def __init__(self, classes=None, device=None, pretrained=True, modelname=\'fasterrcnn_resnet50_fpn\'):\n",
-                  "        # Load a model pre-trained on COCO - User-Modified",
+                  "        # Load a model pre-trained on COCO - User-Modified\n",
                   "            self._model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=pretrained)\n"]
   cAddLineVals = ["        if modelname == \'fasterrcnn_resnet50_fpn\':\n",
                   "        elif modelname == \'fasterrcnn_mobilenet_v3_large_fpn\':\n",
@@ -81,7 +81,7 @@ def returnModel(device, labelSet, modelLoc, modelFile):
   return model
 
 #### Live Detection
-def detectLive(model, minDetectionScore = 0.90, showSight = True):
+def detectLive(url , model, minDetectionScore = 0.90, showSight = True):
     '''
     Descrption:
         ball detection ML Functions
diff --git a/Code/Control/Laptop_Code/ball_detection/ball_detection_full.py b/Code/Control/Laptop_Code/ball_detection/ball_detection_full.py
deleted file mode 100644
index ee9dceaa208cff7dc279518acd52ca0286831657..0000000000000000000000000000000000000000
--- a/Code/Control/Laptop_Code/ball_detection/ball_detection_full.py
+++ /dev/null
@@ -1,255 +0,0 @@
-## Codebase - Live Training-based Ball Detection
-### Import Modules and Drive
-import os
-import cv2
-import glob
-import torch
-import numpy as np
-import torch.nn as nn
-import torch.quantization
-import matplotlib.pyplot as plt
-import matplotlib.patches as patches
-
-from urllib.request import urlopen, Request  #
-
-from base64 import b64decode
-from datetime import datetime
-from matplotlib import patches
-from detecto import core, utils
-from torchvision import transforms
-from matplotlib import pyplot as plt
-distanceDetect = __import__('ball_detection.distance-detection-torch.distance-detection-torch', fromlist = ['distanceDetect']).distanceDetect
-print("torch.cuda.is_available() = ", torch.cuda.is_available())
-
-minDetectionScore    =   0.50
-
-# change the IP address below according to the IP shown in the Serial monitor of Arduino code
-# url='http://192.168.1.107/cam-lo.jpg'
-url='http://192.168.4.1/cam-hi.jpg'
-# url='http://192.168.1.107/cam-mid.jpg'
-
-#### Modify Detecto Core to include possibility of other base models
-def modifyCore():
-  cModLineNums = [221, 253, 254]
-  cAddLineNums = [254, 256, 257, 258, 259]
-
-  # REPLACABLE LINE FOR DIFFERENT LOCAL COMPUTER DEVICES
-  coreFile     = 'C:\\Users\\uclal\\.conda\\envs\\foray2\\Lib\\site-packages\\detecto\\core.py'
-
-  cModLineVals = ["    def __init__(self, classes=None, device=None, pretrained=True, modelname=\'fasterrcnn_resnet50_fpn\'):\n",
-                  "        # Load a model pre-trained on COCO - User-Modified",
-                  "            self._model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=pretrained)\n"]
-  cAddLineVals = ["        if modelname == \'fasterrcnn_resnet50_fpn\':\n",
-                  "        elif modelname == \'fasterrcnn_mobilenet_v3_large_fpn\':\n",
-                  "            self._model = torchvision.models.detection.fasterrcnn_mobilenet_v3_large_fpn(pretrained=pretrained)\n",
-                  "        elif modelname == \'fasterrcnn_mobilenet_v3_large_320_fpn\':\n",
-                  "            self._model = torchvision.models.detection.fasterrcnn_mobilenet_v3_large_320_fpn(pretrained=pretrained)\n",
-                  "        else:",
-                  "            return ValueError('Unknown Pretrained Model')"]
-  coreRead = open(coreFile, "r")
-  coreLines = coreRead.readlines()
-  if coreLines[253][-14:-1] != 'User-Modified':
-    for count, cModLineNum in enumerate(cModLineNums):
-      coreLines[cModLineNum] = cModLineVals[count]
-    for count, cAddLineNum in enumerate(cAddLineNums):
-      coreLines.insert(cAddLineNum, cAddLineVals[count])
-    coreRead.close()
-    coreWrite = open(coreFile, "w")
-    coreWrite.writelines(coreLines)
-    coreWrite.close()
-
-### Train the Model
-def modelName(type = 1):
-  if type == 1:
-    return 'fasterrcnn_resnet50_fpn'
-  elif type == 2:
-    return 'fasterrcnn_mobilenet_v3_large_fpn'
-  elif type == 3:
-    return 'fasterrcnn_mobilenet_v3_large_320_fpn'
-  else:
-    return ValueError('Unknown Pretrained Model')
-
-def modelTitle(modelLoc, device, type):
-  time = datetime.now().strftime("%Y%m%d_%H%M%S")
-  if device == 'cpu':
-    dev = 'cpu'
-  elif device[:4] == 'cuda':
-    dev = 'cuda'
-    print("using cuda")
-  return modelLoc + 'model_weights-' + str(type) + '-' + time + '-' + dev + '.pth'
-
-def returnModel(modelAction, device, trainLoc, labelSet, modelLoc, modelFile):
-  if modelAction == 'new':
-    dataset = core.Dataset(trainLoc)
-    model   = core.Model(labelSet, device = device, modelname = modelName(modelType))
-    losses  = model.fit(dataset, epochs = 10, verbose = True)
-    model.save(modelTitle(modelLoc, device, modelType))
-  elif modelAction == 'load':
-    model = core.Model(labelSet, modelname = modelname)
-    #model = core.Model(classes = labelSet, device = device, pretrained = True, model_name = modelName(modelType))
-    model._model.load_state_dict(torch.load(modelLoc + modelFile, map_location = torch.device(device)))
-  # model = torch.quantization.quantize_dynamic(model.get_internal_model(), dtype=torch.qint8)
-  return model
-
-### Object Detection
-def objectDetection(loc):
-  image = utils.read_image(loc)
-  predictions = model.predict(image)
-  tLabels, tBoxes, tScores = predictions
-  labels,  boxes,  scores  = [[] for i in range(3)]
-  imHeight, imWidth, _ = image.shape
-  for count, box in enumerate(tBoxes):
-    x0, y0 = float(box[0]), float(box[1])
-    x1, y1 = float(box[2]), float(box[3])
-    w      = x1 - x0
-    h      = y1 - y0
-    center = (x0 + (w/2), y0 + (h/2))
-    dCrop  = [int(y0*cropFactor + y1*(1-cropFactor)), int(y1*cropFactor + y0*(1-cropFactor)),
-              int(x0*cropFactor + x1*(1-cropFactor)), int(x1*cropFactor + x0*(1-cropFactor))]
-    distance     = distanceDetect('load-testImg', distWtsFile, [[x0, x1, y0, y1], [imWidth, imHeight]])
-    avgClRGB     = cv2.mean(image[dCrop[0]:dCrop[1], dCrop[2]:dCrop[3]])
-    avgClHue     = rgbToHue(avgClRGB)
-    print('Detection Score     : ', round(float(tScores[count])*100, 2), '%')
-    print('Average Color (RGB) : ', avgClRGB)
-    print('Average Color (Hue) : ', avgClHue)
-    print('Bounding Box Center : ', center)
-    print('Distance to Ball    : ', distance)
-    # print('Relative Distance   : ', relativeDist)
-    # print('Coordinates         : ', coordinates)
-    print()
-    if tScores[count] > minDetectionScore and avgClHue > colorLow and avgClHue < colorHigh:
-      scores.append(float(tScores[count]))
-      labels.append(tLabels[count]+' '+str(round(float(tScores[count])*100, 2))+'%')
-      boxes.append ([x0, y0, x1, y1])
-  displayBoxedImage(image, boxes, labels)
-
-#### Live Detection
-def detectLive(model, showSight = True):
-    gbx = 0
-    gby = 0
-    dist = 0
-
-    header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36."}
-    req = Request(url, headers=header)
-    img_resp = urlopen(req, timeout=60)
-    imgnp=np.array(bytearray(img_resp.read()),dtype=np.uint8)
-    frame=cv2.imdecode(imgnp,-1)
-
-    labels, boxes, scores = model.predict(frame)
-    for i in range(boxes.shape[0]):
-      box = boxes[i]
-      x0, y0 = float(box[0]), float(box[1])
-      x1, y1 = float(box[2]), float(box[3])
-      w      = x1 - x0
-      h      = y1 - y0
-      dCrop  = [int(y0*cropFactor + y1*(1-cropFactor)), int(y1*cropFactor + y0*(1-cropFactor)),
-                int(x0*cropFactor + x1*(1-cropFactor)), int(x1*cropFactor + x0*(1-cropFactor))]
-      avgClRGB = cv2.mean(frame[dCrop[0]:dCrop[1], dCrop[2]:dCrop[3]])
-      avgClHue = rgbToHue(avgClRGB)
-
-      if scores[i] > minDetectionScore and avgClHue > colorLow and avgClHue < colorHigh:
-        cv2.rectangle(frame, (int(x0), int(y0)),
-                             (int(x1), int(y1)),
-                             (0, 255, 0), 2)
-        if labels:
-          dist = distanceDetect('load-testImg', distWtsFile, [[x0, x1, y0, y1], frame.shape[:2]])
-          gbx = int((x1 + x0) / 2)
-          gby = int((y1 + y0) / 2)
-          cv2.putText(frame, 'x:{}, y:{}'.format(gbx, gby),
-                             (int(box[0]), int(box[1]) - 10),
-                             cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 3)
-
-
-    cv2.imshow('Ball Detection', frame)
-    key = cv2.waitKey(1) & 0xFF
-    return gbx, gby,dist
-
-### Supplementary Functions
-#### Display of Image with Bounding Boxes
-def displayBoxedImage(image, boxes = [], labels = None):
-  fig, ax = plt.subplots(1)
-  if isinstance(image, torch.Tensor):
-    image = utils.reverse_normalize(image)
-    image = transforms.ToPILImage()(image)
-  ax.imshow(image)
-  if labels is not None and not utils._is_iterable(labels):
-    labels = [labels]
-  for i in range(len(boxes)):
-    box = boxes[i]
-    width, height =  box[2] - box[0], box[3] - box[1]
-    initial_pos   = (box[0], box[1])
-    rect = patches.Rectangle(initial_pos, width, height, linewidth = 1, edgecolor = 'r', facecolor = 'none')
-    if labels:
-      ax.text(box[0] + 5, box[1] - 5, '{}'.format(labels[i]), color='red')
-    ax.add_patch(rect)
-  plt.show()
-
-#### Calculation of Hue from RGB (adopted from [code](https://www.geeksforgeeks.org/program-change-rgb-color-model-hsv-color-model/))
-def rgbToHue(RGB):
-  RGB = [val/255.0 for val in RGB]
-  cmax = max(RGB)
-  cmin = min(RGB)
-  diff = cmax - cmin
-  r, g, b = RGB[0:3]
-  if cmax == cmin:
-    return 0
-  if cmax == r:
-    return (60 * ((g - b) / diff) + 360) % 360
-  if cmax == g:
-    return (60 * ((b - r) / diff) + 120) % 360
-  if cmax == b:
-    return (60 * ((r - g) / diff) + 240) % 360
-
-#### Formula-based Depth Estimation (adopted from [mono_depth.py](https://github.com/agrawalparth10/FORAY-Perception/blob/master/mono_depth/mono_depth.py))
-def depth_estimate(figDims, boundingBox):
-  def x_hat(realLen, ip, i0, imageLen):
-    return (realLen * (ip-i0)) / imageLen
-  def y_hat(realLen, jp, j0, imageLen):
-    return (realLen * (jp-j0)) / imageLen
-  def z_hat(dist, pixelLen, imageLen):
-    return dist*(pixelLen/imageLen)
-  def cal_coordinates(dist, realLen, ip, jp, i0, j0, imageLen, pixelLen):
-    return (x_hat(realLen, ip, i0, imageLen), y_hat(realLen, jp, j0, imageLen), z_hat(dist, pixelLen, imageLen))
-  def measure(dist, realLen, ip, jp, i0, j0, imageLen, pixelLen):
-    x_cor = x_hat(realLen, ip, i0, imageLen)
-    z_cor = z_hat(dist, pixelLen, imageLen)
-    dist  = (x_cor ** 2 + z_cor ** 2) ** 0.5
-    return dist
-  imHeight, imWidth = figDims
-  center = (imWidth // 2, imHeight // 2)
-  x, y, w, h   = boundingBox[0:4]
-  relativeDist = measure        (dist = 0.51, realLen = 0.228, ip = x, jp = y, i0 = center[0], j0 = center[1], imageLen = w, pixelLen = 500)
-  coordinates  = cal_coordinates(dist = 0.51, realLen = 0.228, ip = x, jp = y, i0 = center[0], j0 = center[1], imageLen = w, pixelLen = 500)
-  return relativeDist, coordinates
-
-### Declare Varables and Constants
-device      = 'cuda'
-imageLoc    = './ball_detection/images/train-test-4/'  #
-labelSet    = ['ball']
-modelLoc    = './ball_detection/model_weights/'  #
-trainLoc    = imageLoc + 'train/'
-colorLow    =  60
-colorHigh   = 180
-modelFile   = 'model_weights-2-20210818_002355-cpu.pth'
-modelname   = modelName(int(modelFile[14]))
-modelType   =   2
-cropFactor  =   0.90
-distWtsFile = './ball_detection/distance-detection-torch/distance-detection-weights-3-2.0sd-20210808_212550.json'
-modelAction = 'load' # 'load' to load previous model, 'new' to train new model (only possible on Colab)
-
-#FOR THE NEXT LINE : UNCOMMENT  the first time you run, COMMENT OUT after the first time
-modifyCore()
-#########
-
-# model = returnModel(modelAction, device, trainLoc, labelSet, modelLoc, modelFile)
-# # # ## Testing (using Live Streaming)
-# while True:
-#     detectLive(model)
-
-# ## Testing (using Untrained Images)
-# for file in sorted(glob.glob(imageLoc + '/test/*.jpg')):
-#   objectDetection(file)
-#
-# ## Evaluation (using Trained Images)
-# for file in sorted(glob.glob(imageLoc + '/train/*.jpg')):
-#   objectDetection(file)
diff --git a/Code/Control/Laptop_Code/basic_comm_test/ESP32_master/ESP32_master.ino b/Code/Control/Laptop_Code/basic_comm_test/ESP32_master/ESP32_master.ino
index 446b2506f8497ee6d91e1e8a121d0b4f0ffc28cb..19c4fbe747a1eb1079353f5fe7550c168944e001 100644
--- a/Code/Control/Laptop_Code/basic_comm_test/ESP32_master/ESP32_master.ino
+++ b/Code/Control/Laptop_Code/basic_comm_test/ESP32_master/ESP32_master.ino
@@ -9,8 +9,8 @@
 //uint8_t broadcastAddress[] = {0xC4, 0xDD, 0x57, 0x9E, 0x8A, 0x98}; // #3
 //uint8_t broadcastAddress[] = {0x40, 0xF5, 0x20, 0x44, 0xB6, 0x4C}; // #4
 //uint8_t broadcastAddress[] = {0x40, 0xF5, 0x20, 0x44, 0xC0, 0xD8}; // #5
-//uint8_t broadcastAddress[] = {0x40, 0xF5, 0x20, 0x44, 0xDE, 0xE0}; // #6
-uint8_t broadcastAddress[] = {0x3C, 0x61, 0x05, 0x4A, 0xD3, 0x3C}; // #7
+uint8_t broadcastAddress[] = {0x40, 0xF5, 0x20, 0x44, 0xDE, 0xE0}; // #6
+//uint8_t broadcastAddress[] = {0x3C, 0x61, 0x05, 0x4A, 0xD3, 0x3C}; // #7
 //uint8_t broadcastAddress[] = {0x3C, 0x61, 0x05, 0x9B, 0x04, 0x98}; // #8
 // ==================================== global data =================================================
 String success;
@@ -29,7 +29,8 @@ typedef struct struct_message {
   int Rrx;
   int Rry;
   int Rrz;
-  int Rdist;
+  int Rdist1;
+  int Rdist2; 
   String DebugM;
   int Spwm1;
   int Spwm2;
@@ -70,7 +71,8 @@ void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
   Serial.println(sentData.Rrx);
   Serial.println(sentData.Rry);
   Serial.println(sentData.Rrz);
-  Serial.println(sentData.Rdist);
+  Serial.println(sentData.Rdist1);
+  Serial.println(sentData.Rdist2);
   Serial.println(sentData.DebugM);
 }
 // =================================== setup ==================================================
diff --git a/Code/Control/Laptop_Code/constants.py b/Code/Control/Laptop_Code/constants.py
index 9c7c47bd4b54c1f04a243ba48dd0bfd7d372fcfe..4bf80a33dc3d73df3ba1b13f4423b82830ae9aae 100644
--- a/Code/Control/Laptop_Code/constants.py
+++ b/Code/Control/Laptop_Code/constants.py
@@ -31,11 +31,10 @@ Bmax = 127
 threshold = [Lmin, Lmax, Amin, Amax, Bmin, Bmax]
 
 base_speed    = 120
-seeking_speed =  70
+seeking_speed =  50
 LIDAR_Thres   = 300 # mm
 
 
-
 # PID Control in move2ball
 kpx,kix,kdx = 1.2, 0.01, 0.5
 # kpx,kix,kdx = 0.0, 0.00, 0.0
@@ -44,14 +43,20 @@ kpy,kiy,kdy = 1.2, 0.05, 0.9
 
 # PID Control in move2goal
 # kpx_g,kix_g,kdx_g = 1.5, 0.01, 0.5
-kpx_g,kix_g,kdx_g = 2, 0.01, 0.7
+kpx_g,kix_g,kdx_g = 1.6, 0.01, 0.7
 # kpx_g,kix_g,kdx_g = 0.0, 0.0, 0.0
-kpy_g,kiy_g,kdy_g = 1.7, 0.01, 0.7
+kpy_g,kiy_g,kdy_g = 2, 0.01, 0.7
 # kpy_g,kiy_g,kdy_g = 0.0, 0.0, 0.0
 
 # difference between center of AT and center of goal
 AT_goal_Delta =  0 #cm
 
-AT_h1 = 50 # meters
+AT_h1 = 140 # openmv: | esp32_cam:meters
+
+kph,kih,kdh = 1.2,0.01,0.5
+
+# Break between AT detection during ball seeking
+AT_detectBreak = 60
+
 
-kph,kih,kdh = 1.2,0.01,0.5
\ No newline at end of file
+url_gb = 'http://10.0.0.4/cam-hi.jpg'  # 6
\ No newline at end of file
diff --git a/Code/Control/Laptop_Code/imageThread_AT_gb_1_6.py b/Code/Control/Laptop_Code/imageThread_AT_gb_1_6.py
new file mode 100644
index 0000000000000000000000000000000000000000..69853142d45e29164e24affea9288054418c6eda
--- /dev/null
+++ b/Code/Control/Laptop_Code/imageThread_AT_gb_1_6.py
@@ -0,0 +1,38 @@
+# import sys
+# sys.path.append("../")
+
+from ESP32_AT.imageTread_AT import get_AT_6DOF_info
+
+from constants import *
+import ball_detection.ball_detection as ball_detection
+import cv2
+
+# detector = apriltag.Detector()
+
+
+if __name__ == "__main__":
+    url_AT = 'http://10.0.0.5/cam-hi.jpg' #1
+    url_gb = 'http://10.0.0.9/cam-hi.jpg' #6
+
+    tid,tx,ty,tz,rx,ry,rz = 0,0,0,0,0,0,0
+
+    # GB
+    ball_detection.modifyCore()
+    # modelLoc          = './ball_detection/model_weights/'
+    # modelFile         = 'model_weights-2-20210818_002355-cpu.pth'
+    model = ball_detection.returnModel(device, labelSet, modelLoc, modelFile)
+
+    gbx, gby  = -1, -1   # by default (-1 means no found green ball)
+    gb_dist = -1         # by default (-1 means no found green ball)
+
+
+    while True:
+        tid,tx,ty,tz,rx,ry,rz = get_AT_6DOF_info(url_AT)
+
+        # gbx, gby, gb_dist = ball_detection.detectLive(url_gb, model, minDetectionScore, showSight = True)
+
+        key=cv2.waitKey(5)
+        if key==ord('q'):
+            break
+
+    cv2.destroyAllWindows()
diff --git a/Code/Control/Laptop_Code/imageThread_AT_gb.py b/Code/Control/Laptop_Code/imageThread_AT_gb_2_4.py
similarity index 75%
rename from Code/Control/Laptop_Code/imageThread_AT_gb.py
rename to Code/Control/Laptop_Code/imageThread_AT_gb_2_4.py
index fde64ac8e5d881978b58d3bd82a4cb24d13a791c..62ffb17295f372259451b2dc2030c6303d368906 100644
--- a/Code/Control/Laptop_Code/imageThread_AT_gb.py
+++ b/Code/Control/Laptop_Code/imageThread_AT_gb_2_4.py
@@ -11,8 +11,8 @@ import cv2
 
 
 if __name__ == "__main__":
-    url1 = 'http://192.168.0.230/cam-hi.jpg'
-    url2 = 'http://192.168.0.204/cam-hi.jpg'
+    url_AT = 'http://10.0.0.3/cam-hi.jpg' #2
+    url_gb = 'http://10.0.0.6/cam-hi.jpg' #4
 
 
     tid,tx,ty,tz,rx,ry,rz = 0,0,0,0,0,0,0
@@ -28,9 +28,9 @@ if __name__ == "__main__":
 
 
     while True:
-        tid,tx,ty,tz,rx,ry,rz = get_AT_6DOF_info(url1)
+        tid,tx,ty,tz,rx,ry,rz = get_AT_6DOF_info(url_AT)
 
-        gbx, gby, gb_dist = ball_detection.detectLive(model, minDetectionScore, showSight = True)
+        # gbx, gby, gb_dist = ball_detection.detectLive(url_gb, model, minDetectionScore, showSight = True)
 
         key=cv2.waitKey(5)
         if key==ord('q'):
diff --git a/Code/Control/Laptop_Code/main_keyboard.py b/Code/Control/Laptop_Code/main_keyboard.py
index e709ad57f84b34abe946a024c72fcf7b28066f61..2911a2a52615c3b36e2b570d1fa27cfb1fc6b341 100644
--- a/Code/Control/Laptop_Code/main_keyboard.py
+++ b/Code/Control/Laptop_Code/main_keyboard.py
@@ -9,8 +9,10 @@ from ESP32_AT.imageTread_AT import get_AT_6DOF_info
 
 global ml,esp_cam_on,openmv_on
 ml = 1
-esp_cam_on = 0
-openmv_on = 1
+esp_cam_on = 1
+openmv_on = 0
+seekVertDir = 1
+AT_detected_time = time.time()
 if ml == 1:
     import ball_detection.ball_detection as ball_detection
 
@@ -31,7 +33,7 @@ def serial_port_in_v1(serial_port):
     # DEBUG Verbose
     print("initiating one round of serial in ...")
 
-    for i in range(8):
+    for i in range(7):
         line = serial_port.readline()
         val = int(line.decode())
 
@@ -49,9 +51,10 @@ def serial_port_in_v1(serial_port):
             rz = val
         elif i == 6:
             LIDAR_dist1 = val
-        elif i == 7:
-            LIDAR_dist2 = val
+        # elif i == 7:
+            # LIDAR_dist2 = val
 
+    LIDAR_dist2 = 0
     line = serial_port.readline()
     debugM = line.decode()
 
@@ -190,16 +193,17 @@ def move2goal(tx, ty,tz):
     setpoint_x1 = 0.0
     setpoint_y1 = 0.0
 
-    if tz <200:
-        kpy_g,kiy_g,kdy_g = 0.0, 0.0, 0.0
-        base_speed = 150
-        AT_goal_Delta = 150
+    if tz < 2.0:
+        kpy_g,kiy_g,kdy_g =  2, 0.1, 0.5
+        base_speed = 200
+        AT_goal_Delta = -150
     else:
-        kpy_g,kiy_g,kdy_g = 2, 0.01, 0.5
-        base_speed = 120
+        kpy_g,kiy_g,kdy_g = 2, 0.1, 0.5
+        # kpy_g,kiy_g,kdy_g = 0.0, 0.00, 0.0
+        base_speed = 140
         AT_goal_Delta = 0
-    inputx = tx / 1.00
-    inputy =  (ty + AT_goal_Delta) / 1.00 #
+    inputx = tx * 100/ 1.00
+    inputy =  (ty * 100 + AT_goal_Delta) / 1.00 #
 
     pid_x = PID(kpx_g, kix_g, kdx_g, setpoint = setpoint_x1)
     pid_y = PID(kpy_g, kiy_g, kdy_g, setpoint = setpoint_y1)
@@ -211,17 +215,17 @@ def move2goal(tx, ty,tz):
 
     outputx = pid_x(inputx)
     outputy = pid_y(inputy)
-
+    print("outputy:{}".format(outputy))
     # Vertical
     pwm1 = abs(outputy)
     pwm2 = abs(outputy)
 
     if(outputy > 0):
-        dir1 = '-'
-        dir2 = '-'
-    else:
         dir1 = '+'
         dir2 = '+'
+    else:
+        dir1 = '-'
+        dir2 = '-'
 
     # Horizontal
     lspeed = -1 * outputx + base_speed
@@ -253,9 +257,9 @@ def ball_seeking(count_h,tx,ty):
         pwm1, pwm2, pwm3, pwm4
         dir1, dir2, dir3, dir4
     """
-    global set_h
+    global set_h, seekVertDir
     if openmv_on == 1:
-        delta_h = 100
+        delta_h = 100 # cm
         threshold_h = 20
     elif esp_cam_on == 1:
         delta_h = 2 # meter
@@ -282,6 +286,23 @@ def ball_seeking(count_h,tx,ty):
     else:
         pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = rotate_one_direction()
 
+
+    # if time.time() > AT_detected_time + AT_detectBreak:
+    #     AT_detected = AT_detect(tx, ty)
+    #     AT_detected_time = time.time()
+    #
+    # while facingWall():
+    #     pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = rotate_one_direction_ssp(new_ssp)
+    #
+    # if AT_detected:
+    #     current_h = get_altitude_from_AT(AT_h1,ty)
+    #
+    # if LIDAR_dist2 < LIDAR2_Thres:
+    #     seekVertDir = 0
+    # if baroHeight < baroThres:
+    #     seekVertDir = 1
+    # pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = move_in_spiral(new_ssp, seekVertDir)
+
     return int(pwm1), int(pwm2), int(pwm3), int(pwm4), dir1, dir2, dir3, dir4
 
 def vertical_control(current_h,set_h):
@@ -317,6 +338,14 @@ def rotate_one_direction_ssp(ssp):
 
     return int(pwm1), int(pwm2), int(pwm3), int(pwm4), dir1, dir2, dir3, dir4
 
+def move_in_spiral(ssp, dir):
+    pwm1, pwm2, pwm3, pwm4 = ssp, ssp, ssp, ssp/2
+    dir1, dir2, dir3, dir4 = '+', '+', '+', '-'
+    if dir == 0:
+        dir1, dir2 = '-', '-'
+
+    return int(pwm1), int(pwm2), int(pwm3), int(pwm4), dir1, dir2, dir3, dir4
+
 def move2ball(gbx, gby, gb_dist):
     """
     Description:
@@ -379,7 +408,7 @@ def move2ball(gbx, gby, gb_dist):
 
 
 #  =========== Main Control ===========
-def main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM, count_h):
+def main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM, count_h,bcap_man):
     '''
     Description:
         Given green ball information and AT information, the main control logic
@@ -394,20 +423,29 @@ def main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_d
     Output:
         pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4  :   Blimp motor manuver parameters
     '''
+    print('in main_control')
     # placeholder
     pwm1, pwm2, pwm3, pwm4 = 0 , 0 , 0 , 0
     dir1, dir2, dir3, dir4 = '+', '-', '+', '-'
 
     ballDetect  = ball_detect(gbx, gby)
-    ballCapture = ball_capture(LIDAR_dist1)
+    # ballCapture = ball_capture(LIDAR_dist1)
     goalDetect  = goal_detect(tx, ty)
 
-    ballCapture = 1
+    ballCapture = 0
 
     # debug
-    # ballCapture = 1
-    # goalDetect = 0
+    if bcap_man == 1:
+        ballCapture = 1  # Manually determine Ball captured
+    elif bcap_man == 0:
+        ballCapture = 0 # Ball not captured
+    elif bcap_man == -1:
+        ballCapture = ball_capture(LIDAR_dist1)
+
+        # goalDetect = 0
+    # ballDetect = 0
     if ballCapture: # Ball captured
+        print('ballCapture TRUE')
         if goalDetect:  # Goal detected
             # stop_all()  # Debug
             pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = move2goal(tx, ty,tz)
@@ -415,21 +453,24 @@ def main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_d
             # stop_all()  # Debug
             pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = rotate_one_direction()
     else:  # Ball not captured
+        print('ballCapture FALSE')
         if ballDetect:  # Ball detected
             pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = move2ball(gbx,gby,gb_dist)
         else:  # Ball not detected
             # stop_all()  # Debug
-            # pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = rotate_one_direction()
-            pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = ball_seeking(count_h,tx,ty)
+            pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = rotate_one_direction()
+
+            # pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = ball_seeking(count_h,tx,ty)
 
     return pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4
 
-def auto_control(serial_port,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM,count_h):
+def auto_control(serial_port,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM,count_h,bcap_man):
     # ===== STEP 1: TAKE ALL INPUT =====
+    # print('in auto_control')
     if ml ==1:
-        gbx, gby, gb_dist = ball_detection.detectLive(model, minDetectionScore, showSight = True)
+        gbx, gby, gb_dist = ball_detection.detectLive(url_gb, model, minDetectionScore, showSight = True)
     line = serial_port.readline()
-
+    # print('auto')
     if openmv_on == 1:
         if line == b'SERIAL_IN_START\r\n':
             tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM = serial_port_in_v1(serial_port)
@@ -438,12 +479,15 @@ def auto_control(serial_port,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_di
 
 
     if esp_cam_on == 1:
-        url = 'http://192.168.1.118/cam-hi.jpg'
+        url = 'http://10.0.0.5/cam-hi.jpg'  # 1
         tid, tx, ty, tz, rx, ry, rz = get_AT_6DOF_info(url)
+        LIDAR_dist1 = 0
+        LIDAR_dist2 = 0
+        debugM = "using two esp32 cam"
+
 
     # ===== STEP 2: MAIN CONTROL LOOP =====
-    pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2,
-                                                                  debugM, count_h)
+    pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM, count_h,bcap_man)
 
     # ===== STEP 3: FEED ALL OUTPUT =====
     serial_port_out(serial_port, pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4)
@@ -452,12 +496,13 @@ def auto_control(serial_port,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_di
 
 def auto_init(init_count,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM):
     count_h = 0
-    # gbx, gby, gb_dist = ball_detection.detectLive(model, minDetectionScore, showSight = True)
-    pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM, count_h)
+    bcap_man = -1
+    # gbx, gby, gb_dist = ball_detection.detectLive(url_gb, model, minDetectionScore, showSight = True)
+    pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM, count_h,bcap_man)
     serial_port_out(serial_port, pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4)
     init_count += 1
 
-    return init_count,count_h
+    return init_count,count_h,bcap_man
 
 def init():
     pygame.init()
@@ -572,7 +617,7 @@ def manual_control(Ctl_com,serial_port):
 
     waitTime = 0.05
     # changed
-    # gbx, gby, gb_dist = ball_detection.detectLive(model, minDetectionScore, showSight = True)
+    # gbx, gby, gb_dist = ball_detection.detectLive(url_gb, model, minDetectionScore, showSight = True)
 
     serial_port_out(serial_port, pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4)
 
@@ -606,21 +651,59 @@ def get_altitude_from_AT(AT_h,ty):
     altitude = AT_h - ty
     return altitude
 
+
+
 def test_function():
-    url = 'http://192.168.1.118/cam-hi.jpg'
+    url_AT = 'http://10.0.0.5/cam-hi.jpg'  # 1
+    url_gb = 'http://10.0.0.4/cam-hi.jpg'  # 6
+
+    tid, tx, ty, tz, rx, ry, rz = get_AT_6DOF_info(url_AT)
+    gbx, gby, gb_dist = ball_detection.detectLive(url_gb, model, minDetectionScore, showSight=True)
+
+    print("testing new function")
+    print("-----------------------")
+    print("tid:{}".format(tid))
+    print("tx,ty,tz:{},{},{}".format(tx,ty,tz))
+    print("rx,ry,rz:{},{},{}".format(rx,ry,rz))
+    print("gbx,gby,gb_dist:{},{},{}".format(gbx,gby,gb_dist))
+
+def test_function1():
+    url = 'http://192.168.0.230/cam-hi.jpg'
     tid, tx, ty, tz, rx, ry, rz = get_AT_6DOF_info(url)
+
     print("testing new function")
     print("-----------------------")
     print("tid:{}".format(tid))
     print("tx,ty,tz:{},{},{}".format(tx,ty,tz))
     print("rx,ry,rz:{},{},{}".format(rx,ry,rz))
 
+def manual_in_auto(Ctl_com, serial_port, flag):
+    if get_key('m'):
+        flag = 12
+    while (flag == 12):
+        manual_control(Ctl_com, serial_port)
+        flag = manual_return2auto('r',flag)
+    return flag
+
+def manual_return2auto(key_press,flag_r):
+    if get_key(key_press):
+        flag_r = 1
+    return flag_r
+
+def manual_ballcapture(bcap_man):
+    if get_key('b'): # the green ball is captured
+        bcap_man = 1
+    elif get_key('n'): # no ball is captured
+        bcap_man = 0
+    elif get_key('v'): # visual
+        bcap_man = -1
+    return bcap_man
 
 # ===== Main Function =====
 if __name__ == '__main__':
     # =========== SET UP ============
     # Defining Variables for ESP 32 Serial I/O
-    PORT = "COM9" # for Alienware
+    PORT = "COM11" # for Alienware
     serial_port = serial.Serial(PORT, 115200)
     serial_port.close()
     serial_port.open()
@@ -649,9 +732,10 @@ if __name__ == '__main__':
     pwm1, pwm2, pwm3, pwm4 = 0 , 0 , 0 , 0   # Not moving
     dir1, dir2, dir3, dir4 = '+', '+', '+', '+'
     Ctl_com = [0, 0, 0, 0, "+", "+", "+", "+"]
+
     # Trigger the ESP32_SLAVE to talk first
     """
-    gbx, gby, gb_dist = ball_detection.detectLive(model, minDetectionScore, showSight = True)
+    gbx, gby, gb_dist = ball_detection.detectLive(url_gb, model, minDetectionScore, showSight = True)
     pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = main_control(gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM, count_h)
     serial_port_out(serial_port, pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4)
     """
@@ -668,9 +752,13 @@ if __name__ == '__main__':
             flag = 1
             while (flag == 1):
                 if init_count == 0:
-                     init_count,count_h = auto_init(init_count,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM)
-                auto_control(serial_port,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM,count_h)
+                     init_count,count_h,bcap_man = auto_init(init_count,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM)
+                print('auto_control')
+                auto_control(serial_port,gbx, gby, gb_dist, tx, ty, tz, rx, ry, rz, LIDAR_dist1, LIDAR_dist2, debugM,count_h,bcap_man)
                 flag, print_count = keyboard_stop(flag,print_count)
+                flag = manual_in_auto(Ctl_com, serial_port, flag)
+                bcap_man = manual_ballcapture(bcap_man)
+
         elif get_key('s'):
             pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4 = stop_all()
             serial_port_out(serial_port, pwm1, pwm2, pwm3, pwm4, dir1, dir2, dir3, dir4)
diff --git a/Code/ESP32_Cam/WifiCam/WifiCam.ino b/Code/ESP32_Cam/WifiCam/WifiCam.ino
index 6515ca9d1834f969bc466cf54edd0ac5300dd85b..ef9e520b37486e33033bac5aa344f183057c7d83 100644
--- a/Code/ESP32_Cam/WifiCam/WifiCam.ino
+++ b/Code/ESP32_Cam/WifiCam/WifiCam.ino
@@ -3,8 +3,14 @@
 #include <esp32cam.h>
 
 
-const char* WIFI_SSID = "lemur";
-const char* WIFI_PASS = "lemur9473";
+// const char* WIFI_SSID = "lemur";
+// const char* WIFI_PASS = "lemur9473";
+
+// const char* WIFI_SSID = "uclahci";
+// const char* WIFI_PASS = "94739473";
+
+const char* WIFI_SSID = "NETGEAR33";
+const char* WIFI_PASS = "freestreet163";
 
 // const char* WIFI_SSID = "LEMUR_ESP32_EYE_AP_1";
 // const char* WIFI_PASS = "123456789";