From dc4d9840815ee5a03f29eadf852f54a416d68f5e Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:05:53 -0500 Subject: [PATCH 01/16] setup --- .gitignore | 1 + requirements.txt | 0 rerun_node.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 .gitignore create mode 100644 requirements.txt create mode 100644 rerun_node.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7275bb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +venv/ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/rerun_node.py b/rerun_node.py new file mode 100644 index 0000000..4211b7e --- /dev/null +++ b/rerun_node.py @@ -0,0 +1,66 @@ +import depthai as dai +import sys + +from pathlib import Path +installExamplesStr = Path(__file__).absolute().parents[2] / 'install_requirements.py --install_rerun' +try: + import rerun as rr +except ImportError: + sys.exit("Critical dependency missing: Rerun. Please install it using the command: '{} {}' and then rerun the script.".format(sys.executable, installExamplesStr)) + +import cv2 + +class RerunNode(dai.node.ThreadedHostNode): + def __init__(self): + dai.node.ThreadedHostNode.__init__(self) + self.inputTrans = dai.Node.Input(self) + self.inputImg = dai.Node.Input(self) + self.inputObstaclePCL = dai.Node.Input(self) + self.inputGroundPCL = dai.Node.Input(self) + self.inputGrid = dai.Node.Input(self) + self.positions = [] + self.fx = 400.0 + self.fy = 400.0 + self.intrinsicsSet = False + + def getFocalLengthFromImage(self, imgFrame): + p = self.getParentPipeline() + calibHandler = p.getDefaultDevice().readCalibration() + intrinsics = calibHandler.getCameraIntrinsics(dai.CameraBoardSocket(imgFrame.getInstanceNum()), imgFrame.getWidth(), imgFrame.getHeight()) + self.fx = intrinsics[0][0] + self.fy = intrinsics[1][1] + self.intrinsicsSet = True + + + def run(self): + rr.init("", spawn=True) + rr.log("world", rr.ViewCoordinates.FLU) + rr.log("world/ground", rr.Boxes3D(half_sizes=[3.0, 3.0, 0.00001])) + while self.isRunning(): + transData = self.inputTrans.get() + imgFrame = self.inputImg.get() + if not self.intrinsicsSet: + self.getFocalLengthFromImage(imgFrame) + pclObstData = self.inputObstaclePCL.tryGet() + pclGrndData = self.inputGroundPCL.tryGet() + mapData = self.inputGrid.tryGet() + if transData is not None: + trans = transData.getTranslation() + quat = transData.getQuaternion() + position = rr.datatypes.Vec3D([trans.x, trans.y, trans.z]) + rr.log("world/camera", rr.Transform3D(translation=position, rotation=rr.datatypes.Quaternion(xyzw=[quat.qx, quat.qy, quat.qz, quat.qw]))) + self.positions.append(position) + lineStrip = rr.components.LineStrip3D(self.positions) + rr.log("world/trajectory", rr.LineStrips3D(lineStrip)) + rr.log("world/camera/image", rr.Pinhole(resolution=[imgFrame.getWidth(), imgFrame.getHeight()], focal_length=[self.fx, self.fy], camera_xyz=rr.ViewCoordinates.FLU)) + img = imgFrame.getCvFrame() + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + rr.log("world/camera/image/rgb", rr.Image(img)) + if pclObstData is not None: + points, colors = pclObstData.getPointsRGB() + rr.log("world/obstacle_pcl", rr.Points3D(points, colors=colors, radii=[0.01])) + if pclGrndData is not None: + points, colors = pclGrndData.getPointsRGB() + rr.log("world/ground_pcl", rr.Points3D(points, colors=colors, radii=[0.01])) + if mapData is not None: + rr.log("map", rr.Image(mapData.getCvFrame())) \ No newline at end of file From 07e12b77af2a14ab2e037bcb3acea4913492427e Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Sat, 24 Jan 2026 14:07:43 -0500 Subject: [PATCH 02/16] combined two example scripts --- .gitignore | 1 + Basalt_VIO_RTab.py | 53 +++++++++++++++++++++++ object_tracker.py | 100 ++++++++++++++++++++++++++++++++++++++++++++ pipeline-combine.py | 13 ++++++ requirements.txt | 3 ++ 5 files changed, 170 insertions(+) create mode 100644 Basalt_VIO_RTab.py create mode 100644 object_tracker.py create mode 100644 pipeline-combine.py diff --git a/.gitignore b/.gitignore index f7275bb..cdf5d40 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ venv/ +notes.txt \ No newline at end of file diff --git a/Basalt_VIO_RTab.py b/Basalt_VIO_RTab.py new file mode 100644 index 0000000..cb88aee --- /dev/null +++ b/Basalt_VIO_RTab.py @@ -0,0 +1,53 @@ +import time +import depthai as dai +from rerun_node import RerunNode + +# Create pipeline +def add_basalt_vio_rtab(p: dai.Pipeline): + with p: + fps = 60 + width = 640 + height = 400 + # Define sources and outputs + left = p.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B, sensorFps=fps) + right = p.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C, sensorFps=fps) + imu = p.create(dai.node.IMU) + odom = p.create(dai.node.BasaltVIO) + slam = p.create(dai.node.RTABMapSLAM) + stereo = p.create(dai.node.StereoDepth) + params = {"RGBD/CreateOccupancyGrid": "true", + "Grid/3D": "true", + "Rtabmap/SaveWMState": "true"} + slam.setParams(params) + + rerunViewer = RerunNode() + imu.enableIMUSensor([dai.IMUSensor.ACCELEROMETER_RAW, dai.IMUSensor.GYROSCOPE_RAW], 200) + imu.setBatchReportThreshold(1) + imu.setMaxBatchReports(10) + + stereo.setExtendedDisparity(False) + stereo.setLeftRightCheck(True) + stereo.setSubpixel(True) + stereo.setRectifyEdgeFillColor(0) + stereo.enableDistortionCorrection(True) + stereo.initialConfig.setLeftRightCheckThreshold(10) + stereo.setDepthAlign(dai.CameraBoardSocket.CAM_B) + + + left.requestOutput((width, height)).link(stereo.left) + right.requestOutput((width, height)).link(stereo.right) + stereo.syncedLeft.link(odom.left) + stereo.syncedRight.link(odom.right) + stereo.depth.link(slam.depth) + stereo.rectifiedLeft.link(slam.rect) + imu.out.link(odom.imu) + + odom.transform.link(slam.odom) + slam.transform.link(rerunViewer.inputTrans) + slam.passthroughRect.link(rerunViewer.inputImg) + slam.occupancyGridMap.link(rerunViewer.inputGrid) + slam.obstaclePCL.link(rerunViewer.inputObstaclePCL) + slam.groundPCL.link(rerunViewer.inputGroundPCL) + p.start() + while p.isRunning(): + time.sleep(1) diff --git a/object_tracker.py b/object_tracker.py new file mode 100644 index 0000000..f8582db --- /dev/null +++ b/object_tracker.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +import cv2 +import depthai as dai +import time + + +fullFrameTracking = False + +# Create pipeline +def add_object_tracker(pipeline: dai.Pipeline): + with pipeline: + # Define sources and outputs + camRgb = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_A) + monoLeft = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B) + monoRight = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C) + + stereo = pipeline.create(dai.node.StereoDepth) + leftOutput = monoLeft.requestOutput((640, 400)) + rightOutput = monoRight.requestOutput((640, 400)) + leftOutput.link(stereo.left) + rightOutput.link(stereo.right) + + spatialDetectionNetwork = pipeline.create(dai.node.SpatialDetectionNetwork).build(camRgb, stereo, "yolov6-nano") + objectTracker = pipeline.create(dai.node.ObjectTracker) + + spatialDetectionNetwork.setConfidenceThreshold(0.6) + spatialDetectionNetwork.input.setBlocking(False) + spatialDetectionNetwork.setBoundingBoxScaleFactor(0.5) + spatialDetectionNetwork.setDepthLowerThreshold(100) + spatialDetectionNetwork.setDepthUpperThreshold(5000) + labelMap = spatialDetectionNetwork.getClasses() + + objectTracker.setDetectionLabelsToTrack([0]) # track only person + # possible tracking types: ZERO_TERM_COLOR_HISTOGRAM, ZERO_TERM_IMAGELESS, SHORT_TERM_IMAGELESS, SHORT_TERM_KCF + objectTracker.setTrackerType(dai.TrackerType.SHORT_TERM_IMAGELESS) + # take the smallest ID when new object is tracked, possible options: SMALLEST_ID, UNIQUE_ID + objectTracker.setTrackerIdAssignmentPolicy(dai.TrackerIdAssignmentPolicy.SMALLEST_ID) + + preview = objectTracker.passthroughTrackerFrame.createOutputQueue() + tracklets = objectTracker.out.createOutputQueue() + + if fullFrameTracking: + camRgb.requestFullResolutionOutput().link(objectTracker.inputTrackerFrame) + # do not block the pipeline if it's too slow on full frame + objectTracker.inputTrackerFrame.setBlocking(False) + objectTracker.inputTrackerFrame.setMaxSize(1) + else: + spatialDetectionNetwork.passthrough.link(objectTracker.inputTrackerFrame) + + spatialDetectionNetwork.passthrough.link(objectTracker.inputDetectionFrame) + spatialDetectionNetwork.out.link(objectTracker.inputDetections) + + startTime = time.monotonic() + counter = 0 + fps = 0 + color = (255, 255, 255) + pipeline.start() + while(pipeline.isRunning()): + imgFrame = preview.get() + track = tracklets.get() + assert isinstance(imgFrame, dai.ImgFrame), "Expected ImgFrame" + assert isinstance(track, dai.Tracklets), "Expected Tracklets" + + counter+=1 + current_time = time.monotonic() + if (current_time - startTime) > 1 : + fps = counter / (current_time - startTime) + counter = 0 + startTime = current_time + + frame = imgFrame.getCvFrame() + trackletsData = track.tracklets + for t in trackletsData: + roi = t.roi.denormalize(frame.shape[1], frame.shape[0]) + x1 = int(roi.topLeft().x) + y1 = int(roi.topLeft().y) + x2 = int(roi.bottomRight().x) + y2 = int(roi.bottomRight().y) + + try: + label = labelMap[t.label] + except: + label = t.label + + cv2.putText(frame, str(label), (x1 + 10, y1 + 20), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) + cv2.putText(frame, f"ID: {[t.id]}", (x1 + 10, y1 + 35), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) + cv2.putText(frame, t.status.name, (x1 + 10, y1 + 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) + cv2.rectangle(frame, (x1, y1), (x2, y2), color, cv2.FONT_HERSHEY_SIMPLEX) + + cv2.putText(frame, f"X: {int(t.spatialCoordinates.x)} mm", (x1 + 10, y1 + 65), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) + cv2.putText(frame, f"Y: {int(t.spatialCoordinates.y)} mm", (x1 + 10, y1 + 80), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) + cv2.putText(frame, f"Z: {int(t.spatialCoordinates.z)} mm", (x1 + 10, y1 + 95), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) + + cv2.putText(frame, "NN fps: {:.2f}".format(fps), (2, frame.shape[0] - 4), cv2.FONT_HERSHEY_TRIPLEX, 0.4, color) + + cv2.imshow("tracker", frame) + + if cv2.waitKey(1) == ord('q'): + break diff --git a/pipeline-combine.py b/pipeline-combine.py new file mode 100644 index 0000000..8996bb1 --- /dev/null +++ b/pipeline-combine.py @@ -0,0 +1,13 @@ +import Basalt_VIO_RTab +import rerun_node +import object_tracker +import depthai as dai +# This is the main pipeline-combine.py file that integrates Basalt VIO with RTAB-Map SLAM + + + +with dai.Pipeline() as pipeline: + + object_tracker.add_object_tracker(pipeline) + Basalt_VIO_RTab.add_basalt_vio_rtab(pipeline) + pipeline.start() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e69de29..4a85825 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,3 @@ +depthai +rerun +opencv-python \ No newline at end of file From b6233fce7c753f771e753c6e54a91ac4f1cb9a09 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Tue, 27 Jan 2026 21:22:26 -0500 Subject: [PATCH 03/16] adding main loop --- pipeline-combine.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pipeline-combine.py b/pipeline-combine.py index 8996bb1..8d8005a 100644 --- a/pipeline-combine.py +++ b/pipeline-combine.py @@ -10,4 +10,7 @@ object_tracker.add_object_tracker(pipeline) Basalt_VIO_RTab.add_basalt_vio_rtab(pipeline) - pipeline.start() \ No newline at end of file + pipeline.start() + while not KeyboardInterrupt and pipeline.isRunning(): + pass + pipeline.stop() From 95f03b15990d8591e34f13ffa6844ca21b81f431 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Wed, 28 Jan 2026 19:32:17 -0500 Subject: [PATCH 04/16] helper function to pass along one camera instance --- cameraBundle.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 cameraBundle.py diff --git a/cameraBundle.py b/cameraBundle.py new file mode 100644 index 0000000..c78befe --- /dev/null +++ b/cameraBundle.py @@ -0,0 +1,16 @@ +import depthai as dai + + +class CameraBundle: + """Helper to create and link camera nodes and stereo outputs.""" + def __init__(self, pipeline: dai.Pipeline, rgb_socket=dai.CameraBoardSocket.CAM_A, left_socket=dai.CameraBoardSocket.CAM_B, right_socket=dai.CameraBoardSocket.CAM_C, mono_resolution=(640, 400)): + self.pipeline = pipeline + self.camRgb = pipeline.create(dai.node.Camera).build(rgb_socket) + self.monoLeft = pipeline.create(dai.node.Camera).build(left_socket) + self.monoRight = pipeline.create(dai.node.Camera).build(right_socket) + + self.stereo = pipeline.create(dai.node.StereoDepth) + self.leftOutput = self.monoLeft.requestOutput(mono_resolution) + self.rightOutput = self.monoRight.requestOutput(mono_resolution) + self.leftOutput.link(self.stereo.left) + self.rightOutput.link(self.stereo.right) From 5e7a8beea9ecd6b14cec0c1fe185a378ebfdbc23 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Wed, 28 Jan 2026 19:38:01 -0500 Subject: [PATCH 05/16] Functions now use helper functions --- Basalt_VIO_RTab.py | 11 ++++++----- object_tracker.py | 22 ++++++++++------------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Basalt_VIO_RTab.py b/Basalt_VIO_RTab.py index cb88aee..b6f4fc0 100644 --- a/Basalt_VIO_RTab.py +++ b/Basalt_VIO_RTab.py @@ -1,20 +1,21 @@ import time import depthai as dai from rerun_node import RerunNode - +from cameraBundle import CameraBundle # Create pipeline -def add_basalt_vio_rtab(p: dai.Pipeline): +def add_basalt_vio_rtab(p: dai.Pipeline, cameras: 'CameraBundle' = None): with p: fps = 60 width = 640 height = 400 # Define sources and outputs - left = p.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B, sensorFps=fps) - right = p.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C, sensorFps=fps) + cameras = CameraBundle(p) + left = cameras.monoLeft + right = cameras.monoRight imu = p.create(dai.node.IMU) odom = p.create(dai.node.BasaltVIO) slam = p.create(dai.node.RTABMapSLAM) - stereo = p.create(dai.node.StereoDepth) + stereo = cameras.stereo params = {"RGBD/CreateOccupancyGrid": "true", "Grid/3D": "true", "Rtabmap/SaveWMState": "true"} diff --git a/object_tracker.py b/object_tracker.py index f8582db..57576cc 100644 --- a/object_tracker.py +++ b/object_tracker.py @@ -3,23 +3,21 @@ import cv2 import depthai as dai import time - +from cameraBundle import CameraBundle fullFrameTracking = False # Create pipeline -def add_object_tracker(pipeline: dai.Pipeline): + +def add_object_tracker(pipeline: dai.Pipeline, cameras: 'CameraBundle' = None): with pipeline: - # Define sources and outputs - camRgb = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_A) - monoLeft = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B) - monoRight = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C) - - stereo = pipeline.create(dai.node.StereoDepth) - leftOutput = monoLeft.requestOutput((640, 400)) - rightOutput = monoRight.requestOutput((640, 400)) - leftOutput.link(stereo.left) - rightOutput.link(stereo.right) + cameras = cameras or CameraBundle(pipeline) + camRgb = cameras.camRgb + monoLeft = cameras.monoLeft + monoRight = cameras.monoRight + stereo = cameras.stereo + leftOutput = cameras.leftOutput + rightOutput = cameras.rightOutput spatialDetectionNetwork = pipeline.create(dai.node.SpatialDetectionNetwork).build(camRgb, stereo, "yolov6-nano") objectTracker = pipeline.create(dai.node.ObjectTracker) From fc78a577f74077e33b53991f0a43cfc8721982a5 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Wed, 28 Jan 2026 19:40:51 -0500 Subject: [PATCH 06/16] removed while loop --- Basalt_VIO_RTab.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Basalt_VIO_RTab.py b/Basalt_VIO_RTab.py index b6f4fc0..0f4d5c9 100644 --- a/Basalt_VIO_RTab.py +++ b/Basalt_VIO_RTab.py @@ -50,5 +50,4 @@ def add_basalt_vio_rtab(p: dai.Pipeline, cameras: 'CameraBundle' = None): slam.obstaclePCL.link(rerunViewer.inputObstaclePCL) slam.groundPCL.link(rerunViewer.inputGroundPCL) p.start() - while p.isRunning(): - time.sleep(1) + time.sleep(2) #buffer time for nodes to start \ No newline at end of file From f5c15450f2283fe0b392fa1a4d97e3c5b65dbfdb Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Wed, 28 Jan 2026 21:14:15 -0500 Subject: [PATCH 07/16] addressing comments --- Basalt_VIO_RTab.py | 21 +++--- __pycache__/Basalt_VIO_RTab.cpython-312.pyc | Bin 0 -> 4198 bytes __pycache__/cameraBundle.cpython-312.pyc | Bin 0 -> 2116 bytes __pycache__/object_tracker.cpython-312.pyc | Bin 0 -> 6876 bytes __pycache__/rerun_node.cpython-312.pyc | Bin 0 -> 6605 bytes cameraBundle.py | 10 ++- object_tracker.py | 73 +++----------------- pipeline-combine.py | 6 +- rerun_node.py | 52 +++++++++++--- 9 files changed, 78 insertions(+), 84 deletions(-) create mode 100644 __pycache__/Basalt_VIO_RTab.cpython-312.pyc create mode 100644 __pycache__/cameraBundle.cpython-312.pyc create mode 100644 __pycache__/object_tracker.cpython-312.pyc create mode 100644 __pycache__/rerun_node.cpython-312.pyc diff --git a/Basalt_VIO_RTab.py b/Basalt_VIO_RTab.py index 0f4d5c9..755ede7 100644 --- a/Basalt_VIO_RTab.py +++ b/Basalt_VIO_RTab.py @@ -2,8 +2,10 @@ import depthai as dai from rerun_node import RerunNode from cameraBundle import CameraBundle + + # Create pipeline -def add_basalt_vio_rtab(p: dai.Pipeline, cameras: 'CameraBundle' = None): +def add_basalt_vio_rtab(p: dai.Pipeline, cameras: "CameraBundle" = None) -> RerunNode: with p: fps = 60 width = 640 @@ -16,13 +18,17 @@ def add_basalt_vio_rtab(p: dai.Pipeline, cameras: 'CameraBundle' = None): odom = p.create(dai.node.BasaltVIO) slam = p.create(dai.node.RTABMapSLAM) stereo = cameras.stereo - params = {"RGBD/CreateOccupancyGrid": "true", - "Grid/3D": "true", - "Rtabmap/SaveWMState": "true"} + params = { + "RGBD/CreateOccupancyGrid": "true", + "Grid/3D": "true", + "Rtabmap/SaveWMState": "true", + } slam.setParams(params) rerunViewer = RerunNode() - imu.enableIMUSensor([dai.IMUSensor.ACCELEROMETER_RAW, dai.IMUSensor.GYROSCOPE_RAW], 200) + imu.enableIMUSensor( + [dai.IMUSensor.ACCELEROMETER_RAW, dai.IMUSensor.GYROSCOPE_RAW], 200 + ) imu.setBatchReportThreshold(1) imu.setMaxBatchReports(10) @@ -34,7 +40,6 @@ def add_basalt_vio_rtab(p: dai.Pipeline, cameras: 'CameraBundle' = None): stereo.initialConfig.setLeftRightCheckThreshold(10) stereo.setDepthAlign(dai.CameraBoardSocket.CAM_B) - left.requestOutput((width, height)).link(stereo.left) right.requestOutput((width, height)).link(stereo.right) stereo.syncedLeft.link(odom.left) @@ -49,5 +54,5 @@ def add_basalt_vio_rtab(p: dai.Pipeline, cameras: 'CameraBundle' = None): slam.occupancyGridMap.link(rerunViewer.inputGrid) slam.obstaclePCL.link(rerunViewer.inputObstaclePCL) slam.groundPCL.link(rerunViewer.inputGroundPCL) - p.start() - time.sleep(2) #buffer time for nodes to start \ No newline at end of file + time.sleep(2) # buffer time for nodes to start + return rerunViewer \ No newline at end of file diff --git a/__pycache__/Basalt_VIO_RTab.cpython-312.pyc b/__pycache__/Basalt_VIO_RTab.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d1f2642e357d01c2e943746fe639177aa4ca217 GIT binary patch literal 4198 zcmbVPTTC0-8J_X=_y&e#6TjLcR;F(m%XICi6Ui_VkwqRQgcN~&smUdNm^63 zIU9|A)}%ezu zi;})d=V+mvr4+JiM}FMJfos)~qXaZJ2QL-%S-b>e4vAIrc`I#fz0JV+UW|v#=vzkc zUX1>q$VgW5YcNQL}Sb5Ip-GoiQkk5IL?{~(S-9vGv$HtT`&=%mCgJ`;xnZ%Wa>mK z8?9aVhtcVeoeflJTyb_jtt$x zh{-^-BbeTm(~WZuK%0KE8t`9z*WICa{xr1DItC|E_bUuK?Q+mrmT23|2z}@xEoa^=x4s~ zvs4##o>J(C7Mhwxl>$v=sTJ!i^^gvDC-?Eoh5rm44*U~TDL|VlXSjg%QA70R$ml>w z<`|WW#A2B=BgV2fWuATH#P@*ifX1Sv_B#$}&8(iKrTa*0G7(&^5v+Oj5lw7J;7V zOmJj^Nl%XlC!j-7Ihm87OX1WhMrKlqjEf;y%Zbcll0!|WIZ=^h=rYy1U?>zG4@V;t z;hAuBAsYMy`fkofBh#VCRM;?2BDN7mjU}R7T9Vb7gv==kDapcm1WYh1WtakwBVTw$ z@#WcUdB_Zx2%EeTEDH~?v+zmdN3`t3p zXk#&R#H6CGc}WaOvWx>I5&C$MS9u0Sic5SPHdggvX6i%OD3?|f!6Y9SVO^=9lo*+v zmSW4C3hklb#KH*l$=v-6r>K#Pn$D=umgL1{bjRyrmyI=XD_JqdvBpw)ih6Oe>@4m8 zGvIOXr4So7p;ba;Rz8)1E>&hkWl54#&?d1`3c7g_^)!RMur|#oikgt6OdL%%Y6lE( zEER`-seGrQ1&1yJ!#fUoq(wz#Vo7c)G!FfSKT_s##Sx>(Vz8#vh}d@2PDXo3~nhCBKZTYG_?bE71OsXVD-X2@X$&jEfYx2j6hfAmh3K+LR=d zl5r6T9ccN{CWIatSMzsx?ja{DK7_QFUq6LnSLSak2%1-zR4h9ml30|W#* zUil|_);^=4%U!7PuUQNJV{7(8-SIWY5B05E_rDlea~5h(=(TNHZQGiy;6JJRJ2Za> zim9pHNUSIRplq%@UD?b%&F$5kM$K#e8!PK8&#XIO8|V!^T0_rXZ7*tA>F?7T`u1x3 zk-x5Cv-N4~nxk;`Vxg&{@L~Utc1!)hn&Y*Da``rD)@z zXx70c4P5%hk_T7c`kqbeErVLipx$y>Yq^{U9~r|bF^6}Dwyy7iULBm%z`2(vzHa)e zDGz>C0KVejwr=m<*oy3dJ{_Fb!1P~h$OY*`w>!3{o zZM(KF-Ot^5(2L?Xyz5>a;5J*QcY3ya^5D$d9Cgs4fsWnNUk08B@}LjR(S~!~iCa9G z*}VJoE}Hi5ffp}9DXr0+vF$Nqj>^5i(VGXg=D|F;Pync};*1!~y?W=6);W|1mkgvu z11&n})IjI%RlV!7)`jQAKpHgApaYC=E$gjUwAL%eTps9UNNX-~xp1D3U3dd7uP;AN z{ln|uxV3)k$^FL@udNi?Xvq6{>c97B%I(>xTd(^`!Jn7Eo3c;UTVK`Nr<$ArdNSaW zuOlyX8m}gXm+|KvbQ@3O0zOWP$Ah={IbHm|E*(cxe40ZqKhAiB{zSb&4Jr91ZVrZ1 z5}QeK*W?H?@p-2F0^MF)X`23)@_b8u@Ez6u9d+hM+c~;%>%z|P_V8;8sV~p|8w(j1 Ga{mL5BRetx literal 0 HcmV?d00001 diff --git a/__pycache__/cameraBundle.cpython-312.pyc b/__pycache__/cameraBundle.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dbd30d155b699053fff5771269d9e63b6c1ecc85 GIT binary patch literal 2116 zcmcgtOKclO7@l3PoyCuuQfk(YAIqh}NKTtdZNUT=*DX|{NlM#XT%*-ycbu$W>+Y_l zI<=}EasUYlIHf+BNJx=srBs}9$p6*q%9t z+hI_djx<75*k|Bay@&IYQwcbHns#W{iZhSny^zeFsmwEOO)n%fGnIMVum6?#fVVUi zd;HovpmM<5t-R)b^@Ml4Q~u-0!2Sok=zsJNxpA>S=gJdaNlau{!pK)$dBQ8niR?;l zofN=6G52=D|3h?s;^j({=xvaumePkcFE$~cGlR$@iwa`MT~XH74HUR)Pw08rG}e*N8CMk2;Efj4jb(dmk-vtWMsh$SZX<;u zLys6@Mqb;1mj$E4TG^@1udS^Lx++y6PDD_y612gt7AEBg8r0QV%TUyYPNt5x&mZqe z+0u#*HNB*Zb*Wt{sIt;nE9F~;n#o_t7cwVLoIIVmChFD9e5SCxc)8^4AZJ(2HQR_4 z1f`)Eg0OMa>C4FEUXx_{J|=g-kmEmLJ_`*a$u0Fu^=oNoeS3XJ-Bt&Y(^h1`j4bRG z2a$^y62Qn_xEsFj*=76eZnz&FaBo>$&g61?w+7sYc9iJry;L`K|Hv-a=XO*5)FAq{ z6+LT4&wdviL>DpS(9hF}tYca8SauM3$BrLM_A=d!6+30dPCZZuvG?(9csQHt<+?d* z_KZ1uW-mOL#kD+Qxgi_;Jp5_cV&f(ozk98By?fnCWXwe75j%%%7R#9|XR!&BP281x z)o#^F9ygQ6e_&6L&jw5B0BKSK?`}arenF_Ka;rwv?^@Yq zGrMeMSIq3nL#b>@H%;lLCEYfq+mCU<^hfkl!X)~M!)#4)G=;{HTl59b6X5sGe|2Oh zz8(Lah)!mbEA2ruGI{Z$Vtmr@kOH K{~N%>_W2Y1q?r!@ literal 0 HcmV?d00001 diff --git a/__pycache__/object_tracker.cpython-312.pyc b/__pycache__/object_tracker.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6213b655973cd4f6f5b85ba598b8d1466cd6d08 GIT binary patch literal 6876 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 literal 0 HcmV?d00001 diff --git a/__pycache__/rerun_node.cpython-312.pyc b/__pycache__/rerun_node.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a2808be93d1ae1112a62564f5fd43b6689dc992 GIT binary patch literal 6605 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 literal 0 HcmV?d00001 diff --git a/cameraBundle.py b/cameraBundle.py index c78befe..fe8cfd6 100644 --- a/cameraBundle.py +++ b/cameraBundle.py @@ -3,7 +3,15 @@ class CameraBundle: """Helper to create and link camera nodes and stereo outputs.""" - def __init__(self, pipeline: dai.Pipeline, rgb_socket=dai.CameraBoardSocket.CAM_A, left_socket=dai.CameraBoardSocket.CAM_B, right_socket=dai.CameraBoardSocket.CAM_C, mono_resolution=(640, 400)): + + def __init__( + self, + pipeline: dai.Pipeline, + rgb_socket=dai.CameraBoardSocket.CAM_A, + left_socket=dai.CameraBoardSocket.CAM_B, + right_socket=dai.CameraBoardSocket.CAM_C, + mono_resolution=(640, 400), + ): self.pipeline = pipeline self.camRgb = pipeline.create(dai.node.Camera).build(rgb_socket) self.monoLeft = pipeline.create(dai.node.Camera).build(left_socket) diff --git a/object_tracker.py b/object_tracker.py index 57576cc..38d0aca 100644 --- a/object_tracker.py +++ b/object_tracker.py @@ -9,34 +9,31 @@ # Create pipeline -def add_object_tracker(pipeline: dai.Pipeline, cameras: 'CameraBundle' = None): - with pipeline: - cameras = cameras or CameraBundle(pipeline) + +def add_object_tracker(p: dai.Pipeline, cameras: "CameraBundle" = None): + with p: + cameras = cameras or CameraBundle(p) camRgb = cameras.camRgb - monoLeft = cameras.monoLeft - monoRight = cameras.monoRight stereo = cameras.stereo - leftOutput = cameras.leftOutput - rightOutput = cameras.rightOutput - spatialDetectionNetwork = pipeline.create(dai.node.SpatialDetectionNetwork).build(camRgb, stereo, "yolov6-nano") - objectTracker = pipeline.create(dai.node.ObjectTracker) + spatialDetectionNetwork = p.create( + dai.node.SpatialDetectionNetwork + ).build(camRgb, stereo, "yolov6-nano") + objectTracker = p.create(dai.node.ObjectTracker) spatialDetectionNetwork.setConfidenceThreshold(0.6) spatialDetectionNetwork.input.setBlocking(False) spatialDetectionNetwork.setBoundingBoxScaleFactor(0.5) spatialDetectionNetwork.setDepthLowerThreshold(100) spatialDetectionNetwork.setDepthUpperThreshold(5000) - labelMap = spatialDetectionNetwork.getClasses() objectTracker.setDetectionLabelsToTrack([0]) # track only person # possible tracking types: ZERO_TERM_COLOR_HISTOGRAM, ZERO_TERM_IMAGELESS, SHORT_TERM_IMAGELESS, SHORT_TERM_KCF objectTracker.setTrackerType(dai.TrackerType.SHORT_TERM_IMAGELESS) # take the smallest ID when new object is tracked, possible options: SMALLEST_ID, UNIQUE_ID - objectTracker.setTrackerIdAssignmentPolicy(dai.TrackerIdAssignmentPolicy.SMALLEST_ID) - - preview = objectTracker.passthroughTrackerFrame.createOutputQueue() - tracklets = objectTracker.out.createOutputQueue() + objectTracker.setTrackerIdAssignmentPolicy( + dai.TrackerIdAssignmentPolicy.SMALLEST_ID + ) if fullFrameTracking: camRgb.requestFullResolutionOutput().link(objectTracker.inputTrackerFrame) @@ -48,51 +45,3 @@ def add_object_tracker(pipeline: dai.Pipeline, cameras: 'CameraBundle' = None): spatialDetectionNetwork.passthrough.link(objectTracker.inputDetectionFrame) spatialDetectionNetwork.out.link(objectTracker.inputDetections) - - startTime = time.monotonic() - counter = 0 - fps = 0 - color = (255, 255, 255) - pipeline.start() - while(pipeline.isRunning()): - imgFrame = preview.get() - track = tracklets.get() - assert isinstance(imgFrame, dai.ImgFrame), "Expected ImgFrame" - assert isinstance(track, dai.Tracklets), "Expected Tracklets" - - counter+=1 - current_time = time.monotonic() - if (current_time - startTime) > 1 : - fps = counter / (current_time - startTime) - counter = 0 - startTime = current_time - - frame = imgFrame.getCvFrame() - trackletsData = track.tracklets - for t in trackletsData: - roi = t.roi.denormalize(frame.shape[1], frame.shape[0]) - x1 = int(roi.topLeft().x) - y1 = int(roi.topLeft().y) - x2 = int(roi.bottomRight().x) - y2 = int(roi.bottomRight().y) - - try: - label = labelMap[t.label] - except: - label = t.label - - cv2.putText(frame, str(label), (x1 + 10, y1 + 20), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) - cv2.putText(frame, f"ID: {[t.id]}", (x1 + 10, y1 + 35), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) - cv2.putText(frame, t.status.name, (x1 + 10, y1 + 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) - cv2.rectangle(frame, (x1, y1), (x2, y2), color, cv2.FONT_HERSHEY_SIMPLEX) - - cv2.putText(frame, f"X: {int(t.spatialCoordinates.x)} mm", (x1 + 10, y1 + 65), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) - cv2.putText(frame, f"Y: {int(t.spatialCoordinates.y)} mm", (x1 + 10, y1 + 80), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) - cv2.putText(frame, f"Z: {int(t.spatialCoordinates.z)} mm", (x1 + 10, y1 + 95), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255) - - cv2.putText(frame, "NN fps: {:.2f}".format(fps), (2, frame.shape[0] - 4), cv2.FONT_HERSHEY_TRIPLEX, 0.4, color) - - cv2.imshow("tracker", frame) - - if cv2.waitKey(1) == ord('q'): - break diff --git a/pipeline-combine.py b/pipeline-combine.py index 8d8005a..d6bcd08 100644 --- a/pipeline-combine.py +++ b/pipeline-combine.py @@ -2,15 +2,15 @@ import rerun_node import object_tracker import depthai as dai -# This is the main pipeline-combine.py file that integrates Basalt VIO with RTAB-Map SLAM +# This is the main pipeline-combine.py file that integrates Basalt VIO with RTAB-Map SLAM with dai.Pipeline() as pipeline: object_tracker.add_object_tracker(pipeline) - Basalt_VIO_RTab.add_basalt_vio_rtab(pipeline) + rerunViewer = Basalt_VIO_RTab.add_basalt_vio_rtab(pipeline) pipeline.start() while not KeyboardInterrupt and pipeline.isRunning(): - pass + pass pipeline.stop() diff --git a/rerun_node.py b/rerun_node.py index 4211b7e..db9e01b 100644 --- a/rerun_node.py +++ b/rerun_node.py @@ -2,14 +2,22 @@ import sys from pathlib import Path -installExamplesStr = Path(__file__).absolute().parents[2] / 'install_requirements.py --install_rerun' + +installExamplesStr = ( + Path(__file__).absolute().parents[2] / "install_requirements.py --install_rerun" +) try: import rerun as rr except ImportError: - sys.exit("Critical dependency missing: Rerun. Please install it using the command: '{} {}' and then rerun the script.".format(sys.executable, installExamplesStr)) + sys.exit( + "Critical dependency missing: Rerun. Please install it using the command: '{} {}' and then rerun the script.".format( + sys.executable, installExamplesStr + ) + ) import cv2 + class RerunNode(dai.node.ThreadedHostNode): def __init__(self): dai.node.ThreadedHostNode.__init__(self) @@ -26,16 +34,19 @@ def __init__(self): def getFocalLengthFromImage(self, imgFrame): p = self.getParentPipeline() calibHandler = p.getDefaultDevice().readCalibration() - intrinsics = calibHandler.getCameraIntrinsics(dai.CameraBoardSocket(imgFrame.getInstanceNum()), imgFrame.getWidth(), imgFrame.getHeight()) + intrinsics = calibHandler.getCameraIntrinsics( + dai.CameraBoardSocket(imgFrame.getInstanceNum()), + imgFrame.getWidth(), + imgFrame.getHeight(), + ) self.fx = intrinsics[0][0] self.fy = intrinsics[1][1] self.intrinsicsSet = True - def run(self): rr.init("", spawn=True) rr.log("world", rr.ViewCoordinates.FLU) - rr.log("world/ground", rr.Boxes3D(half_sizes=[3.0, 3.0, 0.00001])) + rr.log("world/ground", rr.Boxes3D(half_sizes=[3.0, 3.0, 0.00001])) while self.isRunning(): transData = self.inputTrans.get() imgFrame = self.inputImg.get() @@ -48,19 +59,40 @@ def run(self): trans = transData.getTranslation() quat = transData.getQuaternion() position = rr.datatypes.Vec3D([trans.x, trans.y, trans.z]) - rr.log("world/camera", rr.Transform3D(translation=position, rotation=rr.datatypes.Quaternion(xyzw=[quat.qx, quat.qy, quat.qz, quat.qw]))) + rr.log( + "world/camera", + rr.Transform3D( + translation=position, + rotation=rr.datatypes.Quaternion( + xyzw=[quat.qx, quat.qy, quat.qz, quat.qw] + ), + ), + ) self.positions.append(position) lineStrip = rr.components.LineStrip3D(self.positions) rr.log("world/trajectory", rr.LineStrips3D(lineStrip)) - rr.log("world/camera/image", rr.Pinhole(resolution=[imgFrame.getWidth(), imgFrame.getHeight()], focal_length=[self.fx, self.fy], camera_xyz=rr.ViewCoordinates.FLU)) + rr.log( + "world/camera/image", + rr.Pinhole( + resolution=[imgFrame.getWidth(), imgFrame.getHeight()], + focal_length=[self.fx, self.fy], + camera_xyz=rr.ViewCoordinates.FLU, + ), + ) img = imgFrame.getCvFrame() img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) rr.log("world/camera/image/rgb", rr.Image(img)) if pclObstData is not None: points, colors = pclObstData.getPointsRGB() - rr.log("world/obstacle_pcl", rr.Points3D(points, colors=colors, radii=[0.01])) + rr.log( + "world/obstacle_pcl", + rr.Points3D(points, colors=colors, radii=[0.01]), + ) if pclGrndData is not None: points, colors = pclGrndData.getPointsRGB() - rr.log("world/ground_pcl", rr.Points3D(points, colors=colors, radii=[0.01])) + rr.log( + "world/ground_pcl", + rr.Points3D(points, colors=colors, radii=[0.01]), + ) if mapData is not None: - rr.log("map", rr.Image(mapData.getCvFrame())) \ No newline at end of file + rr.log("map", rr.Image(mapData.getCvFrame())) From 0da04f6e4c26aaf1106106b8a0c85ec9a6b1afe9 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Wed, 28 Jan 2026 21:15:08 -0500 Subject: [PATCH 08/16] removed uneccessary libraries --- object_tracker.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/object_tracker.py b/object_tracker.py index 38d0aca..1492ab1 100644 --- a/object_tracker.py +++ b/object_tracker.py @@ -1,8 +1,6 @@ #!/usr/bin/env python3 -import cv2 import depthai as dai -import time from cameraBundle import CameraBundle fullFrameTracking = False From 44c7a61a221e5bc1d7ce8dab29160ea135db7b07 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Thu, 29 Jan 2026 21:42:55 -0500 Subject: [PATCH 09/16] moved slam and rerun node to pipeline-combine.py --- .gitignore | 3 ++- Basalt_VIO_RTab.py | 19 +++++----------- __pycache__/Basalt_VIO_RTab.cpython-312.pyc | Bin 4198 -> 0 bytes __pycache__/cameraBundle.cpython-312.pyc | Bin 2116 -> 0 bytes __pycache__/object_tracker.cpython-312.pyc | Bin 6876 -> 0 bytes __pycache__/rerun_node.cpython-312.pyc | Bin 6605 -> 0 bytes cameraBundle.py | 1 + pipeline-combine.py | 24 +++++++++++++++----- 8 files changed, 27 insertions(+), 20 deletions(-) delete mode 100644 __pycache__/Basalt_VIO_RTab.cpython-312.pyc delete mode 100644 __pycache__/cameraBundle.cpython-312.pyc delete mode 100644 __pycache__/object_tracker.cpython-312.pyc delete mode 100644 __pycache__/rerun_node.cpython-312.pyc diff --git a/.gitignore b/.gitignore index cdf5d40..6906b5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ venv/ -notes.txt \ No newline at end of file +notes.txt +__pycache__/ \ No newline at end of file diff --git a/Basalt_VIO_RTab.py b/Basalt_VIO_RTab.py index 755ede7..41746d1 100644 --- a/Basalt_VIO_RTab.py +++ b/Basalt_VIO_RTab.py @@ -1,22 +1,22 @@ -import time import depthai as dai -from rerun_node import RerunNode from cameraBundle import CameraBundle # Create pipeline -def add_basalt_vio_rtab(p: dai.Pipeline, cameras: "CameraBundle" = None) -> RerunNode: +def add_basalt_vio_rtab(p: dai.Pipeline, cameras: "CameraBundle" = None): with p: + # Ensure we have a CameraBundle (created only if not provided) + cameras = cameras or CameraBundle(p) fps = 60 width = 640 height = 400 # Define sources and outputs - cameras = CameraBundle(p) + left = cameras.monoLeft right = cameras.monoRight imu = p.create(dai.node.IMU) odom = p.create(dai.node.BasaltVIO) - slam = p.create(dai.node.RTABMapSLAM) + slam = cameras.slam stereo = cameras.stereo params = { "RGBD/CreateOccupancyGrid": "true", @@ -25,7 +25,6 @@ def add_basalt_vio_rtab(p: dai.Pipeline, cameras: "CameraBundle" = None) -> Reru } slam.setParams(params) - rerunViewer = RerunNode() imu.enableIMUSensor( [dai.IMUSensor.ACCELEROMETER_RAW, dai.IMUSensor.GYROSCOPE_RAW], 200 ) @@ -49,10 +48,4 @@ def add_basalt_vio_rtab(p: dai.Pipeline, cameras: "CameraBundle" = None) -> Reru imu.out.link(odom.imu) odom.transform.link(slam.odom) - slam.transform.link(rerunViewer.inputTrans) - slam.passthroughRect.link(rerunViewer.inputImg) - slam.occupancyGridMap.link(rerunViewer.inputGrid) - slam.obstaclePCL.link(rerunViewer.inputObstaclePCL) - slam.groundPCL.link(rerunViewer.inputGroundPCL) - time.sleep(2) # buffer time for nodes to start - return rerunViewer \ No newline at end of file + diff --git a/__pycache__/Basalt_VIO_RTab.cpython-312.pyc b/__pycache__/Basalt_VIO_RTab.cpython-312.pyc deleted file mode 100644 index 7d1f2642e357d01c2e943746fe639177aa4ca217..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4198 zcmbVPTTC0-8J_X=_y&e#6TjLcR;F(m%XICi6Ui_VkwqRQgcN~&smUdNm^63 zIU9|A)}%ezu zi;})d=V+mvr4+JiM}FMJfos)~qXaZJ2QL-%S-b>e4vAIrc`I#fz0JV+UW|v#=vzkc zUX1>q$VgW5YcNQL}Sb5Ip-GoiQkk5IL?{~(S-9vGv$HtT`&=%mCgJ`;xnZ%Wa>mK z8?9aVhtcVeoeflJTyb_jtt$x zh{-^-BbeTm(~WZuK%0KE8t`9z*WICa{xr1DItC|E_bUuK?Q+mrmT23|2z}@xEoa^=x4s~ zvs4##o>J(C7Mhwxl>$v=sTJ!i^^gvDC-?Eoh5rm44*U~TDL|VlXSjg%QA70R$ml>w z<`|WW#A2B=BgV2fWuATH#P@*ifX1Sv_B#$}&8(iKrTa*0G7(&^5v+Oj5lw7J;7V zOmJj^Nl%XlC!j-7Ihm87OX1WhMrKlqjEf;y%Zbcll0!|WIZ=^h=rYy1U?>zG4@V;t z;hAuBAsYMy`fkofBh#VCRM;?2BDN7mjU}R7T9Vb7gv==kDapcm1WYh1WtakwBVTw$ z@#WcUdB_Zx2%EeTEDH~?v+zmdN3`t3p zXk#&R#H6CGc}WaOvWx>I5&C$MS9u0Sic5SPHdggvX6i%OD3?|f!6Y9SVO^=9lo*+v zmSW4C3hklb#KH*l$=v-6r>K#Pn$D=umgL1{bjRyrmyI=XD_JqdvBpw)ih6Oe>@4m8 zGvIOXr4So7p;ba;Rz8)1E>&hkWl54#&?d1`3c7g_^)!RMur|#oikgt6OdL%%Y6lE( zEER`-seGrQ1&1yJ!#fUoq(wz#Vo7c)G!FfSKT_s##Sx>(Vz8#vh}d@2PDXo3~nhCBKZTYG_?bE71OsXVD-X2@X$&jEfYx2j6hfAmh3K+LR=d zl5r6T9ccN{CWIatSMzsx?ja{DK7_QFUq6LnSLSak2%1-zR4h9ml30|W#* zUil|_);^=4%U!7PuUQNJV{7(8-SIWY5B05E_rDlea~5h(=(TNHZQGiy;6JJRJ2Za> zim9pHNUSIRplq%@UD?b%&F$5kM$K#e8!PK8&#XIO8|V!^T0_rXZ7*tA>F?7T`u1x3 zk-x5Cv-N4~nxk;`Vxg&{@L~Utc1!)hn&Y*Da``rD)@z zXx70c4P5%hk_T7c`kqbeErVLipx$y>Yq^{U9~r|bF^6}Dwyy7iULBm%z`2(vzHa)e zDGz>C0KVejwr=m<*oy3dJ{_Fb!1P~h$OY*`w>!3{o zZM(KF-Ot^5(2L?Xyz5>a;5J*QcY3ya^5D$d9Cgs4fsWnNUk08B@}LjR(S~!~iCa9G z*}VJoE}Hi5ffp}9DXr0+vF$Nqj>^5i(VGXg=D|F;Pync};*1!~y?W=6);W|1mkgvu z11&n})IjI%RlV!7)`jQAKpHgApaYC=E$gjUwAL%eTps9UNNX-~xp1D3U3dd7uP;AN z{ln|uxV3)k$^FL@udNi?Xvq6{>c97B%I(>xTd(^`!Jn7Eo3c;UTVK`Nr<$ArdNSaW zuOlyX8m}gXm+|KvbQ@3O0zOWP$Ah={IbHm|E*(cxe40ZqKhAiB{zSb&4Jr91ZVrZ1 z5}QeK*W?H?@p-2F0^MF)X`23)@_b8u@Ez6u9d+hM+c~;%>%z|P_V8;8sV~p|8w(j1 Ga{mL5BRetx diff --git a/__pycache__/cameraBundle.cpython-312.pyc b/__pycache__/cameraBundle.cpython-312.pyc deleted file mode 100644 index dbd30d155b699053fff5771269d9e63b6c1ecc85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2116 zcmcgtOKclO7@l3PoyCuuQfk(YAIqh}NKTtdZNUT=*DX|{NlM#XT%*-ycbu$W>+Y_l zI<=}EasUYlIHf+BNJx=srBs}9$p6*q%9t z+hI_djx<75*k|Bay@&IYQwcbHns#W{iZhSny^zeFsmwEOO)n%fGnIMVum6?#fVVUi zd;HovpmM<5t-R)b^@Ml4Q~u-0!2Sok=zsJNxpA>S=gJdaNlau{!pK)$dBQ8niR?;l zofN=6G52=D|3h?s;^j({=xvaumePkcFE$~cGlR$@iwa`MT~XH74HUR)Pw08rG}e*N8CMk2;Efj4jb(dmk-vtWMsh$SZX<;u zLys6@Mqb;1mj$E4TG^@1udS^Lx++y6PDD_y612gt7AEBg8r0QV%TUyYPNt5x&mZqe z+0u#*HNB*Zb*Wt{sIt;nE9F~;n#o_t7cwVLoIIVmChFD9e5SCxc)8^4AZJ(2HQR_4 z1f`)Eg0OMa>C4FEUXx_{J|=g-kmEmLJ_`*a$u0Fu^=oNoeS3XJ-Bt&Y(^h1`j4bRG z2a$^y62Qn_xEsFj*=76eZnz&FaBo>$&g61?w+7sYc9iJry;L`K|Hv-a=XO*5)FAq{ z6+LT4&wdviL>DpS(9hF}tYca8SauM3$BrLM_A=d!6+30dPCZZuvG?(9csQHt<+?d* z_KZ1uW-mOL#kD+Qxgi_;Jp5_cV&f(ozk98By?fnCWXwe75j%%%7R#9|XR!&BP281x z)o#^F9ygQ6e_&6L&jw5B0BKSK?`}arenF_Ka;rwv?^@Yq zGrMeMSIq3nL#b>@H%;lLCEYfq+mCU<^hfkl!X)~M!)#4)G=;{HTl59b6X5sGe|2Oh zz8(Lah)!mbEA2ruGI{Z$Vtmr@kOH K{~N%>_W2Y1q?r!@ diff --git a/__pycache__/object_tracker.cpython-312.pyc b/__pycache__/object_tracker.cpython-312.pyc deleted file mode 100644 index e6213b655973cd4f6f5b85ba598b8d1466cd6d08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6876 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 diff --git a/__pycache__/rerun_node.cpython-312.pyc b/__pycache__/rerun_node.cpython-312.pyc deleted file mode 100644 index 4a2808be93d1ae1112a62564f5fd43b6689dc992..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6605 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 diff --git a/cameraBundle.py b/cameraBundle.py index fe8cfd6..c4a2447 100644 --- a/cameraBundle.py +++ b/cameraBundle.py @@ -16,6 +16,7 @@ def __init__( self.camRgb = pipeline.create(dai.node.Camera).build(rgb_socket) self.monoLeft = pipeline.create(dai.node.Camera).build(left_socket) self.monoRight = pipeline.create(dai.node.Camera).build(right_socket) + self.slam = pipeline.create(dai.node.RTABMapSLAM) self.stereo = pipeline.create(dai.node.StereoDepth) self.leftOutput = self.monoLeft.requestOutput(mono_resolution) diff --git a/pipeline-combine.py b/pipeline-combine.py index d6bcd08..46ceab7 100644 --- a/pipeline-combine.py +++ b/pipeline-combine.py @@ -1,16 +1,28 @@ import Basalt_VIO_RTab -import rerun_node +from rerun_node import RerunNode import object_tracker import depthai as dai - +import time +from cameraBundle import CameraBundle # This is the main pipeline-combine.py file that integrates Basalt VIO with RTAB-Map SLAM with dai.Pipeline() as pipeline: - + cameraBundle = CameraBundle(pipeline) object_tracker.add_object_tracker(pipeline) - rerunViewer = Basalt_VIO_RTab.add_basalt_vio_rtab(pipeline) + Basalt_VIO_RTab.add_basalt_vio_rtab(pipeline, cameraBundle) + rerunViewer = RerunNode() + slam = cameraBundle.slam + slam.transform.link(rerunViewer.inputTrans) + slam.passthroughRect.link(rerunViewer.inputImg) + slam.occupancyGridMap.link(rerunViewer.inputGrid) + slam.obstaclePCL.link(rerunViewer.inputObstaclePCL) + slam.groundPCL.link(rerunViewer.inputGroundPCL) pipeline.start() - while not KeyboardInterrupt and pipeline.isRunning(): + try: + while pipeline.isRunning(): + time.sleep(0.1) + except KeyboardInterrupt: pass - pipeline.stop() + finally: + pipeline.stop() From 281aa5600d1b1fee59531b9b857ad0b34a998516 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:28:27 -0500 Subject: [PATCH 10/16] renaming files and passing in cameraBundle --- cameraBundle.py => camera_bundle.py | 0 pipeline-combine.py => pipeline_combine.py | 6 ++++-- 2 files changed, 4 insertions(+), 2 deletions(-) rename cameraBundle.py => camera_bundle.py (100%) rename pipeline-combine.py => pipeline_combine.py (88%) diff --git a/cameraBundle.py b/camera_bundle.py similarity index 100% rename from cameraBundle.py rename to camera_bundle.py diff --git a/pipeline-combine.py b/pipeline_combine.py similarity index 88% rename from pipeline-combine.py rename to pipeline_combine.py index 46ceab7..10509a5 100644 --- a/pipeline-combine.py +++ b/pipeline_combine.py @@ -3,14 +3,15 @@ import object_tracker import depthai as dai import time -from cameraBundle import CameraBundle +from camera_bundle import CameraBundle # This is the main pipeline-combine.py file that integrates Basalt VIO with RTAB-Map SLAM with dai.Pipeline() as pipeline: cameraBundle = CameraBundle(pipeline) - object_tracker.add_object_tracker(pipeline) + object_tracker.add_object_tracker(pipeline, cameraBundle) Basalt_VIO_RTab.add_basalt_vio_rtab(pipeline, cameraBundle) + rerunViewer = RerunNode() slam = cameraBundle.slam slam.transform.link(rerunViewer.inputTrans) @@ -18,6 +19,7 @@ slam.occupancyGridMap.link(rerunViewer.inputGrid) slam.obstaclePCL.link(rerunViewer.inputObstaclePCL) slam.groundPCL.link(rerunViewer.inputGroundPCL) + pipeline.start() try: while pipeline.isRunning(): From 91366697d3205fb5c50e8efcd56d21865e9a011a Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:29:51 -0500 Subject: [PATCH 11/16] import fix --- object_tracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/object_tracker.py b/object_tracker.py index 1492ab1..d45cfe7 100644 --- a/object_tracker.py +++ b/object_tracker.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import depthai as dai -from cameraBundle import CameraBundle +from camera_bundle import CameraBundle fullFrameTracking = False From cf08fe01b125d4f516a52539e9417760a933fcce Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:36:33 -0500 Subject: [PATCH 12/16] moved folders and linted --- Basalt_VIO_RTab.py => airside/oakd/Basalt_VIO_RTab.py | 3 +-- camera_bundle.py => airside/oakd/camera_bundle.py | 0 object_tracker.py => airside/oakd/object_tracker.py | 6 +++--- pipeline_combine.py => airside/oakd/pipeline_combine.py | 3 ++- requirements.txt => airside/oakd/requirements.txt | 0 rerun_node.py => airside/oakd/rerun_node.py | 0 util.py => airside/oakd/util.py | 9 ++++++--- 7 files changed, 12 insertions(+), 9 deletions(-) rename Basalt_VIO_RTab.py => airside/oakd/Basalt_VIO_RTab.py (98%) rename camera_bundle.py => airside/oakd/camera_bundle.py (100%) rename object_tracker.py => airside/oakd/object_tracker.py (92%) rename pipeline_combine.py => airside/oakd/pipeline_combine.py (99%) rename requirements.txt => airside/oakd/requirements.txt (100%) rename rerun_node.py => airside/oakd/rerun_node.py (100%) rename util.py => airside/oakd/util.py (98%) diff --git a/Basalt_VIO_RTab.py b/airside/oakd/Basalt_VIO_RTab.py similarity index 98% rename from Basalt_VIO_RTab.py rename to airside/oakd/Basalt_VIO_RTab.py index 41746d1..621494a 100644 --- a/Basalt_VIO_RTab.py +++ b/airside/oakd/Basalt_VIO_RTab.py @@ -11,7 +11,7 @@ def add_basalt_vio_rtab(p: dai.Pipeline, cameras: "CameraBundle" = None): width = 640 height = 400 # Define sources and outputs - + left = cameras.monoLeft right = cameras.monoRight imu = p.create(dai.node.IMU) @@ -48,4 +48,3 @@ def add_basalt_vio_rtab(p: dai.Pipeline, cameras: "CameraBundle" = None): imu.out.link(odom.imu) odom.transform.link(slam.odom) - diff --git a/camera_bundle.py b/airside/oakd/camera_bundle.py similarity index 100% rename from camera_bundle.py rename to airside/oakd/camera_bundle.py diff --git a/object_tracker.py b/airside/oakd/object_tracker.py similarity index 92% rename from object_tracker.py rename to airside/oakd/object_tracker.py index d45cfe7..6b7670c 100644 --- a/object_tracker.py +++ b/airside/oakd/object_tracker.py @@ -14,9 +14,9 @@ def add_object_tracker(p: dai.Pipeline, cameras: "CameraBundle" = None): camRgb = cameras.camRgb stereo = cameras.stereo - spatialDetectionNetwork = p.create( - dai.node.SpatialDetectionNetwork - ).build(camRgb, stereo, "yolov6-nano") + spatialDetectionNetwork = p.create(dai.node.SpatialDetectionNetwork).build( + camRgb, stereo, "yolov6-nano" + ) objectTracker = p.create(dai.node.ObjectTracker) spatialDetectionNetwork.setConfidenceThreshold(0.6) diff --git a/pipeline_combine.py b/airside/oakd/pipeline_combine.py similarity index 99% rename from pipeline_combine.py rename to airside/oakd/pipeline_combine.py index 10509a5..d7c362f 100644 --- a/pipeline_combine.py +++ b/airside/oakd/pipeline_combine.py @@ -4,6 +4,7 @@ import depthai as dai import time from camera_bundle import CameraBundle + # This is the main pipeline-combine.py file that integrates Basalt VIO with RTAB-Map SLAM @@ -11,7 +12,7 @@ cameraBundle = CameraBundle(pipeline) object_tracker.add_object_tracker(pipeline, cameraBundle) Basalt_VIO_RTab.add_basalt_vio_rtab(pipeline, cameraBundle) - + rerunViewer = RerunNode() slam = cameraBundle.slam slam.transform.link(rerunViewer.inputTrans) diff --git a/requirements.txt b/airside/oakd/requirements.txt similarity index 100% rename from requirements.txt rename to airside/oakd/requirements.txt diff --git a/rerun_node.py b/airside/oakd/rerun_node.py similarity index 100% rename from rerun_node.py rename to airside/oakd/rerun_node.py diff --git a/util.py b/airside/oakd/util.py similarity index 98% rename from util.py rename to airside/oakd/util.py index e0b8b74..f5d0eec 100644 --- a/util.py +++ b/airside/oakd/util.py @@ -9,18 +9,20 @@ # MAVLink communication constants AIRSIDE_COMPONENT_ID = 191 -MAVLINK_TCP_HOST = '127.0.0.1' +MAVLINK_TCP_HOST = "127.0.0.1" MAVLINK_TCP_PORT = 14550 MAVLINK_RECEIVE_TIMEOUT_SEC = 1 class MavlinkMessageType(Enum): """MAVLink message types used in drone communication""" + RC_CHANNELS = "RC_CHANNELS" class Colour(Enum): """Target colors""" + RED = "RED" GREEN = "GREEN" BLACK = "BLACK" @@ -30,6 +32,7 @@ class Colour(Enum): class Direction(Enum): """Cardinal directions""" + NORTH = "NORTH" SOUTH = "SOUTH" EAST = "EAST" @@ -46,7 +49,7 @@ def __init__(self, x: float, y: float, z: float): def __str__(self): return f"({self.x}, {self.y}, {self.z})" - + class Target: """Represents a target with a color and location.""" @@ -84,7 +87,7 @@ def __init__(self, x: float, y: float, z: float): def __str__(self): return f"({self.x}, {self.y}, {self.z})" - + class Plane: """Represents a plane in 3D space defined by an offset from origin and a normal vector.""" From 9050c697372f8939f786add7d718a1a765c9d889 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:37:39 -0500 Subject: [PATCH 13/16] oops --- airside/oakd/util.py | 100 ------------------------------------------- 1 file changed, 100 deletions(-) delete mode 100644 airside/oakd/util.py diff --git a/airside/oakd/util.py b/airside/oakd/util.py deleted file mode 100644 index f5d0eec..0000000 --- a/airside/oakd/util.py +++ /dev/null @@ -1,100 +0,0 @@ -""" -Utility classes and constants for drone communication and data structures. - -This module provides core data structures and enums used throughout the drone control system, -including local coordinate representation, MAVLink message types, and RC channel data. -""" - -from enum import Enum - -# MAVLink communication constants -AIRSIDE_COMPONENT_ID = 191 -MAVLINK_TCP_HOST = "127.0.0.1" -MAVLINK_TCP_PORT = 14550 -MAVLINK_RECEIVE_TIMEOUT_SEC = 1 - - -class MavlinkMessageType(Enum): - """MAVLink message types used in drone communication""" - - RC_CHANNELS = "RC_CHANNELS" - - -class Colour(Enum): - """Target colors""" - - RED = "RED" - GREEN = "GREEN" - BLACK = "BLACK" - BLUE = "BLUE" - YELLOW = "YELLOW" - - -class Direction(Enum): - """Cardinal directions""" - - NORTH = "NORTH" - SOUTH = "SOUTH" - EAST = "EAST" - WEST = "WEST" - - -class Coordinate: - """Represents a local coordinate with x, y, and z components.""" - - def __init__(self, x: float, y: float, z: float): - self.x = x - self.y = y - self.z = z - - def __str__(self): - return f"({self.x}, {self.y}, {self.z})" - - -class Target: - """Represents a target with a color and location.""" - - def __init__(self, colour: Colour, location: Coordinate): - self.colour = colour - self.location = location - - def __str__(self): - return f"(colour={self.colour}, location={self.location})" - - -class RCChannel: - """Represents a single RC channel with raw value and activity status.""" - - def __init__(self, channel: int, raw: int = 0, is_active: bool = False): - self.channel = channel - self.raw = raw - self.is_active = is_active - - def __str__(self): - return f"({self.channel}, {self.raw}, {self.is_active})" - - def __repr__(self): - return f"RCChannel(channel={self.channel}, raw={self.raw}, is_active={self.is_active})" - - -class Vector3d: - """Represents a 3D vector with x, y, and z components.""" - - def __init__(self, x: float, y: float, z: float): - self.x = x - self.y = y - self.z = z - - def __str__(self): - return f"({self.x}, {self.y}, {self.z})" - - -class Plane: - """Represents a plane in 3D space defined by an offset from origin and a normal vector.""" - - def __init__(self, offset: float, normal: Vector3d): - self.offset = offset - self.normal = normal - - def __str__(self): - return f"(offset={self.offset}, normal={self.normal})" From a17da7ed826f8302ea7fe73ac2c5dcdaa2767169 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:39:01 -0500 Subject: [PATCH 14/16] ... --- util.py | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 util.py diff --git a/util.py b/util.py new file mode 100644 index 0000000..f5d0eec --- /dev/null +++ b/util.py @@ -0,0 +1,100 @@ +""" +Utility classes and constants for drone communication and data structures. + +This module provides core data structures and enums used throughout the drone control system, +including local coordinate representation, MAVLink message types, and RC channel data. +""" + +from enum import Enum + +# MAVLink communication constants +AIRSIDE_COMPONENT_ID = 191 +MAVLINK_TCP_HOST = "127.0.0.1" +MAVLINK_TCP_PORT = 14550 +MAVLINK_RECEIVE_TIMEOUT_SEC = 1 + + +class MavlinkMessageType(Enum): + """MAVLink message types used in drone communication""" + + RC_CHANNELS = "RC_CHANNELS" + + +class Colour(Enum): + """Target colors""" + + RED = "RED" + GREEN = "GREEN" + BLACK = "BLACK" + BLUE = "BLUE" + YELLOW = "YELLOW" + + +class Direction(Enum): + """Cardinal directions""" + + NORTH = "NORTH" + SOUTH = "SOUTH" + EAST = "EAST" + WEST = "WEST" + + +class Coordinate: + """Represents a local coordinate with x, y, and z components.""" + + def __init__(self, x: float, y: float, z: float): + self.x = x + self.y = y + self.z = z + + def __str__(self): + return f"({self.x}, {self.y}, {self.z})" + + +class Target: + """Represents a target with a color and location.""" + + def __init__(self, colour: Colour, location: Coordinate): + self.colour = colour + self.location = location + + def __str__(self): + return f"(colour={self.colour}, location={self.location})" + + +class RCChannel: + """Represents a single RC channel with raw value and activity status.""" + + def __init__(self, channel: int, raw: int = 0, is_active: bool = False): + self.channel = channel + self.raw = raw + self.is_active = is_active + + def __str__(self): + return f"({self.channel}, {self.raw}, {self.is_active})" + + def __repr__(self): + return f"RCChannel(channel={self.channel}, raw={self.raw}, is_active={self.is_active})" + + +class Vector3d: + """Represents a 3D vector with x, y, and z components.""" + + def __init__(self, x: float, y: float, z: float): + self.x = x + self.y = y + self.z = z + + def __str__(self): + return f"({self.x}, {self.y}, {self.z})" + + +class Plane: + """Represents a plane in 3D space defined by an offset from origin and a normal vector.""" + + def __init__(self, offset: float, normal: Vector3d): + self.offset = offset + self.normal = normal + + def __str__(self): + return f"(offset={self.offset}, normal={self.normal})" From 1bbef64ea91d632ba66201ddedcc5c7a4c2be0cd Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Sun, 8 Feb 2026 16:46:03 -0500 Subject: [PATCH 15/16] moved requirements --- airside/oakd/requirements.txt => requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename airside/oakd/requirements.txt => requirements.txt (100%) diff --git a/airside/oakd/requirements.txt b/requirements.txt similarity index 100% rename from airside/oakd/requirements.txt rename to requirements.txt From b7dd5fe9ad728bb0939bb0aa7f3b6b8eab755457 Mon Sep 17 00:00:00 2001 From: Sam <70551337+samcyx@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:15:14 -0500 Subject: [PATCH 16/16] fix import --- airside/oakd/Basalt_VIO_RTab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airside/oakd/Basalt_VIO_RTab.py b/airside/oakd/Basalt_VIO_RTab.py index 621494a..a34314a 100644 --- a/airside/oakd/Basalt_VIO_RTab.py +++ b/airside/oakd/Basalt_VIO_RTab.py @@ -1,5 +1,5 @@ import depthai as dai -from cameraBundle import CameraBundle +from camera_bundle import CameraBundle # Create pipeline