Anthropic Claude
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema_version": "1.2",
|
||||
"stage": "initial_triangulation",
|
||||
"created_utc": "2026-05-31T08:47:11Z",
|
||||
"created_utc": "2026-06-01T12:30:25Z",
|
||||
"summary": {
|
||||
"num_cameras": 7,
|
||||
"num_markers": 50,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.2",
|
||||
"created_utc": "2026-05-31T08:47:48Z",
|
||||
"created_utc": "2026-06-01T12:31:31Z",
|
||||
"summary": {
|
||||
"num_cameras": 7,
|
||||
"num_markers": 50,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:06Z",
|
||||
"created_utc": "2026-06-01T12:38:59Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "47838397-be6e-45aa-a6f1-0f646a7c7e32",
|
||||
"observation_id": "44109558-03cb-4d11-bd08-768cc37ee9dc",
|
||||
"type": "aruco",
|
||||
"marker_id": 219,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.9601597205345928
|
||||
},
|
||||
{
|
||||
"observation_id": "3e933766-f9eb-4688-8403-fa53df74032d",
|
||||
"observation_id": "e2aaaf5e-4666-411e-b9cf-dd1166602e83",
|
||||
"type": "aruco",
|
||||
"marker_id": 42,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.7977507265243933
|
||||
},
|
||||
{
|
||||
"observation_id": "c0653e64-f844-4038-9d51-b1d78f9287ad",
|
||||
"observation_id": "3b590630-b80a-4061-b9d0-7d4c07b7bc11",
|
||||
"type": "aruco",
|
||||
"marker_id": 218,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.9114881811828396
|
||||
},
|
||||
{
|
||||
"observation_id": "d220625a-6d4b-4caa-ac48-a4f58bd03e15",
|
||||
"observation_id": "9228f5a3-d039-4f3c-9da7-2b49f72a382f",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.8788055127363418
|
||||
},
|
||||
{
|
||||
"observation_id": "f47bdd0d-5cf1-45c1-9d34-8a3225a0d5b4",
|
||||
"observation_id": "2172f251-719c-4585-8d14-0045867cfe89",
|
||||
"type": "aruco",
|
||||
"marker_id": 247,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.7804137133263228
|
||||
},
|
||||
{
|
||||
"observation_id": "abaf559c-aa07-4e86-bc8b-6dc5de0d4862",
|
||||
"observation_id": "35b0c1d9-0342-472b-be65-b1f7a9286ed9",
|
||||
"type": "aruco",
|
||||
"marker_id": 246,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.7125165224268091
|
||||
},
|
||||
{
|
||||
"observation_id": "f2135fd0-f994-4db3-be7c-b31098957721",
|
||||
"observation_id": "374b176d-eecc-403a-9f12-c213b213a5f5",
|
||||
"type": "aruco",
|
||||
"marker_id": 114,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.4775336476164635
|
||||
},
|
||||
{
|
||||
"observation_id": "92febfcc-e966-45cd-8b60-868e105a03c6",
|
||||
"observation_id": "c73a38d2-c84a-4ee3-aa46-dc4f67173f8d",
|
||||
"type": "aruco",
|
||||
"marker_id": 120,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.48472798261140293
|
||||
},
|
||||
{
|
||||
"observation_id": "f25902ac-cf8e-4fdc-9788-5645b1c4a3f9",
|
||||
"observation_id": "7998bb95-459e-494b-a10b-b784803f328d",
|
||||
"type": "aruco",
|
||||
"marker_id": 47,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.12146268776527554
|
||||
},
|
||||
{
|
||||
"observation_id": "9f1b0912-d591-4371-bfb9-a5fa6c571e60",
|
||||
"observation_id": "70728a47-787b-4753-9f07-ed9ed93a1d1b",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.46829700346999537
|
||||
},
|
||||
{
|
||||
"observation_id": "d5647595-eed8-4487-b564-5e6bd14436a8",
|
||||
"observation_id": "95f6ceb3-6a73-48d5-a13b-6fe4343582fd",
|
||||
"type": "aruco",
|
||||
"marker_id": 85,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.4560525484643318
|
||||
},
|
||||
{
|
||||
"observation_id": "3a2b7364-a8bd-484d-aed5-314fbbc12d50",
|
||||
"observation_id": "834a222f-4225-4342-8070-74ea49c5b0f8",
|
||||
"type": "aruco",
|
||||
"marker_id": 79,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.5734281513866332
|
||||
},
|
||||
{
|
||||
"observation_id": "0a981d4c-f32c-42bc-ba1c-7db45aca4f09",
|
||||
"observation_id": "cc2d1afa-c0ef-4697-963c-3a2814f9773d",
|
||||
"type": "aruco",
|
||||
"marker_id": 96,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.525542829627259
|
||||
},
|
||||
{
|
||||
"observation_id": "4ba55d56-3956-4f58-9000-8c9e9b9ea4a0",
|
||||
"observation_id": "89d81c95-61e8-4afb-acd0-21f763434708",
|
||||
"type": "aruco",
|
||||
"marker_id": 215,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.456911083882938
|
||||
},
|
||||
{
|
||||
"observation_id": "8800627a-400c-4cca-b4e2-89a1661fbcad",
|
||||
"observation_id": "9749a99a-5444-41a2-a9e2-37b7dfe57fc5",
|
||||
"type": "aruco",
|
||||
"marker_id": 105,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.43622925667631085
|
||||
},
|
||||
{
|
||||
"observation_id": "077b0333-5b5a-4b9b-adb4-6b5a01517280",
|
||||
"observation_id": "c90dc06c-55c0-418e-a622-90ec11369da5",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.4417935296159658
|
||||
},
|
||||
{
|
||||
"observation_id": "c6a375f4-8084-490f-84f2-f59d68badae7",
|
||||
"observation_id": "b487e11c-faa7-499e-9972-6d5409375476",
|
||||
"type": "aruco",
|
||||
"marker_id": 211,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.3826078272694969
|
||||
},
|
||||
{
|
||||
"observation_id": "af422433-75e2-4f3a-b2c1-d94d366d249d",
|
||||
"observation_id": "b4bccfd1-3478-4800-bafa-6971665221b1",
|
||||
"type": "aruco",
|
||||
"marker_id": 75,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.29844141482805986
|
||||
},
|
||||
{
|
||||
"observation_id": "33e5f248-80ea-47b3-82d5-89d0865f9cf8",
|
||||
"observation_id": "a611e7c5-aa9c-4c5c-b755-a81b7695c1b1",
|
||||
"type": "aruco",
|
||||
"marker_id": 102,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.2521714913889437
|
||||
},
|
||||
{
|
||||
"observation_id": "df611a6c-c7bf-46c6-9751-9a4c1df50115",
|
||||
"observation_id": "5657f220-8852-49fa-9505-fc03bc0ebe44",
|
||||
"type": "aruco",
|
||||
"marker_id": 214,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.38467027802270787
|
||||
},
|
||||
{
|
||||
"observation_id": "7769664a-962f-4d15-83a0-353f114f5be1",
|
||||
"observation_id": "1dded302-fde5-4e65-bd40-50bfe59f2a2b",
|
||||
"type": "aruco",
|
||||
"marker_id": 92,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.31777455864589965
|
||||
},
|
||||
{
|
||||
"observation_id": "203a986b-496b-4aa9-b09d-92f87f1e9c96",
|
||||
"observation_id": "947e6510-f8af-4867-a162-6a40ef047627",
|
||||
"type": "aruco",
|
||||
"marker_id": 217,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.3029173397022545
|
||||
},
|
||||
{
|
||||
"observation_id": "e714abfe-bd7f-4f26-a013-7e8d30fc3e86",
|
||||
"observation_id": "95f3a159-c4bf-4a1a-9860-05994d6cf8ec",
|
||||
"type": "aruco",
|
||||
"marker_id": 61,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.1527342148240039
|
||||
},
|
||||
{
|
||||
"observation_id": "10d67411-73d3-4a16-95fc-4b6fb66ce9d2",
|
||||
"observation_id": "86f955f5-a2c1-4a57-abd6-f09e00cd68c0",
|
||||
"type": "aruco",
|
||||
"marker_id": 83,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.19743498130596515
|
||||
},
|
||||
{
|
||||
"observation_id": "fe02d1ed-cbfe-4986-b8c4-07822592c803",
|
||||
"observation_id": "eb2003a3-90a5-4923-a211-c9acf598de4f",
|
||||
"type": "aruco",
|
||||
"marker_id": 206,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.2849187633475991
|
||||
},
|
||||
{
|
||||
"observation_id": "a64c5eb5-f28a-4443-b1b1-e38533229ae0",
|
||||
"observation_id": "1ae4253b-50d1-409a-9823-5e7c59974646",
|
||||
"type": "aruco",
|
||||
"marker_id": 207,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.24627951083020566
|
||||
},
|
||||
{
|
||||
"observation_id": "921da138-9354-401f-b719-aad7dcb82b95",
|
||||
"observation_id": "fa04c51a-fce3-449d-aecb-9eb18b58acb1",
|
||||
"type": "aruco",
|
||||
"marker_id": 93,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:09Z",
|
||||
"created_utc": "2026-06-01T12:39:04Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene4\\render_a_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:07Z",
|
||||
"created_utc": "2026-06-01T12:39:00Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "6aab51d3-8f8e-4b78-b4d4-cca9fa9b98ae",
|
||||
"observation_id": "fe0a2cf0-2197-4f51-b085-f3405d4f42aa",
|
||||
"type": "aruco",
|
||||
"marker_id": 114,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.80343703773924
|
||||
},
|
||||
{
|
||||
"observation_id": "082bf1b8-a4c4-4c38-88fd-0cd995c7e479",
|
||||
"observation_id": "d8dbf9c7-f93f-436e-b64a-f8308039eda3",
|
||||
"type": "aruco",
|
||||
"marker_id": 120,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.7694115459687173
|
||||
},
|
||||
{
|
||||
"observation_id": "16876b6c-315f-4a34-81c0-242a4fe4d482",
|
||||
"observation_id": "5a1a8c48-5b97-4c5e-be74-ae9599453b0f",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.770675991358623
|
||||
},
|
||||
{
|
||||
"observation_id": "9e8d2195-7a17-44c9-9ce6-7c84adbaa920",
|
||||
"observation_id": "39454e6a-6bd1-4a64-ae3b-fd46338f3d25",
|
||||
"type": "aruco",
|
||||
"marker_id": 219,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.6459779993693033
|
||||
},
|
||||
{
|
||||
"observation_id": "7f252298-54c7-448d-a3de-d72e687ce77f",
|
||||
"observation_id": "2e21a031-bb5d-4d5a-9908-4c9059da2282",
|
||||
"type": "aruco",
|
||||
"marker_id": 247,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.6729142857142857
|
||||
},
|
||||
{
|
||||
"observation_id": "2643b320-0e47-46a8-8379-129e66bbee84",
|
||||
"observation_id": "2852564f-d5d4-471b-8220-7099c409aa1d",
|
||||
"type": "aruco",
|
||||
"marker_id": 246,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.6507344589435812
|
||||
},
|
||||
{
|
||||
"observation_id": "8a11802b-a1ad-4f63-8f4b-2ee6d490eef3",
|
||||
"observation_id": "f3f8786b-acb0-46e0-9be1-c5a399871039",
|
||||
"type": "aruco",
|
||||
"marker_id": 218,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.5993310137356028
|
||||
},
|
||||
{
|
||||
"observation_id": "c1d9cbb1-18fd-473f-a177-bf60900ada21",
|
||||
"observation_id": "3bbf6533-d32c-4276-b8ee-f1da5a5a823e",
|
||||
"type": "aruco",
|
||||
"marker_id": 44,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.46011560227730974
|
||||
},
|
||||
{
|
||||
"observation_id": "626151f8-b54e-48ce-8ec1-104711123983",
|
||||
"observation_id": "bd2800e6-5fbf-4e49-9448-2630290bb0f2",
|
||||
"type": "aruco",
|
||||
"marker_id": 42,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.0456345257443131
|
||||
},
|
||||
{
|
||||
"observation_id": "95a84990-d6a4-42c9-9e9d-9dff35ca6309",
|
||||
"observation_id": "26ed215c-7e3c-4b29-b2d5-06726c033f09",
|
||||
"type": "aruco",
|
||||
"marker_id": 63,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.1539593300495616
|
||||
},
|
||||
{
|
||||
"observation_id": "ee9e53b4-e504-4389-bacf-0d4f4fad0888",
|
||||
"observation_id": "afefe8e9-77a4-4f67-bbc9-fdcb28b7b355",
|
||||
"type": "aruco",
|
||||
"marker_id": 102,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.39637168760361213
|
||||
},
|
||||
{
|
||||
"observation_id": "6940a210-9090-4489-972a-fc96cd0dbff6",
|
||||
"observation_id": "7348f772-d89a-42c6-9c08-eebd24909b3d",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.4633649853376546
|
||||
},
|
||||
{
|
||||
"observation_id": "070b352d-fd05-4038-8290-5beadbbfef88",
|
||||
"observation_id": "5b4796e4-688c-484d-984d-af848f97562f",
|
||||
"type": "aruco",
|
||||
"marker_id": 58,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.3638956157928849
|
||||
},
|
||||
{
|
||||
"observation_id": "78223644-d61c-4a3c-8e97-418d3249791f",
|
||||
"observation_id": "49fbee39-de95-4344-83c3-35d813b23aae",
|
||||
"type": "aruco",
|
||||
"marker_id": 92,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.46896024883690896
|
||||
},
|
||||
{
|
||||
"observation_id": "02e00e55-85f9-4f0a-8216-776d9caf8300",
|
||||
"observation_id": "254ac7ad-2a62-4299-87cf-4608468f0113",
|
||||
"type": "aruco",
|
||||
"marker_id": 96,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.44372569385651617
|
||||
},
|
||||
{
|
||||
"observation_id": "df5fb02f-0ad6-447c-afa4-63b614af09ae",
|
||||
"observation_id": "2aafd9ad-8294-40e5-b8c4-8397c7069a9e",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.45199802144368495
|
||||
},
|
||||
{
|
||||
"observation_id": "e8214723-46f6-4d85-96ac-e27f720ffd85",
|
||||
"observation_id": "6ecdcc3e-c7d3-46c5-b8fe-0a8e9cdb10be",
|
||||
"type": "aruco",
|
||||
"marker_id": 51,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.45199802144368495
|
||||
},
|
||||
{
|
||||
"observation_id": "e23e2c6d-d0f1-40b0-922a-7c51e2dbd83e",
|
||||
"observation_id": "086a56a9-db3f-4da8-88cc-fad22bd9073b",
|
||||
"type": "aruco",
|
||||
"marker_id": 62,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.44348322079976393
|
||||
},
|
||||
{
|
||||
"observation_id": "506cca57-5935-4563-8f31-c13b4925889a",
|
||||
"observation_id": "f5277845-c781-43e9-aad1-c7d209965635",
|
||||
"type": "aruco",
|
||||
"marker_id": 205,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.3958181457519531
|
||||
},
|
||||
{
|
||||
"observation_id": "a0fcaf48-6973-4616-afd3-5c528ea43e9a",
|
||||
"observation_id": "d69af31c-84a4-4fb6-9980-0818c7893b9c",
|
||||
"type": "aruco",
|
||||
"marker_id": 217,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.4015868133874269
|
||||
},
|
||||
{
|
||||
"observation_id": "b0e0409b-cd3c-4fb7-8280-441914fb7924",
|
||||
"observation_id": "ec172895-8fd1-4f96-85f1-a01aaa3ab035",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.3776
|
||||
},
|
||||
{
|
||||
"observation_id": "f76e08ae-1b93-43e6-8415-4f02895c9ab1",
|
||||
"observation_id": "67e9ecf5-4aeb-45c4-962f-2603024131b3",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.3320910299473707
|
||||
},
|
||||
{
|
||||
"observation_id": "15018bcd-f7be-46b3-9ca5-0106eb98ab2a",
|
||||
"observation_id": "137b3477-8774-4bc6-8c97-21967a32a691",
|
||||
"type": "aruco",
|
||||
"marker_id": 206,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.3579602826436361
|
||||
},
|
||||
{
|
||||
"observation_id": "14a99a02-7aa5-4239-9d1a-0532822098ba",
|
||||
"observation_id": "857e233a-65a2-417d-b0d2-eea89e3e9a18",
|
||||
"type": "aruco",
|
||||
"marker_id": 207,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.343462485354258
|
||||
},
|
||||
{
|
||||
"observation_id": "85986399-de4c-4d08-a06d-0b502e6b2b6e",
|
||||
"observation_id": "e901c6fa-3362-4a34-bf85-95793699da92",
|
||||
"type": "aruco",
|
||||
"marker_id": 214,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.3244367816091954
|
||||
},
|
||||
{
|
||||
"observation_id": "28819d00-f6b7-4f9a-b84b-0fa65f93567b",
|
||||
"observation_id": "ce3e90c6-3287-4a84-ac2e-73275069ec31",
|
||||
"type": "aruco",
|
||||
"marker_id": 94,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.06057156860351561
|
||||
},
|
||||
{
|
||||
"observation_id": "19751dd7-e8f6-40d3-87fe-a317bb39fc64",
|
||||
"observation_id": "6bf5e710-8059-4279-a7e4-ec6c9795fb9d",
|
||||
"type": "aruco",
|
||||
"marker_id": 76,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.2459421895345052
|
||||
},
|
||||
{
|
||||
"observation_id": "b05b3442-249a-4049-9ee9-52fab70fd806",
|
||||
"observation_id": "f4002814-f5e4-485c-acb0-c097cf551c2e",
|
||||
"type": "aruco",
|
||||
"marker_id": 100,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1558,7 +1558,7 @@
|
||||
"confidence": 0.24407473894265982
|
||||
},
|
||||
{
|
||||
"observation_id": "7fcc6be4-ba8c-47db-822d-7b1166e7687f",
|
||||
"observation_id": "0da68db6-9b7f-4e47-a7af-b7461d42e46e",
|
||||
"type": "aruco",
|
||||
"marker_id": 75,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1612,7 +1612,7 @@
|
||||
"confidence": 0.23896265492072474
|
||||
},
|
||||
{
|
||||
"observation_id": "8203bb0e-9610-4fcb-a657-07da2e5efa4f",
|
||||
"observation_id": "6fc4aefe-44f9-42fc-98ee-6df03dd1ef33",
|
||||
"type": "aruco",
|
||||
"marker_id": 68,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1666,7 +1666,7 @@
|
||||
"confidence": 0.24909137483284013
|
||||
},
|
||||
{
|
||||
"observation_id": "997abfa1-eb73-4059-a522-4c3a809e30b4",
|
||||
"observation_id": "36e190fb-2d99-47da-860f-d5ce99949c0d",
|
||||
"type": "aruco",
|
||||
"marker_id": 46,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1720,7 +1720,7 @@
|
||||
"confidence": 0.23734254719660833
|
||||
},
|
||||
{
|
||||
"observation_id": "dffbadef-3d8a-40a4-b2af-0b4c6716fe72",
|
||||
"observation_id": "f8a88985-c2f6-4ac0-ac79-411eaa37e209",
|
||||
"type": "aruco",
|
||||
"marker_id": 50,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1774,7 +1774,7 @@
|
||||
"confidence": 0.21965114789131363
|
||||
},
|
||||
{
|
||||
"observation_id": "8798463c-9700-4b8f-a92f-c95a20f50fa9",
|
||||
"observation_id": "93718e9d-dceb-4150-b430-e28908c36f62",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1828,7 +1828,7 @@
|
||||
"confidence": 0.21841319450965294
|
||||
},
|
||||
{
|
||||
"observation_id": "f5547d61-969f-43cd-b1ab-2c675642f73c",
|
||||
"observation_id": "3f2a6ca5-6962-4c24-8263-4ff387aaef7e",
|
||||
"type": "aruco",
|
||||
"marker_id": 104,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1882,7 +1882,7 @@
|
||||
"confidence": 0.22417849731445313
|
||||
},
|
||||
{
|
||||
"observation_id": "9e1204a9-d33a-41b6-84e1-c937808249ac",
|
||||
"observation_id": "ed250cb9-65b1-4e09-83da-d928a3ad844c",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1936,7 +1936,7 @@
|
||||
"confidence": 0.22367025973033955
|
||||
},
|
||||
{
|
||||
"observation_id": "2f9601fd-2ea6-4b1e-9012-9c3b1cdbb7e8",
|
||||
"observation_id": "258286b4-d8c6-4521-8c38-f70a7c3512e6",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1990,7 +1990,7 @@
|
||||
"confidence": 0.21633306884765624
|
||||
},
|
||||
{
|
||||
"observation_id": "224abf5b-2d4d-46ee-80a1-2865fd7cdcb2",
|
||||
"observation_id": "c83c00ca-cd46-4ab1-adab-48d1ff64f056",
|
||||
"type": "aruco",
|
||||
"marker_id": 60,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2044,7 +2044,7 @@
|
||||
"confidence": 0.2000031054889577
|
||||
},
|
||||
{
|
||||
"observation_id": "6207cccf-06ae-4761-bd81-361e3c22f8bf",
|
||||
"observation_id": "c0b59de2-361d-40b9-ae38-81b9490eef13",
|
||||
"type": "aruco",
|
||||
"marker_id": 67,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2098,7 +2098,7 @@
|
||||
"confidence": 0.19627771759033205
|
||||
},
|
||||
{
|
||||
"observation_id": "e8cf49ff-9083-465e-a4f7-b755ba2fcad9",
|
||||
"observation_id": "c6edf188-51a4-40a1-9692-1c21b237a7d4",
|
||||
"type": "aruco",
|
||||
"marker_id": 86,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2152,7 +2152,7 @@
|
||||
"confidence": 0.18966921411877496
|
||||
},
|
||||
{
|
||||
"observation_id": "885fc5c0-30dd-4c72-b8b8-f7fd8cf97d19",
|
||||
"observation_id": "ae07c431-9c4a-4b0c-b746-770b7c893d7c",
|
||||
"type": "aruco",
|
||||
"marker_id": 70,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2206,7 +2206,7 @@
|
||||
"confidence": 0.193995418548584
|
||||
},
|
||||
{
|
||||
"observation_id": "905aec40-0624-4f4b-8ff5-4b21f3ef65fa",
|
||||
"observation_id": "0f240018-89fa-4c58-ac24-a3999faaa2b1",
|
||||
"type": "aruco",
|
||||
"marker_id": 88,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2260,7 +2260,7 @@
|
||||
"confidence": 0.2032033303021305
|
||||
},
|
||||
{
|
||||
"observation_id": "670f78f0-1bf6-4695-b0e2-adcfb9605369",
|
||||
"observation_id": "8a45fbfc-cbcd-4cc7-a799-16eadbf18e4c",
|
||||
"type": "aruco",
|
||||
"marker_id": 73,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2314,7 +2314,7 @@
|
||||
"confidence": 0.1929997138977051
|
||||
},
|
||||
{
|
||||
"observation_id": "89894577-9d7a-4e8a-aa6c-eab38b66716c",
|
||||
"observation_id": "0c73cf5a-0427-49a3-8333-f2ffe2722ffc",
|
||||
"type": "aruco",
|
||||
"marker_id": 82,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2368,7 +2368,7 @@
|
||||
"confidence": 0.19249963767972095
|
||||
},
|
||||
{
|
||||
"observation_id": "ebee6900-dc82-44da-a887-7656afde3cdb",
|
||||
"observation_id": "15d9c41d-7b71-49c6-882c-567ee764196d",
|
||||
"type": "aruco",
|
||||
"marker_id": 98,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2422,7 +2422,7 @@
|
||||
"confidence": 0.1899538473288218
|
||||
},
|
||||
{
|
||||
"observation_id": "2aef8bd4-d3eb-4131-a6c0-ba06153ad499",
|
||||
"observation_id": "4a1a16f8-c933-439b-a545-5e4fda212642",
|
||||
"type": "aruco",
|
||||
"marker_id": 83,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2476,7 +2476,7 @@
|
||||
"confidence": 0.17676838843571283
|
||||
},
|
||||
{
|
||||
"observation_id": "9568032e-d400-4bfb-8776-acd22ca10e90",
|
||||
"observation_id": "ad9bf2c3-1405-446c-b51b-44250af0e010",
|
||||
"type": "aruco",
|
||||
"marker_id": 61,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2530,7 +2530,7 @@
|
||||
"confidence": 0.1668050360320266
|
||||
},
|
||||
{
|
||||
"observation_id": "0ffbe58e-4317-4b1f-847d-454ee59bc667",
|
||||
"observation_id": "7d2c13fe-06e1-46c6-a1e3-2a29d69ebe56",
|
||||
"type": "aruco",
|
||||
"marker_id": 90,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2584,7 +2584,7 @@
|
||||
"confidence": 0.17612778902053833
|
||||
},
|
||||
{
|
||||
"observation_id": "2dc36177-77bc-4b16-98f1-2ebae1bb9806",
|
||||
"observation_id": "3a1a4106-e7c3-4d72-819d-ef25b9962862",
|
||||
"type": "aruco",
|
||||
"marker_id": 91,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:10Z",
|
||||
"created_utc": "2026-06-01T12:39:05Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene4\\render_b_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:07Z",
|
||||
"created_utc": "2026-06-01T12:39:01Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "28b40528-3f47-4b34-bed6-9cbffc75f09d",
|
||||
"observation_id": "73fa7cb9-bdee-43b8-b4a6-42c3668baac3",
|
||||
"type": "aruco",
|
||||
"marker_id": 42,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.8343550641259049
|
||||
},
|
||||
{
|
||||
"observation_id": "bd049558-ecd2-4a34-ade7-1be26c010823",
|
||||
"observation_id": "07686c0e-10b6-48e2-b13c-3e8436bb834e",
|
||||
"type": "aruco",
|
||||
"marker_id": 41,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.7789736723135801
|
||||
},
|
||||
{
|
||||
"observation_id": "481a9285-9060-409b-9e13-f225f1befe11",
|
||||
"observation_id": "2f94b38d-59d8-46b0-941d-d6b12fd04ad5",
|
||||
"type": "aruco",
|
||||
"marker_id": 44,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.734766387939453
|
||||
},
|
||||
{
|
||||
"observation_id": "c1291740-3e8a-43ef-8f5f-d12025f3219e",
|
||||
"observation_id": "b42b25e1-b9fc-4036-a705-301174699a63",
|
||||
"type": "aruco",
|
||||
"marker_id": 219,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.6138985440690424
|
||||
},
|
||||
{
|
||||
"observation_id": "d082660a-f4f3-44c8-a6a6-62f07f35087b",
|
||||
"observation_id": "da7c2892-65e9-4f39-aa60-9fdbb956043c",
|
||||
"type": "aruco",
|
||||
"marker_id": 114,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.5645808242627047
|
||||
},
|
||||
{
|
||||
"observation_id": "7f1b7764-c669-4fd4-bf3e-9727533f6499",
|
||||
"observation_id": "0dd0dbf0-5b65-4efc-b39f-bfe5ac96f6b1",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.755998822943334
|
||||
},
|
||||
{
|
||||
"observation_id": "fb63a2c0-f203-4787-a7c6-49bae65ef133",
|
||||
"observation_id": "e04b2446-097f-4c47-8f9d-761cc5045a0a",
|
||||
"type": "aruco",
|
||||
"marker_id": 120,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.5284366390074502
|
||||
},
|
||||
{
|
||||
"observation_id": "91412bdc-d88b-470a-a8bc-d33ce48c8598",
|
||||
"observation_id": "beb1d9df-07d5-48e1-a827-4ad0821f0408",
|
||||
"type": "aruco",
|
||||
"marker_id": 218,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.5315859761486594
|
||||
},
|
||||
{
|
||||
"observation_id": "021daa16-c95f-49cc-a61d-f8d093fae96d",
|
||||
"observation_id": "b108c1c1-00f6-4ec2-baa8-2dd4153a66f8",
|
||||
"type": "aruco",
|
||||
"marker_id": 242,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.6006520365292345
|
||||
},
|
||||
{
|
||||
"observation_id": "55ba6a69-7bb2-4231-9b5e-170fda6b841c",
|
||||
"observation_id": "0429dbf4-5f3e-472e-bbb7-88b99d9a4f5a",
|
||||
"type": "aruco",
|
||||
"marker_id": 246,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.3823850960994706
|
||||
},
|
||||
{
|
||||
"observation_id": "82fbe71a-39ad-42da-8187-b3c3e012ec68",
|
||||
"observation_id": "cae8b3a0-fe38-4cdd-b851-fd8d8c04690a",
|
||||
"type": "aruco",
|
||||
"marker_id": 247,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.3808358629990202
|
||||
},
|
||||
{
|
||||
"observation_id": "a7b5c93a-3346-49cb-8745-29550d51c781",
|
||||
"observation_id": "4d8b3a92-6626-43d5-b890-bc1c7951967c",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.2964796698261984
|
||||
},
|
||||
{
|
||||
"observation_id": "5c788bd2-e930-4250-ab34-432ff4be26b5",
|
||||
"observation_id": "1fc7ad0f-8cbe-46a5-8901-0bb7b6f878ea",
|
||||
"type": "aruco",
|
||||
"marker_id": 215,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.2743742952602821
|
||||
},
|
||||
{
|
||||
"observation_id": "8ca922db-623b-4acf-8457-1c29629bd2c3",
|
||||
"observation_id": "661a0f09-0909-422d-8bcb-1e541200079c",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.233781757000696
|
||||
},
|
||||
{
|
||||
"observation_id": "bfe2089b-34da-4273-bc5e-530c81aa42db",
|
||||
"observation_id": "93193d2e-cde2-4535-bd07-ad42886e7faa",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:10Z",
|
||||
"created_utc": "2026-06-01T12:39:05Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene4\\render_c_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:07Z",
|
||||
"created_utc": "2026-06-01T12:39:01Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "c7800982-7597-49f0-a539-664a5a7b9f0f",
|
||||
"observation_id": "63516b30-cccd-44c6-abd6-59bb22705260",
|
||||
"type": "aruco",
|
||||
"marker_id": 44,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.9829005790795233
|
||||
},
|
||||
{
|
||||
"observation_id": "2e5134ba-500f-494c-8250-ec316939eed2",
|
||||
"observation_id": "3d9d6277-c9cc-4a6c-a27d-a1f04ccc36a3",
|
||||
"type": "aruco",
|
||||
"marker_id": 114,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.7952853072848569
|
||||
},
|
||||
{
|
||||
"observation_id": "c78334cf-0a73-4de6-a876-1b9ac6558381",
|
||||
"observation_id": "ee9204a8-f2b6-483f-bfcc-9d13a44b52ae",
|
||||
"type": "aruco",
|
||||
"marker_id": 120,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.7534617346649917
|
||||
},
|
||||
{
|
||||
"observation_id": "693762cb-1dcf-4784-97f8-1831334569ed",
|
||||
"observation_id": "d05e5d3e-e5f3-47dd-8258-36d34b57f2ee",
|
||||
"type": "aruco",
|
||||
"marker_id": 115,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.7282777200221999
|
||||
},
|
||||
{
|
||||
"observation_id": "177177d6-6f49-46ac-a9df-40327a4e0e53",
|
||||
"observation_id": "3ae5fc25-b290-4b69-8c8d-4953ad32f9bd",
|
||||
"type": "aruco",
|
||||
"marker_id": 95,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.5518116657099041
|
||||
},
|
||||
{
|
||||
"observation_id": "30cb20f9-6091-43ab-b7e4-3a700987491e",
|
||||
"observation_id": "7c734697-b05f-46cd-aed7-30ddf2f89e4a",
|
||||
"type": "aruco",
|
||||
"marker_id": 79,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.589171450268867
|
||||
},
|
||||
{
|
||||
"observation_id": "08d4c176-3b7d-4366-a0c6-782ee6acd47d",
|
||||
"observation_id": "d8980bf9-3418-4c1a-8048-a2f4b4cdc2c3",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.4569666605043164
|
||||
},
|
||||
{
|
||||
"observation_id": "4021c02f-cfa4-4e8f-9592-a4c05f5f799f",
|
||||
"observation_id": "1745de3b-38e9-430c-bdd2-02b005fe8a1b",
|
||||
"type": "aruco",
|
||||
"marker_id": 69,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.5412868278516675
|
||||
},
|
||||
{
|
||||
"observation_id": "6b51617e-c611-413c-b849-7d7fbf2c8aea",
|
||||
"observation_id": "2f7b97cc-3904-4095-a15d-18b1af3dd5ed",
|
||||
"type": "aruco",
|
||||
"marker_id": 51,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.5367694875460974
|
||||
},
|
||||
{
|
||||
"observation_id": "cd3418b9-2ab6-4687-865f-7ec70111db52",
|
||||
"observation_id": "325c319b-9ee4-4f82-a519-1343766270ab",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.5683985238307451
|
||||
},
|
||||
{
|
||||
"observation_id": "e1a9f903-9fb4-4495-9aca-9dc90140f462",
|
||||
"observation_id": "954ed70d-b44e-4753-9755-2f9829ddc455",
|
||||
"type": "aruco",
|
||||
"marker_id": 58,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.5703994452422884
|
||||
},
|
||||
{
|
||||
"observation_id": "dbf23df8-d025-4344-adc6-afefebfa866a",
|
||||
"observation_id": "5a476087-84f0-45e8-8c4e-e90412197f0b",
|
||||
"type": "aruco",
|
||||
"marker_id": 215,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.408432388349621
|
||||
},
|
||||
{
|
||||
"observation_id": "3b17118d-d631-49e9-91e5-4394e2ce4586",
|
||||
"observation_id": "b3ec733c-6965-481f-9174-3e1c09ad8d60",
|
||||
"type": "aruco",
|
||||
"marker_id": 214,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.32753550791646946
|
||||
},
|
||||
{
|
||||
"observation_id": "9af71b24-2089-4df1-bfad-0d556b02cd27",
|
||||
"observation_id": "2d3bcba2-4b4d-4b0b-b67d-8263e6ceffda",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.4466430195499723
|
||||
},
|
||||
{
|
||||
"observation_id": "795aa7d5-5dca-4baf-9200-069c52e314ca",
|
||||
"observation_id": "281f43dc-bf2f-4c59-aac0-db3d30869c1b",
|
||||
"type": "aruco",
|
||||
"marker_id": 211,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.29690586628373444
|
||||
},
|
||||
{
|
||||
"observation_id": "960cb8db-1da7-4fee-91ee-3e49f768a39a",
|
||||
"observation_id": "f103c2f7-62db-4b37-827c-4196dc382473",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.03479010216782576
|
||||
},
|
||||
{
|
||||
"observation_id": "6dfc58e6-a930-48a0-9738-e3bdc8a8e44b",
|
||||
"observation_id": "e24431ac-4ca2-465f-90bb-7ace791ee924",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.09228958358804855
|
||||
},
|
||||
{
|
||||
"observation_id": "7e29173d-d504-457e-a775-9cef4f094361",
|
||||
"observation_id": "00f84bce-5b4a-4d7e-8ac6-dc5e44261677",
|
||||
"type": "aruco",
|
||||
"marker_id": 86,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.12403848180952393
|
||||
},
|
||||
{
|
||||
"observation_id": "31f1d5f6-96b5-4610-aac5-9656d693736f",
|
||||
"observation_id": "b5f4ad5f-0737-405a-b5aa-075fc57e2e13",
|
||||
"type": "aruco",
|
||||
"marker_id": 73,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:10Z",
|
||||
"created_utc": "2026-06-01T12:39:06Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene4\\render_d_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:08Z",
|
||||
"created_utc": "2026-06-01T12:39:02Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "e1959889-bda0-4a15-889c-dcb237998151",
|
||||
"observation_id": "b01e9f3c-6fe9-4872-922e-411e5dbfc2ea",
|
||||
"type": "aruco",
|
||||
"marker_id": 44,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.9774738327603469
|
||||
},
|
||||
{
|
||||
"observation_id": "3e54f3ff-6015-4c97-ace8-76df1f832966",
|
||||
"observation_id": "62c8d5ce-5709-4fa6-96c1-1e5f97323074",
|
||||
"type": "aruco",
|
||||
"marker_id": 92,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.15369374989294518
|
||||
},
|
||||
{
|
||||
"observation_id": "dc12e7da-78a8-4898-ad88-3e9ec94c08cd",
|
||||
"observation_id": "031bff8c-d03f-42bb-bbb2-25eeddc2f1e6",
|
||||
"type": "aruco",
|
||||
"marker_id": 217,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.3233651345714012
|
||||
},
|
||||
{
|
||||
"observation_id": "2aa4875f-083f-4a99-8c01-d6b220b69ac3",
|
||||
"observation_id": "b884a4eb-e0bc-4c72-ac91-f1ac392b6b68",
|
||||
"type": "aruco",
|
||||
"marker_id": 85,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.3248781943257027
|
||||
},
|
||||
{
|
||||
"observation_id": "7a8cb838-ba44-48de-a105-4bf5918a6873",
|
||||
"observation_id": "6b35c8a3-9e92-4558-96c3-6d43cfb412b2",
|
||||
"type": "aruco",
|
||||
"marker_id": 115,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.5419921532895585
|
||||
},
|
||||
{
|
||||
"observation_id": "e6a2a887-92c1-42f6-824f-b37a2e9e7bb7",
|
||||
"observation_id": "eaeaa1dc-4aeb-4d1f-a334-8ab8f9fa1968",
|
||||
"type": "aruco",
|
||||
"marker_id": 105,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.42546318190651866
|
||||
},
|
||||
{
|
||||
"observation_id": "70957fc9-2b92-4587-b8cb-96d9159b4171",
|
||||
"observation_id": "005f787d-a9bb-4150-812b-1286c4783e78",
|
||||
"type": "aruco",
|
||||
"marker_id": 244,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.4483121499334993
|
||||
},
|
||||
{
|
||||
"observation_id": "ae62e780-0a88-4645-9cc6-c9207f8c5a99",
|
||||
"observation_id": "285fc325-51a8-4935-b80b-950d2cca3fdf",
|
||||
"type": "aruco",
|
||||
"marker_id": 206,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.15136171428561934
|
||||
},
|
||||
{
|
||||
"observation_id": "810be360-dc4c-4095-8831-c140c5b60957",
|
||||
"observation_id": "c704aef8-def1-4f67-ae3a-bd8e263acc3e",
|
||||
"type": "aruco",
|
||||
"marker_id": 114,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.430473829601915
|
||||
},
|
||||
{
|
||||
"observation_id": "36adc3e6-d127-456d-aff9-785a052bac4f",
|
||||
"observation_id": "328aa30c-3189-45d0-83db-dba19cd586e3",
|
||||
"type": "aruco",
|
||||
"marker_id": 120,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.40218814597808433
|
||||
},
|
||||
{
|
||||
"observation_id": "d4b087ec-b495-4b5f-998b-74f31f8d5dcb",
|
||||
"observation_id": "8321281a-9485-4454-995d-ab8c0dd7f04c",
|
||||
"type": "aruco",
|
||||
"marker_id": 97,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.22596816505744277
|
||||
},
|
||||
{
|
||||
"observation_id": "a7d2f473-331a-43c3-a140-4aa5a0c2b219",
|
||||
"observation_id": "4d748d62-69cf-4bed-a3d1-019372c684ec",
|
||||
"type": "aruco",
|
||||
"marker_id": 47,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.24626971873720385
|
||||
},
|
||||
{
|
||||
"observation_id": "be5118c7-495e-41d0-881a-02b544045b0f",
|
||||
"observation_id": "4a3ea52f-7bca-46f9-9a64-5df042c17e37",
|
||||
"type": "aruco",
|
||||
"marker_id": 96,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.28140192555287236
|
||||
},
|
||||
{
|
||||
"observation_id": "ec8c2388-adac-4e80-a55b-0cc149da6a78",
|
||||
"observation_id": "393e6269-6563-4d96-8f3e-7dfc0ff6bc65",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.20905304008181452
|
||||
},
|
||||
{
|
||||
"observation_id": "f37486dc-e295-43f5-823c-c453e3e90e4a",
|
||||
"observation_id": "7c21d48f-394d-4c3c-b4cd-46f62b6302f4",
|
||||
"type": "aruco",
|
||||
"marker_id": 62,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.2664122029520185
|
||||
},
|
||||
{
|
||||
"observation_id": "fc85af2e-53ff-4320-9de5-f6e2077e6954",
|
||||
"observation_id": "fb07d6c6-544c-4401-8bcc-427f00077448",
|
||||
"type": "aruco",
|
||||
"marker_id": 66,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.16725963004706537
|
||||
},
|
||||
{
|
||||
"observation_id": "2c3d8edb-15fb-424f-a4a7-c05e75337a26",
|
||||
"observation_id": "66eca3bb-779f-4760-91c2-d219117a278a",
|
||||
"type": "aruco",
|
||||
"marker_id": 55,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.22298824455832925
|
||||
},
|
||||
{
|
||||
"observation_id": "7f41ae4a-a449-4226-92b7-445670832ebe",
|
||||
"observation_id": "d16e224f-71cc-4782-a795-f3a420153807",
|
||||
"type": "aruco",
|
||||
"marker_id": 40,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.06522200557737874
|
||||
},
|
||||
{
|
||||
"observation_id": "9d0fe286-bd31-4572-80d6-b09a8a074018",
|
||||
"observation_id": "35df855b-d3a9-4f3a-8d55-286e8a6ab0ea",
|
||||
"type": "aruco",
|
||||
"marker_id": 79,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.19757108839994864
|
||||
},
|
||||
{
|
||||
"observation_id": "ef206c3f-3edb-408b-9d6c-c4e6c2f24213",
|
||||
"observation_id": "dec2d1bb-fa98-4171-8357-ccc3feef9636",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.15675000342230294
|
||||
},
|
||||
{
|
||||
"observation_id": "1e64dc44-786e-4705-b77b-5b962cce7411",
|
||||
"observation_id": "870af66b-fc7b-4a84-aa78-32989d29ac46",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.13595850692924102
|
||||
},
|
||||
{
|
||||
"observation_id": "bf4376b5-55ad-4fa9-baac-43b0a7205448",
|
||||
"observation_id": "ff2537d0-4d0b-4c6a-a390-1eb9c229f1d5",
|
||||
"type": "aruco",
|
||||
"marker_id": 51,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.12157403976480062
|
||||
},
|
||||
{
|
||||
"observation_id": "030ffa08-f2ba-499d-b757-331688a40990",
|
||||
"observation_id": "79c806e2-3282-4aeb-8fa1-20334f36500a",
|
||||
"type": "aruco",
|
||||
"marker_id": 95,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.14922985097126407
|
||||
},
|
||||
{
|
||||
"observation_id": "86ee27a0-bc7a-4601-a165-61a43687dc70",
|
||||
"observation_id": "cbc8985f-eaa9-49f3-937c-715752fdc92d",
|
||||
"type": "aruco",
|
||||
"marker_id": 247,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.1099085657112018
|
||||
},
|
||||
{
|
||||
"observation_id": "2d16ba79-b6df-43bd-8b90-c520fa0773a0",
|
||||
"observation_id": "74ad1afe-9dc2-4899-99fc-625938bb0589",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.13220570535010506
|
||||
},
|
||||
{
|
||||
"observation_id": "58e3279c-d241-4d55-ad32-dab6234d8d84",
|
||||
"observation_id": "5bce3260-0e1c-449a-ad22-6239210e8a03",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.11373255626245794
|
||||
},
|
||||
{
|
||||
"observation_id": "3b94ef95-ff5d-41f8-b56e-83f7830db2ca",
|
||||
"observation_id": "4e21f98e-21e8-40c4-8f25-88096cfe6d12",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.13255097071329755
|
||||
},
|
||||
{
|
||||
"observation_id": "f194a7cb-b7f6-464d-aad2-c3cde87ab14f",
|
||||
"observation_id": "442b9349-5ce5-43c9-afd2-ede9817319ae",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1558,7 +1558,7 @@
|
||||
"confidence": 0.09620577544552089
|
||||
},
|
||||
{
|
||||
"observation_id": "68a654aa-ba54-4ee9-a5f7-1b496106bc28",
|
||||
"observation_id": "523bf3cb-bcc3-4893-b8fa-a0c56cf253d5",
|
||||
"type": "aruco",
|
||||
"marker_id": 86,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1612,7 +1612,7 @@
|
||||
"confidence": 0.11774828338549573
|
||||
},
|
||||
{
|
||||
"observation_id": "c16cfc52-0ccf-41f6-bbac-cd224e4151ca",
|
||||
"observation_id": "4a85a399-7713-48ef-b57d-2abfdcc20d6a",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:10Z",
|
||||
"created_utc": "2026-06-01T12:39:06Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene4\\render_e_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:08Z",
|
||||
"created_utc": "2026-06-01T12:39:03Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "9fb92c22-8274-4e34-89d0-6cc9b25a21cf",
|
||||
"observation_id": "60874d01-7e6e-4012-988a-2acb09e07544",
|
||||
"type": "aruco",
|
||||
"marker_id": 246,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.8595541333255614
|
||||
},
|
||||
{
|
||||
"observation_id": "40e5dd35-505f-413e-a0c4-76f33dac19a4",
|
||||
"observation_id": "8f52fc86-80b5-480e-8c10-c1c359ec3afd",
|
||||
"type": "aruco",
|
||||
"marker_id": 247,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.8446693980390577
|
||||
},
|
||||
{
|
||||
"observation_id": "ede8e441-7f04-478c-b47a-5a98e0336dfe",
|
||||
"observation_id": "520dc828-34f8-438b-baa9-ee1e7c8c644a",
|
||||
"type": "aruco",
|
||||
"marker_id": 120,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.8383841261229988
|
||||
},
|
||||
{
|
||||
"observation_id": "5564bf05-32cc-4b27-96f4-b450d7646ccb",
|
||||
"observation_id": "e53b0a7e-c971-43ea-8ef6-7096bf65fd66",
|
||||
"type": "aruco",
|
||||
"marker_id": 114,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.7722445599677091
|
||||
},
|
||||
{
|
||||
"observation_id": "dd04b27d-fefc-4a86-a792-1c74b98ceed5",
|
||||
"observation_id": "9303ebdb-e184-49a8-b1b0-20f391738f7b",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.6913219978931935
|
||||
},
|
||||
{
|
||||
"observation_id": "280457bc-1662-4659-af7d-3736ca0fa43d",
|
||||
"observation_id": "22f46d6c-c463-4ecd-beb1-753b2788497a",
|
||||
"type": "aruco",
|
||||
"marker_id": 40,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.46826993269571887
|
||||
},
|
||||
{
|
||||
"observation_id": "11eabbd5-188e-459e-b227-43c2bb616731",
|
||||
"observation_id": "f57758b3-3fc0-445d-a82b-7741ec41b3f8",
|
||||
"type": "aruco",
|
||||
"marker_id": 218,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.45659746024893416
|
||||
},
|
||||
{
|
||||
"observation_id": "8116fb34-059b-4e13-88c1-cc998bbca2c7",
|
||||
"observation_id": "ebb96164-fd9f-4c0a-a359-c902f15d6f1e",
|
||||
"type": "aruco",
|
||||
"marker_id": 46,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.2988751797371847
|
||||
},
|
||||
{
|
||||
"observation_id": "81c7a325-dfde-4532-87e0-d903afbd975c",
|
||||
"observation_id": "ed06eb95-7cc7-4d7a-bb72-915ce6ca2e37",
|
||||
"type": "aruco",
|
||||
"marker_id": 219,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.4719563350095902
|
||||
},
|
||||
{
|
||||
"observation_id": "13f934d5-4384-42db-90d0-07bfdd026205",
|
||||
"observation_id": "731f40e5-7885-4569-b4a2-b98ee523c500",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.5954364184044425
|
||||
},
|
||||
{
|
||||
"observation_id": "2738e43b-1bc7-423b-a63b-dd01c1fda2e0",
|
||||
"observation_id": "453a8d5d-45f6-4412-b1b5-b517bebfa3b0",
|
||||
"type": "aruco",
|
||||
"marker_id": 56,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.5697620483284124
|
||||
},
|
||||
{
|
||||
"observation_id": "8c22fb4b-c2b3-450a-9d07-4f887eb80578",
|
||||
"observation_id": "cc84d225-14b4-4f99-8045-7b89d3d7f1b1",
|
||||
"type": "aruco",
|
||||
"marker_id": 62,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.5711737708098855
|
||||
},
|
||||
{
|
||||
"observation_id": "87718790-ff49-452d-90f8-695a69a78c9d",
|
||||
"observation_id": "e942d364-5d3c-4760-a28d-41aa399254bc",
|
||||
"type": "aruco",
|
||||
"marker_id": 47,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.5768583617164568
|
||||
},
|
||||
{
|
||||
"observation_id": "b6929125-2ff5-4c97-9c46-04137d0a0853",
|
||||
"observation_id": "3eee5192-167b-4525-b40c-a2f6dd6ad3ef",
|
||||
"type": "aruco",
|
||||
"marker_id": 96,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.570786168435231
|
||||
},
|
||||
{
|
||||
"observation_id": "1adc35ff-a482-4884-b26d-8697d5fab01b",
|
||||
"observation_id": "d203b336-0c7d-4011-90a9-818d7866d702",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.21364841201201337
|
||||
},
|
||||
{
|
||||
"observation_id": "efc60dbd-a3ca-4c35-ab3c-a53b9df9fbd5",
|
||||
"observation_id": "d78ae257-fb84-484b-bdaa-997c44f07527",
|
||||
"type": "aruco",
|
||||
"marker_id": 97,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.5705029634947052
|
||||
},
|
||||
{
|
||||
"observation_id": "8631c7f3-70cb-4c3f-bb78-db524b3c102a",
|
||||
"observation_id": "16ef8e1b-6b30-4c13-92a4-3c0e3a29ad92",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.5440516905787338
|
||||
},
|
||||
{
|
||||
"observation_id": "7829d9fc-9b12-4272-8906-2d7a742c1516",
|
||||
"observation_id": "a58db514-b080-43b6-afc7-5898b068cff4",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.06519221426443914
|
||||
},
|
||||
{
|
||||
"observation_id": "17370d70-c669-47a8-ae50-8c63225e88f7",
|
||||
"observation_id": "f6c8b510-33d0-4965-9dd0-333e98307c9e",
|
||||
"type": "aruco",
|
||||
"marker_id": 79,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.5460974493377216
|
||||
},
|
||||
{
|
||||
"observation_id": "4e29c39d-d70d-47f8-9b21-969f38ad9e6f",
|
||||
"observation_id": "f6752d16-36e5-4fed-9257-8a6a0d51898d",
|
||||
"type": "aruco",
|
||||
"marker_id": 51,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.4817209906880129
|
||||
},
|
||||
{
|
||||
"observation_id": "abe73a5b-a80f-49e0-9640-f23b5c98d52f",
|
||||
"observation_id": "f91b5f95-42de-4d09-a504-c4b12cbbc0f2",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.5046333482067283
|
||||
},
|
||||
{
|
||||
"observation_id": "bff5c572-91a0-4451-9b12-55d41d03dfe8",
|
||||
"observation_id": "48f9368d-3778-40ab-bec8-b520d6f4af84",
|
||||
"type": "aruco",
|
||||
"marker_id": 44,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.31387842129667237
|
||||
},
|
||||
{
|
||||
"observation_id": "293eeee8-c372-42c5-aed4-9a2d95724362",
|
||||
"observation_id": "2570865f-4d33-40cd-b11f-2e59c7c17e0c",
|
||||
"type": "aruco",
|
||||
"marker_id": 73,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.13607001327160623
|
||||
},
|
||||
{
|
||||
"observation_id": "e7f3630f-1503-4b1d-b065-f32d4efe6048",
|
||||
"observation_id": "293db9bc-f56c-4416-ad28-dd57170ffe4f",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.46988879526830113
|
||||
},
|
||||
{
|
||||
"observation_id": "3b2d82c4-0038-4bc5-b496-cf1d3d2933a1",
|
||||
"observation_id": "5dcf2be5-6ebe-4a4d-b616-7b9125a4ea38",
|
||||
"type": "aruco",
|
||||
"marker_id": 58,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.4655541127751829
|
||||
},
|
||||
{
|
||||
"observation_id": "94a8ab5c-920b-483f-b557-9e798350b435",
|
||||
"observation_id": "03376f13-2be5-45fd-8c3d-e665f26ab164",
|
||||
"type": "aruco",
|
||||
"marker_id": 69,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.4655541127751829
|
||||
},
|
||||
{
|
||||
"observation_id": "af1459fc-5bee-451a-bb1a-a6850d9369fe",
|
||||
"observation_id": "7f99cfd3-01ee-492e-99fc-18b28e43dda7",
|
||||
"type": "aruco",
|
||||
"marker_id": 82,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.49001748422717006
|
||||
},
|
||||
{
|
||||
"observation_id": "94734722-fda2-4f02-9f67-ab68b5b0841e",
|
||||
"observation_id": "0b350cc2-cfab-4330-9fe6-600222d4eb2d",
|
||||
"type": "aruco",
|
||||
"marker_id": 101,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1558,7 +1558,7 @@
|
||||
"confidence": 0.46225891142368675
|
||||
},
|
||||
{
|
||||
"observation_id": "0edd8b80-f56d-4d9d-9fd4-d799eb0c919c",
|
||||
"observation_id": "827bb163-83c3-4647-a06a-7436299a3c0a",
|
||||
"type": "aruco",
|
||||
"marker_id": 52,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1612,7 +1612,7 @@
|
||||
"confidence": 0.46225891142368675
|
||||
},
|
||||
{
|
||||
"observation_id": "032ff99b-d91d-4016-a0cd-75ae11b1c198",
|
||||
"observation_id": "60bc5613-6517-443e-8374-21e315c3a9a9",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1666,7 +1666,7 @@
|
||||
"confidence": 0.43211414091114625
|
||||
},
|
||||
{
|
||||
"observation_id": "7895db9d-08fa-47fc-ad50-e23ee7f32328",
|
||||
"observation_id": "ac9cc54f-a69a-419c-ba58-dcc5a468a51b",
|
||||
"type": "aruco",
|
||||
"marker_id": 83,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1720,7 +1720,7 @@
|
||||
"confidence": 0.4377857805109236
|
||||
},
|
||||
{
|
||||
"observation_id": "ceb9c06b-47cf-40d0-b2cf-adee1e079dad",
|
||||
"observation_id": "9e501bf5-642c-4d94-8bb9-e50d532454b1",
|
||||
"type": "aruco",
|
||||
"marker_id": 75,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:11Z",
|
||||
"created_utc": "2026-06-01T12:39:07Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene4\\render_f_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:09Z",
|
||||
"created_utc": "2026-06-01T12:39:04Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "6f9e7654-a6e3-4795-99f3-d1098a899578",
|
||||
"observation_id": "0e43ec43-5f58-4467-a134-2c4ba16ca653",
|
||||
"type": "aruco",
|
||||
"marker_id": 229,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.5315105976452267
|
||||
},
|
||||
{
|
||||
"observation_id": "a4292486-d21a-4af7-819c-1ed79e415381",
|
||||
"observation_id": "04fbd6f4-74f2-4810-99e7-75394f053767",
|
||||
"type": "aruco",
|
||||
"marker_id": 247,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.5729494608527742
|
||||
},
|
||||
{
|
||||
"observation_id": "03baadaa-520c-4abb-b8a7-4fada5328682",
|
||||
"observation_id": "4586324d-8be9-4c43-9c0e-e6e80fab8ef3",
|
||||
"type": "aruco",
|
||||
"marker_id": 246,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.5765483710806963
|
||||
},
|
||||
{
|
||||
"observation_id": "25476efb-763e-460a-91d9-56bafa8fc456",
|
||||
"observation_id": "e6100dc3-7135-48c3-ac69-afef90e0a044",
|
||||
"type": "aruco",
|
||||
"marker_id": 218,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.4621566714491005
|
||||
},
|
||||
{
|
||||
"observation_id": "b6d0798e-baf1-4f7f-af0e-acddb709b755",
|
||||
"observation_id": "48895ec9-6841-452c-8067-fd676012f395",
|
||||
"type": "aruco",
|
||||
"marker_id": 198,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.43078987568380794
|
||||
},
|
||||
{
|
||||
"observation_id": "5e5f3558-11ec-4a2c-8be6-c59adbdf28d1",
|
||||
"observation_id": "d774cc26-6a40-47f7-9c8d-12e34c816f4c",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.3490767193505014
|
||||
},
|
||||
{
|
||||
"observation_id": "4012cbf6-af42-4029-911e-720d9601dc1e",
|
||||
"observation_id": "c1e0bbff-0ddb-4e44-886b-50ea7041da5a",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.5331747682067169
|
||||
},
|
||||
{
|
||||
"observation_id": "25901d5b-2a1c-4531-8299-5dc07448851d",
|
||||
"observation_id": "db072350-65d7-43b0-949f-3f2b232dec46",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.43254677700170213
|
||||
},
|
||||
{
|
||||
"observation_id": "5cfa5600-5262-4a7d-a69d-03db75b552fc",
|
||||
"observation_id": "28574883-4c42-4354-8362-46bdc7523a4a",
|
||||
"type": "aruco",
|
||||
"marker_id": 219,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.4062135721795724
|
||||
},
|
||||
{
|
||||
"observation_id": "1c33de07-23d0-4572-93c7-e3acf913a7a7",
|
||||
"observation_id": "fe1646ea-c4ee-4c6c-8d79-415d9f80db0f",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.27711751756945874
|
||||
},
|
||||
{
|
||||
"observation_id": "4ab41dd3-62fb-480b-8c66-702389b226aa",
|
||||
"observation_id": "7a5a67ae-3776-4e00-8f68-6ef3b6aa957e",
|
||||
"type": "aruco",
|
||||
"marker_id": 58,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.48073279309443956
|
||||
},
|
||||
{
|
||||
"observation_id": "6b6d8a74-4f99-445a-82e5-091d8fc067df",
|
||||
"observation_id": "18b635b8-4bfc-4a64-bb26-742fc65fe3ef",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.29073788994886046
|
||||
},
|
||||
{
|
||||
"observation_id": "0e8e4398-31d2-4fe2-82ce-40afd0d3dc24",
|
||||
"observation_id": "f85c63e3-188b-47bb-81c8-c205c8dd905c",
|
||||
"type": "aruco",
|
||||
"marker_id": 69,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.45546210617301425
|
||||
},
|
||||
{
|
||||
"observation_id": "e48f8c4c-995c-4d9d-b87b-dbd77a3da6e2",
|
||||
"observation_id": "7042aab7-d942-4133-919e-a08d8060a991",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.47991555158957017
|
||||
},
|
||||
{
|
||||
"observation_id": "192f4fa2-f958-42bc-82a0-59df612ac1fb",
|
||||
"observation_id": "22e21b40-a948-4e2f-a807-10dd57e50b6a",
|
||||
"type": "aruco",
|
||||
"marker_id": 51,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.4668259742313624
|
||||
},
|
||||
{
|
||||
"observation_id": "a16d40c2-4c9c-4ecb-beeb-4ab023808ee6",
|
||||
"observation_id": "31bda626-6e7c-4725-be49-d805d4604f98",
|
||||
"type": "aruco",
|
||||
"marker_id": 56,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.39662908657084783
|
||||
},
|
||||
{
|
||||
"observation_id": "b9e74a92-cd82-4835-b29d-151c3fb8c6c5",
|
||||
"observation_id": "735feed2-2c0c-48f8-a558-5bf75f048e14",
|
||||
"type": "aruco",
|
||||
"marker_id": 120,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.3851482516876627
|
||||
},
|
||||
{
|
||||
"observation_id": "5afec636-d2bf-435c-89d9-f8d036479136",
|
||||
"observation_id": "0ac84d8c-fd18-45cc-832c-2e9a4ef75c20",
|
||||
"type": "aruco",
|
||||
"marker_id": 46,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.1698001278724927
|
||||
},
|
||||
{
|
||||
"observation_id": "fb3cfe63-1875-4fab-bc54-0a12a23346c3",
|
||||
"observation_id": "6df22bf0-2cbd-48f3-bb2b-34f540a87c38",
|
||||
"type": "aruco",
|
||||
"marker_id": 68,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.07718187630567852
|
||||
},
|
||||
{
|
||||
"observation_id": "059b200b-5d64-4180-b337-1afe0cb7bdfe",
|
||||
"observation_id": "4689b1ec-9f1b-4e24-b9a1-8f007d49c92c",
|
||||
"type": "aruco",
|
||||
"marker_id": 114,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.3840475911850059
|
||||
},
|
||||
{
|
||||
"observation_id": "721f86a3-ae50-44d8-b572-b26751895c29",
|
||||
"observation_id": "9547b3d0-a4ea-43f2-95e2-ec5fe2158b35",
|
||||
"type": "aruco",
|
||||
"marker_id": 40,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.2827516911478211
|
||||
},
|
||||
{
|
||||
"observation_id": "3b2824ee-8dbc-4b88-9092-dbf8e189cbf7",
|
||||
"observation_id": "f079fd34-3e10-49da-8792-5e893b9e1779",
|
||||
"type": "aruco",
|
||||
"marker_id": 95,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.4181682027393045
|
||||
},
|
||||
{
|
||||
"observation_id": "c65ae958-9591-4789-b061-9cc12f562c36",
|
||||
"observation_id": "551dfa01-2b6c-4ef8-89a7-c066042fe23d",
|
||||
"type": "aruco",
|
||||
"marker_id": 55,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.3865263920875397
|
||||
},
|
||||
{
|
||||
"observation_id": "5d3b4fa9-1a98-4d68-8655-938ee93daf96",
|
||||
"observation_id": "a338c014-3a34-4c54-9e59-872cd352e2e5",
|
||||
"type": "aruco",
|
||||
"marker_id": 66,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.3829765144945479
|
||||
},
|
||||
{
|
||||
"observation_id": "437d776a-cbe6-48a5-b2e1-a300bb6bf283",
|
||||
"observation_id": "a7ddef97-0211-4b3f-baf5-af37f7eeedd8",
|
||||
"type": "aruco",
|
||||
"marker_id": 217,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.3382587531306593
|
||||
},
|
||||
{
|
||||
"observation_id": "21d95087-a5e1-4a3a-b970-04f13e2d9653",
|
||||
"observation_id": "c9081401-82b0-442f-a616-dc305709b937",
|
||||
"type": "aruco",
|
||||
"marker_id": 205,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.29591817114314195
|
||||
},
|
||||
{
|
||||
"observation_id": "8a202d87-e0c3-4ade-9059-db618dfaa554",
|
||||
"observation_id": "d0300eee-76ca-4421-a5bb-569d603cde9a",
|
||||
"type": "aruco",
|
||||
"marker_id": 92,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.3158166687011719
|
||||
},
|
||||
{
|
||||
"observation_id": "4817da56-afa5-4099-8c59-d81bbe1b4562",
|
||||
"observation_id": "e5093d27-4a20-48c8-971f-cf35a42bcf1f",
|
||||
"type": "aruco",
|
||||
"marker_id": 105,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1558,7 +1558,7 @@
|
||||
"confidence": 0.31800273344664126
|
||||
},
|
||||
{
|
||||
"observation_id": "dc9990d7-442a-4269-b50a-be4a4c5def56",
|
||||
"observation_id": "348bd199-0ba0-49e3-ac08-1152ba39bfb3",
|
||||
"type": "aruco",
|
||||
"marker_id": 85,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1612,7 +1612,7 @@
|
||||
"confidence": 0.2969848480224609
|
||||
},
|
||||
{
|
||||
"observation_id": "6121d9b2-36e0-4dec-b0a6-91e1e82e8754",
|
||||
"observation_id": "56831078-4d76-414d-bdff-835fa2d2cea3",
|
||||
"type": "aruco",
|
||||
"marker_id": 102,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1666,7 +1666,7 @@
|
||||
"confidence": 0.3170967427530611
|
||||
},
|
||||
{
|
||||
"observation_id": "53c0c869-8130-46dc-b45b-8edb2178e6f1",
|
||||
"observation_id": "bcb121fd-dc27-477d-955f-402f49341383",
|
||||
"type": "aruco",
|
||||
"marker_id": 59,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1720,7 +1720,7 @@
|
||||
"confidence": 0.3170967427530611
|
||||
},
|
||||
{
|
||||
"observation_id": "6d1009ad-303f-4309-bc3c-d9ff9fcd5537",
|
||||
"observation_id": "3176af44-c8dc-43d1-a97c-116b57fa3540",
|
||||
"type": "aruco",
|
||||
"marker_id": 48,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1774,7 +1774,7 @@
|
||||
"confidence": 0.17828567290874034
|
||||
},
|
||||
{
|
||||
"observation_id": "240bf892-88b2-4a21-9b78-f315fa68b8b8",
|
||||
"observation_id": "87c35bc2-55f2-4e24-a24f-e1b4cf13fc94",
|
||||
"type": "aruco",
|
||||
"marker_id": 57,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1828,7 +1828,7 @@
|
||||
"confidence": 0.3167426670523156
|
||||
},
|
||||
{
|
||||
"observation_id": "8f6d08f0-56b3-42af-8f75-52e28846f30c",
|
||||
"observation_id": "9655d0c7-86c1-46e5-92ed-87264bdf541b",
|
||||
"type": "aruco",
|
||||
"marker_id": 63,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1882,7 +1882,7 @@
|
||||
"confidence": 0.15449597168691093
|
||||
},
|
||||
{
|
||||
"observation_id": "539569c4-e4b9-4403-ae1d-487d69ef5d61",
|
||||
"observation_id": "0d057b5e-7dd5-4b2a-bca5-153bd94bab66",
|
||||
"type": "aruco",
|
||||
"marker_id": 71,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T08:47:11Z",
|
||||
"created_utc": "2026-06-01T12:39:07Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene4\\render_g_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:20Z",
|
||||
"created_utc": "2026-05-31T20:34:15Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "07252577-b78d-4dc9-86aa-7330f72deb1d",
|
||||
"observation_id": "67a22d5d-4026-4e16-9f17-1060b5ea5c29",
|
||||
"type": "aruco",
|
||||
"marker_id": 42,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.8374556851639195
|
||||
},
|
||||
{
|
||||
"observation_id": "2ed73348-4823-409b-bc2b-07d392b86de2",
|
||||
"observation_id": "346f6e91-7aa3-4100-b93f-ca5215b9caad",
|
||||
"type": "aruco",
|
||||
"marker_id": 43,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.8294132973023032
|
||||
},
|
||||
{
|
||||
"observation_id": "d7487e91-577a-4ae9-b4cd-904b9fd28d66",
|
||||
"observation_id": "b232e7ff-255e-4f4e-b371-3aeea8d050d8",
|
||||
"type": "aruco",
|
||||
"marker_id": 219,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.8981552472038941
|
||||
},
|
||||
{
|
||||
"observation_id": "d09f9fde-716f-4051-ab6d-617304ef3117",
|
||||
"observation_id": "178d6570-814d-4952-93c2-c2f68475a1de",
|
||||
"type": "aruco",
|
||||
"marker_id": 218,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.6805707817398313
|
||||
},
|
||||
{
|
||||
"observation_id": "a2bef799-eb10-4d35-898d-552e69ddb3ac",
|
||||
"observation_id": "b942b747-333a-4ea7-ac87-efd7e8899eac",
|
||||
"type": "aruco",
|
||||
"marker_id": 229,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.6358432130578832
|
||||
},
|
||||
{
|
||||
"observation_id": "5716b245-f8ce-4a65-9262-f6133257facb",
|
||||
"observation_id": "90b7a93c-81fd-4464-bd1e-e341a2bdcbaa",
|
||||
"type": "aruco",
|
||||
"marker_id": 47,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.12146268776527554
|
||||
},
|
||||
{
|
||||
"observation_id": "db738d4a-041d-4850-a310-4410550ec21d",
|
||||
"observation_id": "d6a5cffb-fd8b-4b7f-8b32-f80dcc9527d0",
|
||||
"type": "aruco",
|
||||
"marker_id": 113,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.3676840060581848
|
||||
},
|
||||
{
|
||||
"observation_id": "8212ecdd-49de-439b-9302-b087d237a243",
|
||||
"observation_id": "07b8af76-65e8-4941-82e3-1ddeab647fd5",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.46829700346999537
|
||||
},
|
||||
{
|
||||
"observation_id": "e6ecadd4-75f7-4be6-8eb9-c7a893bf0d4a",
|
||||
"observation_id": "fd3cc01c-3141-4534-9986-a55fda47d0ff",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.4531062923543488
|
||||
},
|
||||
{
|
||||
"observation_id": "3aab1062-4f5a-4644-93e9-fc2f99c6d9d5",
|
||||
"observation_id": "f7ae1dfd-024a-4284-985a-ca346e4eb5a5",
|
||||
"type": "aruco",
|
||||
"marker_id": 245,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.5158823529411765
|
||||
},
|
||||
{
|
||||
"observation_id": "59a12a89-4127-4faf-a3c0-6f54249782d8",
|
||||
"observation_id": "29ebabdd-bdbd-4f1b-aa81-80b8fa62b49b",
|
||||
"type": "aruco",
|
||||
"marker_id": 198,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.5036164123338793
|
||||
},
|
||||
{
|
||||
"observation_id": "71cd0671-e57a-4d52-a107-5f331ebf7ef2",
|
||||
"observation_id": "b1438e02-112a-48dd-8889-fb322f2799e3",
|
||||
"type": "aruco",
|
||||
"marker_id": 85,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.4560525484643318
|
||||
},
|
||||
{
|
||||
"observation_id": "c87c2e77-f2e3-4c59-9908-0da5b573b369",
|
||||
"observation_id": "3e594a8a-ad7e-43a2-aa71-04b0b0cb5217",
|
||||
"type": "aruco",
|
||||
"marker_id": 79,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.5734281513866332
|
||||
},
|
||||
{
|
||||
"observation_id": "65e2b404-0cf0-4058-aa14-4f1b808e5489",
|
||||
"observation_id": "e8da5709-31ad-4ab5-b777-a692e87259d8",
|
||||
"type": "aruco",
|
||||
"marker_id": 96,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.525542829627259
|
||||
},
|
||||
{
|
||||
"observation_id": "36e77981-3a0b-4b4c-b6ae-011b3ced58c0",
|
||||
"observation_id": "744cc031-f8e1-436a-b30b-6827ca778984",
|
||||
"type": "aruco",
|
||||
"marker_id": 62,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.5038606541951498
|
||||
},
|
||||
{
|
||||
"observation_id": "d494b08e-3308-478e-836e-4cd895f1454e",
|
||||
"observation_id": "4f4e19b9-00fb-4d87-b8a8-ddfc3139c8ca",
|
||||
"type": "aruco",
|
||||
"marker_id": 105,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.43622925667631085
|
||||
},
|
||||
{
|
||||
"observation_id": "808485d0-8179-4cc5-9e1d-ec62f0f66354",
|
||||
"observation_id": "b25eed22-8b38-482d-b5d5-6d77dc3651ad",
|
||||
"type": "aruco",
|
||||
"marker_id": 75,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.29844141482805986
|
||||
},
|
||||
{
|
||||
"observation_id": "f0d25675-7a33-484b-909f-0267f6e3dd67",
|
||||
"observation_id": "e481fef6-3682-4ed2-b7d4-dd47584c4442",
|
||||
"type": "aruco",
|
||||
"marker_id": 102,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.2521714913889437
|
||||
},
|
||||
{
|
||||
"observation_id": "5d4bbda7-c0d7-4e2f-a22c-d137d8c3664e",
|
||||
"observation_id": "6bbb92a3-7cfd-4625-881a-71e9ac9fc80c",
|
||||
"type": "aruco",
|
||||
"marker_id": 92,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.31777455864589965
|
||||
},
|
||||
{
|
||||
"observation_id": "e33ab0fa-121d-4097-a5cf-886cad9eb349",
|
||||
"observation_id": "4e4968c9-60d3-487b-a9c2-e7b457ae1345",
|
||||
"type": "aruco",
|
||||
"marker_id": 217,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.3029173397022545
|
||||
},
|
||||
{
|
||||
"observation_id": "1e1cad29-60b0-40ff-89ca-406c4272dfbe",
|
||||
"observation_id": "b872d2c6-30d4-4d0f-ac46-4409ceead01d",
|
||||
"type": "aruco",
|
||||
"marker_id": 61,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.1527342148240039
|
||||
},
|
||||
{
|
||||
"observation_id": "36aa2935-a803-4509-8e38-9146138173e4",
|
||||
"observation_id": "84259927-1320-40f6-9b10-13643d3722c5",
|
||||
"type": "aruco",
|
||||
"marker_id": 83,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.19743498130596515
|
||||
},
|
||||
{
|
||||
"observation_id": "14e7cb1b-933d-4c6b-9c3d-35660fe9349f",
|
||||
"observation_id": "6cb603d3-e307-4bd1-b103-c94cc981299c",
|
||||
"type": "aruco",
|
||||
"marker_id": 206,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.2849187633475991
|
||||
},
|
||||
{
|
||||
"observation_id": "ca221065-cd43-4a9d-af60-b892c166d444",
|
||||
"observation_id": "c7c04197-beb8-4950-a9ca-4de2c9192d1c",
|
||||
"type": "aruco",
|
||||
"marker_id": 207,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.24627951083020566
|
||||
},
|
||||
{
|
||||
"observation_id": "45d83bd5-faeb-4da3-bb45-e07df67f87a7",
|
||||
"observation_id": "5f92c89f-d4b4-42bc-9ae6-e2d842b938ea",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.1970529186973567
|
||||
},
|
||||
{
|
||||
"observation_id": "cb5ad474-e667-4577-a956-fae72c44a230",
|
||||
"observation_id": "0a81577c-f821-446e-acef-d0fcc928084e",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.1988568274481309
|
||||
},
|
||||
{
|
||||
"observation_id": "354be54e-6e82-49b0-90e1-eebd4f306e1d",
|
||||
"observation_id": "657f9cfc-99fc-4b4b-8549-f5887bceb19d",
|
||||
"type": "aruco",
|
||||
"marker_id": 86,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.17646704338372862
|
||||
},
|
||||
{
|
||||
"observation_id": "ae2a2273-34af-4261-98d8-947c12679062",
|
||||
"observation_id": "4763bd83-3dfb-4cce-bddd-887ffd3d113f",
|
||||
"type": "aruco",
|
||||
"marker_id": 93,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:23Z",
|
||||
"created_utc": "2026-05-31T20:34:18Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene9\\render_a_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:20Z",
|
||||
"created_utc": "2026-05-31T20:34:15Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "01068640-be27-4517-aec5-25aae7340145",
|
||||
"observation_id": "510916c6-1485-4f24-aa33-b1193a1fa6c6",
|
||||
"type": "aruco",
|
||||
"marker_id": 43,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.7925285650886857
|
||||
},
|
||||
{
|
||||
"observation_id": "e6b5925e-0c11-4377-bc3c-a519e9f39f43",
|
||||
"observation_id": "91139bf6-1704-465c-a40b-f9ce94bbf46c",
|
||||
"type": "aruco",
|
||||
"marker_id": 63,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.1539593300495616
|
||||
},
|
||||
{
|
||||
"observation_id": "5bddacbc-162f-41f0-a120-ddb61f017cc0",
|
||||
"observation_id": "7576d0a1-6cd9-4370-80b2-04ff857d9c0e",
|
||||
"type": "aruco",
|
||||
"marker_id": 229,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.4787342723608016
|
||||
},
|
||||
{
|
||||
"observation_id": "8783b700-77a1-4659-88b8-fc240c36212c",
|
||||
"observation_id": "84fba295-d3ac-4e69-9a58-0cde131f74b4",
|
||||
"type": "aruco",
|
||||
"marker_id": 102,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.39637168760361213
|
||||
},
|
||||
{
|
||||
"observation_id": "5dc9e8fa-af4e-405a-b5d9-c447dc0a410b",
|
||||
"observation_id": "14027746-489e-4cc0-9d69-89dbc086f119",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.4633649853376546
|
||||
},
|
||||
{
|
||||
"observation_id": "3f9a4760-d443-49ae-b94c-34fb45410b82",
|
||||
"observation_id": "6c6be389-03ea-4d1e-b8cd-4a9714b00715",
|
||||
"type": "aruco",
|
||||
"marker_id": 58,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.3638956157928849
|
||||
},
|
||||
{
|
||||
"observation_id": "e1cbfacd-7320-408b-ba10-33b475383fab",
|
||||
"observation_id": "2dea0619-d038-4900-b2ee-b5a841379415",
|
||||
"type": "aruco",
|
||||
"marker_id": 113,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.33787297122479
|
||||
},
|
||||
{
|
||||
"observation_id": "3b32f333-2016-4fd2-a15c-ea910d42770d",
|
||||
"observation_id": "cbc3ea5b-622b-4308-940c-4a01685d21e2",
|
||||
"type": "aruco",
|
||||
"marker_id": 92,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.46896024883690896
|
||||
},
|
||||
{
|
||||
"observation_id": "415d829e-9984-4318-8524-ee5af224e866",
|
||||
"observation_id": "3a377ad5-4bc3-4647-af82-26e3a8c61667",
|
||||
"type": "aruco",
|
||||
"marker_id": 96,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.44372569385651617
|
||||
},
|
||||
{
|
||||
"observation_id": "52af5975-b6cc-4f2d-a07e-a650b128e2b3",
|
||||
"observation_id": "aad6d120-6b5a-4b9c-90a7-3ccd8c3572ed",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.45199802144368495
|
||||
},
|
||||
{
|
||||
"observation_id": "f16d21d0-6c14-467f-85bd-dd3acdacbfb7",
|
||||
"observation_id": "824124ba-30c5-4dba-9993-7caab7810db2",
|
||||
"type": "aruco",
|
||||
"marker_id": 62,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.44348322079976393
|
||||
},
|
||||
{
|
||||
"observation_id": "0033762d-71b5-4327-b9b5-a859e3a5c740",
|
||||
"observation_id": "bd6272ab-ff0d-4f80-a159-a4bb430a1467",
|
||||
"type": "aruco",
|
||||
"marker_id": 51,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.44348322079976393
|
||||
},
|
||||
{
|
||||
"observation_id": "d1fa1197-e5eb-4967-a466-7e9c7f5c440e",
|
||||
"observation_id": "f44c4c0e-cb0e-46e2-968e-851bc82a7b26",
|
||||
"type": "aruco",
|
||||
"marker_id": 42,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.24113570084112637
|
||||
},
|
||||
{
|
||||
"observation_id": "874226da-78b7-4b23-9ab2-3d61e9abc737",
|
||||
"observation_id": "84287a52-6997-4743-8d4f-cbe5005cecd0",
|
||||
"type": "aruco",
|
||||
"marker_id": 79,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.41815762699787656
|
||||
},
|
||||
{
|
||||
"observation_id": "dcbbb855-d629-4a37-8ada-7262b55b3c05",
|
||||
"observation_id": "f5ceb28c-98b2-4cc8-8dab-b712e59e1005",
|
||||
"type": "aruco",
|
||||
"marker_id": 205,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.3958181457519531
|
||||
},
|
||||
{
|
||||
"observation_id": "adc921c9-ae5a-4406-b1b8-769d71ab0ce1",
|
||||
"observation_id": "59ac044d-7e01-4021-872f-9ed5f0016f15",
|
||||
"type": "aruco",
|
||||
"marker_id": 198,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.3918555899450243
|
||||
},
|
||||
{
|
||||
"observation_id": "753bd80d-3796-40c4-8fb3-403428283e16",
|
||||
"observation_id": "b298a6a6-e0a4-45eb-be17-50da5919327c",
|
||||
"type": "aruco",
|
||||
"marker_id": 217,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.4015868133874269
|
||||
},
|
||||
{
|
||||
"observation_id": "63a71e13-fe5c-41de-809a-d698eecca618",
|
||||
"observation_id": "ff352796-9c20-4e9b-bacd-8f3c479e156c",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.3776
|
||||
},
|
||||
{
|
||||
"observation_id": "9d562528-ffda-49ee-864a-6aafa7585f5d",
|
||||
"observation_id": "9908343d-37d8-41cc-b5b5-d9fe37d725b9",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.3320910299473707
|
||||
},
|
||||
{
|
||||
"observation_id": "78307cf0-8bb2-4905-b5d5-ef00e3164c90",
|
||||
"observation_id": "7b584155-5f04-48e1-9844-5637fc702f19",
|
||||
"type": "aruco",
|
||||
"marker_id": 214,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.3465862068965517
|
||||
},
|
||||
{
|
||||
"observation_id": "eb787833-efc2-4abc-98f2-0247f364abb6",
|
||||
"observation_id": "68141292-bd29-4277-a74c-acf8f5406c40",
|
||||
"type": "aruco",
|
||||
"marker_id": 206,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.3579602826436361
|
||||
},
|
||||
{
|
||||
"observation_id": "0534c618-efd8-4a33-9b15-a6e6db83cc1c",
|
||||
"observation_id": "2111f2b4-2d23-4688-b170-96c2f10605e5",
|
||||
"type": "aruco",
|
||||
"marker_id": 207,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.343462485354258
|
||||
},
|
||||
{
|
||||
"observation_id": "9da11e9d-6d2b-4ee2-8267-625e043baba3",
|
||||
"observation_id": "b85e551b-f979-48eb-86f7-28ded65f6b60",
|
||||
"type": "aruco",
|
||||
"marker_id": 245,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.212625
|
||||
},
|
||||
{
|
||||
"observation_id": "d0ac2453-7640-48fc-bbca-dc3013a61baa",
|
||||
"observation_id": "7816cfee-8ad0-4255-b839-3acd7a4b2cd5",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.15432248002290727
|
||||
},
|
||||
{
|
||||
"observation_id": "9eb315df-83be-43e9-acb1-738d1bc9c7ff",
|
||||
"observation_id": "fca5ddbc-02d1-45bb-968c-28a9bf2274f0",
|
||||
"type": "aruco",
|
||||
"marker_id": 94,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.06057156860351561
|
||||
},
|
||||
{
|
||||
"observation_id": "7cacc81b-7305-4ae5-af1d-9bee6aeb647a",
|
||||
"observation_id": "e4c224d2-104d-48dc-a5c5-45bcfa897e33",
|
||||
"type": "aruco",
|
||||
"marker_id": 76,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.2459421895345052
|
||||
},
|
||||
{
|
||||
"observation_id": "68c87cbb-3fa9-4643-b538-3a065e46f545",
|
||||
"observation_id": "c04c91e2-33b8-4690-8c1e-faa54996af3b",
|
||||
"type": "aruco",
|
||||
"marker_id": 100,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.24407473894265982
|
||||
},
|
||||
{
|
||||
"observation_id": "0903146d-64ec-4882-acf0-ed62e64d436e",
|
||||
"observation_id": "e271ab38-30e9-4f70-991a-4a78614052d0",
|
||||
"type": "aruco",
|
||||
"marker_id": 75,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1558,7 +1558,7 @@
|
||||
"confidence": 0.23896265492072474
|
||||
},
|
||||
{
|
||||
"observation_id": "deefe266-8d68-4216-9fbb-bcdaffd243e4",
|
||||
"observation_id": "c677eeb1-3ddd-4090-b61d-3312ff93698a",
|
||||
"type": "aruco",
|
||||
"marker_id": 68,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1612,7 +1612,7 @@
|
||||
"confidence": 0.24909137483284013
|
||||
},
|
||||
{
|
||||
"observation_id": "340c3083-57e5-4889-b1c4-62b232c629b6",
|
||||
"observation_id": "e2e965fe-0688-4956-b5c8-b472a1a866c0",
|
||||
"type": "aruco",
|
||||
"marker_id": 46,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1666,7 +1666,7 @@
|
||||
"confidence": 0.23734254719660833
|
||||
},
|
||||
{
|
||||
"observation_id": "687d1bc8-5183-4e14-ae4f-104d2cbbebd3",
|
||||
"observation_id": "0b1fa639-5719-4a92-bb61-de3a5f537d8a",
|
||||
"type": "aruco",
|
||||
"marker_id": 50,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1720,7 +1720,7 @@
|
||||
"confidence": 0.2211554500544793
|
||||
},
|
||||
{
|
||||
"observation_id": "a47ce685-b6dc-46eb-9d9a-280ec8e56fdb",
|
||||
"observation_id": "e4d57e40-7524-4912-9997-ed57b457fc94",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1774,7 +1774,7 @@
|
||||
"confidence": 0.21841319450965294
|
||||
},
|
||||
{
|
||||
"observation_id": "e7d953e1-bba2-4121-8fb4-74811adcacc3",
|
||||
"observation_id": "e9e486eb-586e-4f60-82cd-8e85af24a057",
|
||||
"type": "aruco",
|
||||
"marker_id": 104,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1828,7 +1828,7 @@
|
||||
"confidence": 0.22417849731445313
|
||||
},
|
||||
{
|
||||
"observation_id": "f39e0707-77cf-4757-b7bf-1a1a24407955",
|
||||
"observation_id": "e7f14793-e43b-4833-9c66-4141dec2bc44",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1882,7 +1882,7 @@
|
||||
"confidence": 0.22367025973033955
|
||||
},
|
||||
{
|
||||
"observation_id": "575acfb5-3d1e-4090-9fb6-ed15f60a3ff4",
|
||||
"observation_id": "4d779391-632e-4fa2-9853-5cf1920fd3c2",
|
||||
"type": "aruco",
|
||||
"marker_id": 60,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1936,7 +1936,7 @@
|
||||
"confidence": 0.19874429613402733
|
||||
},
|
||||
{
|
||||
"observation_id": "fe8cc3dd-23f4-4c8c-846f-57623eea9c62",
|
||||
"observation_id": "7a4ef42c-1ecc-457f-8ba8-be79ad9ab714",
|
||||
"type": "aruco",
|
||||
"marker_id": 67,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1990,7 +1990,7 @@
|
||||
"confidence": 0.19627771759033205
|
||||
},
|
||||
{
|
||||
"observation_id": "8fcd54f5-1f2c-47f7-b93a-4268a5be6da9",
|
||||
"observation_id": "ed010846-c477-4e11-821d-c398fe02d4c5",
|
||||
"type": "aruco",
|
||||
"marker_id": 86,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2044,7 +2044,7 @@
|
||||
"confidence": 0.18966921411877496
|
||||
},
|
||||
{
|
||||
"observation_id": "7cbfc038-4fc4-43b9-b5ab-2f9d663e44b5",
|
||||
"observation_id": "8b24e54f-2f2f-4a41-b036-d7e55b982d9c",
|
||||
"type": "aruco",
|
||||
"marker_id": 88,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2098,7 +2098,7 @@
|
||||
"confidence": 0.17697203515072252
|
||||
},
|
||||
{
|
||||
"observation_id": "2d33a74f-b95e-477e-8487-cecee4108905",
|
||||
"observation_id": "31dd65cb-5813-47b5-9957-2dae2e0c89df",
|
||||
"type": "aruco",
|
||||
"marker_id": 70,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2152,7 +2152,7 @@
|
||||
"confidence": 0.193995418548584
|
||||
},
|
||||
{
|
||||
"observation_id": "796f565c-74c6-4201-82fe-f56c82aa967f",
|
||||
"observation_id": "846b18ed-d381-4034-b6bd-d6b6fcb77418",
|
||||
"type": "aruco",
|
||||
"marker_id": 90,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2206,7 +2206,7 @@
|
||||
"confidence": 0.17958947754575058
|
||||
},
|
||||
{
|
||||
"observation_id": "0dcef397-888c-4f8b-adcf-09c1eda4d48d",
|
||||
"observation_id": "2462b7ec-9d3b-49c8-8e34-4c1bf041a4e9",
|
||||
"type": "aruco",
|
||||
"marker_id": 83,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2260,7 +2260,7 @@
|
||||
"confidence": 0.17676838843571283
|
||||
},
|
||||
{
|
||||
"observation_id": "f4e38593-d83d-41e4-8aa9-c093f7b52629",
|
||||
"observation_id": "db18b721-d773-47da-8622-1405b9f373b0",
|
||||
"type": "aruco",
|
||||
"marker_id": 61,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -2314,7 +2314,7 @@
|
||||
"confidence": 0.1668050360320266
|
||||
},
|
||||
{
|
||||
"observation_id": "ade767bd-3d2c-4358-ab09-e8b895b5516a",
|
||||
"observation_id": "205fe12e-ab3a-4d0c-8e00-ca28cb40ccf6",
|
||||
"type": "aruco",
|
||||
"marker_id": 91,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:24Z",
|
||||
"created_utc": "2026-05-31T20:34:18Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene9\\render_b_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:21Z",
|
||||
"created_utc": "2026-05-31T20:34:16Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "cf64993e-b0a4-4fe2-a4e1-d8643c540187",
|
||||
"observation_id": "4f5542a8-14df-46c1-82db-1a2d97500448",
|
||||
"type": "aruco",
|
||||
"marker_id": 113,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.9487615650349993
|
||||
},
|
||||
{
|
||||
"observation_id": "9ade8ea3-f326-4723-98d6-b421f37f1a9c",
|
||||
"observation_id": "13234fdc-5a13-4483-8a76-a2bc6e98df26",
|
||||
"type": "aruco",
|
||||
"marker_id": 245,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.9266602848500798
|
||||
},
|
||||
{
|
||||
"observation_id": "571e5890-a3a4-4a23-a10c-70be6f47ae17",
|
||||
"observation_id": "7ea6faca-9c46-4c3c-8552-b4595421a9eb",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.8890505808415132
|
||||
},
|
||||
{
|
||||
"observation_id": "11cb203b-8d89-4e20-be1d-a5e9dbbd4a3c",
|
||||
"observation_id": "5278689c-fb4a-4af8-8fe5-93419ea45e5f",
|
||||
"type": "aruco",
|
||||
"marker_id": 229,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.3082915922280886
|
||||
},
|
||||
{
|
||||
"observation_id": "49e82dbc-71de-489e-8ca0-86e9c4b2ab4a",
|
||||
"observation_id": "4f80c066-e5e2-4ccf-9e4e-b7761c3af848",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.2964796698261984
|
||||
},
|
||||
{
|
||||
"observation_id": "469170de-53fc-4e6d-a6a8-f92f01716d35",
|
||||
"observation_id": "b1513300-6853-43ac-b878-e1ae65d2d3fe",
|
||||
"type": "aruco",
|
||||
"marker_id": 198,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.21181999247805575
|
||||
},
|
||||
{
|
||||
"observation_id": "ed58e338-4cb5-4be9-8742-caff231c4191",
|
||||
"observation_id": "f3e582e8-fd00-41cf-a08c-77c541df935b",
|
||||
"type": "aruco",
|
||||
"marker_id": 214,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.21966133686197709
|
||||
},
|
||||
{
|
||||
"observation_id": "59f45fec-95ea-45d5-a313-01d1df02f5ca",
|
||||
"observation_id": "e80baad4-7612-45c8-95cd-62c61fb3c41d",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:24Z",
|
||||
"created_utc": "2026-05-31T20:34:18Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene9\\render_c_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:21Z",
|
||||
"created_utc": "2026-05-31T20:34:16Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "acd36297-8590-4e39-9e07-2d14934c5b18",
|
||||
"observation_id": "62159d0c-7b40-4e16-940f-ba2767d8b5a6",
|
||||
"type": "aruco",
|
||||
"marker_id": 113,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.9819147066961816
|
||||
},
|
||||
{
|
||||
"observation_id": "c7a8b343-4662-4b4a-91b8-cdd7f8446e9d",
|
||||
"observation_id": "1fc62b88-87cf-4431-a2f7-3e53816f7d82",
|
||||
"type": "aruco",
|
||||
"marker_id": 245,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.896516741806838
|
||||
},
|
||||
{
|
||||
"observation_id": "cf69ef4e-b613-438a-96b9-d511cf7ecd86",
|
||||
"observation_id": "172aef68-2afd-4e3a-9889-a65832c5e04f",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.8782459535277616
|
||||
},
|
||||
{
|
||||
"observation_id": "5b126bae-1879-4dc7-8fc1-693a130fbc9c",
|
||||
"observation_id": "2d83b0a9-eeb7-4eea-92c5-26b6fab011f1",
|
||||
"type": "aruco",
|
||||
"marker_id": 244,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.49420707353484883
|
||||
},
|
||||
{
|
||||
"observation_id": "0adc2d3d-2c76-4b58-ba67-0453b429ed43",
|
||||
"observation_id": "a6adc44e-d309-4347-8774-3657ec0daab2",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.06739671544456982
|
||||
},
|
||||
{
|
||||
"observation_id": "d56b98b1-2379-40c1-ab4a-97ddc90789cf",
|
||||
"observation_id": "01e98ce0-0dcf-4d46-963f-24ec97298b77",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.17416420855033052
|
||||
},
|
||||
{
|
||||
"observation_id": "e1dea64d-2ef1-4704-bd32-0d8d37fce07f",
|
||||
"observation_id": "24c04561-73ac-4449-8531-9d8339d1f07d",
|
||||
"type": "aruco",
|
||||
"marker_id": 229,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.4189637021373363
|
||||
},
|
||||
{
|
||||
"observation_id": "d225f050-e98e-4cdb-98c7-7f4ec1993abe",
|
||||
"observation_id": "5d001e51-cdd2-495c-9a83-b69e0dd68eba",
|
||||
"type": "aruco",
|
||||
"marker_id": 58,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.24540823915500745
|
||||
},
|
||||
{
|
||||
"observation_id": "8c1178ae-dc58-45e3-a325-f548f6ea7643",
|
||||
"observation_id": "5bc6c7d7-afd3-4476-90fc-2c5d4f7e419e",
|
||||
"type": "aruco",
|
||||
"marker_id": 214,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.32624039952470835
|
||||
},
|
||||
{
|
||||
"observation_id": "498cfff6-84bf-4369-b8ff-d0b0acf8eff6",
|
||||
"observation_id": "51592f44-1c5c-477a-9d79-e1ad40f54542",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.45882243623190877
|
||||
},
|
||||
{
|
||||
"observation_id": "cc88dc5c-c96e-4e67-82a1-310dcecc12df",
|
||||
"observation_id": "75a9e37b-d35c-46c0-8cab-8bff0d5cd43f",
|
||||
"type": "aruco",
|
||||
"marker_id": 124,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.051262886894149665
|
||||
},
|
||||
{
|
||||
"observation_id": "49db44ed-8e8a-4331-84d1-6f55790d7b47",
|
||||
"observation_id": "37a0443d-aa46-443e-b12c-cf1d29945553",
|
||||
"type": "aruco",
|
||||
"marker_id": 211,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.3071912693949274
|
||||
},
|
||||
{
|
||||
"observation_id": "f63a04b0-f0d8-4170-99f3-6518cdb08b18",
|
||||
"observation_id": "433745c3-3bd1-4a0e-96d7-628a9e937461",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.013395930107400523
|
||||
},
|
||||
{
|
||||
"observation_id": "c4dd4579-b90d-4016-b3e1-eac48bda6442",
|
||||
"observation_id": "a8bfa26a-c9ef-4963-929a-c0cd66fdd06c",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.07285288505606423
|
||||
},
|
||||
{
|
||||
"observation_id": "65696218-7213-45e6-95c5-7e190bafc3e2",
|
||||
"observation_id": "6e2ea730-94e9-4abc-abb3-f45cb792c57d",
|
||||
"type": "aruco",
|
||||
"marker_id": 86,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:24Z",
|
||||
"created_utc": "2026-05-31T20:34:19Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene9\\render_d_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:22Z",
|
||||
"created_utc": "2026-05-31T20:34:16Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "6fc71185-930f-4f82-8373-039be269c229",
|
||||
"observation_id": "087a4182-fd74-451b-ae82-efe6961bb3d0",
|
||||
"type": "aruco",
|
||||
"marker_id": 92,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.15369374989294518
|
||||
},
|
||||
{
|
||||
"observation_id": "61c58ced-3657-4aee-a0a8-2dc1e52f188f",
|
||||
"observation_id": "6280ab09-ea6b-43d4-a293-02574271eabe",
|
||||
"type": "aruco",
|
||||
"marker_id": 113,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.6379583967674639
|
||||
},
|
||||
{
|
||||
"observation_id": "56c7a16a-772b-4998-9078-04d725ed6014",
|
||||
"observation_id": "babe888a-58a7-4b93-b1c8-939be23f7d0d",
|
||||
"type": "aruco",
|
||||
"marker_id": 217,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.3233651345714012
|
||||
},
|
||||
{
|
||||
"observation_id": "31696819-1ec7-4797-9bff-85b0cb2b5bb6",
|
||||
"observation_id": "6c8a6edf-9a0e-4b8e-86ae-1af551e3a817",
|
||||
"type": "aruco",
|
||||
"marker_id": 105,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.420622587927407
|
||||
},
|
||||
{
|
||||
"observation_id": "d7f50fce-2ff0-491b-b7cb-149bc590cf17",
|
||||
"observation_id": "5612df49-9322-4027-89dc-2c2c2e52b874",
|
||||
"type": "aruco",
|
||||
"marker_id": 85,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.3128949822399185
|
||||
},
|
||||
{
|
||||
"observation_id": "eb7f9038-c6ee-4e17-b0de-a38cd18ddebd",
|
||||
"observation_id": "0f42e339-6b98-455e-a330-4a03c4b0f611",
|
||||
"type": "aruco",
|
||||
"marker_id": 206,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.11623157468788738
|
||||
},
|
||||
{
|
||||
"observation_id": "d4d2d4aa-e45d-4ddb-a590-e80eda4b032a",
|
||||
"observation_id": "0d648a76-257f-4f3f-988f-a309c3ec7876",
|
||||
"type": "aruco",
|
||||
"marker_id": 244,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.48895218467117135
|
||||
},
|
||||
{
|
||||
"observation_id": "ab93b57a-0627-49cd-b984-cb5a79a35f56",
|
||||
"observation_id": "6117d8df-1de6-47d6-a5e7-f7d2e8342dc0",
|
||||
"type": "aruco",
|
||||
"marker_id": 97,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.22596816505744277
|
||||
},
|
||||
{
|
||||
"observation_id": "1ad81425-7f91-45d0-b57b-c8d0818a41b7",
|
||||
"observation_id": "e1e687e2-1724-457b-901c-d2e2fa569bd5",
|
||||
"type": "aruco",
|
||||
"marker_id": 245,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.32694949112255345
|
||||
},
|
||||
{
|
||||
"observation_id": "b48dfcec-0a2a-46a9-b33a-43b0ecdcc4d4",
|
||||
"observation_id": "8fb4f342-49f9-4aca-bdfe-b5d5021b00a3",
|
||||
"type": "aruco",
|
||||
"marker_id": 47,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.24626971873720385
|
||||
},
|
||||
{
|
||||
"observation_id": "3f50ac96-2803-4036-9552-f5c55e9d954f",
|
||||
"observation_id": "08ee9bb4-11bd-4097-b2db-c97798dbdc93",
|
||||
"type": "aruco",
|
||||
"marker_id": 96,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.2205630261207473
|
||||
},
|
||||
{
|
||||
"observation_id": "2e4f216d-8e34-4267-841d-2ec2180a49e6",
|
||||
"observation_id": "ee4404fa-8fe5-4204-b84d-bd335ca480ce",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.22017552547080893
|
||||
},
|
||||
{
|
||||
"observation_id": "c288b7ab-bf08-4fc0-b2df-07acd15f1ccc",
|
||||
"observation_id": "bde7c5f2-db1b-4788-a1f8-6bb7a955e04d",
|
||||
"type": "aruco",
|
||||
"marker_id": 62,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.24902550615732547
|
||||
},
|
||||
{
|
||||
"observation_id": "0f6715ed-0518-44e9-87cb-2037e0c0edcf",
|
||||
"observation_id": "6e7fde78-5661-492a-bb85-d21098b3624d",
|
||||
"type": "aruco",
|
||||
"marker_id": 124,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.1717072854797086
|
||||
},
|
||||
{
|
||||
"observation_id": "24e7ae54-0d18-48fd-a549-630fbc0d8974",
|
||||
"observation_id": "6fc14e4d-6ac6-4027-b6e5-6e96e4ec868d",
|
||||
"type": "aruco",
|
||||
"marker_id": 79,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.2093822185726055
|
||||
},
|
||||
{
|
||||
"observation_id": "ccde6c14-9316-46d4-a2e5-b525942989ba",
|
||||
"observation_id": "23a1ff79-0495-4970-a7bc-841534293457",
|
||||
"type": "aruco",
|
||||
"marker_id": 66,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.16725963004706537
|
||||
},
|
||||
{
|
||||
"observation_id": "a9d19be1-0346-4edd-b414-7cdddbd7b046",
|
||||
"observation_id": "2adc985e-f3c4-4d36-a489-eaa53d748de7",
|
||||
"type": "aruco",
|
||||
"marker_id": 55,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.22298824455832925
|
||||
},
|
||||
{
|
||||
"observation_id": "4d14965d-15bf-41fe-9af7-fbe19be926d5",
|
||||
"observation_id": "c3240208-5b4d-40de-b5ab-39afc4c88548",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.13595850692924102
|
||||
},
|
||||
{
|
||||
"observation_id": "e0ca82e9-8ae2-4203-a93e-deb9be852c63",
|
||||
"observation_id": "e256e786-c86f-4fd8-8ec4-0f0f3a34e42a",
|
||||
"type": "aruco",
|
||||
"marker_id": 243,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.2298583378390498
|
||||
},
|
||||
{
|
||||
"observation_id": "c8bef757-29ac-48c2-963a-d5c52a772606",
|
||||
"observation_id": "24595212-9a3b-4e2b-a7d6-5d39a5cb223b",
|
||||
"type": "aruco",
|
||||
"marker_id": 214,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.17248468175234963
|
||||
},
|
||||
{
|
||||
"observation_id": "3d2f550e-8c4e-4f5a-a981-40b902dda77f",
|
||||
"observation_id": "ac844a2b-7454-49ad-b0b6-ffc98daa75de",
|
||||
"type": "aruco",
|
||||
"marker_id": 51,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.12157403976480062
|
||||
},
|
||||
{
|
||||
"observation_id": "687e5bbc-d03e-4665-a206-7398ad988fe3",
|
||||
"observation_id": "484a5752-8e57-48f6-8776-24baaa0faece",
|
||||
"type": "aruco",
|
||||
"marker_id": 95,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.14922985097126407
|
||||
},
|
||||
{
|
||||
"observation_id": "9a20c3d5-a6ba-470d-891d-2d685d393d73",
|
||||
"observation_id": "69ef89b5-3cac-49c4-90e5-a2ee74240362",
|
||||
"type": "aruco",
|
||||
"marker_id": 122,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.1374474660290558
|
||||
},
|
||||
{
|
||||
"observation_id": "727c58a5-0255-41f7-b4af-dd829c4009aa",
|
||||
"observation_id": "46447d39-c157-4276-bed1-aaf72d779e03",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.11373255626245794
|
||||
},
|
||||
{
|
||||
"observation_id": "c564521c-9730-47d5-8293-fe67b0f7f7f0",
|
||||
"observation_id": "fa2028b6-f95a-4d46-b903-dd9b6e203384",
|
||||
"type": "aruco",
|
||||
"marker_id": 60,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.1208904643109979
|
||||
},
|
||||
{
|
||||
"observation_id": "e360c493-84f1-4cc1-bdbb-124070ff3d49",
|
||||
"observation_id": "56844b60-5be2-4144-9eec-3d423d8323d6",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.15549629518828512
|
||||
},
|
||||
{
|
||||
"observation_id": "2c51d601-5297-48a7-8b2e-356724e40aff",
|
||||
"observation_id": "3c548f42-f562-4dd2-8cb4-435b5523a476",
|
||||
"type": "aruco",
|
||||
"marker_id": 211,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.13332463075982282
|
||||
},
|
||||
{
|
||||
"observation_id": "1bb69ea4-2eb6-473c-8502-3defa78b93a8",
|
||||
"observation_id": "585ff40e-feb5-421c-b5a4-fdfe4f0ffe95",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1558,7 +1558,7 @@
|
||||
"confidence": 0.13255097071329755
|
||||
},
|
||||
{
|
||||
"observation_id": "7276115d-9eb1-4c73-81fd-33fa9ff7e6b7",
|
||||
"observation_id": "60a6c00b-2ae8-4f32-b8de-9651580a458e",
|
||||
"type": "aruco",
|
||||
"marker_id": 86,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1612,7 +1612,7 @@
|
||||
"confidence": 0.1265670983135443
|
||||
},
|
||||
{
|
||||
"observation_id": "c49290ca-b544-441c-a823-50f8d3ba44a4",
|
||||
"observation_id": "452571be-6bd4-4954-98a6-4259782c8434",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:25Z",
|
||||
"created_utc": "2026-05-31T20:34:19Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene9\\render_e_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:22Z",
|
||||
"created_utc": "2026-05-31T20:34:17Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "6ddfe847-9814-4c0d-9668-c35105142bec",
|
||||
"observation_id": "4340a67e-546b-4c41-b6af-b97dd46642dd",
|
||||
"type": "aruco",
|
||||
"marker_id": 43,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.850354724870378
|
||||
},
|
||||
{
|
||||
"observation_id": "1d6e7db3-9a78-4ace-99e6-2e5e939a8194",
|
||||
"observation_id": "acd51a2d-4136-47fc-852a-70689177fa34",
|
||||
"type": "aruco",
|
||||
"marker_id": 41,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.3023072583773299
|
||||
},
|
||||
{
|
||||
"observation_id": "843b3a74-fad4-47b1-80b5-659b5fd39894",
|
||||
"observation_id": "77d60b7b-c067-4e3c-abbb-8380c5da0f3a",
|
||||
"type": "aruco",
|
||||
"marker_id": 46,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.2988751797371847
|
||||
},
|
||||
{
|
||||
"observation_id": "e008eefa-bde9-4e56-893b-8a242d07916a",
|
||||
"observation_id": "819ab1d7-7d29-4b81-9062-b07c701f1350",
|
||||
"type": "aruco",
|
||||
"marker_id": 56,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.5697620483284124
|
||||
},
|
||||
{
|
||||
"observation_id": "c0297b0f-9fd9-44f5-9235-9f76b5400e20",
|
||||
"observation_id": "bb8f3982-3298-4607-98e0-6c3a4c56bf4f",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.5829305549976826
|
||||
},
|
||||
{
|
||||
"observation_id": "cbfc45a8-cb5d-4f49-af82-7847232cf35b",
|
||||
"observation_id": "1ef7e9ca-13bb-4e2b-a3a4-0cd2bccefe83",
|
||||
"type": "aruco",
|
||||
"marker_id": 47,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.5768583617164568
|
||||
},
|
||||
{
|
||||
"observation_id": "a68e5a34-cba4-4d8a-996c-4d781f0c9581",
|
||||
"observation_id": "bc995fa0-7605-4c8d-90bb-4af814e6061a",
|
||||
"type": "aruco",
|
||||
"marker_id": 62,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.5593704450665263
|
||||
},
|
||||
{
|
||||
"observation_id": "9feb6cc3-2216-4e37-94df-4e7aacf33c98",
|
||||
"observation_id": "e461b461-3ef5-450c-a12a-ac55cb3d794c",
|
||||
"type": "aruco",
|
||||
"marker_id": 54,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.5766374039623903
|
||||
},
|
||||
{
|
||||
"observation_id": "397dfde9-511c-45e0-a6fd-51174f857bab",
|
||||
"observation_id": "941f9bb4-6fb1-4626-9087-cbefd12708ee",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.21364841201201337
|
||||
},
|
||||
{
|
||||
"observation_id": "057b424e-f5a5-4a46-8f9a-13419d869f5a",
|
||||
"observation_id": "631f849f-8529-4736-a48a-56c96c63df45",
|
||||
"type": "aruco",
|
||||
"marker_id": 229,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.5464657910873614
|
||||
},
|
||||
{
|
||||
"observation_id": "b758b327-ded4-4b8c-8e7f-7ef3c63c6449",
|
||||
"observation_id": "91689ac4-9a7d-4351-b639-cf6167c31caf",
|
||||
"type": "aruco",
|
||||
"marker_id": 97,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.5705029634947052
|
||||
},
|
||||
{
|
||||
"observation_id": "a0e9f5d6-1a3f-467c-927c-8f840e59a9e7",
|
||||
"observation_id": "6dded9ad-709d-4344-9afe-84a004afe01f",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.5440516905787338
|
||||
},
|
||||
{
|
||||
"observation_id": "e1f16cc8-2556-419f-a310-e04d6d67a82a",
|
||||
"observation_id": "d82fedd2-e4a3-474b-9a26-ff1b582e197e",
|
||||
"type": "aruco",
|
||||
"marker_id": 55,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.5461315019106076
|
||||
},
|
||||
{
|
||||
"observation_id": "a8673501-6341-4af5-a033-84c0736ab193",
|
||||
"observation_id": "67b636ba-958b-4c40-9e89-de2eb56df02e",
|
||||
"type": "aruco",
|
||||
"marker_id": 96,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.5763709732716893
|
||||
},
|
||||
{
|
||||
"observation_id": "fba0b4e6-a0aa-4d7e-8dab-4ca9ceffbc6d",
|
||||
"observation_id": "6b6c2dc7-ef6d-4d08-aea3-d746e5f6a63b",
|
||||
"type": "aruco",
|
||||
"marker_id": 42,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.2932628535560303
|
||||
},
|
||||
{
|
||||
"observation_id": "75b08127-82a6-49d5-8839-06937726ff41",
|
||||
"observation_id": "a7edbdb6-f08e-466b-9fee-3347c9b08986",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.06519221426443914
|
||||
},
|
||||
{
|
||||
"observation_id": "6786a8ed-59e5-43ff-8110-d9c5755245fa",
|
||||
"observation_id": "a7897d0b-c733-4e3b-a8db-43cf6944f367",
|
||||
"type": "aruco",
|
||||
"marker_id": 79,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.5460974493377216
|
||||
},
|
||||
{
|
||||
"observation_id": "31d831ff-3911-482f-b9cb-3a77510ecefb",
|
||||
"observation_id": "d798d53b-ecae-48e8-ade1-c81a09646783",
|
||||
"type": "aruco",
|
||||
"marker_id": 66,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.5349107016469481
|
||||
},
|
||||
{
|
||||
"observation_id": "cce8a642-14c5-49b7-b26d-83a3324a7504",
|
||||
"observation_id": "6717e240-6eb7-4b86-9ca0-58345243742c",
|
||||
"type": "aruco",
|
||||
"marker_id": 95,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.5227826547122322
|
||||
},
|
||||
{
|
||||
"observation_id": "088ccc39-f28b-48af-8994-5121fce0f677",
|
||||
"observation_id": "a1932f32-df0d-4d1c-a709-ef1e66ebc81b",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.5046333482067283
|
||||
},
|
||||
{
|
||||
"observation_id": "d2921bf5-88b2-4228-93e9-b314c1618c2a",
|
||||
"observation_id": "f772f877-7ecd-473e-98cb-da1867c7665e",
|
||||
"type": "aruco",
|
||||
"marker_id": 52,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.4723088830007061
|
||||
},
|
||||
{
|
||||
"observation_id": "af43368a-46d6-47b3-910d-677baf8ba363",
|
||||
"observation_id": "d1cb3430-fb40-413a-813b-69935f64c227",
|
||||
"type": "aruco",
|
||||
"marker_id": 73,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.13607001327160623
|
||||
},
|
||||
{
|
||||
"observation_id": "246998d9-f26e-4532-92f1-f5f3f59e5e35",
|
||||
"observation_id": "645a8fff-2f5d-4222-8b9c-4a5710cc9385",
|
||||
"type": "aruco",
|
||||
"marker_id": 210,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.46988879526830113
|
||||
},
|
||||
{
|
||||
"observation_id": "05cf03d4-39eb-44de-83d2-325cb5c7c4bd",
|
||||
"observation_id": "5917e84e-acd4-4f59-95a2-926ec5e58eb2",
|
||||
"type": "aruco",
|
||||
"marker_id": 58,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.4655541127751829
|
||||
},
|
||||
{
|
||||
"observation_id": "a5bb8f95-2ffe-493e-b89f-72fad459e4ca",
|
||||
"observation_id": "0793b521-e3f5-4828-8315-911513e51eba",
|
||||
"type": "aruco",
|
||||
"marker_id": 69,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.4655541127751829
|
||||
},
|
||||
{
|
||||
"observation_id": "77d07710-1005-4c77-9244-553436afaf7e",
|
||||
"observation_id": "41c0f927-51ad-456b-a7c3-4e8ff9e54772",
|
||||
"type": "aruco",
|
||||
"marker_id": 82,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.49001748422717006
|
||||
},
|
||||
{
|
||||
"observation_id": "0bd33220-1839-484f-95bc-44de9bce5d97",
|
||||
"observation_id": "7023258e-89dc-49b3-a06d-4a28bcf34830",
|
||||
"type": "aruco",
|
||||
"marker_id": 101,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.46225891142368675
|
||||
},
|
||||
{
|
||||
"observation_id": "caf17446-e76c-440f-8cd9-c7e98d6b5951",
|
||||
"observation_id": "8a6809ef-8d1e-44b3-a6ff-c97449b0a254",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1558,7 +1558,7 @@
|
||||
"confidence": 0.43211414091114625
|
||||
},
|
||||
{
|
||||
"observation_id": "f150d187-dfd4-4f83-a5d1-98961098732a",
|
||||
"observation_id": "ffcef9f7-fa42-4b89-95be-09b12acc120b",
|
||||
"type": "aruco",
|
||||
"marker_id": 81,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1612,7 +1612,7 @@
|
||||
"confidence": 0.4468602604238168
|
||||
},
|
||||
{
|
||||
"observation_id": "4bb4bd97-e41e-49e4-8c5b-98521aea2496",
|
||||
"observation_id": "02bd9dda-2fde-4e66-93b8-5e2780868170",
|
||||
"type": "aruco",
|
||||
"marker_id": 83,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1666,7 +1666,7 @@
|
||||
"confidence": 0.4377857805109236
|
||||
},
|
||||
{
|
||||
"observation_id": "959fcf81-a6a5-47e7-affa-f9008534bb98",
|
||||
"observation_id": "eeba6e41-6ab3-43bd-9433-a5450cc61039",
|
||||
"type": "aruco",
|
||||
"marker_id": 75,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1720,7 +1720,7 @@
|
||||
"confidence": 0.22473325223116958
|
||||
},
|
||||
{
|
||||
"observation_id": "29339bc4-3728-4704-b422-d14f40ecea8a",
|
||||
"observation_id": "18425f53-7811-4549-a413-e43d54ea7e40",
|
||||
"type": "aruco",
|
||||
"marker_id": 113,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:25Z",
|
||||
"created_utc": "2026-05-31T20:34:19Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene9\\render_f_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:23Z",
|
||||
"created_utc": "2026-05-31T20:34:17Z",
|
||||
"vision_config": {
|
||||
"MarkerType": "DICT_4X4_250",
|
||||
"MarkerSize": 0.025
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"detections": [
|
||||
{
|
||||
"observation_id": "89f2a226-35fc-4b08-b10a-42dd771b9d53",
|
||||
"observation_id": "4ed22d16-c2d8-4fbc-9165-23bb3c671bb5",
|
||||
"type": "aruco",
|
||||
"marker_id": 41,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -100,7 +100,7 @@
|
||||
"confidence": 0.7407693857081211
|
||||
},
|
||||
{
|
||||
"observation_id": "af0773a4-adfa-4bae-8d87-f364ba4246b1",
|
||||
"observation_id": "1bca4d06-1a3b-4543-9cdd-784e7b28df4c",
|
||||
"type": "aruco",
|
||||
"marker_id": 42,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -154,7 +154,7 @@
|
||||
"confidence": 0.47851333141876906
|
||||
},
|
||||
{
|
||||
"observation_id": "90d1ce64-bff4-4d3f-b495-9828603377c5",
|
||||
"observation_id": "babe0171-8902-4db2-9a50-27a4ec7d84f5",
|
||||
"type": "aruco",
|
||||
"marker_id": 198,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -208,7 +208,7 @@
|
||||
"confidence": 0.5891588970505985
|
||||
},
|
||||
{
|
||||
"observation_id": "01ee36ee-0a8e-4c2e-9536-341b642931d4",
|
||||
"observation_id": "db3ca2c8-3d8d-47ff-a38b-742ae4c9cd29",
|
||||
"type": "aruco",
|
||||
"marker_id": 43,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -262,7 +262,7 @@
|
||||
"confidence": 0.38340186913811386
|
||||
},
|
||||
{
|
||||
"observation_id": "5fc86ae6-dc58-4ae6-9375-c891e53bac96",
|
||||
"observation_id": "6ec27886-7e79-4b00-9ec6-628cd009b08c",
|
||||
"type": "aruco",
|
||||
"marker_id": 84,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -316,7 +316,7 @@
|
||||
"confidence": 0.3490767193505014
|
||||
},
|
||||
{
|
||||
"observation_id": "1322c03c-a58b-44f4-a882-b6d0f4e8b6c9",
|
||||
"observation_id": "e7dd82cb-dde0-4160-bec7-054e7909d8e1",
|
||||
"type": "aruco",
|
||||
"marker_id": 229,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -370,7 +370,7 @@
|
||||
"confidence": 0.519411428244808
|
||||
},
|
||||
{
|
||||
"observation_id": "c255fa4e-aee9-4400-882f-ac74c8aff039",
|
||||
"observation_id": "6b4de8d0-a32a-449f-b04d-ee559444e718",
|
||||
"type": "aruco",
|
||||
"marker_id": 64,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -424,7 +424,7 @@
|
||||
"confidence": 0.5331747682067169
|
||||
},
|
||||
{
|
||||
"observation_id": "9d36ead0-1e68-4b45-8bd4-97f9e3a677e9",
|
||||
"observation_id": "740f2e43-ff17-4f67-9458-ab4fb221e9f4",
|
||||
"type": "aruco",
|
||||
"marker_id": 72,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -478,7 +478,7 @@
|
||||
"confidence": 0.43254677700170213
|
||||
},
|
||||
{
|
||||
"observation_id": "4a355ea6-ad8e-47aa-8328-ea9371df477f",
|
||||
"observation_id": "a16dc8e1-76f3-4955-98ec-bbc84353e784",
|
||||
"type": "aruco",
|
||||
"marker_id": 53,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -532,7 +532,7 @@
|
||||
"confidence": 0.27711751756945874
|
||||
},
|
||||
{
|
||||
"observation_id": "e0ec4ae1-3371-4cdc-be4d-0a72a7446054",
|
||||
"observation_id": "ec157b33-fe28-4527-b0a4-01f5b5b32c05",
|
||||
"type": "aruco",
|
||||
"marker_id": 58,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -586,7 +586,7 @@
|
||||
"confidence": 0.48073279309443956
|
||||
},
|
||||
{
|
||||
"observation_id": "0e9ffeb3-8d24-400e-845a-e2c703621ab4",
|
||||
"observation_id": "c09306da-02d6-4ee4-a39d-82d37977c242",
|
||||
"type": "aruco",
|
||||
"marker_id": 69,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -640,7 +640,7 @@
|
||||
"confidence": 0.45515519100712953
|
||||
},
|
||||
{
|
||||
"observation_id": "faee1e72-775f-4c5d-bca3-f6ad68517fe7",
|
||||
"observation_id": "45fb5703-ed8b-471a-bc43-0b4ad7645c6a",
|
||||
"type": "aruco",
|
||||
"marker_id": 215,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -694,7 +694,7 @@
|
||||
"confidence": 0.3775515964613595
|
||||
},
|
||||
{
|
||||
"observation_id": "01d694e4-9b96-48ad-8045-7caf42ce8202",
|
||||
"observation_id": "3fd57096-a6e8-4769-90e2-d837174de623",
|
||||
"type": "aruco",
|
||||
"marker_id": 103,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -748,7 +748,7 @@
|
||||
"confidence": 0.47991555158957017
|
||||
},
|
||||
{
|
||||
"observation_id": "be35393c-2383-4661-a6f1-5f3610d12f80",
|
||||
"observation_id": "1a3cdb7d-3652-43d6-abc8-31ea64d3f28b",
|
||||
"type": "aruco",
|
||||
"marker_id": 56,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -802,7 +802,7 @@
|
||||
"confidence": 0.39662908657084783
|
||||
},
|
||||
{
|
||||
"observation_id": "a26a80d6-cf59-40a8-ab91-be2f6e2202b0",
|
||||
"observation_id": "deee817b-c3c7-457d-ac86-33da00f01a6e",
|
||||
"type": "aruco",
|
||||
"marker_id": 46,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -856,7 +856,7 @@
|
||||
"confidence": 0.1698001278724927
|
||||
},
|
||||
{
|
||||
"observation_id": "06d1df75-8efa-4f65-bc16-ac1d6876285f",
|
||||
"observation_id": "0d469273-c77d-4957-8cc9-1f6c6d931af4",
|
||||
"type": "aruco",
|
||||
"marker_id": 68,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -910,7 +910,7 @@
|
||||
"confidence": 0.07718187630567852
|
||||
},
|
||||
{
|
||||
"observation_id": "3ff3bfd5-ac16-4247-b696-05a854c73d8c",
|
||||
"observation_id": "02a463ef-1804-4a53-a63f-2cb8458bed4b",
|
||||
"type": "aruco",
|
||||
"marker_id": 208,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -964,7 +964,7 @@
|
||||
"confidence": 0.4316478958478293
|
||||
},
|
||||
{
|
||||
"observation_id": "97e6d81e-2741-40dc-9ee9-aad045cca8f5",
|
||||
"observation_id": "c98f83f0-e394-4066-b019-6336c024481b",
|
||||
"type": "aruco",
|
||||
"marker_id": 95,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"confidence": 0.4181682027393045
|
||||
},
|
||||
{
|
||||
"observation_id": "01b67ab6-8c50-4ce4-bed6-0158823efd10",
|
||||
"observation_id": "0500566e-ae2e-4b4b-9c41-bf3f14800fa3",
|
||||
"type": "aruco",
|
||||
"marker_id": 55,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"confidence": 0.39668368657567366
|
||||
},
|
||||
{
|
||||
"observation_id": "5371b799-160f-4bbe-85cc-13b1f810e89d",
|
||||
"observation_id": "bdb0d68d-4129-4a69-9d7f-d08d652bddfc",
|
||||
"type": "aruco",
|
||||
"marker_id": 66,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1126,7 +1126,7 @@
|
||||
"confidence": 0.3829765144945479
|
||||
},
|
||||
{
|
||||
"observation_id": "070f02e4-16d1-429a-8aaa-12ba52832ba0",
|
||||
"observation_id": "64b5825c-8a9b-4c80-897d-d1e4784a10d7",
|
||||
"type": "aruco",
|
||||
"marker_id": 217,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"confidence": 0.3382587531306593
|
||||
},
|
||||
{
|
||||
"observation_id": "7293ca8e-6a90-4254-9a08-60f99f49abb2",
|
||||
"observation_id": "7aebb928-3025-4810-a7b4-35b4559be3bf",
|
||||
"type": "aruco",
|
||||
"marker_id": 47,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"confidence": 0.36403279165733554
|
||||
},
|
||||
{
|
||||
"observation_id": "cacec511-b043-4ca3-aad2-d6dd9ec22a85",
|
||||
"observation_id": "bb0a4c02-152c-41e5-a371-69b6bea6619d",
|
||||
"type": "aruco",
|
||||
"marker_id": 97,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
"confidence": 0.3623898971459892
|
||||
},
|
||||
{
|
||||
"observation_id": "a54637d5-a3d5-4762-8f85-b4d191559761",
|
||||
"observation_id": "e8584ad2-273d-4262-a830-621fe38ca751",
|
||||
"type": "aruco",
|
||||
"marker_id": 54,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1342,7 +1342,7 @@
|
||||
"confidence": 0.3590718541167963
|
||||
},
|
||||
{
|
||||
"observation_id": "16f58f33-e6e5-461c-bf93-88b7b0b3b97d",
|
||||
"observation_id": "ada6e22d-6a63-4808-afea-66a6b2b3b4e1",
|
||||
"type": "aruco",
|
||||
"marker_id": 205,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1396,7 +1396,7 @@
|
||||
"confidence": 0.29591817114314195
|
||||
},
|
||||
{
|
||||
"observation_id": "7d767a3b-2803-4269-abe5-3ce24ceebcc9",
|
||||
"observation_id": "a139d459-3682-4d55-a6b3-10cdbfdcfee4",
|
||||
"type": "aruco",
|
||||
"marker_id": 92,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1450,7 +1450,7 @@
|
||||
"confidence": 0.3158166687011719
|
||||
},
|
||||
{
|
||||
"observation_id": "cdd3d10b-e739-42de-bb66-1b25f7158e3f",
|
||||
"observation_id": "b975fa8f-44a8-412a-94f4-deab777415a5",
|
||||
"type": "aruco",
|
||||
"marker_id": 105,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1504,7 +1504,7 @@
|
||||
"confidence": 0.31800273344664126
|
||||
},
|
||||
{
|
||||
"observation_id": "37e24568-f70c-4d6f-aec5-2f33a9ee3d71",
|
||||
"observation_id": "e1350236-4eae-44f2-b963-94c28546d631",
|
||||
"type": "aruco",
|
||||
"marker_id": 85,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1558,7 +1558,7 @@
|
||||
"confidence": 0.2969848480224609
|
||||
},
|
||||
{
|
||||
"observation_id": "a2431c76-a23a-4a5f-b47d-b22b00ddd415",
|
||||
"observation_id": "392187f5-b834-461a-9e43-986e2c912ba3",
|
||||
"type": "aruco",
|
||||
"marker_id": 102,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1612,7 +1612,7 @@
|
||||
"confidence": 0.3170967427530611
|
||||
},
|
||||
{
|
||||
"observation_id": "c193ec7b-1bde-4095-8f76-da8c5e340b8e",
|
||||
"observation_id": "c085910a-f4d0-4bee-a5d2-7e2bff50a155",
|
||||
"type": "aruco",
|
||||
"marker_id": 59,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1666,7 +1666,7 @@
|
||||
"confidence": 0.3170967427530611
|
||||
},
|
||||
{
|
||||
"observation_id": "d415cabf-ddf6-4ab5-ba62-463b52fe51c7",
|
||||
"observation_id": "1f7d0314-b32b-4ca0-80ed-7e109c2ae31a",
|
||||
"type": "aruco",
|
||||
"marker_id": 48,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1720,7 +1720,7 @@
|
||||
"confidence": 0.17828567290874034
|
||||
},
|
||||
{
|
||||
"observation_id": "4f84f376-49b7-4aac-9faa-f96f6506b37d",
|
||||
"observation_id": "d94ccf50-2d35-4bd9-a6e5-ccebe10e5161",
|
||||
"type": "aruco",
|
||||
"marker_id": 57,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1774,7 +1774,7 @@
|
||||
"confidence": 0.3167426670523156
|
||||
},
|
||||
{
|
||||
"observation_id": "2134752b-c53b-4e3e-aa96-8f436e96f112",
|
||||
"observation_id": "56f4064b-e40d-4434-a971-c7b9c3fe8426",
|
||||
"type": "aruco",
|
||||
"marker_id": 63,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1828,7 +1828,7 @@
|
||||
"confidence": 0.15449597168691093
|
||||
},
|
||||
{
|
||||
"observation_id": "a407682b-43a5-47e0-8929-bd602c104234",
|
||||
"observation_id": "efac90a0-f0ab-4cee-b44b-9d25324c0a04",
|
||||
"type": "aruco",
|
||||
"marker_id": 71,
|
||||
"marker_size_m": 0.025,
|
||||
@@ -1882,7 +1882,7 @@
|
||||
"confidence": 0.08171792300897739
|
||||
},
|
||||
{
|
||||
"observation_id": "dc4c9c88-a776-4638-92cc-b67db3baf003",
|
||||
"observation_id": "edd7aeff-78d1-41bd-9902-227c83bf1b78",
|
||||
"type": "aruco",
|
||||
"marker_id": 120,
|
||||
"marker_size_m": 0.025,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"created_utc": "2026-05-31T10:25:25Z",
|
||||
"created_utc": "2026-05-31T20:34:19Z",
|
||||
"source": {
|
||||
"detection_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\evaluations\\Scene9\\render_g_aruco_detection.json",
|
||||
"robot_json": "C:\\Users\\kech\\SynologyDrive\\2026-AppServer-AppRobot\\appRobotRendering\\data\\robot\\robot.json"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
BIN
data/robot/robot_r.json
Normal file
BIN
data/robot/robot_r.json
Normal file
Binary file not shown.
@@ -172,6 +172,19 @@
|
||||
"spin_factor": 0.3,
|
||||
"weight_floor": 0.3
|
||||
},
|
||||
"robot_test_poses": {
|
||||
"sim04": {"x": 70, "y": 50,"z": -70,"a": 120,"b": 50,"c": 30,"e": 20},
|
||||
"sim05": {"x": 180,"y": 86,"z": -120,"a": -60,"b": 22,"c": 91,"e": 10},
|
||||
"sim06": {"x": 80, "y": 20, "z": 80, "a": -120, "b": 23, "c": 9, "e": 3},
|
||||
"sim07": {"x": 30, "y": -2, "z": 95, "a": 20, "b": 23, "c": 9, "e": 9},
|
||||
"sim08": {"x": 50, "y": -2, "z": 95, "a": 20, "b": 60, "c": 9, "e": 3},
|
||||
"sim09": {"x": 60, "y": -2, "z": 95, "a": 200, "b": 60, "c": 9, "e": 8},
|
||||
"sim09a": {"x": 60, "y": -2, "z": 95, "a": 200, "b": 60, "c": 9, "e": 8},
|
||||
"sim09b": {"x": 60, "y": -2, "z": 95, "a": 200, "b": 60, "c": 9, "e": 8},
|
||||
"sim010": {"x": 120, "y": 60, "z": -110, "a": 20, "b": 30, "c": 180, "e": 4},
|
||||
"sim011": {"x": 50, "y": 4, "z": 176, "a": 20, "b": 60, "c": 9, "e": 5},
|
||||
"sim012": {"x": 50, "y": 0, "z": 178, "a": 210, "b": 80, "c": 90, "e": 6}
|
||||
},
|
||||
"movements": {
|
||||
"x": null,
|
||||
"y": null,
|
||||
@@ -183,7 +196,7 @@
|
||||
},
|
||||
"state_pose_params":{
|
||||
"numbers_of_Elements_to_consider_start": 3,
|
||||
"numbers_of_Elements_to_consider_final": 5,
|
||||
"numbers_of_Elements_to_consider_final": 4,
|
||||
"solver_in_between_geometrical": false,
|
||||
"solver_after_geometrical": false,
|
||||
"geometric_passes_per_stage": 2,
|
||||
@@ -416,36 +429,13 @@
|
||||
}
|
||||
],
|
||||
"markers": [
|
||||
{
|
||||
"id": 244,
|
||||
"name": "aruco_244",
|
||||
"position": [125, 0, 0],
|
||||
"normal": [1, 0, 0],
|
||||
"size": 25,
|
||||
"spin": 0
|
||||
},
|
||||
{
|
||||
"id": 245,
|
||||
"name": "aruco_245",
|
||||
"position": [90, 0, -35],
|
||||
"normal": [0, 0, -1],
|
||||
"size": 25,
|
||||
"spin": 0
|
||||
},
|
||||
{
|
||||
"id": 246,
|
||||
"name": "aruco_246",
|
||||
"position": [90, 0, 35],
|
||||
"normal": [0, 0, 1],
|
||||
"size": 25
|
||||
},
|
||||
{
|
||||
"id": 247,
|
||||
"name": "aruco_247",
|
||||
"position": [52.5, 0, 35],
|
||||
"normal": [0, 0, 1],
|
||||
"size": 25
|
||||
}
|
||||
{"id": 244, "name": "aruco_244", "position": [125, 0, 0], "normal": [1, 0, 0], "size": 25, "spin": 0},
|
||||
{"id": 245, "name": "aruco_245", "position": [90, 0, -35], "normal": [0, 0, -1], "size": 25, "spin": 0},
|
||||
{"id": 246, "name": "aruco_246", "position": [90, 0, 35], "normal": [0, 0, 1], "size": 25},
|
||||
{"id": 247, "name": "aruco_247", "position": [52.5, 0, 35], "normal": [0, 0, 1], "size": 25},
|
||||
{"id": 248, "name": "aruco_248", "position": [52.5, 0, -35], "normal": [0, 0, -1], "size": 25},
|
||||
{"id": 232, "name": "aruco_232", "position": [90, 24.75, -24.75], "normal": [0, 1, -1], "size": 25},
|
||||
{"id": 231, "name": "aruco_231", "position": [90, 24.75, 24.75], "normal": [0, 1, 1], "size": 25}
|
||||
]
|
||||
|
||||
},
|
||||
|
||||
0
pipeline/3_anchor_patch.py
Normal file
0
pipeline/3_anchor_patch.py
Normal file
File diff suppressed because it is too large
Load Diff
229
pipeline/3_multiview_bundle_adjustment_v5_board_anchor_patch.py
Normal file
229
pipeline/3_multiview_bundle_adjustment_v5_board_anchor_patch.py
Normal file
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
3_board_anchor_patch.py
|
||||
-----------------------
|
||||
DROP-IN PATCH for 3_multiview_bundle_adjustment_v4.py
|
||||
|
||||
What it adds
|
||||
------------
|
||||
Board markers have KNOWN world positions (they are fixed to the physical board,
|
||||
which defines the coordinate frame). Letting the optimizer move them freely
|
||||
makes them drift, which degrades all arm-marker estimates.
|
||||
|
||||
This patch adds a PositionAnchorConstraint that pins each observed Board
|
||||
marker to its robot.json world position during bundle adjustment.
|
||||
|
||||
How to integrate
|
||||
----------------
|
||||
Copy the three sections labelled [PATCH – copy into v4] into the v4 file:
|
||||
|
||||
1. The PositionAnchorConstraint dataclass → after the JointAxisConstraint dataclass
|
||||
2. Update the Constraint type alias → replace the existing line
|
||||
3. The load_board_anchors() function → anywhere before main()
|
||||
4. The change to bundle_adjustment_residuals → add one branch inside the for-loop
|
||||
5. The three lines in main() → just before "STEP 4"
|
||||
|
||||
Quick-test without editing v4
|
||||
------------------------------
|
||||
You can also run this file standalone — it imports from v4 and patches it at
|
||||
runtime. Then call main_anchored() instead of main() for the patched run.
|
||||
|
||||
python 3_board_anchor_patch.py -det ... -pose ... -robot ... -outDir ...
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# [PATCH section 1 – copy into v4 after JointAxisConstraint]
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
from dataclasses import dataclass
|
||||
import numpy as np
|
||||
from typing import Dict, Any, List, Optional, Tuple
|
||||
|
||||
|
||||
@dataclass
|
||||
class PositionAnchorConstraint:
|
||||
"""
|
||||
Pins a single marker to a known world-space position.
|
||||
Used to anchor Board markers whose world positions are read from robot.json.
|
||||
"""
|
||||
marker_id: int
|
||||
target_world_m: np.ndarray # shape (3,), in metres
|
||||
weight: float = 100.0
|
||||
source: str = "board_anchor"
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# [PATCH section 2 – replace the Constraint type alias in v4]
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# OLD: Constraint = MarkerDistanceConstraint | JointAxisConstraint
|
||||
# NEW:
|
||||
# from 3_board_anchor_patch import PositionAnchorConstraint
|
||||
# Constraint = MarkerDistanceConstraint | JointAxisConstraint | PositionAnchorConstraint
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# [PATCH section 3 – new function, copy anywhere before main()]
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
|
||||
def load_board_anchors(
|
||||
robot_data: Dict[str, Any],
|
||||
length_scale: float,
|
||||
weight: float = 100.0,
|
||||
) -> List[PositionAnchorConstraint]:
|
||||
"""
|
||||
Build PositionAnchorConstraints for every marker on the 'Board' link.
|
||||
|
||||
Board is the root link; its marker positions are in the Board (world) frame.
|
||||
length_scale = 1/1000 when robot.json uses mm (the standard).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
robot_data : loaded robot.json
|
||||
length_scale : float (1/1000 to convert mm → m)
|
||||
weight : constraint weight (100 ≈ 1 mm anchor tolerance at λ=100)
|
||||
"""
|
||||
links = robot_data.get("links", {}) or {}
|
||||
board = links.get("Board", {}) or {}
|
||||
anchors: List[PositionAnchorConstraint] = []
|
||||
|
||||
for m in board.get("markers", []):
|
||||
mid = int(m.get("id", -1))
|
||||
pos = m.get("position", None)
|
||||
if mid < 0 or pos is None or len(pos) != 3:
|
||||
continue
|
||||
world_m = np.array(pos, dtype=np.float64) * float(length_scale)
|
||||
anchors.append(
|
||||
PositionAnchorConstraint(
|
||||
marker_id=mid,
|
||||
target_world_m=world_m,
|
||||
weight=weight,
|
||||
source="board_anchor",
|
||||
)
|
||||
)
|
||||
|
||||
return anchors
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# [PATCH section 4 – add this branch inside bundle_adjustment_residuals,
|
||||
# in the "for constraint in constraints:" loop, after the JointAxisConstraint branch]
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
|
||||
def _anchor_residuals(constraint: PositionAnchorConstraint,
|
||||
marker_dict: Dict[int, np.ndarray],
|
||||
lambda_constraint: float) -> List[float]:
|
||||
"""
|
||||
Returns 3 residual components w·λ·(X_observed - X_target) for each axis.
|
||||
|
||||
Paste the body of this function into bundle_adjustment_residuals like this:
|
||||
|
||||
elif isinstance(constraint, PositionAnchorConstraint):
|
||||
if constraint.marker_id in marker_dict:
|
||||
diff = marker_dict[constraint.marker_id] - constraint.target_world_m
|
||||
for d in diff:
|
||||
residuals.append(float(d) * constraint.weight * lambda_constraint)
|
||||
"""
|
||||
residuals: List[float] = []
|
||||
if constraint.marker_id in marker_dict:
|
||||
diff = marker_dict[constraint.marker_id] - constraint.target_world_m
|
||||
for d in diff:
|
||||
residuals.append(float(d) * constraint.weight * lambda_constraint)
|
||||
return residuals
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# [PATCH section 5 – add these lines in main(), just BEFORE
|
||||
# "print('\n[STEP 4] Bundle adjustment with constraints...')"]
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
#
|
||||
# board_anchors = load_board_anchors(robot_data, length_scale, weight=100.0)
|
||||
# constraints += board_anchors
|
||||
# print(f"[INFO] Board anchors added: {len(board_anchors)}")
|
||||
#
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# STANDALONE RUNTIME PATCH (alternative to editing v4)
|
||||
# Run this file directly and it patches v4 in memory.
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _monkey_patch_v4():
|
||||
"""
|
||||
Import the v4 module under an alias and patch it so Board markers are
|
||||
anchored without touching the original file.
|
||||
"""
|
||||
import importlib.util, sys, types, pathlib
|
||||
|
||||
v4_path = pathlib.Path(__file__).parent / "3_multiview_bundle_adjustment_v4.py"
|
||||
if not v4_path.exists():
|
||||
raise FileNotFoundError(
|
||||
f"Expected v4 at {v4_path}.\n"
|
||||
"Place this patch file alongside 3_multiview_bundle_adjustment_v4.py."
|
||||
)
|
||||
|
||||
spec = importlib.util.spec_from_file_location("ba_v4", v4_path)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
|
||||
# Inject PositionAnchorConstraint into the module namespace
|
||||
mod.PositionAnchorConstraint = PositionAnchorConstraint
|
||||
|
||||
# Patch bundle_adjustment_residuals ─────────────────────────
|
||||
_orig_residuals = mod.bundle_adjustment_residuals
|
||||
|
||||
def _patched_residuals(marker_positions_flat, marker_ids, marker_observations,
|
||||
cameras, constraints, obs_weights, lambda_constraint=100.0):
|
||||
r = _orig_residuals(marker_positions_flat, marker_ids, marker_observations,
|
||||
cameras, constraints, obs_weights, lambda_constraint)
|
||||
# Rebuild marker_dict (same as inside the original function)
|
||||
marker_dict = {
|
||||
mid: marker_positions_flat[i*3:(i+1)*3]
|
||||
for i, mid in enumerate(marker_ids)
|
||||
}
|
||||
extra = []
|
||||
for c in constraints:
|
||||
if isinstance(c, PositionAnchorConstraint):
|
||||
extra.extend(_anchor_residuals(c, marker_dict, lambda_constraint))
|
||||
if extra:
|
||||
r = np.concatenate([r, np.array(extra, dtype=np.float64)])
|
||||
return r
|
||||
|
||||
mod.bundle_adjustment_residuals = _patched_residuals
|
||||
|
||||
# Patch main to inject board anchors ────────────────────────
|
||||
_orig_main = mod.main
|
||||
|
||||
def _patched_main():
|
||||
import sys as _sys
|
||||
# We hijack the module-level function calls by patching compile_constraints
|
||||
_orig_compile = mod.compile_constraints
|
||||
|
||||
def _compile_with_anchors(robot_data, length_scale, cfg):
|
||||
marker_to_link, link_markers, constraints, issues, marker_meta = \
|
||||
_orig_compile(robot_data, length_scale, cfg)
|
||||
|
||||
anchors = load_board_anchors(robot_data, length_scale, weight=100.0)
|
||||
print(f"[PATCH] Board anchors added: {len(anchors)}")
|
||||
constraints = constraints + anchors
|
||||
return marker_to_link, link_markers, constraints, issues, marker_meta
|
||||
|
||||
mod.compile_constraints = _compile_with_anchors
|
||||
_orig_main()
|
||||
mod.compile_constraints = _orig_compile # restore
|
||||
|
||||
mod.main = _patched_main
|
||||
return mod
|
||||
|
||||
|
||||
def main():
|
||||
"""Run the patched v4 pipeline with Board marker anchoring."""
|
||||
import sys
|
||||
mod = _monkey_patch_v4()
|
||||
sys.argv[0] = "3_multiview_bundle_adjustment_v4.py" # cosmetic
|
||||
mod.main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
207
pipeline/4_v8_4a_base_slider.py
Normal file
207
pipeline/4_v8_4a_base_slider.py
Normal file
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
4a_base_slider.py
|
||||
-----------------
|
||||
Estimate the Base linear-slider position (variable 'x', in mm) from
|
||||
observed world-space marker positions produced by step 3.
|
||||
|
||||
Mathematical principle
|
||||
----------------------
|
||||
The Base slides along the world x-axis.
|
||||
Every joint between Base and the observable arm markers rotates around
|
||||
the x-axis (axis ≈ [-1,0,0] for Arm1, Ellbow, Arm2).
|
||||
|
||||
Rotation around the x-axis NEVER changes the x-coordinate of any point.
|
||||
Therefore, for every marker on Arm1, Ellbow, or Arm2:
|
||||
|
||||
world_x = x_slider + link_frame_x_at_zero + local_x
|
||||
|
||||
where link_frame_x_at_zero is the x of the link-frame origin in world
|
||||
when all joint variables are zero (constant, readable from robot.json).
|
||||
|
||||
Rearranging:
|
||||
x_slider = world_x - link_frame_x_at_zero - local_x
|
||||
|
||||
This holds for ANY rotation angle y, z, a of the arm links.
|
||||
|
||||
This gives one independent estimate per observed marker.
|
||||
We report their mean (and statistics) as the final estimate.
|
||||
|
||||
Usage
|
||||
-----
|
||||
python 4a_base_slider.py --robot robot.json --aruco aruco_positions_optimized.json
|
||||
|
||||
python 4a_base_slider.py --robot robot.json --aruco aruco_positions_optimized.json \\
|
||||
--links Arm1 Ellbow Arm2 --output 4a_result.json
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import numpy as np
|
||||
from robot_fk import RobotFK
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# I/O helpers
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _load_json(path: Path) -> dict:
|
||||
with path.open("r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def _load_observed_mm(aruco_json: dict) -> Dict[int, np.ndarray]:
|
||||
"""marker_id → world position in mm, from aruco_positions_optimized.json."""
|
||||
result: Dict[int, np.ndarray] = {}
|
||||
for m in aruco_json.get("markers", []):
|
||||
mid = int(m.get("marker_id", m.get("id", -1)))
|
||||
if mid < 0:
|
||||
continue
|
||||
if "position_mm" in m:
|
||||
result[mid] = np.array(m["position_mm"], dtype=float)
|
||||
elif "position_m" in m:
|
||||
result[mid] = np.array(m["position_m"], dtype=float) * 1000.0
|
||||
return result
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Core estimator
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def estimate_base_slider(
|
||||
fk: RobotFK,
|
||||
observed_mm: Dict[int, np.ndarray],
|
||||
use_links: Optional[List[str]] = None,
|
||||
verbose: bool = True,
|
||||
) -> dict:
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
fk : RobotFK instance
|
||||
observed_mm : dict marker_id -> world position [mm]
|
||||
use_links : links whose markers are used (default: Arm1, Ellbow, Arm2)
|
||||
All must be connected to Base via only x-axis rotations.
|
||||
verbose : print breakdown
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict with keys:
|
||||
status, x_mean_mm, x_median_mm, x_std_mm,
|
||||
num_markers, per_marker
|
||||
"""
|
||||
if use_links is None:
|
||||
use_links = ["Arm1", "Ellbow", "Arm2"]
|
||||
|
||||
# Pre-compute link_frame_x at zero-state for each target link
|
||||
link_x0: Dict[str, float] = {}
|
||||
for lname in use_links:
|
||||
if lname in fk.links:
|
||||
link_x0[lname] = fk.link_x_at_zero_state(lname)
|
||||
|
||||
estimates: List[float] = []
|
||||
per_marker: List[dict] = []
|
||||
|
||||
for lname in use_links:
|
||||
if lname not in fk.links or lname not in link_x0:
|
||||
continue
|
||||
x0 = link_x0[lname]
|
||||
|
||||
for m in fk.links[lname].get("markers", []):
|
||||
mid = int(m.get("id", -1))
|
||||
if mid < 0 or "position" not in m:
|
||||
continue
|
||||
if mid not in observed_mm:
|
||||
continue # marker not seen in this pose
|
||||
|
||||
local_x = float(m["position"][0])
|
||||
world_x = float(observed_mm[mid][0])
|
||||
x_est = world_x - x0 - local_x
|
||||
|
||||
estimates.append(x_est)
|
||||
per_marker.append({
|
||||
"marker_id": mid,
|
||||
"link": lname,
|
||||
"local_x_mm": local_x,
|
||||
"link_x0_mm": x0,
|
||||
"world_x_mm": world_x,
|
||||
"x_estimate_mm": x_est,
|
||||
})
|
||||
|
||||
if not estimates:
|
||||
msg = (f"No observed markers found on links {use_links}. "
|
||||
"Check that aruco_positions_optimized.json contains "
|
||||
"markers from those links.")
|
||||
if verbose:
|
||||
print(f"[4a FAILED] {msg}")
|
||||
return {"status": "failed", "reason": msg, "use_links": use_links}
|
||||
|
||||
arr = np.array(estimates)
|
||||
x_mean = float(np.mean(arr))
|
||||
x_median = float(np.median(arr))
|
||||
x_std = float(np.std(arr, ddof=0))
|
||||
|
||||
if verbose:
|
||||
print("\n── 4a: Base slider (x) ──────────────────────────────────")
|
||||
print(f" Links used: {use_links}")
|
||||
print(f" Markers used: {len(estimates)}")
|
||||
print(f" x = {x_mean:+.2f} mm (median {x_median:+.2f}, σ {x_std:.2f})")
|
||||
if x_std > 5.0:
|
||||
print(f" [WARN] high spread ({x_std:.1f} mm) – step-3 errors or wrong link list")
|
||||
print(f"\n Per-marker:")
|
||||
print(f" {'ID':>5} {'Link':8} {'local_x':>8} {'world_x':>8} {'x_est':>8}")
|
||||
print(f" " + "-"*46)
|
||||
for pm in per_marker:
|
||||
print(f" {pm['marker_id']:>5} {pm['link']:8} "
|
||||
f"{pm['local_x_mm']:>8.2f} {pm['world_x_mm']:>8.2f} {pm['x_estimate_mm']:>8.2f}")
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"joint": "x",
|
||||
"description": "Base linear slider",
|
||||
"x_mean_mm": x_mean,
|
||||
"x_median_mm": x_median,
|
||||
"x_std_mm": x_std,
|
||||
"num_markers": len(estimates),
|
||||
"use_links": use_links,
|
||||
"per_marker": per_marker,
|
||||
}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# CLI
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def main() -> int:
|
||||
p = argparse.ArgumentParser(description="4a: estimate Base slider (x)")
|
||||
p.add_argument("--robot", type=Path, default=Path("robot.json"))
|
||||
p.add_argument("--aruco", type=Path, default=Path("aruco_positions_optimized.json"))
|
||||
p.add_argument("--links", nargs="+", default=["Arm1", "Ellbow", "Arm2"],
|
||||
dest="links",
|
||||
help="Links whose markers to use (must be x-axis-rotation chain)")
|
||||
p.add_argument("--output", type=Path, default=None,
|
||||
help="Optional JSON output path (e.g. 4a_result.json)")
|
||||
args = p.parse_args()
|
||||
|
||||
fk = RobotFK.from_file(args.robot)
|
||||
aruco_json = _load_json(args.aruco)
|
||||
observed_mm = _load_observed_mm(aruco_json)
|
||||
|
||||
result = estimate_base_slider(fk, observed_mm, use_links=args.links)
|
||||
|
||||
if args.output and result["status"] == "ok":
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with args.output.open("w", encoding="utf-8") as f:
|
||||
json.dump(result, f, indent=2)
|
||||
print(f"\n Saved → {args.output}")
|
||||
|
||||
return 0 if result["status"] == "ok" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
360
pipeline/4_v8_4b_revolute_angle.py
Normal file
360
pipeline/4_v8_4b_revolute_angle.py
Normal file
@@ -0,0 +1,360 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
4b_revolute_angle.py
|
||||
--------------------
|
||||
Generic revolute-joint angle estimator.
|
||||
|
||||
For each movable link (Arm1, Ellbow, Arm2 …) whose joint type is 'revolute',
|
||||
this script estimates the rotation angle using the pairwise-vector method:
|
||||
|
||||
For every PAIR (m1, m2) of markers belonging to the target link:
|
||||
v_model = local_pos_m2 - local_pos_m1 (in link's own frame)
|
||||
v_obs = world_pos_m2 - world_pos_m1 (in world frame)
|
||||
|
||||
Both vectors are projected perpendicular to the joint axis (in world frame),
|
||||
and the signed angle from v_model_perp to v_obs_perp is measured.
|
||||
|
||||
The joint axis in world frame is computed via FK using the already-known
|
||||
joint values (from 4a, 4b-prev …), so it is ALWAYS correct — even for
|
||||
deeply-nested joints whose world-frame axis differs from their local axis.
|
||||
|
||||
Pair weights = baseline_model × baseline_obs (longer baselines → more reliable).
|
||||
|
||||
How to use sequentially
|
||||
-----------------------
|
||||
Run 4b once per revolute joint, from root to tip:
|
||||
|
||||
python 4b_revolute_angle.py --robot r.json --aruco obs.json --link Arm1 --x-mm 180
|
||||
python 4b_revolute_angle.py --robot r.json --aruco obs.json --link Ellbow --from-state state.json
|
||||
python 4b_revolute_angle.py --robot r.json --aruco obs.json --link Arm2 --from-state state.json
|
||||
|
||||
The --from-state flag reads the accumulated joint state JSON so you don't have
|
||||
to pass every preceding value on the command line.
|
||||
|
||||
Output JSON
|
||||
-----------
|
||||
{
|
||||
"link": "Arm1",
|
||||
"joint": "y",
|
||||
"mean_angle_deg": 86.3,
|
||||
"circular_std_deg": 0.7,
|
||||
"num_pairs": 6,
|
||||
"joint_origin_world_mm": [290, 108, 61],
|
||||
"joint_axis_world": [-1, 0, 0],
|
||||
...
|
||||
}
|
||||
|
||||
The file also contains the full accumulated state so the next 4b invocation
|
||||
can read it via --from-state.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import math
|
||||
from itertools import combinations
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
import numpy as np
|
||||
from robot_fk import RobotFK
|
||||
|
||||
STATE_KEYS = ("x", "y", "z", "a", "b", "c", "e")
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# I/O
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _load_json(path: Path) -> dict:
|
||||
with path.open("r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def _load_observed_mm(aruco_json: dict) -> Dict[int, np.ndarray]:
|
||||
result: Dict[int, np.ndarray] = {}
|
||||
for m in aruco_json.get("markers", []):
|
||||
mid = int(m.get("marker_id", m.get("id", -1)))
|
||||
if mid < 0:
|
||||
continue
|
||||
if "position_mm" in m:
|
||||
result[mid] = np.array(m["position_mm"], dtype=float)
|
||||
elif "position_m" in m:
|
||||
result[mid] = np.array(m["position_m"], dtype=float) * 1000.0
|
||||
return result
|
||||
|
||||
|
||||
def _load_state(path: Path) -> Dict[str, float]:
|
||||
"""Load accumulated joint state from a previous 4b output JSON."""
|
||||
raw = _load_json(path)
|
||||
state = raw.get("accumulated_state", raw.get("state", {}))
|
||||
return {k: float(v) for k, v in state.items() if k in STATE_KEYS}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Angle maths
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _project_perp(v: np.ndarray, axis: np.ndarray) -> np.ndarray:
|
||||
"""Remove the component of v along axis."""
|
||||
a = axis / (np.linalg.norm(axis) + 1e-15)
|
||||
return v - np.dot(v, a) * a
|
||||
|
||||
|
||||
def _signed_angle_rad(v_from: np.ndarray, v_to: np.ndarray,
|
||||
axis: np.ndarray) -> float:
|
||||
"""Signed angle rotating v_from onto v_to around axis (radians)."""
|
||||
a = axis / (np.linalg.norm(axis) + 1e-15)
|
||||
return math.atan2(float(np.dot(a, np.cross(v_from, v_to))),
|
||||
float(np.dot(v_from, v_to)))
|
||||
|
||||
|
||||
def _wrap(angle: float) -> float:
|
||||
"""Wrap to (−π, π]."""
|
||||
return (angle + math.pi) % (2.0 * math.pi) - math.pi
|
||||
|
||||
|
||||
def _circular_mean_deg(angles_rad: np.ndarray,
|
||||
weights: np.ndarray) -> Tuple[float, float, float]:
|
||||
"""Returns mean_deg, circular_variance, circular_std_deg."""
|
||||
w = np.clip(weights, 0, None)
|
||||
if w.sum() < 1e-15:
|
||||
w = np.ones_like(w)
|
||||
s, c = np.sum(w * np.sin(angles_rad)), np.sum(w * np.cos(angles_rad))
|
||||
mean = math.atan2(s, c)
|
||||
R = math.sqrt(s*s + c*c) / w.sum()
|
||||
R = float(np.clip(R, 0, 1))
|
||||
c_var = 1.0 - R
|
||||
c_std = math.sqrt(max(0.0, -2.0 * math.log(max(R, 1e-15))))
|
||||
return math.degrees(mean), c_var, math.degrees(c_std)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Core estimator (generic — works for any revolute joint)
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def estimate_revolute_angle(
|
||||
fk: RobotFK,
|
||||
observed_mm: Dict[int, np.ndarray],
|
||||
link_name: str,
|
||||
known_state: Dict[str, float],
|
||||
min_baseline_mm: float = 15.0,
|
||||
verbose: bool = True,
|
||||
) -> dict:
|
||||
"""
|
||||
Estimate the revolute joint angle for `link_name`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fk : RobotFK
|
||||
observed_mm : world marker positions from step 3
|
||||
link_name : e.g. "Arm1", "Ellbow", "Arm2"
|
||||
known_state : already-estimated joint values (e.g. {"x": 180.0, "y": 86.0})
|
||||
The target joint variable should NOT be in this dict.
|
||||
min_baseline_mm : skip pairs with model or observed baseline shorter than this
|
||||
verbose : print report
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict with estimation results + updated accumulated_state
|
||||
"""
|
||||
|
||||
# ── sanity checks ─────────────────────────────────────────
|
||||
links = fk.links
|
||||
if link_name not in links:
|
||||
return {"status": "failed",
|
||||
"reason": f"Link '{link_name}' not in robot.json"}
|
||||
|
||||
ji = links[link_name].get("jointToParent", {}) or {}
|
||||
jtype = str(ji.get("type", "")).lower()
|
||||
if jtype != "revolute":
|
||||
return {"status": "failed",
|
||||
"reason": f"Joint of '{link_name}' is not revolute (type='{jtype}')"}
|
||||
|
||||
var = str(ji.get("variable", "")).lower()
|
||||
|
||||
# ── FK: joint origin and axis in world ───────────────────
|
||||
# Use known_state with the TARGET joint at 0
|
||||
zero_state = dict(known_state)
|
||||
zero_state[var] = 0.0
|
||||
|
||||
origin_world = fk.joint_origin_world(link_name, zero_state)
|
||||
axis_world = fk.joint_axis_world(link_name, zero_state)
|
||||
|
||||
# ── collect matched markers ───────────────────────────────
|
||||
model_local: Dict[int, np.ndarray] = {}
|
||||
for m in links[link_name].get("markers", []):
|
||||
mid = int(m.get("id", -1))
|
||||
if mid >= 0 and "position" in m:
|
||||
model_local[mid] = np.array(m["position"], dtype=float)
|
||||
|
||||
matched = {mid: (model_local[mid], observed_mm[mid])
|
||||
for mid in model_local if mid in observed_mm}
|
||||
|
||||
if len(matched) < 2:
|
||||
return {
|
||||
"status": "failed",
|
||||
"reason": (f"Need ≥2 matched markers, found {len(matched)}: "
|
||||
f"{list(matched.keys())}. "
|
||||
f"Model marker IDs: {list(model_local.keys())}"),
|
||||
}
|
||||
|
||||
# ── pairwise estimation ───────────────────────────────────
|
||||
ids = sorted(matched.keys())
|
||||
angle_rad_list: List[float] = []
|
||||
weight_list: List[float] = []
|
||||
per_pair: List[dict] = []
|
||||
|
||||
for id1, id2 in combinations(ids, 2):
|
||||
l1, o1 = matched[id1]
|
||||
l2, o2 = matched[id2]
|
||||
|
||||
v_model = l2 - l1 # local frame, both in same link
|
||||
v_obs = o2 - o1 # world frame
|
||||
|
||||
v_model_perp = _project_perp(v_model, axis_world)
|
||||
v_obs_perp = _project_perp(v_obs, axis_world)
|
||||
|
||||
bl_model = float(np.linalg.norm(v_model_perp))
|
||||
bl_obs = float(np.linalg.norm(v_obs_perp))
|
||||
|
||||
if bl_model < min_baseline_mm or bl_obs < min_baseline_mm:
|
||||
per_pair.append({
|
||||
"marker_ids": [id1, id2],
|
||||
"skipped": True,
|
||||
"reason": f"bl_model={bl_model:.1f} bl_obs={bl_obs:.1f} < {min_baseline_mm}",
|
||||
})
|
||||
continue
|
||||
|
||||
angle = _wrap(_signed_angle_rad(v_model_perp, v_obs_perp, axis_world))
|
||||
w = bl_model * bl_obs
|
||||
|
||||
angle_rad_list.append(angle)
|
||||
weight_list.append(w)
|
||||
per_pair.append({
|
||||
"marker_ids": [id1, id2],
|
||||
"skipped": False,
|
||||
"angle_deg": math.degrees(angle),
|
||||
"baseline_model_mm": bl_model,
|
||||
"baseline_obs_mm": bl_obs,
|
||||
"weight": w,
|
||||
})
|
||||
|
||||
if not angle_rad_list:
|
||||
return {
|
||||
"status": "failed",
|
||||
"reason": "All pairs below min_baseline_mm. "
|
||||
"Try --min-baseline 5 or check step-3 output.",
|
||||
}
|
||||
|
||||
mean_deg, c_var, c_std_deg = _circular_mean_deg(
|
||||
np.array(angle_rad_list), np.array(weight_list)
|
||||
)
|
||||
|
||||
# ── verbose report ────────────────────────────────────────
|
||||
if verbose:
|
||||
print(f"\n── 4b: '{link_name}' angle ({var}) ──────────────────────")
|
||||
print(f" Joint origin (world): [{', '.join(f'{v:.1f}' for v in origin_world)}] mm")
|
||||
print(f" Joint axis (world): [{', '.join(f'{v:.3f}' for v in axis_world)}]")
|
||||
print(f" Matched markers: {list(matched.keys())}")
|
||||
print(f" Pairs used: {len(angle_rad_list)} / {len(list(combinations(ids, 2)))}")
|
||||
print(f" Angle: {mean_deg:+.2f} ° circular_σ {c_std_deg:.2f} °")
|
||||
if c_std_deg > 5.0:
|
||||
print(f" [WARN] high spread – step-3 errors or marker overlap")
|
||||
print(f"\n Pair detail:")
|
||||
for pp in per_pair:
|
||||
if pp["skipped"]:
|
||||
print(f" M{pp['marker_ids'][0]}↔M{pp['marker_ids'][1]}: SKIPPED – {pp['reason']}")
|
||||
else:
|
||||
print(f" M{pp['marker_ids'][0]}↔M{pp['marker_ids'][1]}: "
|
||||
f"{pp['angle_deg']:+7.2f}° "
|
||||
f"bl_model={pp['baseline_model_mm']:.1f} "
|
||||
f"bl_obs={pp['baseline_obs_mm']:.1f}")
|
||||
|
||||
# ── build accumulated state ───────────────────────────────
|
||||
accumulated = dict(known_state)
|
||||
accumulated[var] = mean_deg
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"link": link_name,
|
||||
"joint": var,
|
||||
"joint_origin_world_mm": origin_world.tolist(),
|
||||
"joint_axis_world": axis_world.tolist(),
|
||||
"mean_angle_deg": mean_deg,
|
||||
"circular_variance": c_var,
|
||||
"circular_std_deg": c_std_deg,
|
||||
"num_pairs_used": len(angle_rad_list),
|
||||
"num_markers_matched": len(matched),
|
||||
"per_pair": per_pair,
|
||||
"accumulated_state": accumulated,
|
||||
}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# CLI
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def main() -> int:
|
||||
p = argparse.ArgumentParser(
|
||||
description="4b: estimate revolute joint angle for any link")
|
||||
p.add_argument("--robot", type=Path, default=Path("robot.json"))
|
||||
p.add_argument("--aruco", type=Path,
|
||||
default=Path("aruco_positions_optimized.json"))
|
||||
p.add_argument("--link", type=str, required=True,
|
||||
help="Link name, e.g. Arm1, Ellbow, Arm2")
|
||||
p.add_argument("--from-state", type=Path, default=None,
|
||||
help="JSON from a previous 4b run (carries accumulated state)")
|
||||
|
||||
# Manual joint-value overrides (for use without --from-state)
|
||||
for k in STATE_KEYS:
|
||||
p.add_argument(f"--{k}-mm" if k in ("x", "e") else f"--{k}-deg",
|
||||
type=float, default=None,
|
||||
help=f"Known value for joint '{k}'"
|
||||
+ (" (mm)" if k in ("x", "e") else " (deg)"))
|
||||
|
||||
p.add_argument("--min-baseline", type=float, default=15.0,
|
||||
help="Skip pairs with perpendicular baseline < this (mm)")
|
||||
p.add_argument("--output", type=Path, default=None,
|
||||
help="Save result JSON (readable by next 4b as --from-state)")
|
||||
args = p.parse_args()
|
||||
|
||||
# Assemble known state
|
||||
if args.from_state:
|
||||
known_state = _load_state(args.from_state)
|
||||
print(f" Loaded state from {args.from_state}: {known_state}")
|
||||
else:
|
||||
known_state = {}
|
||||
|
||||
# CLI overrides
|
||||
for k in STATE_KEYS:
|
||||
attr = f"{k}_mm" if k in ("x", "e") else f"{k}_deg"
|
||||
v = getattr(args, attr, None)
|
||||
if v is not None:
|
||||
known_state[k] = float(v)
|
||||
|
||||
fk = RobotFK.from_file(args.robot)
|
||||
aruco_json = _load_json(args.aruco)
|
||||
observed_mm = _load_observed_mm(aruco_json)
|
||||
|
||||
result = estimate_revolute_angle(
|
||||
fk = fk,
|
||||
observed_mm = observed_mm,
|
||||
link_name = args.link,
|
||||
known_state = known_state,
|
||||
min_baseline_mm = args.min_baseline,
|
||||
verbose = True,
|
||||
)
|
||||
|
||||
if args.output and result["status"] == "ok":
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with args.output.open("w", encoding="utf-8") as f:
|
||||
json.dump(result, f, indent=2)
|
||||
print(f"\n Saved → {args.output}")
|
||||
|
||||
return 0 if result["status"] == "ok" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
464
pipeline/4_v8_4d_direct_hand_pose.py
Normal file
464
pipeline/4_v8_4d_direct_hand_pose.py
Normal file
@@ -0,0 +1,464 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
4d_direct_hand_pose.py
|
||||
----------------------
|
||||
Estimate Hand/Palm/Finger joint angles (b, c, e) directly from ArUco
|
||||
marker observations — WITHOUT relying on step-3 triangulated positions.
|
||||
|
||||
Why this is needed
|
||||
------------------
|
||||
Step 3 triangulates marker centres from multiple cameras. For markers
|
||||
far above the board (arm extended in Z), the depth estimation from
|
||||
triangulation degrades: all reference Board markers lie in a flat plane,
|
||||
so the cameras are poorly conditioned for Z estimation of out-of-plane points.
|
||||
|
||||
This script takes a completely different route:
|
||||
|
||||
1. For each camera that sees a finger or hand marker, run cv2.solvePnP
|
||||
on the four detected corners. solvePnP uses the apparent size /
|
||||
aspect ratio of the marker to recover depth — it is NOT affected
|
||||
by the flat-board reference plane problem.
|
||||
|
||||
2. Use the known camera-in-world pose (from step 2) to convert the
|
||||
per-camera marker pose to world frame.
|
||||
|
||||
3. Fuse all world-frame marker poses with quality weighting.
|
||||
|
||||
4. Given world-frame positions for all visible finger markers, and the
|
||||
known local positions in the FingerA/FingerB frames, solve a small
|
||||
nonlinear LS problem for (b, c, e) using scipy.
|
||||
|
||||
What you need
|
||||
-------------
|
||||
- robot.json
|
||||
- Step-2 camera-pose JSONs for all cameras
|
||||
- Step-1 aruco-detection JSONs for all cameras
|
||||
- Already-estimated x, y, z, a from 4a/4b (pass via --state-json or CLI)
|
||||
|
||||
Usage
|
||||
-----
|
||||
python 4d_direct_hand_pose.py \\
|
||||
--robot robot.json \\
|
||||
--det cam1_aruco_detection.json cam2_aruco_detection.json ... \\
|
||||
--pose cam1_camera_pose.json cam2_camera_pose.json ... \\
|
||||
--state 4b_arm2_result.json \\
|
||||
--output 4d_result.json
|
||||
|
||||
Output
|
||||
------
|
||||
{
|
||||
"b_deg": ..., "c_deg": ..., "e_mm": ...,
|
||||
"rms_mm": ...,
|
||||
"accumulated_state": {"x":..., "y":..., "z":..., "a":..., "b":..., "c":..., "e":...}
|
||||
}
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
from scipy.optimize import least_squares
|
||||
_HAS_SCIPY = True
|
||||
except ImportError:
|
||||
_HAS_SCIPY = False
|
||||
|
||||
from robot_fk import RobotFK, STATE_KEYS
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# I/O
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _load(path: Path) -> dict:
|
||||
with path.open("r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def _load_state(path: Path) -> Dict[str, float]:
|
||||
raw = _load(path)
|
||||
state = raw.get("accumulated_state", raw.get("state", {}))
|
||||
return {k: float(v) for k, v in state.items() if k in STATE_KEYS}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# ArUco / PnP helpers
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _marker_local_corners(size_m: float) -> np.ndarray:
|
||||
"""Four local corners of a marker (same order as OpenCV ArUco)."""
|
||||
h = size_m / 2.0
|
||||
return np.array([[-h, h, 0], [h, h, 0], [h, -h, 0], [-h, -h, 0]], dtype=np.float32)
|
||||
|
||||
|
||||
def _camera_pose_from_json(pose_json: dict) -> Tuple[np.ndarray, np.ndarray]:
|
||||
"""
|
||||
Load world-to-camera rotation and translation from step-2 JSON.
|
||||
Returns rvec (3,), tvec (3,) — the same convention used in step 2.
|
||||
"""
|
||||
wtc = pose_json["camera_pose"]["world_to_camera"]
|
||||
R = np.array(wtc["rotation_matrix"], dtype=np.float32).reshape(3, 3)
|
||||
t = np.array(wtc["translation_m"], dtype=np.float32).reshape(3)
|
||||
rvec, _ = cv2.Rodrigues(R)
|
||||
return rvec.reshape(3), t
|
||||
|
||||
|
||||
def _intrinsics_from_detection(det: dict) -> Tuple[np.ndarray, np.ndarray]:
|
||||
cam = det["camera"]
|
||||
K = np.array(cam["camera_matrix"], dtype=np.float32).reshape(3, 3)
|
||||
D = np.array(cam["distortion_coefficients"], dtype=np.float32).reshape(-1, 1)
|
||||
return K, D
|
||||
|
||||
|
||||
def _solve_marker_pose_in_camera(
|
||||
corners_px: np.ndarray,
|
||||
marker_size_m: float,
|
||||
K: np.ndarray,
|
||||
D: np.ndarray
|
||||
) -> Optional[Tuple[np.ndarray, np.ndarray]]:
|
||||
"""
|
||||
Estimate marker-in-camera pose via solvePnP (IPPE_SQUARE).
|
||||
Returns (rvec_cm, tvec_cm) or None on failure.
|
||||
"""
|
||||
obj = _marker_local_corners(marker_size_m)
|
||||
img = corners_px.astype(np.float32)
|
||||
ok, rvec, tvec = cv2.solvePnP(obj, img, K, D, flags=cv2.SOLVEPNP_IPPE_SQUARE)
|
||||
if not ok:
|
||||
ok, rvec, tvec = cv2.solvePnP(obj, img, K, D, flags=cv2.SOLVEPNP_ITERATIVE)
|
||||
if not ok:
|
||||
return None
|
||||
return rvec.reshape(3), tvec.reshape(3)
|
||||
|
||||
|
||||
def _marker_world_pose(
|
||||
rvec_cm: np.ndarray,
|
||||
tvec_cm: np.ndarray,
|
||||
rvec_wc: np.ndarray,
|
||||
tvec_wc: np.ndarray
|
||||
) -> Tuple[np.ndarray, np.ndarray]:
|
||||
"""
|
||||
Convert marker-in-camera pose to marker-in-world pose.
|
||||
|
||||
Convention (same as step 2):
|
||||
X_cam = R_wc @ X_world + t_wc
|
||||
So:
|
||||
R_wc = rvec→R(rvec_wc), camera origin in world = -R_wc^T @ t_wc
|
||||
|
||||
Marker pose in world:
|
||||
R_mw = R_wc^T @ R_cm (world_to_marker rotation)
|
||||
t_mw = R_wc^T @ (tvec_cm - tvec_wc)
|
||||
→ marker centre in world = -R_mw^T @ t_mw = R_mw^T @ (-t_mw)
|
||||
|
||||
We return (pos_world_m, R_marker_in_world) where
|
||||
R_marker_in_world maps local marker axes to world axes.
|
||||
"""
|
||||
R_wc, _ = cv2.Rodrigues(rvec_wc.reshape(3, 1))
|
||||
R_cm, _ = cv2.Rodrigues(rvec_cm.reshape(3, 1))
|
||||
|
||||
R_cw = R_wc.T # camera-to-world rotation
|
||||
|
||||
# Marker centre in world frame
|
||||
pos_w = R_cw @ tvec_cm.reshape(3) - R_cw @ tvec_wc.reshape(3)
|
||||
|
||||
# Marker orientation in world frame (columns = marker x,y,z axes in world)
|
||||
R_mw = R_cw @ R_cm
|
||||
|
||||
return pos_w.astype(np.float64), R_mw.astype(np.float64)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Multi-camera marker pose fusion
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _observation_weight(corners_px: np.ndarray, img_w: int, img_h: int) -> float:
|
||||
"""
|
||||
Simple quality weight: larger markers, more central = higher weight.
|
||||
"""
|
||||
area = float(cv2.contourArea(corners_px.astype(np.float32)))
|
||||
cx, cy = corners_px.mean(axis=0)
|
||||
dx = abs(cx - img_w / 2.0) / (img_w / 2.0)
|
||||
dy = abs(cy - img_h / 2.0) / (img_h / 2.0)
|
||||
centrality = 1.0 - 0.5 * (dx + dy)
|
||||
return max(0.05, (area / 500.0) * centrality)
|
||||
|
||||
|
||||
def collect_marker_world_poses(
|
||||
detection_files: List[Path],
|
||||
pose_files: List[Path],
|
||||
target_marker_ids: set,
|
||||
marker_size_m: float,
|
||||
verbose: bool = True,
|
||||
) -> Dict[int, List[Dict[str, Any]]]:
|
||||
"""
|
||||
For each target marker, collect world-frame pose estimates from all cameras.
|
||||
|
||||
Returns: marker_id → list of {pos_m, R, weight, camera_id}
|
||||
"""
|
||||
result: Dict[int, List[Dict[str, Any]]] = {}
|
||||
|
||||
for det_path, pose_path in zip(detection_files, pose_files):
|
||||
det = _load(det_path)
|
||||
pose_json = _load(pose_path)
|
||||
|
||||
K, D = _intrinsics_from_detection(det)
|
||||
rvec_wc, tvec_wc = _camera_pose_from_json(pose_json)
|
||||
|
||||
cam_id = det.get("camera", {}).get("camera_id", str(det_path))
|
||||
img_w = int(det.get("image", {}).get("width_px", 1280))
|
||||
img_h = int(det.get("image", {}).get("height_px", 720))
|
||||
|
||||
for d in det.get("detections", []):
|
||||
mid = int(d.get("marker_id", -1))
|
||||
if mid not in target_marker_ids:
|
||||
continue
|
||||
corners = np.array(d.get("image_points_px", []), dtype=np.float32).reshape(4, 2)
|
||||
if corners.shape != (4, 2):
|
||||
continue
|
||||
|
||||
pnp = _solve_marker_pose_in_camera(corners, marker_size_m, K, D)
|
||||
if pnp is None:
|
||||
continue
|
||||
rvec_cm, tvec_cm = pnp
|
||||
|
||||
pos_w, R_w = _marker_world_pose(rvec_cm, tvec_cm, rvec_wc, tvec_wc)
|
||||
w = _observation_weight(corners, img_w, img_h)
|
||||
|
||||
result.setdefault(mid, []).append({
|
||||
"pos_m": pos_w,
|
||||
"R": R_w,
|
||||
"weight": w,
|
||||
"camera_id": cam_id,
|
||||
})
|
||||
|
||||
if verbose:
|
||||
for mid, obs in result.items():
|
||||
print(f" M{mid}: {len(obs)} camera(s) — weights "
|
||||
f"{[f'{o[\"weight\"]:.2f}' for o in obs]}")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def fuse_marker_positions(
|
||||
observations: Dict[int, List[Dict[str, Any]]]
|
||||
) -> Dict[int, np.ndarray]:
|
||||
"""
|
||||
Weighted-mean fusion of world-frame marker centre positions (metres).
|
||||
"""
|
||||
result: Dict[int, np.ndarray] = {}
|
||||
for mid, obs_list in observations.items():
|
||||
total_w = sum(o["weight"] for o in obs_list)
|
||||
if total_w < 1e-12:
|
||||
continue
|
||||
pos = sum(o["pos_m"] * o["weight"] for o in obs_list) / total_w
|
||||
result[mid] = pos.astype(np.float64)
|
||||
return result
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# FK-based optimizer for b, c, e
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _fk_finger_positions(
|
||||
fk: RobotFK,
|
||||
base_state: Dict[str, float],
|
||||
b: float,
|
||||
c: float,
|
||||
e: float
|
||||
) -> Dict[int, np.ndarray]:
|
||||
"""
|
||||
Compute world positions (m) of all FingerA and FingerB markers.
|
||||
base_state already contains x, y, z, a.
|
||||
"""
|
||||
state = dict(base_state)
|
||||
state.update({"b": b, "c": c, "e": e})
|
||||
transforms = fk.compute(state)
|
||||
result = {}
|
||||
for link_name in ("FingerA", "FingerB", "Hand", "Palm"):
|
||||
if link_name not in fk.links:
|
||||
continue
|
||||
for m in fk.links[link_name].get("markers", []):
|
||||
mid = int(m.get("id", -1))
|
||||
if mid < 0 or "position" not in m:
|
||||
continue
|
||||
# position in METRES
|
||||
local_mm = np.array(m["position"], dtype=float)
|
||||
world_m = fk.marker_world(transforms, link_name, local_mm) / 1000.0
|
||||
result[mid] = world_m
|
||||
return result
|
||||
|
||||
|
||||
def optimize_bce(
|
||||
fk: RobotFK,
|
||||
base_state: Dict[str, float],
|
||||
observed_m: Dict[int, np.ndarray],
|
||||
b_init: float = 0.0,
|
||||
c_init: float = 0.0,
|
||||
e_init: float = 0.0,
|
||||
verbose: bool = True,
|
||||
) -> dict:
|
||||
"""
|
||||
Find (b, c, e) minimising reprojection of FK finger-marker positions
|
||||
to observed world positions.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fk : RobotFK
|
||||
base_state : already-estimated {x, y, z, a} (all in mm/deg)
|
||||
observed_m : {marker_id: world_position_m}
|
||||
"""
|
||||
|
||||
if not _HAS_SCIPY:
|
||||
return {"status": "failed", "reason": "scipy not available (pip install scipy)"}
|
||||
|
||||
def residuals(p):
|
||||
b, c, e = float(p[0]), float(p[1]), float(p[2])
|
||||
fk_pos = _fk_finger_positions(fk, base_state, b, c, e)
|
||||
r = []
|
||||
for mid, obs_p in observed_m.items():
|
||||
if mid in fk_pos:
|
||||
diff = fk_pos[mid] - obs_p
|
||||
r.extend(diff.tolist())
|
||||
return r
|
||||
|
||||
# Initial residual
|
||||
r0 = residuals([b_init, c_init, e_init])
|
||||
if len(r0) < 3:
|
||||
return {
|
||||
"status": "failed",
|
||||
"reason": f"Only {len(r0)//3} finger markers matched. Need ≥1.",
|
||||
}
|
||||
|
||||
res = least_squares(
|
||||
residuals,
|
||||
x0=[b_init, c_init, e_init],
|
||||
method="lm",
|
||||
max_nfev=2000,
|
||||
)
|
||||
|
||||
b_est, c_est, e_est = float(res.x[0]), float(res.x[1]), float(res.x[2])
|
||||
|
||||
rms_m = float(np.sqrt(np.mean(np.array(res.fun) ** 2)))
|
||||
rms_mm = rms_m * 1000.0
|
||||
|
||||
accum = dict(base_state)
|
||||
accum.update({"b": b_est, "c": c_est, "e": e_est})
|
||||
|
||||
if verbose:
|
||||
print(f"\n── 4d: Hand/Palm/Finger (b, c, e) ──────────────────────")
|
||||
print(f" Markers used: {len(observed_m)} fused positions")
|
||||
print(f" b = {b_est:+.2f} ° c = {c_est:+.2f} ° e = {e_est:+.2f} mm")
|
||||
print(f" RMS position error: {rms_mm:.2f} mm")
|
||||
if not res.success:
|
||||
print(f" [WARN] Optimizer: {res.message}")
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"b_deg": b_est,
|
||||
"c_deg": c_est,
|
||||
"e_mm": e_est,
|
||||
"rms_mm": rms_mm,
|
||||
"optimizer_success": bool(res.success),
|
||||
"num_markers": len(observed_m),
|
||||
"accumulated_state": accum,
|
||||
}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Main
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def main() -> int:
|
||||
p = argparse.ArgumentParser(
|
||||
description="4d: Direct hand/finger pose from per-camera solvePnP")
|
||||
p.add_argument("--robot", type=Path, required=True)
|
||||
p.add_argument("--det", "-d", type=Path, nargs="+", required=True,
|
||||
help="*_aruco_detection.json files (one per camera)")
|
||||
p.add_argument("--pose", "-p", type=Path, nargs="+", required=True,
|
||||
help="*_camera_pose.json files (same order as --det)")
|
||||
p.add_argument("--state", type=Path, default=None,
|
||||
help="JSON from previous 4b step (accumulated_state)")
|
||||
for k in ("x", "y", "z", "a"):
|
||||
p.add_argument(f"--{k}", type=float, default=None,
|
||||
help=f"Known {k} value (overrides --state)")
|
||||
p.add_argument("--b-init", type=float, default=0.0)
|
||||
p.add_argument("--c-init", type=float, default=0.0)
|
||||
p.add_argument("--e-init", type=float, default=0.0)
|
||||
p.add_argument("--output", type=Path, default=None)
|
||||
args = p.parse_args()
|
||||
|
||||
if len(args.det) != len(args.pose):
|
||||
print("[ERROR] --det and --pose must have the same number of files")
|
||||
return 1
|
||||
|
||||
# Base state from file or CLI
|
||||
base_state: Dict[str, float] = {}
|
||||
if args.state:
|
||||
base_state = _load_state(args.state)
|
||||
print(f" Loaded state: {base_state}")
|
||||
for k in ("x", "y", "z", "a"):
|
||||
v = getattr(args, k, None)
|
||||
if v is not None:
|
||||
base_state[k] = float(v)
|
||||
|
||||
# Load FK
|
||||
fk = RobotFK.from_file(args.robot)
|
||||
|
||||
# Which markers belong to Hand/Palm/FingerA/FingerB?
|
||||
target_ids: set = set()
|
||||
for link_name in ("Hand", "Palm", "FingerA", "FingerB"):
|
||||
for m in fk.links.get(link_name, {}).get("markers", []):
|
||||
mid = int(m.get("id", -1))
|
||||
if mid >= 0:
|
||||
target_ids.add(mid)
|
||||
|
||||
marker_size_m = float(
|
||||
fk.robot.get("vision_config", {}).get("MarkerSize", 0.025)
|
||||
)
|
||||
|
||||
print(f"\n Target marker IDs: {sorted(target_ids)}")
|
||||
print(f" Marker size: {marker_size_m*1000:.1f} mm")
|
||||
print(f" Cameras: {len(args.det)}")
|
||||
|
||||
# Collect world-frame poses from all cameras via solvePnP
|
||||
print("\n Per-camera solvePnP:")
|
||||
world_pose_obs = collect_marker_world_poses(
|
||||
args.det, args.pose, target_ids, marker_size_m, verbose=True
|
||||
)
|
||||
|
||||
if not world_pose_obs:
|
||||
print("[ERROR] No target markers found in any detection file.")
|
||||
return 1
|
||||
|
||||
# Fuse positions
|
||||
observed_m = fuse_marker_positions(world_pose_obs)
|
||||
print(f"\n Fused {len(observed_m)} marker world positions")
|
||||
|
||||
# Optimise b, c, e
|
||||
result = optimize_bce(
|
||||
fk = fk,
|
||||
base_state = base_state,
|
||||
observed_m = observed_m,
|
||||
b_init = args.b_init,
|
||||
c_init = args.c_init,
|
||||
e_init = args.e_init,
|
||||
verbose = True,
|
||||
)
|
||||
|
||||
if args.output and result["status"] == "ok":
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with args.output.open("w", encoding="utf-8") as f:
|
||||
json.dump(result, f, indent=2)
|
||||
print(f"\n Saved → {args.output}")
|
||||
|
||||
return 0 if result["status"] == "ok" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Binary file not shown.
BIN
pipeline/__pycache__/robot_fk.cpython-311.pyc
Normal file
BIN
pipeline/__pycache__/robot_fk.cpython-311.pyc
Normal file
Binary file not shown.
310
pipeline/robot_fk.py
Normal file
310
pipeline/robot_fk.py
Normal file
@@ -0,0 +1,310 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
robot_fk.py
|
||||
-----------
|
||||
Minimal forward kinematics engine for the robot.json format.
|
||||
|
||||
Matches the Blender hierarchy used by render_robot.py exactly:
|
||||
world_T_link = world_T_parent
|
||||
@ Translate(mountPosition) @ Rotate_xyz(mountRotation)
|
||||
@ Translate(jointOrigin) @ Rotate_xyz(joint.rotation)
|
||||
@ T_motion
|
||||
|
||||
T_motion = Rotate(axis, value_deg) for revolute joints
|
||||
Translate(axis * value_mm) for linear joints
|
||||
|
||||
Units throughout: millimetres, degrees.
|
||||
|
||||
Public API
|
||||
----------
|
||||
fk = RobotFK.from_file("robot.json")
|
||||
|
||||
transforms = fk.compute({"x": 180, "y": 86, "z": -120,
|
||||
"a": -60, "b": 22, "c": 91, "e": 10})
|
||||
# → dict link_name -> 4×4 np.ndarray (world frame, mm)
|
||||
|
||||
p_world = fk.marker_world(transforms, "Arm1", [0, -160, 35])
|
||||
# → np.ndarray shape (3,), in mm
|
||||
|
||||
all_m = fk.all_markers_world(transforms)
|
||||
# → dict marker_id -> {"world_mm", "link", "local_mm"}
|
||||
|
||||
# Cumulative x-offset for a link at all-zero state
|
||||
# (useful for 4a: x_slider = world_x - local_x - link_x_at_zero)
|
||||
x0 = fk.link_x_at_zero_state("Arm1") # → float mm
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
STATE_KEYS = ("x", "y", "z", "a", "b", "c", "e")
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Low-level matrix helpers
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _rot_axis_angle(axis: Sequence[float], angle_deg: float) -> np.ndarray:
|
||||
"""3×3 rotation matrix via Rodrigues (axis need not be normalised)."""
|
||||
ax = np.asarray(axis, dtype=float)
|
||||
n = float(np.linalg.norm(ax))
|
||||
if n < 1e-12:
|
||||
return np.eye(3)
|
||||
ax = ax / n
|
||||
c = math.cos(math.radians(angle_deg))
|
||||
s = math.sin(math.radians(angle_deg))
|
||||
t = 1.0 - c
|
||||
x, y, z = ax
|
||||
return np.array([
|
||||
[t*x*x + c, t*x*y - s*z, t*x*z + s*y],
|
||||
[t*x*y + s*z, t*y*y + c, t*y*z - s*x],
|
||||
[t*x*z - s*y, t*y*z + s*x, t*z*z + c ],
|
||||
])
|
||||
|
||||
|
||||
def _rot_xyz_euler(rx: float, ry: float, rz: float) -> np.ndarray:
|
||||
"""XYZ Euler angles (degrees) → 3×3 — matches Blender XYZ Euler mode."""
|
||||
return (_rot_axis_angle([0, 0, 1], rz)
|
||||
@ _rot_axis_angle([0, 1, 0], ry)
|
||||
@ _rot_axis_angle([1, 0, 0], rx))
|
||||
|
||||
|
||||
def make_T(R: np.ndarray, t: Sequence[float]) -> np.ndarray:
|
||||
"""4×4 homogeneous transform."""
|
||||
T = np.eye(4)
|
||||
T[:3, :3] = R
|
||||
T[:3, 3] = np.asarray(t, dtype=float)
|
||||
return T
|
||||
|
||||
|
||||
def transform_point(T: np.ndarray, p: Sequence[float]) -> np.ndarray:
|
||||
"""Apply 4×4 transform to a 3-D point."""
|
||||
h = np.array([p[0], p[1], p[2], 1.0])
|
||||
return (T @ h)[:3]
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# FK engine
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
class RobotFK:
|
||||
"""Forward kinematics for the robot.json format."""
|
||||
|
||||
def __init__(self, robot_data: Dict[str, Any]):
|
||||
self.robot = robot_data
|
||||
self.links: Dict[str, Any] = robot_data.get("links", {})
|
||||
self._topo: List[str] = self._topological_sort()
|
||||
|
||||
# ── construction ─────────────────────────────────────────
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, path) -> "RobotFK":
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return cls(json.load(f))
|
||||
|
||||
def _topological_sort(self) -> List[str]:
|
||||
parent_map = {n: d.get("parent") for n, d in self.links.items()}
|
||||
visited, order = set(), []
|
||||
|
||||
def visit(name: str) -> None:
|
||||
if name in visited:
|
||||
return
|
||||
visited.add(name)
|
||||
p = parent_map.get(name)
|
||||
if p and p in self.links:
|
||||
visit(p)
|
||||
order.append(name)
|
||||
|
||||
for name in self.links:
|
||||
visit(name)
|
||||
return order
|
||||
|
||||
# ── core computation ──────────────────────────────────────
|
||||
|
||||
def compute(self, joint_values: Dict[str, float]) -> Dict[str, np.ndarray]:
|
||||
"""
|
||||
Compute link world transforms for the given joint state.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
joint_values : dict variable_name -> value
|
||||
Linear joints (x, e): mm
|
||||
Revolute joints (y, z, a, b, c): degrees
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict link_name -> 4×4 np.ndarray (world frame, mm)
|
||||
"""
|
||||
state = {k: 0.0 for k in STATE_KEYS}
|
||||
for k, v in joint_values.items():
|
||||
if k in state:
|
||||
state[k] = float(v)
|
||||
|
||||
transforms: Dict[str, np.ndarray] = {}
|
||||
|
||||
for link_name in self._topo:
|
||||
d = self.links[link_name]
|
||||
parent = d.get("parent")
|
||||
T_parent = transforms.get(parent, np.eye(4)) if parent else np.eye(4)
|
||||
|
||||
# 1 · Mount (static in parent frame)
|
||||
mp = d.get("mountPosition", [0, 0, 0])
|
||||
mr = d.get("mountRotation", [0, 0, 0])
|
||||
T_m = make_T(_rot_xyz_euler(*mr), mp)
|
||||
|
||||
# 2 · Joint origin (pivot point in mount frame)
|
||||
ji = d.get("jointToParent", {}) or {}
|
||||
jp = ji.get("origin", [0, 0, 0])
|
||||
jr = ji.get("rotation", [0, 0, 0])
|
||||
T_j = make_T(_rot_xyz_euler(*jr), jp)
|
||||
|
||||
# 3 · Motion
|
||||
jtype = str(ji.get("type", "fixed")).lower()
|
||||
var = str(ji.get("variable", "")).lower()
|
||||
axis = np.asarray(ji.get("axis", [1, 0, 0]), dtype=float)
|
||||
val = state.get(var, 0.0)
|
||||
|
||||
if jtype == "revolute":
|
||||
T_mot = make_T(_rot_axis_angle(axis, val), [0, 0, 0])
|
||||
elif jtype == "linear":
|
||||
n = float(np.linalg.norm(axis))
|
||||
u = axis / n if n > 1e-12 else np.array([1.0, 0, 0])
|
||||
T_mot = make_T(np.eye(3), u * val)
|
||||
else:
|
||||
T_mot = np.eye(4)
|
||||
|
||||
transforms[link_name] = T_parent @ T_m @ T_j @ T_mot
|
||||
|
||||
return transforms
|
||||
|
||||
# ── marker helpers ────────────────────────────────────────
|
||||
|
||||
@staticmethod
|
||||
def marker_world(transforms: Dict[str, np.ndarray],
|
||||
link_name: str,
|
||||
local_pos: Sequence[float]) -> np.ndarray:
|
||||
"""Transform a local marker position → world (mm)."""
|
||||
return transform_point(transforms.get(link_name, np.eye(4)), local_pos)
|
||||
|
||||
def all_markers_world(self,
|
||||
transforms: Dict[str, np.ndarray]
|
||||
) -> Dict[int, Dict[str, Any]]:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
dict marker_id -> {world_mm, local_mm, link, normal_world}
|
||||
"""
|
||||
result: Dict[int, Dict[str, Any]] = {}
|
||||
for lname, ldata in self.links.items():
|
||||
T = transforms.get(lname, np.eye(4))
|
||||
R = T[:3, :3]
|
||||
for m in ldata.get("markers", []):
|
||||
mid = int(m.get("id", -1))
|
||||
if mid < 0 or "position" not in m:
|
||||
continue
|
||||
loc = np.array(m["position"], dtype=float)
|
||||
nor = np.array(m.get("normal", [0, 0, 1]), dtype=float)
|
||||
result[mid] = {
|
||||
"world_mm": transform_point(T, loc),
|
||||
"local_mm": loc,
|
||||
"link": lname,
|
||||
"normal_world": (R @ nor) / max(np.linalg.norm(R @ nor), 1e-12),
|
||||
}
|
||||
return result
|
||||
|
||||
# ── x-axis invariant helpers (used by 4a) ────────────────
|
||||
|
||||
def link_x_at_zero_state(self, link_name: str) -> float:
|
||||
"""
|
||||
Return the world x-coordinate of the link-frame origin
|
||||
when ALL joint variables are zero.
|
||||
|
||||
For any link reachable via only x-axis rotations (Arm1, Ellbow, Arm2),
|
||||
this value is constant regardless of the actual revolute angles.
|
||||
Adding the slider value x_mm gives the true link origin x:
|
||||
link_origin_world_x = x_mm + link_x_at_zero_state(link_name)
|
||||
|
||||
And for any marker in that link:
|
||||
marker_world_x = x_mm + link_x_at_zero_state(link_name) + marker_local_x
|
||||
"""
|
||||
T = self.compute({k: 0.0 for k in STATE_KEYS})
|
||||
return float(T[link_name][0, 3])
|
||||
|
||||
def joint_origin_world(self,
|
||||
link_name: str,
|
||||
joint_state: Dict[str, float]) -> np.ndarray:
|
||||
"""
|
||||
World position of the pivot that link_name rotates / slides around.
|
||||
"""
|
||||
d = self.links[link_name]
|
||||
parent = d.get("parent")
|
||||
T_all = self.compute(joint_state)
|
||||
T_parent = T_all.get(parent, np.eye(4)) if parent else np.eye(4)
|
||||
|
||||
mp = d.get("mountPosition", [0, 0, 0])
|
||||
mr = d.get("mountRotation", [0, 0, 0])
|
||||
T_m = make_T(_rot_xyz_euler(*mr), mp)
|
||||
|
||||
ji = d.get("jointToParent", {}) or {}
|
||||
jp = ji.get("origin", [0, 0, 0])
|
||||
jr = ji.get("rotation", [0, 0, 0])
|
||||
T_j = make_T(_rot_xyz_euler(*jr), jp)
|
||||
|
||||
return transform_point(T_parent @ T_m @ T_j, [0, 0, 0])
|
||||
|
||||
def joint_axis_world(self,
|
||||
link_name: str,
|
||||
joint_state: Dict[str, float]) -> np.ndarray:
|
||||
"""
|
||||
Joint axis of link_name expressed in world frame.
|
||||
"""
|
||||
d = self.links[link_name]
|
||||
parent = d.get("parent")
|
||||
T_all = self.compute(joint_state)
|
||||
T_parent = T_all.get(parent, np.eye(4)) if parent else np.eye(4)
|
||||
|
||||
mp = d.get("mountPosition", [0, 0, 0])
|
||||
mr = d.get("mountRotation", [0, 0, 0])
|
||||
T_m = make_T(_rot_xyz_euler(*mr), mp)
|
||||
|
||||
ji = d.get("jointToParent", {}) or {}
|
||||
jp = ji.get("origin", [0, 0, 0])
|
||||
jr = ji.get("rotation", [0, 0, 0])
|
||||
T_j = make_T(_rot_xyz_euler(*jr), jp)
|
||||
|
||||
R_to_pivot = (T_parent @ T_m @ T_j)[:3, :3]
|
||||
axis_local = np.asarray(ji.get("axis", [1, 0, 0]), dtype=float)
|
||||
world = R_to_pivot @ axis_local
|
||||
n = float(np.linalg.norm(world))
|
||||
return world / n if n > 1e-12 else world
|
||||
|
||||
# ── utility ───────────────────────────────────────────────
|
||||
|
||||
def chain(self, link_name: str) -> List[str]:
|
||||
"""Return chain from root to link_name (inclusive)."""
|
||||
out, cur = [], link_name
|
||||
while cur:
|
||||
out.append(cur)
|
||||
cur = self.links.get(cur, {}).get("parent")
|
||||
return list(reversed(out))
|
||||
|
||||
def board_marker_world_positions(self, length_scale: float = 1.0) -> Dict[int, np.ndarray]:
|
||||
"""
|
||||
Return known world positions for all Board markers (in mm).
|
||||
Board is the root, so its marker positions ARE world positions.
|
||||
length_scale: 1/1000 if robot.json uses mm.
|
||||
"""
|
||||
board = self.links.get("Board", {})
|
||||
result: Dict[int, np.ndarray] = {}
|
||||
for m in board.get("markers", []):
|
||||
mid = int(m.get("id", -1))
|
||||
if mid >= 0 and "position" in m:
|
||||
p = np.array(m["position"], dtype=float) * length_scale
|
||||
result[mid] = p
|
||||
return result
|
||||
751
robot_viewer.html
Normal file
751
robot_viewer.html
Normal file
@@ -0,0 +1,751 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Robot FK Viewer</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
:root {
|
||||
--bg: #0d0f13;
|
||||
--panel: #161920;
|
||||
--border: #2a2d35;
|
||||
--text: #c8cdd8;
|
||||
--accent: #4a9eff;
|
||||
--muted: #555b6e;
|
||||
--ok: #3ecf6b;
|
||||
--warn: #f59e0b;
|
||||
--err: #ff4f4f;
|
||||
--panel-w: 300px;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font: 13px/1.5 'IBM Plex Mono', 'Cascadia Code', 'Courier New', monospace;
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── sidebar ── */
|
||||
#sidebar {
|
||||
width: var(--panel-w);
|
||||
flex-shrink: 0;
|
||||
background: var(--panel);
|
||||
border-right: 1px solid var(--border);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.section {
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* file inputs */
|
||||
.file-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.file-row label {
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
width: 58px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.file-row input[type=file] {
|
||||
flex: 1;
|
||||
font-size: 10px;
|
||||
color: var(--text);
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 3px;
|
||||
padding: 3px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.file-row input[type=file]::file-selector-button {
|
||||
background: var(--border);
|
||||
color: var(--text);
|
||||
border: none;
|
||||
padding: 2px 8px;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 10px;
|
||||
border-radius: 2px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/* joint sliders */
|
||||
.slider-row {
|
||||
display: grid;
|
||||
grid-template-columns: 22px 1fr 48px;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.slider-row span { color: var(--accent); font-size: 12px; }
|
||||
input[type=range] {
|
||||
-webkit-appearance: none;
|
||||
height: 3px;
|
||||
background: var(--border);
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type=range]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 12px; height: 12px;
|
||||
background: var(--accent);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.val-box {
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 3px;
|
||||
padding: 2px 4px;
|
||||
font-size: 11px;
|
||||
text-align: right;
|
||||
color: var(--text);
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
/* toggles */
|
||||
.toggle-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.toggle-label { font-size: 11px; color: var(--text); }
|
||||
.toggle {
|
||||
position: relative; width: 36px; height: 18px;
|
||||
}
|
||||
.toggle input { display: none; }
|
||||
.slider-track {
|
||||
position: absolute; inset: 0;
|
||||
background: var(--border);
|
||||
border-radius: 9px;
|
||||
cursor: pointer;
|
||||
transition: background .2s;
|
||||
}
|
||||
.slider-track::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 2px; top: 2px;
|
||||
width: 14px; height: 14px;
|
||||
background: var(--muted);
|
||||
border-radius: 50%;
|
||||
transition: transform .2s, background .2s;
|
||||
}
|
||||
.toggle input:checked + .slider-track { background: var(--accent); }
|
||||
.toggle input:checked + .slider-track::after {
|
||||
transform: translateX(18px);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* stats */
|
||||
#stats-content {
|
||||
font-size: 11px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.stat-line { display: flex; justify-content: space-between; }
|
||||
.stat-val { color: var(--accent); }
|
||||
.stat-ok { color: var(--ok); }
|
||||
.stat-warn { color: var(--warn); }
|
||||
.stat-err { color: var(--err); }
|
||||
|
||||
#status-bar {
|
||||
font-size: 10px;
|
||||
color: var(--muted);
|
||||
padding: 8px 14px;
|
||||
border-top: 1px solid var(--border);
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
/* canvas */
|
||||
#canvas-wrap {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
canvas { display: block; width: 100%; height: 100%; }
|
||||
</style>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://unpkg.com/three@0.162.0/build/three.module.js",
|
||||
"three/addons/": "https://unpkg.com/three@0.162.0/examples/jsm/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="sidebar">
|
||||
|
||||
<!-- files -->
|
||||
<div class="section">
|
||||
<h3>Data Files</h3>
|
||||
<div class="file-row">
|
||||
<label>robot.json</label>
|
||||
<input type="file" id="fRobot" accept=".json">
|
||||
</div>
|
||||
<div class="file-row">
|
||||
<label>aruco</label>
|
||||
<input type="file" id="fAruco" accept=".json">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- joint sliders -->
|
||||
<div class="section">
|
||||
<h3>Joint Values</h3>
|
||||
<div id="sliders"></div>
|
||||
</div>
|
||||
|
||||
<!-- display toggles -->
|
||||
<div class="section">
|
||||
<h3>Display</h3>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Skeleton</span>
|
||||
<label class="toggle"><input type="checkbox" id="tSkeleton" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Model markers</span>
|
||||
<label class="toggle"><input type="checkbox" id="tModel" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Observed markers</span>
|
||||
<label class="toggle"><input type="checkbox" id="tObserved" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Error lines</span>
|
||||
<label class="toggle"><input type="checkbox" id="tErrors" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Board plane</span>
|
||||
<label class="toggle"><input type="checkbox" id="tBoard" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- stats -->
|
||||
<div class="section">
|
||||
<h3>Error Statistics</h3>
|
||||
<div id="stats-content"><span style="color:var(--muted)">Load both files…</span></div>
|
||||
</div>
|
||||
|
||||
<div id="status-bar">Drag to orbit · Scroll to zoom · Right-drag to pan</div>
|
||||
</div>
|
||||
|
||||
<div id="canvas-wrap">
|
||||
<canvas id="cv"></canvas>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// FK in plain JavaScript — mirrors robot_fk.py exactly
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
function norm(v) {
|
||||
const n = Math.sqrt(v.reduce((s, x) => s + x * x, 0));
|
||||
return n < 1e-12 ? v.map(() => 0) : v.map(x => x / n);
|
||||
}
|
||||
|
||||
function mm3(A, B) { // 3×3 row-major mat-mat
|
||||
const C = new Array(9).fill(0);
|
||||
for (let i = 0; i < 3; i++)
|
||||
for (let j = 0; j < 3; j++)
|
||||
for (let k = 0; k < 3; k++)
|
||||
C[i*3+j] += A[i*3+k] * B[k*3+j];
|
||||
return C;
|
||||
}
|
||||
|
||||
function rotAA(axis, deg) { // Rodrigues
|
||||
const [x, y, z] = norm(axis);
|
||||
const r = deg * Math.PI / 180, c = Math.cos(r), s = Math.sin(r), t = 1 - c;
|
||||
return [t*x*x+c, t*x*y-s*z, t*x*z+s*y,
|
||||
t*x*y+s*z, t*y*y+c, t*y*z-s*x,
|
||||
t*x*z-s*y, t*y*z+s*x, t*z*z+c];
|
||||
}
|
||||
|
||||
function rotXYZ(rx, ry, rz) {
|
||||
return mm3(mm3(rotAA([0,0,1],rz), rotAA([0,1,0],ry)), rotAA([1,0,0],rx));
|
||||
}
|
||||
|
||||
// 4×4 row-major
|
||||
function makeT(R3, tx, ty, tz) {
|
||||
return [R3[0],R3[1],R3[2],tx, R3[3],R3[4],R3[5],ty,
|
||||
R3[6],R3[7],R3[8],tz, 0,0,0,1];
|
||||
}
|
||||
function I4() { return [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; }
|
||||
|
||||
function mm4(A, B) {
|
||||
const C = new Array(16).fill(0);
|
||||
for (let i = 0; i < 4; i++)
|
||||
for (let j = 0; j < 4; j++)
|
||||
for (let k = 0; k < 4; k++)
|
||||
C[i*4+j] += A[i*4+k] * B[k*4+j];
|
||||
return C;
|
||||
}
|
||||
|
||||
function applyT(T, p) {
|
||||
return [T[0]*p[0]+T[1]*p[1]+T[2]*p[2]+T[3],
|
||||
T[4]*p[0]+T[5]*p[1]+T[6]*p[2]+T[7],
|
||||
T[8]*p[0]+T[9]*p[1]+T[10]*p[2]+T[11]];
|
||||
}
|
||||
|
||||
function buildTopoOrder(links) {
|
||||
const parent = Object.fromEntries(Object.entries(links).map(([n,d]) => [n, d.parent||null]));
|
||||
const visited = new Set(), order = [];
|
||||
const visit = n => {
|
||||
if (visited.has(n)) return;
|
||||
visited.add(n);
|
||||
if (parent[n]) visit(parent[n]);
|
||||
order.push(n);
|
||||
};
|
||||
Object.keys(links).forEach(visit);
|
||||
return order;
|
||||
}
|
||||
|
||||
function computeFK(robotData, joints) {
|
||||
const links = robotData.links || {};
|
||||
const state = {x:0,y:0,z:0,a:0,b:0,c:0,e:0, ...joints};
|
||||
const T = {};
|
||||
|
||||
for (const lname of buildTopoOrder(links)) {
|
||||
const ld = links[lname];
|
||||
const par = ld.parent;
|
||||
const Tp = T[par] || I4();
|
||||
|
||||
const mp = ld.mountPosition || [0,0,0];
|
||||
const mr = ld.mountRotation || [0,0,0];
|
||||
const Tm = makeT(rotXYZ(...mr), ...mp);
|
||||
|
||||
const jt = ld.jointToParent || {};
|
||||
const jo = jt.origin || [0,0,0];
|
||||
const jr = jt.rotation || [0,0,0];
|
||||
const Tj = makeT(rotXYZ(...jr), ...jo);
|
||||
|
||||
const type = (jt.type||'').toLowerCase();
|
||||
const axis = jt.axis || [1,0,0];
|
||||
const v = state[jt.variable] || 0;
|
||||
|
||||
let Tmot = I4();
|
||||
if (type === 'revolute') {
|
||||
Tmot = makeT(rotAA(axis, v), 0, 0, 0);
|
||||
} else if (type === 'linear') {
|
||||
const [ax, ay, az] = norm(axis);
|
||||
Tmot = makeT([1,0,0,0,1,0,0,0,1], ax*v, ay*v, az*v);
|
||||
}
|
||||
|
||||
T[lname] = mm4(mm4(mm4(Tp, Tm), Tj), Tmot);
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
function markerWorld(T, link, local) {
|
||||
return applyT(T[link] || I4(), local);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Coordinate conversion robot-mm → Three.js scene (metres)
|
||||
// robot: x=right, y=backward, z=up
|
||||
// Three.js: x=right, y=up, z=toward viewer
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const S = 1 / 1000;
|
||||
function r2v(rx, ry, rz) { return new THREE.Vector3(rx*S, rz*S, -ry*S); }
|
||||
function r2vArr(p) { return r2v(p[0], p[1], p[2]); }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Three.js scene
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
const canvas = document.getElementById('cv');
|
||||
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
|
||||
renderer.setPixelRatio(devicePixelRatio);
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 0.9;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x0d0f13);
|
||||
scene.fog = new THREE.FogExp2(0x0d0f13, 0.35);
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(45, 1, 0.001, 20);
|
||||
camera.position.set(0.35, 0.55, 1.1);
|
||||
camera.lookAt(0.2, 0.05, 0);
|
||||
|
||||
const controls = new OrbitControls(camera, canvas);
|
||||
controls.target.set(0.2, 0.05, 0);
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.08;
|
||||
|
||||
// Lighting
|
||||
scene.add(new THREE.AmbientLight(0xffffff, 0.55));
|
||||
const sun = new THREE.DirectionalLight(0xfff4e0, 1.4);
|
||||
sun.position.set(-0.8, 1.2, 0.9);
|
||||
sun.castShadow = true;
|
||||
scene.add(sun);
|
||||
const fill = new THREE.DirectionalLight(0xc0d8ff, 0.4);
|
||||
fill.position.set(0.6, 0.3, -0.5);
|
||||
scene.add(fill);
|
||||
|
||||
// Grid
|
||||
const grid = new THREE.GridHelper(3, 30, 0x1e2230, 0x1a1e28);
|
||||
grid.position.y = -0.028;
|
||||
scene.add(grid);
|
||||
|
||||
// Axes helper (world origin)
|
||||
const axes = new THREE.AxesHelper(0.1);
|
||||
axes.position.set(0, 0, 0);
|
||||
scene.add(axes);
|
||||
|
||||
// ─── geometry helpers ─────────────────────────────────────────
|
||||
|
||||
function makeCylinder(p1, p2, radius, color, opacity=1) {
|
||||
const dir = p2.clone().sub(p1);
|
||||
const len = dir.length();
|
||||
if (len < 0.0001) return null;
|
||||
const geo = new THREE.CylinderGeometry(radius, radius, len, 8, 1);
|
||||
const mat = new THREE.MeshPhongMaterial({
|
||||
color, transparent: opacity < 1, opacity,
|
||||
shininess: 60
|
||||
});
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.castShadow = true;
|
||||
m.position.copy(p1.clone().add(p2).multiplyScalar(0.5));
|
||||
m.quaternion.setFromUnitVectors(new THREE.Vector3(0,1,0), dir.normalize());
|
||||
return m;
|
||||
}
|
||||
|
||||
function makeSphere(pos, radius, color) {
|
||||
const geo = new THREE.SphereGeometry(radius, 12, 8);
|
||||
const mat = new THREE.MeshPhongMaterial({ color, shininess: 80 });
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.position.copy(pos);
|
||||
m.castShadow = true;
|
||||
return m;
|
||||
}
|
||||
|
||||
function makeMarkerSquare(pos, normal, size, color) {
|
||||
const geo = new THREE.BoxGeometry(size, size, size*0.1);
|
||||
const mat = new THREE.MeshPhongMaterial({ color, shininess: 40 });
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.position.copy(pos);
|
||||
// orient normal
|
||||
const n = new THREE.Vector3(...normal).normalize();
|
||||
m.quaternion.setFromUnitVectors(new THREE.Vector3(0,0,1), n);
|
||||
return m;
|
||||
}
|
||||
|
||||
function makeLine(p1, p2, color) {
|
||||
const geo = new THREE.BufferGeometry().setFromPoints([p1, p2]);
|
||||
const mat = new THREE.LineBasicMaterial({ color });
|
||||
return new THREE.Line(geo, mat);
|
||||
}
|
||||
|
||||
// ─── link colours ─────────────────────────────────────────────
|
||||
const LINK_COLORS = {
|
||||
Board: 0x8b6528,
|
||||
Base: 0xc8c8c8,
|
||||
Arm1: 0x3355cc,
|
||||
Ellbow: 0xcccccc,
|
||||
Arm2: 0xbbbbbb,
|
||||
Hand: 0xaaaaaa,
|
||||
Palm: 0x999999,
|
||||
FingerA: 0xdddddd,
|
||||
FingerB: 0xdddddd,
|
||||
};
|
||||
function linkColor(name) { return LINK_COLORS[name] ?? 0x888888; }
|
||||
|
||||
// ─── scene groups ─────────────────────────────────────────────
|
||||
const gSkeleton = new THREE.Group();
|
||||
const gModel = new THREE.Group();
|
||||
const gObserved = new THREE.Group();
|
||||
const gErrors = new THREE.Group();
|
||||
const gBoard = new THREE.Group();
|
||||
scene.add(gSkeleton, gModel, gObserved, gErrors, gBoard);
|
||||
|
||||
// ─── toggle wiring ────────────────────────────────────────────
|
||||
const toggles = {
|
||||
tSkeleton: gSkeleton,
|
||||
tModel: gModel,
|
||||
tObserved: gObserved,
|
||||
tErrors: gErrors,
|
||||
tBoard: gBoard,
|
||||
};
|
||||
for (const [id, grp] of Object.entries(toggles)) {
|
||||
document.getElementById(id).addEventListener('change', e => {
|
||||
grp.visible = e.target.checked;
|
||||
});
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// State
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
let robotData = null;
|
||||
let arucoData = null;
|
||||
const joints = { x:0, y:0, z:0, a:0, b:0, c:0, e:0 };
|
||||
|
||||
// ─── slider setup ─────────────────────────────────────────────
|
||||
const JOINT_DEFS = [
|
||||
{ key:'x', label:'x', min:-50, max:600, step:1, unit:'mm' },
|
||||
{ key:'y', label:'y', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'z', label:'z', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'a', label:'a', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'b', label:'b', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'c', label:'c', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'e', label:'e', min:0, max:60, step:0.5,unit:'mm' },
|
||||
];
|
||||
|
||||
const sliderEls = {}, valEls = {};
|
||||
const slidersDiv = document.getElementById('sliders');
|
||||
|
||||
for (const d of JOINT_DEFS) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'slider-row';
|
||||
|
||||
const lbl = document.createElement('span');
|
||||
lbl.textContent = d.key;
|
||||
|
||||
const sl = document.createElement('input');
|
||||
sl.type = 'range';
|
||||
sl.min = d.min; sl.max = d.max; sl.step = d.step; sl.value = 0;
|
||||
|
||||
const vb = document.createElement('input');
|
||||
vb.type = 'text'; vb.className = 'val-box'; vb.value = '0';
|
||||
vb.style.width = '58px';
|
||||
|
||||
sl.addEventListener('input', () => {
|
||||
joints[d.key] = parseFloat(sl.value);
|
||||
vb.value = parseFloat(sl.value).toFixed(d.step < 1 ? 1 : 0);
|
||||
rebuild();
|
||||
});
|
||||
vb.addEventListener('change', () => {
|
||||
const v = parseFloat(vb.value);
|
||||
if (!isNaN(v)) {
|
||||
joints[d.key] = v;
|
||||
sl.value = v;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
|
||||
row.append(lbl, sl, vb);
|
||||
slidersDiv.appendChild(row);
|
||||
sliderEls[d.key] = sl;
|
||||
valEls[d.key] = vb;
|
||||
}
|
||||
|
||||
function setSlider(key, val) {
|
||||
joints[key] = val;
|
||||
sliderEls[key].value = val;
|
||||
valEls[key].value = val.toFixed(JOINT_DEFS.find(d=>d.key===key)?.step < 1 ? 1 : 0);
|
||||
}
|
||||
|
||||
// ─── file loading ──────────────────────────────────────────────
|
||||
function readJSON(file) {
|
||||
return new Promise((res, rej) => {
|
||||
const r = new FileReader();
|
||||
r.onload = e => { try { res(JSON.parse(e.target.result)); } catch(err) { rej(err); } };
|
||||
r.onerror = rej;
|
||||
r.readAsText(file);
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('fRobot').addEventListener('change', async e => {
|
||||
if (!e.target.files[0]) return;
|
||||
robotData = await readJSON(e.target.files[0]);
|
||||
// init sliders from defaultPosition if present
|
||||
const dp = robotData.defaultPosition || {};
|
||||
for (const k of Object.keys(joints)) {
|
||||
if (dp[k] != null) setSlider(k, dp[k]);
|
||||
}
|
||||
setStatus('robot.json loaded');
|
||||
rebuild();
|
||||
});
|
||||
|
||||
document.getElementById('fAruco').addEventListener('change', async e => {
|
||||
if (!e.target.files[0]) return;
|
||||
arucoData = await readJSON(e.target.files[0]);
|
||||
setStatus('aruco JSON loaded');
|
||||
rebuild();
|
||||
});
|
||||
|
||||
// ─── clear groups ──────────────────────────────────────────────
|
||||
function clearGroup(g) {
|
||||
while (g.children.length) {
|
||||
const c = g.children[0];
|
||||
c.geometry?.dispose?.();
|
||||
if (Array.isArray(c.material)) c.material.forEach(m => m.dispose?.());
|
||||
else c.material?.dispose?.();
|
||||
g.remove(c);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── rebuild scene ─────────────────────────────────────────────
|
||||
function rebuild() {
|
||||
clearGroup(gSkeleton);
|
||||
clearGroup(gModel);
|
||||
clearGroup(gObserved);
|
||||
clearGroup(gErrors);
|
||||
clearGroup(gBoard);
|
||||
|
||||
if (!robotData) return;
|
||||
|
||||
const T = computeFK(robotData, joints);
|
||||
|
||||
// ── board plane ──
|
||||
const boardSize = robotData.links?.Board?.size || [1000, 200, 25];
|
||||
{
|
||||
const w = boardSize[0]*S, d = boardSize[1]*S, h = boardSize[2]*S;
|
||||
const geo = new THREE.BoxGeometry(w, h, d);
|
||||
const mat = new THREE.MeshPhongMaterial({ color:0x7a5520, transparent:true, opacity:0.5 });
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.position.set(w/2, -h/2, -d/2); // board goes x→, y→backward
|
||||
m.receiveShadow = true;
|
||||
gBoard.add(m);
|
||||
}
|
||||
|
||||
// ── skeleton ──
|
||||
const links = robotData.links || {};
|
||||
for (const [lname, ld] of Object.entries(links)) {
|
||||
const sk = ld.skeleton;
|
||||
if (!sk) continue;
|
||||
const from = markerWorld(T, lname, sk.from || [0,0,0]);
|
||||
const to = markerWorld(T, lname, sk.to || [0,0,0]);
|
||||
const r = (sk.radius || 4) * S * 0.8;
|
||||
const col = sk.color ? new THREE.Color(...sk.color) : new THREE.Color(linkColor(lname));
|
||||
const cyl = makeCylinder(r2vArr(from), r2vArr(to), r, col);
|
||||
if (cyl) gSkeleton.add(cyl);
|
||||
}
|
||||
|
||||
// ── model markers ──
|
||||
const modelPositions = {};
|
||||
for (const [lname, ld] of Object.entries(links)) {
|
||||
const col = linkColor(lname);
|
||||
for (const m of (ld.markers||[])) {
|
||||
if (!m.position) continue;
|
||||
const mid = m.id;
|
||||
const wp = markerWorld(T, lname, m.position);
|
||||
modelPositions[mid] = wp;
|
||||
const sq = makeMarkerSquare(r2vArr(wp), m.normal||[0,0,1], 0.022, col);
|
||||
gModel.add(sq);
|
||||
// ID label (not adding for perf, but could)
|
||||
}
|
||||
}
|
||||
|
||||
// ── observed markers + error lines ──
|
||||
const obs = {};
|
||||
if (arucoData) {
|
||||
for (const m of (arucoData.markers||[])) {
|
||||
const mid = m.marker_id ?? m.id;
|
||||
if (mid == null) continue;
|
||||
let pos;
|
||||
if (m.position_mm) pos = m.position_mm;
|
||||
else if (m.position_m) pos = m.position_m.map(v=>v*1000);
|
||||
else continue;
|
||||
obs[mid] = pos;
|
||||
}
|
||||
}
|
||||
|
||||
const errors = [];
|
||||
for (const [midStr, opos] of Object.entries(obs)) {
|
||||
const mid = parseInt(midStr);
|
||||
const mpos = modelPositions[mid];
|
||||
const op = r2vArr(opos);
|
||||
|
||||
// colour by error magnitude
|
||||
const errMm = mpos
|
||||
? Math.sqrt(opos.reduce((s,v,i) => s+(v-mpos[i])**2, 0))
|
||||
: null;
|
||||
const col = errMm == null ? 0x888888
|
||||
: errMm < 5 ? 0x3ecf6b
|
||||
: errMm < 15 ? 0xf59e0b
|
||||
: 0xff4f4f;
|
||||
|
||||
gObserved.add(makeSphere(op, 0.006, col));
|
||||
|
||||
if (mpos) {
|
||||
errors.push(errMm);
|
||||
const mp = r2vArr(mpos);
|
||||
gErrors.add(makeLine(mp, op, col));
|
||||
}
|
||||
}
|
||||
|
||||
// ── stats ──
|
||||
updateStats(errors, Object.keys(obs).length, Object.keys(modelPositions).length);
|
||||
}
|
||||
|
||||
// ─── statistics panel ──────────────────────────────────────────
|
||||
function updateStats(errArr, nObs, nModel) {
|
||||
const el = document.getElementById('stats-content');
|
||||
if (errArr.length === 0) {
|
||||
el.innerHTML = `<div class="stat-line"><span>Observed:</span><span class="stat-val">${nObs}</span></div>
|
||||
<div class="stat-line"><span>Model:</span><span class="stat-val">${nModel}</span></div>
|
||||
<div class="stat-line"><span style="color:var(--muted)">No matches found</span></div>`;
|
||||
return;
|
||||
}
|
||||
const sorted = [...errArr].sort((a,b)=>a-b);
|
||||
const mean = errArr.reduce((s,v)=>s+v,0) / errArr.length;
|
||||
const rms = Math.sqrt(errArr.reduce((s,v)=>s+v*v,0) / errArr.length);
|
||||
const p50 = sorted[Math.floor(sorted.length*0.5)];
|
||||
const p90 = sorted[Math.floor(sorted.length*0.9)];
|
||||
const max = sorted[sorted.length-1];
|
||||
|
||||
const cls = v => v < 5 ? 'stat-ok' : v < 15 ? 'stat-warn' : 'stat-err';
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="stat-line"><span>Observed:</span><span class="stat-val">${nObs}</span></div>
|
||||
<div class="stat-line"><span>Matched:</span><span class="stat-val">${errArr.length}</span></div>
|
||||
<div class="stat-line"><span>Mean error:</span><span class="${cls(mean)}">${mean.toFixed(1)} mm</span></div>
|
||||
<div class="stat-line"><span>RMS error:</span><span class="${cls(rms)}">${rms.toFixed(1)} mm</span></div>
|
||||
<div class="stat-line"><span>Median:</span><span class="${cls(p50)}">${p50.toFixed(1)} mm</span></div>
|
||||
<div class="stat-line"><span>p90:</span><span class="${cls(p90)}">${p90.toFixed(1)} mm</span></div>
|
||||
<div class="stat-line"><span>Max:</span><span class="${cls(max)}">${max.toFixed(1)} mm</span></div>
|
||||
<div style="margin-top:6px;font-size:10px;color:var(--muted)">
|
||||
🟢 <5mm 🟡 5–15mm 🔴 >15mm</div>`;
|
||||
}
|
||||
|
||||
function setStatus(msg) {
|
||||
document.getElementById('status-bar').textContent = msg + ' — Drag to orbit · Scroll to zoom';
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Render loop
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
function onResize() {
|
||||
const w = canvas.parentElement.clientWidth;
|
||||
const h = canvas.parentElement.clientHeight;
|
||||
renderer.setSize(w, h);
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
window.addEventListener('resize', onResize);
|
||||
onResize();
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
894
run/robot_viewer.html
Normal file
894
run/robot_viewer.html
Normal file
@@ -0,0 +1,894 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Robot FK Viewer</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
:root {
|
||||
--bg: #0d0f13;
|
||||
--panel: #161920;
|
||||
--border: #2a2d35;
|
||||
--text: #c8cdd8;
|
||||
--accent: #4a9eff;
|
||||
--muted: #555b6e;
|
||||
--ok: #3ecf6b;
|
||||
--warn: #f59e0b;
|
||||
--err: #ff4f4f;
|
||||
--panel-w: 300px;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font: 13px/1.5 'IBM Plex Mono', 'Cascadia Code', 'Courier New', monospace;
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── sidebar ── */
|
||||
#sidebar {
|
||||
width: var(--panel-w);
|
||||
flex-shrink: 0;
|
||||
background: var(--panel);
|
||||
border-right: 1px solid var(--border);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.section {
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* file inputs */
|
||||
.file-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.file-row label {
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
width: 58px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.file-row input[type=file] {
|
||||
flex: 1;
|
||||
font-size: 10px;
|
||||
color: var(--text);
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 3px;
|
||||
padding: 3px 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.file-row input[type=file]::file-selector-button {
|
||||
background: var(--border);
|
||||
color: var(--text);
|
||||
border: none;
|
||||
padding: 2px 8px;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 10px;
|
||||
border-radius: 2px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/* joint sliders */
|
||||
.slider-row {
|
||||
display: grid;
|
||||
grid-template-columns: 22px 1fr 48px;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.slider-row span { color: var(--accent); font-size: 12px; }
|
||||
input[type=range] {
|
||||
-webkit-appearance: none;
|
||||
height: 3px;
|
||||
background: var(--border);
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type=range]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 12px; height: 12px;
|
||||
background: var(--accent);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.val-box {
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 3px;
|
||||
padding: 2px 4px;
|
||||
font-size: 11px;
|
||||
text-align: right;
|
||||
color: var(--text);
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
/* toggles */
|
||||
.toggle-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.toggle-label { font-size: 11px; color: var(--text); }
|
||||
.toggle {
|
||||
position: relative; width: 36px; height: 18px;
|
||||
}
|
||||
.toggle input { display: none; }
|
||||
.slider-track {
|
||||
position: absolute; inset: 0;
|
||||
background: var(--border);
|
||||
border-radius: 9px;
|
||||
cursor: pointer;
|
||||
transition: background .2s;
|
||||
}
|
||||
.slider-track::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 2px; top: 2px;
|
||||
width: 14px; height: 14px;
|
||||
background: var(--muted);
|
||||
border-radius: 50%;
|
||||
transition: transform .2s, background .2s;
|
||||
}
|
||||
.toggle input:checked + .slider-track { background: var(--accent); }
|
||||
.toggle input:checked + .slider-track::after {
|
||||
transform: translateX(18px);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* stats */
|
||||
#stats-content {
|
||||
font-size: 11px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.stat-line { display: flex; justify-content: space-between; }
|
||||
.stat-val { color: var(--accent); }
|
||||
.stat-ok { color: var(--ok); }
|
||||
.stat-warn { color: var(--warn); }
|
||||
.stat-err { color: var(--err); }
|
||||
|
||||
#status-bar {
|
||||
font-size: 10px;
|
||||
color: var(--muted);
|
||||
padding: 8px 14px;
|
||||
border-top: 1px solid var(--border);
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
/* canvas */
|
||||
#canvas-wrap {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
canvas { display: block; width: 100%; height: 100%; }
|
||||
</style>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "https://unpkg.com/three@0.162.0/build/three.module.js",
|
||||
"three/addons/": "https://unpkg.com/three@0.162.0/examples/jsm/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="sidebar">
|
||||
|
||||
<!-- files -->
|
||||
<div class="section">
|
||||
<h3>Data Files</h3>
|
||||
<div class="file-row">
|
||||
<label>robot.json</label>
|
||||
<input type="file" id="fRobot" accept=".json">
|
||||
</div>
|
||||
<div class="file-row">
|
||||
<label>aruco</label>
|
||||
<input type="file" id="fAruco" accept=".json">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- test poses -->
|
||||
<div class="section" id="poseSection" style="display:none">
|
||||
<h3>Test Poses</h3>
|
||||
<select id="poseSelect" style="
|
||||
width:100%; background:var(--bg); border:1px solid var(--border);
|
||||
color:var(--text); font:inherit; font-size:11px; padding:4px 6px;
|
||||
border-radius:3px; cursor:pointer; margin-bottom:4px;">
|
||||
<option value="">— select pose —</option>
|
||||
</select>
|
||||
<div id="poseInfo" style="font-size:10px;color:var(--muted);min-height:14px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- joint sliders -->
|
||||
<div class="section">
|
||||
<h3>Joint Values</h3>
|
||||
<div id="sliders"></div>
|
||||
</div>
|
||||
|
||||
<!-- display toggles -->
|
||||
<div class="section">
|
||||
<h3>Display</h3>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Skeleton</span>
|
||||
<label class="toggle"><input type="checkbox" id="tSkeleton" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Model markers</span>
|
||||
<label class="toggle"><input type="checkbox" id="tModel" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Model normals</span>
|
||||
<label class="toggle"><input type="checkbox" id="tNormals"><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Observed markers</span>
|
||||
<label class="toggle"><input type="checkbox" id="tObserved" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Observed normals</span>
|
||||
<label class="toggle"><input type="checkbox" id="tObsNormals"><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Error lines</span>
|
||||
<label class="toggle"><input type="checkbox" id="tErrors" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">Board plane</span>
|
||||
<label class="toggle"><input type="checkbox" id="tBoard" checked><span class="slider-track"></span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- stats -->
|
||||
<div class="section">
|
||||
<h3>Error Statistics</h3>
|
||||
<div id="stats-content"><span style="color:var(--muted)">Load both files…</span></div>
|
||||
</div>
|
||||
|
||||
<div id="status-bar">Drag to orbit · Scroll to zoom · Right-drag to pan</div>
|
||||
</div>
|
||||
|
||||
<div id="canvas-wrap">
|
||||
<canvas id="cv"></canvas>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// FK in plain JavaScript — mirrors robot_fk.py exactly
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
function norm(v) {
|
||||
const n = Math.sqrt(v.reduce((s, x) => s + x * x, 0));
|
||||
return n < 1e-12 ? v.map(() => 0) : v.map(x => x / n);
|
||||
}
|
||||
|
||||
function mm3(A, B) { // 3×3 row-major mat-mat
|
||||
const C = new Array(9).fill(0);
|
||||
for (let i = 0; i < 3; i++)
|
||||
for (let j = 0; j < 3; j++)
|
||||
for (let k = 0; k < 3; k++)
|
||||
C[i*3+j] += A[i*3+k] * B[k*3+j];
|
||||
return C;
|
||||
}
|
||||
|
||||
function rotAA(axis, deg) { // Rodrigues
|
||||
const [x, y, z] = norm(axis);
|
||||
const r = deg * Math.PI / 180, c = Math.cos(r), s = Math.sin(r), t = 1 - c;
|
||||
return [t*x*x+c, t*x*y-s*z, t*x*z+s*y,
|
||||
t*x*y+s*z, t*y*y+c, t*y*z-s*x,
|
||||
t*x*z-s*y, t*y*z+s*x, t*z*z+c];
|
||||
}
|
||||
|
||||
function rotXYZ(rx, ry, rz) {
|
||||
return mm3(mm3(rotAA([0,0,1],rz), rotAA([0,1,0],ry)), rotAA([1,0,0],rx));
|
||||
}
|
||||
|
||||
// 4×4 row-major
|
||||
function makeT(R3, tx, ty, tz) {
|
||||
return [R3[0],R3[1],R3[2],tx, R3[3],R3[4],R3[5],ty,
|
||||
R3[6],R3[7],R3[8],tz, 0,0,0,1];
|
||||
}
|
||||
function I4() { return [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]; }
|
||||
|
||||
function mm4(A, B) {
|
||||
const C = new Array(16).fill(0);
|
||||
for (let i = 0; i < 4; i++)
|
||||
for (let j = 0; j < 4; j++)
|
||||
for (let k = 0; k < 4; k++)
|
||||
C[i*4+j] += A[i*4+k] * B[k*4+j];
|
||||
return C;
|
||||
}
|
||||
|
||||
function applyT(T, p) {
|
||||
return [T[0]*p[0]+T[1]*p[1]+T[2]*p[2]+T[3],
|
||||
T[4]*p[0]+T[5]*p[1]+T[6]*p[2]+T[7],
|
||||
T[8]*p[0]+T[9]*p[1]+T[10]*p[2]+T[11]];
|
||||
}
|
||||
|
||||
function buildTopoOrder(links) {
|
||||
const parent = Object.fromEntries(Object.entries(links).map(([n,d]) => [n, d.parent||null]));
|
||||
const visited = new Set(), order = [];
|
||||
const visit = n => {
|
||||
if (visited.has(n)) return;
|
||||
visited.add(n);
|
||||
if (parent[n]) visit(parent[n]);
|
||||
order.push(n);
|
||||
};
|
||||
Object.keys(links).forEach(visit);
|
||||
return order;
|
||||
}
|
||||
|
||||
function computeFK(robotData, joints) {
|
||||
const links = robotData.links || {};
|
||||
const state = {x:0,y:0,z:0,a:0,b:0,c:0,e:0, ...joints};
|
||||
const T = {};
|
||||
|
||||
for (const lname of buildTopoOrder(links)) {
|
||||
const ld = links[lname];
|
||||
const par = ld.parent;
|
||||
const Tp = T[par] || I4();
|
||||
|
||||
const mp = ld.mountPosition || [0,0,0];
|
||||
const mr = ld.mountRotation || [0,0,0];
|
||||
const Tm = makeT(rotXYZ(...mr), ...mp);
|
||||
|
||||
const jt = ld.jointToParent || {};
|
||||
const jo = jt.origin || [0,0,0];
|
||||
const jr = jt.rotation || [0,0,0];
|
||||
const Tj = makeT(rotXYZ(...jr), ...jo);
|
||||
|
||||
const type = (jt.type||'').toLowerCase();
|
||||
const axis = jt.axis || [1,0,0];
|
||||
const v = state[jt.variable] || 0;
|
||||
|
||||
let Tmot = I4();
|
||||
if (type === 'revolute') {
|
||||
Tmot = makeT(rotAA(axis, v), 0, 0, 0);
|
||||
} else if (type === 'linear') {
|
||||
const [ax, ay, az] = norm(axis);
|
||||
Tmot = makeT([1,0,0,0,1,0,0,0,1], ax*v, ay*v, az*v);
|
||||
}
|
||||
|
||||
T[lname] = mm4(mm4(mm4(Tp, Tm), Tj), Tmot);
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
function markerWorld(T, link, local) {
|
||||
return applyT(T[link] || I4(), local);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Coordinate conversion robot-mm → Three.js scene (metres)
|
||||
// robot: x=right, y=backward, z=up
|
||||
// Three.js: x=right, y=up, z=toward viewer
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const S = 1 / 1000;
|
||||
function r2v(rx, ry, rz) { return new THREE.Vector3(rx*S, rz*S, -ry*S); }
|
||||
function r2vArr(p) { return r2v(p[0], p[1], p[2]); }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Three.js scene
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
const canvas = document.getElementById('cv');
|
||||
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
|
||||
renderer.setPixelRatio(devicePixelRatio);
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 0.9;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x0d0f13);
|
||||
scene.fog = new THREE.FogExp2(0x0d0f13, 0.35);
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(45, 1, 0.001, 20);
|
||||
camera.position.set(0.35, 0.55, 1.1);
|
||||
camera.lookAt(0.2, 0.05, 0);
|
||||
|
||||
const controls = new OrbitControls(camera, canvas);
|
||||
controls.target.set(0.2, 0.05, 0);
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.08;
|
||||
|
||||
// Lighting
|
||||
scene.add(new THREE.AmbientLight(0xffffff, 0.55));
|
||||
const sun = new THREE.DirectionalLight(0xfff4e0, 1.4);
|
||||
sun.position.set(-0.8, 1.2, 0.9);
|
||||
sun.castShadow = true;
|
||||
scene.add(sun);
|
||||
const fill = new THREE.DirectionalLight(0xc0d8ff, 0.4);
|
||||
fill.position.set(0.6, 0.3, -0.5);
|
||||
scene.add(fill);
|
||||
|
||||
// Grid
|
||||
const grid = new THREE.GridHelper(3, 30, 0x1e2230, 0x1a1e28);
|
||||
grid.position.y = -0.028;
|
||||
scene.add(grid);
|
||||
|
||||
// Axes helper (world origin)
|
||||
const axes = new THREE.AxesHelper(0.1);
|
||||
axes.position.set(0, 0, 0);
|
||||
scene.add(axes);
|
||||
|
||||
// ─── geometry helpers ─────────────────────────────────────────
|
||||
|
||||
function makeCylinder(p1, p2, radius, color, opacity=1) {
|
||||
const dir = p2.clone().sub(p1);
|
||||
const len = dir.length();
|
||||
if (len < 0.0001) return null;
|
||||
const geo = new THREE.CylinderGeometry(radius, radius, len, 8, 1);
|
||||
const mat = new THREE.MeshPhongMaterial({
|
||||
color, transparent: opacity < 1, opacity,
|
||||
shininess: 60
|
||||
});
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.castShadow = true;
|
||||
m.position.copy(p1.clone().add(p2).multiplyScalar(0.5));
|
||||
m.quaternion.setFromUnitVectors(new THREE.Vector3(0,1,0), dir.normalize());
|
||||
return m;
|
||||
}
|
||||
|
||||
function makeSphere(pos, radius, color) {
|
||||
const geo = new THREE.SphereGeometry(radius, 12, 8);
|
||||
const mat = new THREE.MeshPhongMaterial({ color, shininess: 80 });
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.position.copy(pos);
|
||||
m.castShadow = true;
|
||||
return m;
|
||||
}
|
||||
|
||||
function transformDirByT(T, dir) {
|
||||
return [
|
||||
T[0]*dir[0] + T[1]*dir[1] + T[2]*dir[2],
|
||||
T[4]*dir[0] + T[5]*dir[1] + T[6]*dir[2],
|
||||
T[8]*dir[0] + T[9]*dir[1] + T[10]*dir[2],
|
||||
];
|
||||
}
|
||||
|
||||
function makeMarkerSquare(pos, normal, size, color) {
|
||||
const geo = new THREE.BoxGeometry(size, size, size * 0.1);
|
||||
const mat = new THREE.MeshPhongMaterial({
|
||||
color,
|
||||
shininess: 40
|
||||
});
|
||||
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.position.copy(pos);
|
||||
|
||||
// Fallback falls keine gültige Normale vorhanden
|
||||
let nx = 0, ny = 0, nz = 1;
|
||||
|
||||
if (Array.isArray(normal) && normal.length >= 3) {
|
||||
nx = Number(normal[0]) || 0;
|
||||
ny = Number(normal[1]) || 0;
|
||||
nz = Number(normal[2]) || 1;
|
||||
} else if (normal instanceof THREE.Vector3) {
|
||||
nx = normal.x;
|
||||
ny = normal.y;
|
||||
nz = normal.z;
|
||||
}
|
||||
|
||||
const n = new THREE.Vector3(nx, ny, nz);
|
||||
|
||||
if (n.lengthSq() > 1e-12) {
|
||||
n.normalize();
|
||||
m.quaternion.setFromUnitVectors(
|
||||
new THREE.Vector3(0, 0, 1),
|
||||
n
|
||||
);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
function makeLine(p1, p2, color) {
|
||||
const geo = new THREE.BufferGeometry().setFromPoints([p1, p2]);
|
||||
const mat = new THREE.LineBasicMaterial({ color });
|
||||
return new THREE.Line(geo, mat);
|
||||
}
|
||||
|
||||
// ─── link colours ─────────────────────────────────────────────
|
||||
const LINK_COLORS = {
|
||||
Board: 0x8b6528,
|
||||
Base: 0xc8c8c8,
|
||||
Arm1: 0x3355cc,
|
||||
Ellbow: 0xcccccc,
|
||||
Arm2: 0xbbbbbb,
|
||||
Hand: 0xaaaaaa,
|
||||
Palm: 0x999999,
|
||||
FingerA: 0xdddddd,
|
||||
FingerB: 0xdddddd,
|
||||
};
|
||||
function linkColor(name) { return LINK_COLORS[name] ?? 0x888888; }
|
||||
|
||||
// ─── scene groups ─────────────────────────────────────────────
|
||||
const gSkeleton = new THREE.Group();
|
||||
const gModel = new THREE.Group();
|
||||
const gNormals = new THREE.Group();
|
||||
const gObserved = new THREE.Group();
|
||||
const gObsNormals= new THREE.Group();
|
||||
const gErrors = new THREE.Group();
|
||||
const gBoard = new THREE.Group();
|
||||
scene.add(gSkeleton, gModel, gNormals, gObserved, gObsNormals, gErrors, gBoard);
|
||||
|
||||
// ─── toggle wiring ────────────────────────────────────────────
|
||||
const toggles = {
|
||||
tSkeleton: gSkeleton,
|
||||
tModel: gModel,
|
||||
tNormals: gNormals,
|
||||
tObserved: gObserved,
|
||||
tObsNormals:gObsNormals,
|
||||
tErrors: gErrors,
|
||||
tBoard: gBoard,
|
||||
};
|
||||
for (const [id, grp] of Object.entries(toggles)) {
|
||||
document.getElementById(id).addEventListener('change', e => {
|
||||
grp.visible = e.target.checked;
|
||||
});
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// State
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
let robotData = null;
|
||||
let arucoData = null;
|
||||
const joints = { x:0, y:0, z:0, a:0, b:0, c:0, e:0 };
|
||||
|
||||
// ─── slider setup ─────────────────────────────────────────────
|
||||
const JOINT_DEFS = [
|
||||
{ key:'x', label:'x', min:-50, max:600, step:1, unit:'mm' },
|
||||
{ key:'y', label:'y', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'z', label:'z', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'a', label:'a', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'b', label:'b', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'c', label:'c', min:-180, max:180, step:0.5,unit:'°' },
|
||||
{ key:'e', label:'e', min:0, max:60, step:0.5,unit:'mm' },
|
||||
];
|
||||
|
||||
const sliderEls = {}, valEls = {};
|
||||
const slidersDiv = document.getElementById('sliders');
|
||||
|
||||
for (const d of JOINT_DEFS) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'slider-row';
|
||||
|
||||
const lbl = document.createElement('span');
|
||||
lbl.textContent = d.key;
|
||||
|
||||
const sl = document.createElement('input');
|
||||
sl.type = 'range';
|
||||
sl.min = d.min; sl.max = d.max; sl.step = d.step; sl.value = 0;
|
||||
|
||||
const vb = document.createElement('input');
|
||||
vb.type = 'text'; vb.className = 'val-box'; vb.value = '0';
|
||||
vb.style.width = '58px';
|
||||
|
||||
sl.addEventListener('input', () => {
|
||||
joints[d.key] = parseFloat(sl.value);
|
||||
vb.value = parseFloat(sl.value).toFixed(d.step < 1 ? 1 : 0);
|
||||
rebuild();
|
||||
});
|
||||
vb.addEventListener('change', () => {
|
||||
const v = parseFloat(vb.value);
|
||||
if (!isNaN(v)) {
|
||||
joints[d.key] = v;
|
||||
sl.value = v;
|
||||
rebuild();
|
||||
}
|
||||
});
|
||||
|
||||
row.append(lbl, sl, vb);
|
||||
slidersDiv.appendChild(row);
|
||||
sliderEls[d.key] = sl;
|
||||
valEls[d.key] = vb;
|
||||
}
|
||||
|
||||
function setSlider(key, val) {
|
||||
joints[key] = val;
|
||||
sliderEls[key].value = val;
|
||||
valEls[key].value = val.toFixed(JOINT_DEFS.find(d=>d.key===key)?.step < 1 ? 1 : 0);
|
||||
}
|
||||
|
||||
// ─── file loading ──────────────────────────────────────────────
|
||||
function readJSON(file) {
|
||||
return new Promise((res, rej) => {
|
||||
const r = new FileReader();
|
||||
r.onload = e => { try { res(JSON.parse(e.target.result)); } catch(err) { rej(err); } };
|
||||
r.onerror = rej;
|
||||
r.readAsText(file);
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('fRobot').addEventListener('change', async e => {
|
||||
if (!e.target.files[0]) return;
|
||||
robotData = await readJSON(e.target.files[0]);
|
||||
// init sliders from defaultPosition if present
|
||||
const dp = robotData.defaultPosition || {};
|
||||
for (const k of Object.keys(joints)) {
|
||||
if (dp[k] != null) setSlider(k, dp[k]);
|
||||
}
|
||||
populatePoses(robotData);
|
||||
setStatus('robot.json loaded');
|
||||
rebuild();
|
||||
});
|
||||
|
||||
document.getElementById('fAruco').addEventListener('change', async e => {
|
||||
if (!e.target.files[0]) return;
|
||||
arucoData = await readJSON(e.target.files[0]);
|
||||
setStatus('aruco/markers.json loaded');
|
||||
rebuild();
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Test-pose dropdown
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
function populatePoses(data) {
|
||||
const poses = data.robot_test_poses || {};
|
||||
const keys = Object.keys(poses);
|
||||
const section = document.getElementById('poseSection');
|
||||
const sel = document.getElementById('poseSelect');
|
||||
const info = document.getElementById('poseInfo');
|
||||
|
||||
if (keys.length === 0) { section.style.display = 'none'; return; }
|
||||
section.style.display = '';
|
||||
|
||||
// Rebuild options
|
||||
sel.innerHTML = '<option value="">— select pose —</option>';
|
||||
keys.forEach(k => {
|
||||
const o = document.createElement('option');
|
||||
o.value = k; o.textContent = k;
|
||||
sel.appendChild(o);
|
||||
});
|
||||
|
||||
// Remove old listener by replacing element
|
||||
const newSel = sel.cloneNode(true);
|
||||
sel.parentNode.replaceChild(newSel, sel);
|
||||
|
||||
newSel.addEventListener('change', () => {
|
||||
const k = newSel.value;
|
||||
if (!k) { info.textContent = ''; return; }
|
||||
const p = poses[k];
|
||||
info.textContent = Object.entries(p).map(([a,b])=>`${a}:${b}`).join(' ');
|
||||
for (const [key, val] of Object.entries(p)) {
|
||||
if (key in joints) setSlider(key, Number(val));
|
||||
}
|
||||
rebuild();
|
||||
});
|
||||
}
|
||||
|
||||
// ─── clear groups ──────────────────────────────────────────────
|
||||
function clearGroup(g) {
|
||||
while (g.children.length) {
|
||||
const c = g.children[0];
|
||||
c.geometry?.dispose?.();
|
||||
if (Array.isArray(c.material)) c.material.forEach(m => m.dispose?.());
|
||||
else c.material?.dispose?.();
|
||||
g.remove(c);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Normal-arrow helper
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
function makeNormalArrow(posThreeJS, normalRobot, length, hexColor) {
|
||||
// normalRobot is in robot coords → convert to Three.js direction
|
||||
const dir = new THREE.Vector3(normalRobot[0], normalRobot[2], -normalRobot[1]).normalize();
|
||||
const arrow = new THREE.ArrowHelper(
|
||||
dir,
|
||||
posThreeJS,
|
||||
length,
|
||||
hexColor,
|
||||
length * 0.40, // cone head length
|
||||
length * 0.20 // cone head width
|
||||
);
|
||||
return arrow;
|
||||
}
|
||||
|
||||
// ─── rebuild scene ─────────────────────────────────────────────
|
||||
function r2vDir(rx, ry, rz) {
|
||||
return new THREE.Vector3(rx, rz, -ry).normalize();
|
||||
}
|
||||
|
||||
function rebuild() {
|
||||
clearGroup(gSkeleton);
|
||||
clearGroup(gModel);
|
||||
clearGroup(gNormals);
|
||||
clearGroup(gObserved);
|
||||
clearGroup(gObsNormals);
|
||||
clearGroup(gErrors);
|
||||
clearGroup(gBoard);
|
||||
|
||||
if (!robotData) return;
|
||||
|
||||
const T = computeFK(robotData, joints);
|
||||
|
||||
// ── board plane ──
|
||||
const boardSize = robotData.links?.Board?.size || [1000, 200, 25];
|
||||
{
|
||||
const w = boardSize[0]*S, d = boardSize[1]*S, h = boardSize[2]*S;
|
||||
const geo = new THREE.BoxGeometry(w, h, d);
|
||||
const mat = new THREE.MeshPhongMaterial({ color:0x7a5520, transparent:true, opacity:0.5 });
|
||||
const m = new THREE.Mesh(geo, mat);
|
||||
m.position.set(w/2, -h/2, -d/2);
|
||||
m.receiveShadow = true;
|
||||
gBoard.add(m);
|
||||
}
|
||||
|
||||
// ── skeleton ──
|
||||
const links = robotData.links || {};
|
||||
for (const [lname, ld] of Object.entries(links)) {
|
||||
const sk = ld.skeleton;
|
||||
if (!sk) continue;
|
||||
const from = markerWorld(T, lname, sk.from || [0,0,0]);
|
||||
const to = markerWorld(T, lname, sk.to || [0,0,0]);
|
||||
const r = (sk.radius || 4) * S * 0.8;
|
||||
const col = sk.color ? new THREE.Color(...sk.color) : new THREE.Color(linkColor(lname));
|
||||
const cyl = makeCylinder(r2vArr(from), r2vArr(to), r, col);
|
||||
if (cyl) gSkeleton.add(cyl);
|
||||
}
|
||||
|
||||
// ── model markers + normals ──
|
||||
const modelPositions = {};
|
||||
const modelNormals = {};
|
||||
for (const [lname, ld] of Object.entries(links)) {
|
||||
const col = linkColor(lname);
|
||||
for (const m of (ld.markers||[])) {
|
||||
if (!m.position) continue;
|
||||
const mid = m.id;
|
||||
const wp = markerWorld(T, lname, m.position);
|
||||
const nLocal = m.normal || [0,0,1];
|
||||
const nWorld = transformDirByT(T[lname] || I4(), nLocal);
|
||||
|
||||
modelPositions[mid] = wp;
|
||||
modelNormals[mid] = nWorld;
|
||||
|
||||
const sq = makeMarkerSquare(r2vArr(wp), r2vDir(...nWorld), 0.022, col);
|
||||
gModel.add(sq);
|
||||
|
||||
// normal arrow (length = half a marker size = ~12.5mm → 0.0125m)
|
||||
const arr = makeNormalArrow(r2vArr(wp), nWorld, 0.018, col);
|
||||
gNormals.add(arr);
|
||||
}
|
||||
}
|
||||
|
||||
// ── observed markers + normals + error lines ──
|
||||
const obs = {};
|
||||
if (arucoData) {
|
||||
for (const m of (arucoData.markers||[])) {
|
||||
const mid = m.marker_id ?? m.id;
|
||||
if (mid == null) continue;
|
||||
let pos, nor = null;
|
||||
if (m.position_mm) pos = m.position_mm;
|
||||
else if (m.position_m) pos = m.position_m.map(v=>v*1000);
|
||||
else continue;
|
||||
// optional orientation from step-3 output or render markers.json
|
||||
if (m.normal_world) nor = m.normal_world;
|
||||
else if (m.normal) nor = m.normal;
|
||||
obs[mid] = { pos, nor };
|
||||
}
|
||||
}
|
||||
|
||||
const errors = [];
|
||||
for (const [midStr, {pos: opos, nor: oNor}] of Object.entries(obs)) {
|
||||
const mid = parseInt(midStr);
|
||||
const mpos = modelPositions[mid];
|
||||
const op = r2vArr(opos);
|
||||
|
||||
const errMm = mpos
|
||||
? Math.sqrt(opos.reduce((s,v,i) => s+(v-mpos[i])**2, 0))
|
||||
: null;
|
||||
const col = errMm == null ? 0x888888
|
||||
: errMm < 5 ? 0x3ecf6b
|
||||
: errMm < 15 ? 0xf59e0b
|
||||
: 0xff4f4f;
|
||||
|
||||
gObserved.add(makeSphere(op, 0.006, col));
|
||||
|
||||
// observed normal arrow — orange if available
|
||||
if (oNor) {
|
||||
try {
|
||||
const obsArrow = makeNormalArrow(op, oNor, 0.018, 0xffaa00);
|
||||
gObsNormals.add(obsArrow);
|
||||
} catch (e) {
|
||||
console.warn('Invalid normal for marker', mid, oNor, e);
|
||||
}
|
||||
} else if (modelNormals[mid]) {
|
||||
// fallback: show model normal at observed position (grey = no obs normal data)
|
||||
const obsArrow = makeNormalArrow(op, modelNormals[mid], 0.014, 0x666666);
|
||||
gObsNormals.add(obsArrow);
|
||||
}
|
||||
|
||||
if (mpos) {
|
||||
errors.push(errMm);
|
||||
const mp = r2vArr(mpos);
|
||||
gErrors.add(makeLine(mp, op, col));
|
||||
}
|
||||
}
|
||||
|
||||
// ── stats ──
|
||||
updateStats(errors, Object.keys(obs).length, Object.keys(modelPositions).length);
|
||||
}
|
||||
|
||||
// ─── statistics panel ──────────────────────────────────────────
|
||||
function updateStats(errArr, nObs, nModel) {
|
||||
const el = document.getElementById('stats-content');
|
||||
if (errArr.length === 0) {
|
||||
el.innerHTML = `<div class="stat-line"><span>Observed:</span><span class="stat-val">${nObs}</span></div>
|
||||
<div class="stat-line"><span>Model:</span><span class="stat-val">${nModel}</span></div>
|
||||
<div class="stat-line"><span style="color:var(--muted)">No matches found</span></div>`;
|
||||
return;
|
||||
}
|
||||
const sorted = [...errArr].sort((a,b)=>a-b);
|
||||
const mean = errArr.reduce((s,v)=>s+v,0) / errArr.length;
|
||||
const rms = Math.sqrt(errArr.reduce((s,v)=>s+v*v,0) / errArr.length);
|
||||
const p50 = sorted[Math.floor(sorted.length*0.5)];
|
||||
const p90 = sorted[Math.floor(sorted.length*0.9)];
|
||||
const max = sorted[sorted.length-1];
|
||||
|
||||
const cls = v => v < 5 ? 'stat-ok' : v < 15 ? 'stat-warn' : 'stat-err';
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="stat-line"><span>Observed:</span><span class="stat-val">${nObs}</span></div>
|
||||
<div class="stat-line"><span>Matched:</span><span class="stat-val">${errArr.length}</span></div>
|
||||
<div class="stat-line"><span>Mean error:</span><span class="${cls(mean)}">${mean.toFixed(1)} mm</span></div>
|
||||
<div class="stat-line"><span>RMS error:</span><span class="${cls(rms)}">${rms.toFixed(1)} mm</span></div>
|
||||
<div class="stat-line"><span>Median:</span><span class="${cls(p50)}">${p50.toFixed(1)} mm</span></div>
|
||||
<div class="stat-line"><span>p90:</span><span class="${cls(p90)}">${p90.toFixed(1)} mm</span></div>
|
||||
<div class="stat-line"><span>Max:</span><span class="${cls(max)}">${max.toFixed(1)} mm</span></div>
|
||||
<div style="margin-top:6px;font-size:10px;color:var(--muted)">
|
||||
🟢 <5mm 🟡 5–15mm 🔴 >15mm</div>`;
|
||||
}
|
||||
|
||||
function setStatus(msg) {
|
||||
document.getElementById('status-bar').textContent = msg + ' — Drag to orbit · Scroll to zoom';
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Render loop
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
function onResize() {
|
||||
const w = canvas.parentElement.clientWidth;
|
||||
const h = canvas.parentElement.clientHeight;
|
||||
renderer.setSize(w, h);
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
window.addEventListener('resize', onResize);
|
||||
onResize();
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
animate();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -95,6 +95,6 @@ echo [STEP 4] Robotics Pose calculation of angles and joint positions
|
||||
|
||||
|
||||
python3 "..\pipeline\4_robotState_estimation_v6.py" ^
|
||||
"%OUT_DIR%\aruco_positions_optimized.json" ^
|
||||
"%OUT_DIR%\aruco_positions_initial.json" ^
|
||||
-robot "%ROBOT_JSON%" ^
|
||||
-out "%OUT_DIR%\robot_state.json"
|
||||
|
||||
100
run/run_pipeline_v8.bat
Normal file
100
run/run_pipeline_v8.bat
Normal file
@@ -0,0 +1,100 @@
|
||||
@echo off
|
||||
setlocal EnableDelayedExpansion
|
||||
REM 3_pipeline_multiview.bat
|
||||
REM Multi-camera ArUco detection and pose estimation pipeline
|
||||
REM Parametr e.g.
|
||||
REM run_pipeline.bat ../data/simulation/Scene4
|
||||
|
||||
|
||||
|
||||
|
||||
REM Wenn kein Argument übergeben wurde
|
||||
if "%1"=="" (
|
||||
echo.
|
||||
echo [32m[INFO] Aufruf fehlt![0m
|
||||
echo [32mBeispiel: .\run_pipeline.bat ../data/simulation/Scene4[0m
|
||||
echo.
|
||||
exit /b
|
||||
)
|
||||
|
||||
|
||||
set "IMAGES=%~1"
|
||||
|
||||
REM trailing slash entfernen
|
||||
if "%IMAGES:~-1%"=="\" set "IMAGES=%IMAGES:~0,-1%"
|
||||
if "%IMAGES:~-1%"=="/" set "IMAGES=%IMAGES:~0,-1%"
|
||||
|
||||
set ROBOT_JSON=..\data\robot\robot.json
|
||||
set BASE_OUT_DIR=C:\Users\kech\SynologyDrive\2026-AppServer-AppRobot\appRobotRendering\data\evaluations
|
||||
|
||||
REM ✅ richtigen Namen extrahieren
|
||||
for %%I in ("%IMAGES%") do set "SCENE_NAME=%%~nxI"
|
||||
|
||||
set OUT_DIR=%BASE_OUT_DIR%\%SCENE_NAME%
|
||||
|
||||
|
||||
|
||||
echo.
|
||||
echo [STEP 1] Detect ArUco markers from all cameras in the folder %IMAGES%
|
||||
|
||||
for %%F in ("%IMAGES%\*.png" "%IMAGES%\*.PNG" "%IMAGES%\*.jpg" "%IMAGES%\*.jpeg" "%IMAGES%\*.JPG" "%IMAGES%\*.JPEG") do (
|
||||
|
||||
REM Dateiname ohne Pfad und ohne .png
|
||||
set "NAME=%%~nF"
|
||||
echo Bearbeite: !NAME!
|
||||
|
||||
REM Split bei "_" → nehme 2. Teil (die ID)
|
||||
for /f "tokens=2 delims=_" %%A in ("%%~nF") do (
|
||||
set "CAMID=%%A"
|
||||
|
||||
REM Takes files and detected arucos output to render_c_aruco_detection.json
|
||||
python3 ../pipeline/1_detect_aruco_observations.py ^
|
||||
-i "%%F" ^
|
||||
-npz "%IMAGES%\render_a.npz" ^
|
||||
-outDir %OUT_DIR% ^
|
||||
-robot %ROBOT_JSON% ^
|
||||
-cameraId !CAMID!
|
||||
)
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [STEP 2] Estimate camera poses from detections
|
||||
|
||||
for %%F in ("%OUT_DIR%\*_aruco_detection.json") do (
|
||||
echo Bearbeite: %%F
|
||||
|
||||
python3 ../pipeline/2_estimate_camera_from_observations.py ^
|
||||
-i "%%F" ^
|
||||
-robot %ROBOT_JSON% ^
|
||||
-outDir %OUT_DIR%
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [STEP 3] Triangulate marker positions from multi-view observations
|
||||
|
||||
|
||||
REM Alle detection files sammeln
|
||||
for %%F in ("%OUT_DIR%\*_aruco_detection.json") do (
|
||||
set DET_ARGS=!DET_ARGS! -det "%%F"
|
||||
)
|
||||
|
||||
REM Alle pose files sammeln
|
||||
for %%F in ("%OUT_DIR%\*_camera_pose.json") do (
|
||||
set POSE_ARGS=!POSE_ARGS! -pose "%%F"
|
||||
)
|
||||
|
||||
python3 "..\pipeline\3_multiview_bundle_adjustment_v4.py" ^
|
||||
-robot "%ROBOT_JSON%" ^
|
||||
-lambdaWeight 100.0 ^
|
||||
!DET_ARGS! ^
|
||||
!POSE_ARGS!
|
||||
|
||||
|
||||
echo.
|
||||
echo [STEP 4] Robotics Pose calculation of angles and joint positions
|
||||
|
||||
|
||||
python3 "..\pipeline\4_v8_4a_base_slider.py" ^
|
||||
"%OUT_DIR%\aruco_positions_initial.json" ^
|
||||
-robot "%ROBOT_JSON%" ^
|
||||
-out "%OUT_DIR%\robot_state.json"
|
||||
113
setup/precheck/jsonReadable.py
Normal file
113
setup/precheck/jsonReadable.py
Normal file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Pretty-print JSON with a simple rule:
|
||||
|
||||
- If an object/array fits on one line within 80 characters, keep it on one line.
|
||||
- Otherwise format it across multiple lines with 2-space indentation.
|
||||
- Preserve key order as read from the file.
|
||||
|
||||
Usage:
|
||||
python jsonReadable input.json > output.json
|
||||
python jsonReadable.py input.json --inplace
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
MAX_WIDTH = 120
|
||||
INDENT_STEP = 2
|
||||
|
||||
|
||||
def compact_json(value: Any) -> str:
|
||||
"""Return a compact single-line JSON representation."""
|
||||
if value is None or isinstance(value, (bool, int, float, str)):
|
||||
return json.dumps(value, ensure_ascii=False, separators=(",", ": "))
|
||||
if isinstance(value, list):
|
||||
return "[" + ", ".join(compact_json(v) for v in value) + "]"
|
||||
if isinstance(value, dict):
|
||||
items = []
|
||||
for k, v in value.items():
|
||||
key = json.dumps(k, ensure_ascii=False)
|
||||
items.append(f"{key}: {compact_json(v)}")
|
||||
return "{" + ", ".join(items) + "}"
|
||||
raise TypeError(f"Unsupported JSON type: {type(value)!r}")
|
||||
|
||||
|
||||
def pretty_json(value: Any, indent: int = 0, width: int = MAX_WIDTH) -> str:
|
||||
"""Pretty-print JSON with line-length awareness."""
|
||||
if value is None or isinstance(value, (bool, int, float, str)):
|
||||
return json.dumps(value, ensure_ascii=False)
|
||||
|
||||
if isinstance(value, list):
|
||||
if not value:
|
||||
return "[]"
|
||||
|
||||
single_line = compact_json(value)
|
||||
if indent + len(single_line) <= width:
|
||||
return single_line
|
||||
|
||||
inner_indent = " " * (indent + INDENT_STEP)
|
||||
lines = ["["]
|
||||
for i, item in enumerate(value):
|
||||
rendered = pretty_json(item, indent + INDENT_STEP, width)
|
||||
comma = "," if i < len(value) - 1 else ""
|
||||
lines.append(f"{inner_indent}{rendered}{comma}")
|
||||
lines.append(" " * indent + "]")
|
||||
return "\n".join(lines)
|
||||
|
||||
if isinstance(value, dict):
|
||||
if not value:
|
||||
return "{}"
|
||||
|
||||
single_line = compact_json(value)
|
||||
if indent + len(single_line) <= width:
|
||||
return single_line
|
||||
|
||||
inner_indent = " " * (indent + INDENT_STEP)
|
||||
lines = ["{"]
|
||||
items = list(value.items())
|
||||
for i, (k, v) in enumerate(items):
|
||||
key = json.dumps(k, ensure_ascii=False)
|
||||
rendered = pretty_json(v, indent + INDENT_STEP, width)
|
||||
comma = "," if i < len(items) - 1 else ""
|
||||
lines.append(f"{inner_indent}{key}: {rendered}{comma}")
|
||||
lines.append(" " * indent + "}")
|
||||
return "\n".join(lines)
|
||||
|
||||
raise TypeError(f"Unsupported JSON type: {type(value)!r}")
|
||||
|
||||
|
||||
def format_json_text(text: str) -> str:
|
||||
data = json.loads(text)
|
||||
return pretty_json(data, indent=0, width=MAX_WIDTH) + "\n"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Format JSON so short objects/arrays stay on one line."
|
||||
)
|
||||
parser.add_argument("file", type=Path, help="Path to the .json file")
|
||||
parser.add_argument(
|
||||
"--inplace",
|
||||
action="store_true",
|
||||
help="Overwrite the input file instead of printing to stdout",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
input_path: Path = args.file
|
||||
text = input_path.read_text(encoding="utf-8")
|
||||
formatted = format_json_text(text)
|
||||
|
||||
if args.inplace:
|
||||
input_path.write_text(formatted, encoding="utf-8")
|
||||
else:
|
||||
print(formatted, end="")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user