Anthropic Claude

This commit is contained in:
chk
2026-06-01 16:36:33 +02:00
parent 761919bb93
commit 6655fc6f02
49 changed files with 8379 additions and 7764 deletions

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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,

View File

@@ -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

Binary file not shown.

View File

@@ -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}
]
},

View File

File diff suppressed because it is too large Load Diff

View 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()

View 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())

View 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())

View 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.

310
pipeline/robot_fk.py Normal file
View 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
View 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)">
🟢 &lt;5mm &nbsp; 🟡 515mm &nbsp; 🔴 &gt;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
View 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)">
🟢 &lt;5mm &nbsp; 🟡 515mm &nbsp; 🔴 &gt;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>

View File

@@ -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
View 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 [INFO] Aufruf fehlt!
echo Beispiel: .\run_pipeline.bat ../data/simulation/Scene4
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"

View 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()