diff --git a/examples/synapseproject/deploy/fmap.json b/examples/synapseproject/deploy/fmap.json index 3cfc373f..8c5a52de 100644 --- a/examples/synapseproject/deploy/fmap.json +++ b/examples/synapseproject/deploy/fmap.json @@ -1,55 +1,109 @@ { "tags": [ { - "ID": 3, + "ID": 1, "pose": { "translation": { - "x": 11.560809999999998, - "y": 8.05561, - "z": 1.30175 + "x": 11.8779798, + "y": 7.4247756, + "z": 0.889 }, "rotation": { "quaternion": { - "W": -0.7071067811865475, - "X": -0.0, + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 + } + } + } + }, + { + "ID": 2, + "pose": { + "translation": { + "x": 11.9154194, + "y": 4.638039999999999, + "z": 1.12395 + }, + "rotation": { + "quaternion": { + "W": 0.7071067811865476, + "X": 0.0, "Y": 0.0, "Z": 0.7071067811865476 } } } }, + { + "ID": 3, + "pose": { + "translation": { + "x": 11.3118646, + "y": 4.3902376, + "z": 1.12395 + }, + "rotation": { + "quaternion": { + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 + } + } + } + }, { "ID": 4, "pose": { "translation": { - "x": 9.276079999999999, - "y": 6.137656, - "z": 1.8679160000000001 + "x": 11.3118646, + "y": 4.0346376, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": 0.9659258262890683, + "W": 6.123233995736766e-17, "X": 0.0, - "Y": 0.25881904510252074, - "Z": 0.0 + "Y": 0.0, + "Z": 1.0 } } } }, { - "ID": 6, + "ID": 5, "pose": { "translation": { - "x": 13.474446, - "y": 3.3063179999999996, - "z": 0.308102 + "x": 11.9154194, + "y": 3.4312351999999997, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": -0.8660254037844387, + "W": -0.7071067811865475, "X": -0.0, "Y": 0.0, - "Z": 0.49999999999999994 + "Z": 0.7071067811865476 + } + } + } + }, + { + "ID": 6, + "pose": { + "translation": { + "x": 11.8779798, + "y": 0.6444996, + "z": 0.889 + }, + "rotation": { + "quaternion": { + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 } } } @@ -58,9 +112,9 @@ "ID": 7, "pose": { "translation": { - "x": 13.890498, - "y": 4.0259, - "z": 0.308102 + "x": 11.9528844, + "y": 0.6444996, + "z": 0.889 }, "rotation": { "quaternion": { @@ -76,16 +130,16 @@ "ID": 8, "pose": { "translation": { - "x": 13.474446, - "y": 4.745482, - "z": 0.308102 + "x": 12.2710194, + "y": 3.4312351999999997, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": 0.8660254037844387, - "X": 0.0, + "W": -0.7071067811865475, + "X": -0.0, "Y": 0.0, - "Z": 0.49999999999999994 + "Z": 0.7071067811865476 } } } @@ -94,16 +148,16 @@ "ID": 9, "pose": { "translation": { - "x": 12.643358, - "y": 4.745482, - "z": 0.308102 + "x": 12.519177399999998, + "y": 3.6790375999999996, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": 0.5000000000000001, + "W": 1.0, "X": 0.0, "Y": 0.0, - "Z": 0.8660254037844386 + "Z": 0.0 } } } @@ -112,16 +166,16 @@ "ID": 10, "pose": { "translation": { - "x": 12.227305999999999, - "y": 4.0259, - "z": 0.308102 + "x": 12.519177399999998, + "y": 4.0346376, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": 6.123233995736766e-17, + "W": 1.0, "X": 0.0, "Y": 0.0, - "Z": 1.0 + "Z": 0.0 } } } @@ -130,16 +184,52 @@ "ID": 11, "pose": { "translation": { - "x": 12.643358, - "y": 3.3063179999999996, - "z": 0.308102 + "x": 12.2710194, + "y": 4.638039999999999, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": -0.4999999999999998, - "X": -0.0, + "W": 0.7071067811865476, + "X": 0.0, + "Y": 0.0, + "Z": 0.7071067811865476 + } + } + } + }, + { + "ID": 12, + "pose": { + "translation": { + "x": 11.9528844, + "y": 7.4247756, + "z": 0.889 + }, + "rotation": { + "quaternion": { + "W": 1.0, + "X": 0.0, + "Y": 0.0, + "Z": 0.0 + } + } + } + }, + { + "ID": 13, + "pose": { + "translation": { + "x": 16.5333172, + "y": 7.4033126, + "z": 0.55245 + }, + "rotation": { + "quaternion": { + "W": 6.123233995736766e-17, + "X": 0.0, "Y": 0.0, - "Z": 0.8660254037844387 + "Z": 1.0 } } } @@ -148,16 +238,16 @@ "ID": 14, "pose": { "translation": { - "x": 8.272272, - "y": 6.137656, - "z": 1.8679160000000001 + "x": 16.5333172, + "y": 6.9715126, + "z": 0.55245 }, "rotation": { "quaternion": { - "W": 5.914589856893349e-17, - "X": -0.25881904510252074, - "Y": 1.5848095757158825e-17, - "Z": 0.9659258262890683 + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 } } } @@ -166,16 +256,16 @@ "ID": 15, "pose": { "translation": { - "x": 8.272272, - "y": 1.914906, - "z": 1.8679160000000001 + "x": 16.5329616, + "y": 4.3235626, + "z": 0.55245 }, "rotation": { "quaternion": { - "W": 5.914589856893349e-17, - "X": -0.25881904510252074, - "Y": 1.5848095757158825e-17, - "Z": 0.9659258262890683 + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 } } } @@ -184,16 +274,16 @@ "ID": 16, "pose": { "translation": { - "x": 5.9875419999999995, - "y": -0.0038099999999999996, - "z": 1.30175 + "x": 16.5329616, + "y": 3.8917626, + "z": 0.55245 }, "rotation": { "quaternion": { - "W": 0.7071067811865476, + "W": 6.123233995736766e-17, "X": 0.0, "Y": 0.0, - "Z": 0.7071067811865476 + "Z": 1.0 } } } @@ -202,16 +292,16 @@ "ID": 17, "pose": { "translation": { - "x": 4.073905999999999, - "y": 3.3063179999999996, - "z": 0.308102 + "x": 4.6630844, + "y": 0.6444996, + "z": 0.889 }, "rotation": { "quaternion": { - "W": -0.4999999999999998, - "X": -0.0, + "W": 1.0, + "X": 0.0, "Y": 0.0, - "Z": 0.8660254037844387 + "Z": 0.0 } } } @@ -220,16 +310,16 @@ "ID": 18, "pose": { "translation": { - "x": 3.6576, - "y": 4.0259, - "z": 0.308102 + "x": 4.6256194, + "y": 3.4312351999999997, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": 6.123233995736766e-17, - "X": 0.0, + "W": -0.7071067811865475, + "X": -0.0, "Y": 0.0, - "Z": 1.0 + "Z": 0.7071067811865476 } } } @@ -238,16 +328,16 @@ "ID": 19, "pose": { "translation": { - "x": 4.073905999999999, - "y": 4.745482, - "z": 0.308102 + "x": 5.229174199999999, + "y": 3.6790375999999996, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": 0.5000000000000001, + "W": 1.0, "X": 0.0, "Y": 0.0, - "Z": 0.8660254037844386 + "Z": 0.0 } } } @@ -256,16 +346,16 @@ "ID": 20, "pose": { "translation": { - "x": 4.904739999999999, - "y": 4.745482, - "z": 0.308102 + "x": 5.229174199999999, + "y": 4.0346376, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": 0.8660254037844387, + "W": 1.0, "X": 0.0, "Y": 0.0, - "Z": 0.49999999999999994 + "Z": 0.0 } } } @@ -274,9 +364,27 @@ "ID": 21, "pose": { "translation": { - "x": 5.321046, - "y": 4.0259, - "z": 0.308102 + "x": 4.6256194, + "y": 4.638039999999999, + "z": 1.12395 + }, + "rotation": { + "quaternion": { + "W": 0.7071067811865476, + "X": 0.0, + "Y": 0.0, + "Z": 0.7071067811865476 + } + } + } + }, + { + "ID": 22, + "pose": { + "translation": { + "x": 4.6630844, + "y": 7.4247756, + "z": 0.889 }, "rotation": { "quaternion": { @@ -289,26 +397,188 @@ } }, { - "ID": 22, + "ID": 23, + "pose": { + "translation": { + "x": 4.5881798, + "y": 7.4247756, + "z": 0.889 + }, + "rotation": { + "quaternion": { + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 + } + } + } + }, + { + "ID": 24, + "pose": { + "translation": { + "x": 4.2700194, + "y": 4.638039999999999, + "z": 1.12395 + }, + "rotation": { + "quaternion": { + "W": 0.7071067811865476, + "X": 0.0, + "Y": 0.0, + "Z": 0.7071067811865476 + } + } + } + }, + { + "ID": 25, "pose": { "translation": { - "x": 4.904739999999999, - "y": 3.3063179999999996, - "z": 0.308102 + "x": 4.0218614, + "y": 4.3902376, + "z": 1.12395 }, "rotation": { "quaternion": { - "W": -0.8660254037844387, + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 + } + } + } + }, + { + "ID": 26, + "pose": { + "translation": { + "x": 4.0218614, + "y": 4.0346376, + "z": 1.12395 + }, + "rotation": { + "quaternion": { + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 + } + } + } + }, + { + "ID": 27, + "pose": { + "translation": { + "x": 4.2700194, + "y": 3.4312351999999997, + "z": 1.12395 + }, + "rotation": { + "quaternion": { + "W": -0.7071067811865475, "X": -0.0, "Y": 0.0, - "Z": 0.49999999999999994 + "Z": 0.7071067811865476 + } + } + } + }, + { + "ID": 28, + "pose": { + "translation": { + "x": 4.5881798, + "y": 0.6444996, + "z": 0.889 + }, + "rotation": { + "quaternion": { + "W": 6.123233995736766e-17, + "X": 0.0, + "Y": 0.0, + "Z": 1.0 + } + } + } + }, + { + "ID": 29, + "pose": { + "translation": { + "x": 0.0077469999999999995, + "y": 0.6659626, + "z": 0.55245 + }, + "rotation": { + "quaternion": { + "W": 1.0, + "X": 0.0, + "Y": 0.0, + "Z": 0.0 + } + } + } + }, + { + "ID": 30, + "pose": { + "translation": { + "x": 0.0077469999999999995, + "y": 1.0977626, + "z": 0.55245 + }, + "rotation": { + "quaternion": { + "W": 1.0, + "X": 0.0, + "Y": 0.0, + "Z": 0.0 + } + } + } + }, + { + "ID": 31, + "pose": { + "translation": { + "x": 0.0080772, + "y": 3.7457125999999996, + "z": 0.55245 + }, + "rotation": { + "quaternion": { + "W": 1.0, + "X": 0.0, + "Y": 0.0, + "Z": 0.0 + } + } + } + }, + { + "ID": 32, + "pose": { + "translation": { + "x": 0.0080772, + "y": 4.1775126, + "z": 0.55245 + }, + "rotation": { + "quaternion": { + "W": 1.0, + "X": 0.0, + "Y": 0.0, + "Z": 0.0 } } } } ], "field": { - "length": 17.548, - "width": 8.052 + "length": 16.541, + "width": 8.069 } } diff --git a/synapse_core/src/synapse/__version__.py b/synapse_core/src/synapse/__version__.py index f94bd05a..e866c935 100644 --- a/synapse_core/src/synapse/__version__.py +++ b/synapse_core/src/synapse/__version__.py @@ -5,6 +5,6 @@ from typing import Final -WPILIB_VERSION: Final[str] = "2026.1.1" +WPILIB_VERSION: Final[str] = "2026.2.1" WPILIB_YEAR: Final[str] = "2026" SYNAPSE_VERSION: Final[str] = "2026.0.1" diff --git a/synapse_core/src/synapse/pipelines/apriltag/apriltag_pipeline.py b/synapse_core/src/synapse/pipelines/apriltag/apriltag_pipeline.py index 61cf3a04..f08936dc 100644 --- a/synapse_core/src/synapse/pipelines/apriltag/apriltag_pipeline.py +++ b/synapse_core/src/synapse/pipelines/apriltag/apriltag_pipeline.py @@ -292,19 +292,16 @@ def processFrame(self, img, timestamp: float) -> FrameResult: ) self.setDataValue("hasResults", True) - self.setResults( - ApriltagsJson.toJsonString( - ApriltagResult( - self.combinedApriltagPoseEstimator.estimate( - map( - lambda estimate: estimate.cameraPoseEstimate, - tagEstimates, - ) - ), + result = ApriltagResult( + self.combinedApriltagPoseEstimator.estimate( + map( + lambda estimate: estimate.cameraPoseEstimate, tagEstimates, - ), + ) ), + tagEstimates, ) + self.setResults(ApriltagsJson.toJsonString(result)) return cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) diff --git a/synapse_core/src/synapse/pipelines/apriltag/field_loader.py b/synapse_core/src/synapse/pipelines/apriltag/field_loader.py index 815f6b68..b32d99f9 100644 --- a/synapse_core/src/synapse/pipelines/apriltag/field_loader.py +++ b/synapse_core/src/synapse/pipelines/apriltag/field_loader.py @@ -22,27 +22,31 @@ def __init__(self, jsonDict: Dict[TagId, Pose3d], length: float, width: float): def loadField(filePath: str | Path) -> "ApriltagFieldJson": with open(filePath, "r") as file: jsonDict: dict = json.load(file) - tagsDict: Dict[ApriltagFieldJson.TagId, Pose3d] = {} - for tag in jsonDict.get("tags", {}): - poseDict = tag["pose"] - rotation = poseDict["rotation"]["quaternion"] - translation = poseDict["translation"] - tagsDict[tag["ID"]] = Pose3d( - translation=Translation3d( - translation["x"], translation["y"], translation["z"] - ), - rotation=Rotation3d( - Quaternion( - w=rotation["W"], - x=rotation["X"], - y=rotation["Y"], - z=rotation["Z"], - ) - ), - ) - length = jsonDict["field"]["length"] - width = jsonDict["field"]["width"] - return ApriltagFieldJson(tagsDict, length, width) + return ApriltagFieldJson.loadFieldJson(jsonDict) + + @staticmethod + def loadFieldJson(data: dict) -> "ApriltagFieldJson": + tagsDict: Dict[ApriltagFieldJson.TagId, Pose3d] = {} + for tag in data.get("tags", {}): + poseDict = tag["pose"] + rotation = poseDict["rotation"]["quaternion"] + translation = poseDict["translation"] + tagsDict[tag["ID"]] = Pose3d( + translation=Translation3d( + translation["x"], translation["y"], translation["z"] + ), + rotation=Rotation3d( + Quaternion( + w=rotation["W"], + x=rotation["X"], + y=rotation["Y"], + z=rotation["Z"], + ) + ), + ) + length = data["field"]["length"] + width = data["field"]["width"] + return ApriltagFieldJson(tagsDict, length, width) def getTagPose(self, id: TagId) -> Optional[Pose3d]: if id in self.fieldMap.keys(): diff --git a/synapse_ui/src/app/dashboard/results_view.tsx b/synapse_ui/src/app/dashboard/results_view.tsx index 46e2345e..94c75795 100644 --- a/synapse_ui/src/app/dashboard/results_view.tsx +++ b/synapse_ui/src/app/dashboard/results_view.tsx @@ -24,7 +24,6 @@ function RenderPrimitiveResult({ copyToClipboard: (key: string, text: string) => void; textSize?: string; }) { - // Render `null` if value.value is undefined const val = value.value === undefined ? null : String(protoToSettingValue(value.value)); diff --git a/synapse_ui/src/widgets/msgpackTree.tsx b/synapse_ui/src/widgets/msgpackTree.tsx index 4f43ef9c..7cb9930e 100644 --- a/synapse_ui/src/widgets/msgpackTree.tsx +++ b/synapse_ui/src/widgets/msgpackTree.tsx @@ -115,19 +115,11 @@ export function MsgPackTree({ const [expandedMap, setExpandedMap] = useState>({}); let decoded: unknown = null; // default to null - try { - if (decoded != null && decoded !== 0) { - decoded = decode( - encoded instanceof ArrayBuffer ? new Uint8Array(encoded) : encoded, - ); - } - } catch (e) { - if (e instanceof TypeError) { - decoded = null; // silently fallback to null - } else { - // re-throw other errors - throw e; - } + + if (encoded !== null && encoded.byteLength !== 0) { + decoded = decode( + encoded instanceof ArrayBuffer ? new Uint8Array(encoded) : encoded, + ); } return (