2 Camera Detection
Checke wo sich im Bild die Kamera befindet
This commit is contained in:
@@ -1,45 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name":"Test 0",
|
||||
"robot":"test/data/robot/robot.json",
|
||||
"image":[
|
||||
{
|
||||
"timestamp":11778819665744,
|
||||
"file":"test/data/screenShots/snapshot_video0_11778819665744.jpg",
|
||||
"camera":"c310",
|
||||
"callibration":"data/settings/callibration_cam0.npz"
|
||||
},
|
||||
{
|
||||
"timestamp":11778819665744,
|
||||
"file":"test/data/screenShots/snapshot_video1_11778819665744.jpg",
|
||||
"camera":"c310",
|
||||
"callibration":"data/settings/callibration_cam0.npz"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"Test 1: 45° unterarm",
|
||||
"robot":"test/data/robot/robot.json",
|
||||
"timestamp":1779690911822,
|
||||
"image":[
|
||||
{
|
||||
"timestamp":1779690911822,
|
||||
"file":"test/data/screenShots/snapshot_video0_1779690911822.jpg",
|
||||
"camera":"c310",
|
||||
"callibration":"data/settings/callibration_cam0.npz"
|
||||
},
|
||||
{
|
||||
"timestamp":1779690911822,
|
||||
"file":"test/data/screenShots/snapshot_video0_1779690911822.jpg",
|
||||
"camera":"c310",
|
||||
"callibration":"data/settings/callibration_cam0.npz"
|
||||
},
|
||||
{
|
||||
"timestamp":1779690911822,
|
||||
"file":"test/data/screenShots/1779690911822_DSCF1382.JPG",
|
||||
"camera":"XT1",
|
||||
"callibration":"data/callibration/XT1-16mm28-1mFokus_f8/callibration_XT1-16mm_1m_f8.npz"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,64 +0,0 @@
|
||||
// test/aruco.test.js
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
describe('Aruco Detection Script', () => {
|
||||
const scriptPath = 'programs/01_read_AruCo_jpg_to_json.py';
|
||||
const calibrationFile = 'data/settings/callibration_cam0.npz';
|
||||
const sourceScreenshotsDir = path.join(__dirname, 'data', 'screenShots');
|
||||
const screenshotFiles = [
|
||||
'snapshot_video0_1778819665744.jpg',
|
||||
'snapshot_video1_1778819665744.jpg',
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
screenshotFiles.forEach((file) => {
|
||||
const src = path.join(sourceScreenshotsDir, file);
|
||||
if (!fs.existsSync(src)) {
|
||||
throw new Error(`Missing test fixture screenshot: ${src}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Keep generated detection JSON files in the screenshot directory.
|
||||
});
|
||||
|
||||
test('should exist and be executable', () => {
|
||||
expect(fs.existsSync(scriptPath)).toBe(true);
|
||||
});
|
||||
|
||||
test('should have calibration file', () => {
|
||||
expect(fs.existsSync(calibrationFile)).toBe(true);
|
||||
});
|
||||
|
||||
test('should have screenshot directory', () => {
|
||||
expect(fs.existsSync(sourceScreenshotsDir)).toBe(true);
|
||||
});
|
||||
|
||||
test('should process screenshots successfully', () => {
|
||||
const screenshots = fs.readdirSync(sourceScreenshotsDir)
|
||||
.filter(file => file.endsWith('.jpg') || file.endsWith('.png'))
|
||||
.filter(file => screenshotFiles.includes(file));
|
||||
|
||||
expect(screenshots.length).toBeGreaterThan(0);
|
||||
|
||||
screenshots.forEach(screenshot => {
|
||||
const screenshotPath = path.join(sourceScreenshotsDir, screenshot);
|
||||
const jsonPath = screenshotPath.replace(/\.(jpg|png)$/i, '_aruco_detection.json');
|
||||
const cmd = `python ${scriptPath} -i "${screenshotPath}" -npz "${calibrationFile}" -cameraId 0`;
|
||||
|
||||
try {
|
||||
execSync(cmd, { stdio: 'inherit' });
|
||||
expect(fs.existsSync(jsonPath)).toBe(true);
|
||||
|
||||
const jsonData = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
||||
expect(jsonData).toBeDefined();
|
||||
expect(typeof jsonData).toBe('object');
|
||||
} catch (error) {
|
||||
fail(`Failed to process ${screenshot}: ${error.message}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,55 +0,0 @@
|
||||
// test/02_build_scene_json.test.js
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
describe('Build Scene JSON Script', () => {
|
||||
const scriptPath = 'programs/02_build_scene_json.py';
|
||||
const timestamp = 1778819665744;
|
||||
const screenshotDir = path.join(__dirname, 'data', 'screenShots');
|
||||
const detectionFiles = [
|
||||
'snapshot_video0_1778819665744_aruco_detection.json',
|
||||
'snapshot_video1_1778819665744_aruco_detection.json',
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
detectionFiles.forEach((file) => {
|
||||
const src = path.join(screenshotDir, file);
|
||||
if (!fs.existsSync(src)) {
|
||||
throw new Error(`Missing test fixture detection file: ${src}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Keep the generated scene JSON in the screenshot directory for real-world behavior.
|
||||
});
|
||||
|
||||
test('should exist and be executable', () => {
|
||||
expect(fs.existsSync(scriptPath)).toBe(true);
|
||||
});
|
||||
|
||||
test('should build scene JSON with timestamp parameter', () => {
|
||||
const cmd = `python ${scriptPath} -timestamp ${timestamp} -dir "${screenshotDir}"`;
|
||||
|
||||
try {
|
||||
execSync(cmd, { stdio: 'inherit' });
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to build scene JSON: ${error.message}`);
|
||||
}
|
||||
|
||||
const expectedJsonFile = path.join(screenshotDir, `scene_${timestamp}.json`);
|
||||
expect(fs.existsSync(expectedJsonFile)).toBe(true);
|
||||
|
||||
const jsonData = JSON.parse(fs.readFileSync(expectedJsonFile, 'utf8'));
|
||||
expect(jsonData).toBeDefined();
|
||||
expect(typeof jsonData).toBe('object');
|
||||
expect(jsonData.cameras).toBeDefined();
|
||||
expect(Object.keys(jsonData.cameras).sort()).toEqual(['0', '1']);
|
||||
});
|
||||
|
||||
test('should handle timestamp parameter correctly', () => {
|
||||
// Überprüfe, ob der Timestamp korrekt verarbeitet wird
|
||||
expect(timestamp).toBe(1778819665744);
|
||||
});
|
||||
});
|
||||
@@ -1,74 +0,0 @@
|
||||
// test/03a_cameraPose.test.js
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
describe('Camera Pose Script', () => {
|
||||
const projectRoot = path.resolve(__dirname, '..');
|
||||
const scriptPath = path.resolve(projectRoot, 'programs/03a_cameraPose.py');
|
||||
const timestamp = 1778819665744;
|
||||
const screenshotDir = path.join(__dirname, 'data', 'screenShots');
|
||||
const detectionFiles = [
|
||||
'snapshot_video0_1778819665744_aruco_detection.json',
|
||||
'snapshot_video1_1778819665744_aruco_detection.json',
|
||||
];
|
||||
const robotFile = path.resolve(projectRoot, 'test/data/robot/robot.json');
|
||||
const sceneFile = path.join(screenshotDir, `scene_${timestamp}.json`);
|
||||
const outputFile = path.join(screenshotDir, `scene_${timestamp}_cameras.json`);
|
||||
|
||||
beforeEach(() => {
|
||||
detectionFiles.forEach((file) => {
|
||||
const src = path.join(screenshotDir, file);
|
||||
if (!fs.existsSync(src)) {
|
||||
throw new Error(`Missing test fixture detection file: ${src}`);
|
||||
}
|
||||
});
|
||||
|
||||
if (!fs.existsSync(sceneFile)) {
|
||||
throw new Error(`Missing scene file generated by step 2: ${sceneFile}`);
|
||||
}
|
||||
|
||||
if (fs.existsSync(outputFile)) {
|
||||
fs.unlinkSync(outputFile);
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Keep the generated scene and camera JSON in the screenshot directory.
|
||||
});
|
||||
|
||||
test('should exist and be executable', () => {
|
||||
expect(fs.existsSync(scriptPath)).toBe(true);
|
||||
});
|
||||
|
||||
test('should have scene file', () => {
|
||||
expect(fs.existsSync(sceneFile)).toBe(true);
|
||||
});
|
||||
|
||||
test('should have robot file', () => {
|
||||
expect(fs.existsSync(robotFile)).toBe(true);
|
||||
});
|
||||
|
||||
test('should compute camera poses with timestamp parameter', () => {
|
||||
// Führe das Python-Skript mit den korrekten Parametern aus
|
||||
const cmd = `python "${scriptPath}" -scene "${sceneFile}" -robot "${robotFile}" -out "${outputFile}"`;
|
||||
|
||||
try {
|
||||
execSync(cmd, { stdio: 'inherit', cwd: projectRoot });
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to compute camera poses: ${error.message}`);
|
||||
}
|
||||
// Überprüfe, ob die erwartete Ausgabedatei erstellt wurde
|
||||
expect(fs.existsSync(outputFile)).toBe(true);
|
||||
|
||||
// Prüfe den Inhalt der JSON-Datei
|
||||
const jsonData = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
|
||||
expect(jsonData).toBeDefined();
|
||||
expect(typeof jsonData).toBe('object');
|
||||
expect(jsonData).toHaveProperty('camera_poses');
|
||||
});
|
||||
|
||||
test('should handle timestamp parameter correctly', () => {
|
||||
expect(timestamp).toBe(1778819665744);
|
||||
});
|
||||
});
|
||||
99
test/0_path_OK.test.js
Normal file
99
test/0_path_OK.test.js
Normal file
@@ -0,0 +1,99 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
|
||||
const PROJECT_PATH = process.cwd()
|
||||
const TEST_PATH = path.join(__dirname, '.');
|
||||
const SCRIPT_FILE = path.join(PROJECT_PATH, 'programs', '1_detect_aruco_observations.py');
|
||||
const SOURCE_DIR = path.join(__dirname,'data', 'screenShots');
|
||||
const TARGET_DIR = path.join(__dirname,'data', 'screenshots', '1778819665744_detection_testResults');
|
||||
const PYTHON_CMD = process.platform === 'win32' ? 'python' : 'python3';
|
||||
const TEST_SETUP_FILE = path.join(TEST_PATH, 'data', '0_testSetup.json');
|
||||
const ROBOT_PATH = path.join(__dirname, 'data', 'robot', 'robot.json');
|
||||
const SCRIPT_FILE_2 = path.join(PROJECT_PATH, 'programs', '2_estimate_camera_pose_from_aruco_json.py');
|
||||
|
||||
|
||||
const cam = {
|
||||
id : 'cam1',
|
||||
image: 'snapshot_video1_1779690911822.jpg',
|
||||
intrinsics: path.join(PROJECT_PATH, 'data', 'settings','callibration_cam0.npz')
|
||||
};
|
||||
|
||||
|
||||
// Passe diese Werte an deine echten Daten an
|
||||
const pathsToCheck = {
|
||||
SOURCE_DIR,
|
||||
SCRIPT_FILE,
|
||||
ROBOT_PATH,
|
||||
SCRIPT_FILE_2,
|
||||
NPZ_PATH: cam.intrinsics,
|
||||
IMAGE_PATH: path.join(SOURCE_DIR, cam.image),
|
||||
PYTHON_SCRIPT: path.join(PROJECT_PATH, 'programs', '1_detect_aruco_observations.py'),
|
||||
TEST_SETUP_FILE,
|
||||
};
|
||||
|
||||
|
||||
|
||||
describe('Check if Paths exist', () => {
|
||||
|
||||
test('Each relevant Python File etc.', () => {
|
||||
const missing = [];
|
||||
|
||||
for (const [name, filePath] of Object.entries(pathsToCheck)) {
|
||||
if (!filePath || !fs.existsSync(filePath)) {
|
||||
missing.push(`${name} -> ${filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
throw new Error(
|
||||
'Folgende Pfade fehlen oder sind ungültig:\n' +
|
||||
missing.join('\n')
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('Test if files in Setup exist', () => {
|
||||
|
||||
|
||||
console.log('TEST_PATH:', TEST_PATH);
|
||||
console.log('PROJECT_PATH:', PROJECT_PATH);
|
||||
console.log('SOURCE_DIR:', SOURCE_DIR);
|
||||
|
||||
if (!fs.existsSync(TEST_SETUP_FILE)) {
|
||||
throw new Error(`Test-Setup Datei fehlt: ${TEST_SETUP_FILE}`);
|
||||
}
|
||||
|
||||
const raw = fs.readFileSync(TEST_SETUP_FILE, 'utf8');
|
||||
const data = JSON.parse(raw);
|
||||
|
||||
|
||||
const missing = [];
|
||||
|
||||
data.forEach((testCase, i) => {
|
||||
|
||||
const r = testCase.robot.map(i => i.replace("TEST_PATH", TEST_PATH).replace("PROJECT_PATH", PROJECT_PATH));
|
||||
const pathR = path.join(r.map(p => p.toString()).join(path.sep));
|
||||
if (!pathR || !fs.existsSync(pathR)) {
|
||||
missing.push(`${name} -> ${filePath}`);
|
||||
}
|
||||
|
||||
testCase.image.forEach((img, j) => {
|
||||
const imgPath = path.join(img.file.map(i => i.replace("TEST_PATH", TEST_PATH).replace("PROJECT_PATH", PROJECT_PATH)).join(path.sep));
|
||||
if (!imgPath || !fs.existsSync(imgPath)) {
|
||||
missing.push(`TestCase ${i} Image ${j} -> ${imgPath}`);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
console.log('Missing files in test setup:', missing);
|
||||
if (missing.length > 0) {
|
||||
throw new Error(
|
||||
'Folgende Dateien aus dem Test-Setup fehlen oder sind ungültig:\n' +
|
||||
missing.join('\n')
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
const PROJECT_PATH = process.cwd()
|
||||
const TEST_PATH = path.join(__dirname, '.');
|
||||
const SOURCE_DIR = path.join(__dirname,'data', 'screenShots');
|
||||
const TARGET_DIR = path.join(__dirname,'data', 'screenshots', '1778819665744_detection_singleTest_testResults');
|
||||
const PYTHON_CMD = process.platform === 'win32' ? 'python' : 'python3';
|
||||
const TEST_SETUP_FILE = path.join(TEST_PATH, 'data', '0_testSetup.json');
|
||||
const SCRIPT_FILE = path.join(PROJECT_PATH, 'programs', '1_detect_aruco_observations.py');
|
||||
const ROBOT_PATH = path.join(__dirname, 'data', 'robot', 'robot.json');
|
||||
|
||||
|
||||
const cam = {
|
||||
id : 'cam1',
|
||||
image: 'snapshot_video1_1779690911822.jpg',
|
||||
intrinsics: path.join(PROJECT_PATH, 'data', 'settings','callibration_cam0.npz')
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
describe('Check if Python runs', () => {
|
||||
|
||||
test('First Run of Python', () => {
|
||||
|
||||
|
||||
console.log('Intrinsics : ', cam.intrinsics);
|
||||
execFileSync(PYTHON_CMD, [
|
||||
SCRIPT_FILE,
|
||||
'-i', path.join(SOURCE_DIR, cam.image),
|
||||
'-npz', cam.intrinsics,
|
||||
'-robot', ROBOT_PATH,
|
||||
'-cameraId', cam.id
|
||||
|
||||
,
|
||||
'-outDir', TARGET_DIR
|
||||
], {
|
||||
stdio: 'inherit',
|
||||
cwd: SOURCE_DIR // <- wichtig
|
||||
});
|
||||
|
||||
|
||||
const resultFile = path.join(TARGET_DIR, 'snapshot_video1_1779690911822_aruco_detection.json');
|
||||
|
||||
if (!fs.existsSync(resultFile)) {
|
||||
throw new Error(`Erwartete Datei fehlt: ${resultFile}`);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
// ✅ Cleanup läuft IMMER nach jedem Test
|
||||
afterEach(() => {
|
||||
if (!fs.existsSync(TARGET_DIR)) return;
|
||||
|
||||
fs.readdirSync(TARGET_DIR).forEach(file => {
|
||||
fs.rmSync(path.join(TARGET_DIR, file), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
});
|
||||
78
test/2_estimate_camera_pose_from_aruco_json.test.js
Normal file
78
test/2_estimate_camera_pose_from_aruco_json.test.js
Normal file
@@ -0,0 +1,78 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
const PROJECT_PATH = process.cwd()
|
||||
const TEST_PATH = path.join(__dirname, '.');
|
||||
const SOURCE_DIR = path.join(__dirname,'data', 'screenShots');
|
||||
const TARGET_DIR = path.join(__dirname,'data', 'screenshots', '1778819665744_detection_singleTest_testResults');
|
||||
const PYTHON_CMD = process.platform === 'win32' ? 'python' : 'python3';
|
||||
const TEST_SETUP_FILE = path.join(TEST_PATH, 'data', '0_testSetup.json');
|
||||
const SCRIPT_FILE = path.join(PROJECT_PATH, 'programs', '1_detect_aruco_observations.py');
|
||||
const ROBOT_PATH = path.join(__dirname, 'data', 'robot', 'robot.json');
|
||||
const SCRIPT_FILE_2 = path.join(PROJECT_PATH, 'programs', '2_estimate_camera_pose_from_aruco_json.py');
|
||||
|
||||
|
||||
const cam = {
|
||||
id : 'cam1',
|
||||
image: 'snapshot_video1_1779690911822.jpg',
|
||||
intrinsics: path.join(PROJECT_PATH, 'data', 'settings','callibration_cam0.npz')
|
||||
};
|
||||
|
||||
|
||||
|
||||
describe('Check if Python 2 runs', () => {
|
||||
|
||||
test('First Run of Python second script', () => {
|
||||
|
||||
|
||||
console.log('Intrinsics : ', cam.intrinsics);
|
||||
execFileSync(PYTHON_CMD, [
|
||||
SCRIPT_FILE,
|
||||
'-i', path.join(SOURCE_DIR, cam.image),
|
||||
'-npz', cam.intrinsics,
|
||||
'-robot', ROBOT_PATH,
|
||||
'-cameraId', cam.id
|
||||
|
||||
,
|
||||
'-outDir', TARGET_DIR
|
||||
], {
|
||||
stdio: 'inherit',
|
||||
cwd: SOURCE_DIR // <- wichtig
|
||||
});
|
||||
|
||||
|
||||
const resultFile = path.join(TARGET_DIR, 'snapshot_video1_1779690911822_aruco_detection.json');
|
||||
|
||||
if (!fs.existsSync(resultFile)) {
|
||||
throw new Error(`Erwartete Datei fehlt: ${resultFile}`);
|
||||
}
|
||||
|
||||
|
||||
console.log('Intrinsics : ', cam.intrinsics);
|
||||
execFileSync(PYTHON_CMD, [
|
||||
SCRIPT_FILE_2,
|
||||
'--detections' , resultFile,
|
||||
'--robots', ROBOT_PATH
|
||||
], {
|
||||
stdio: 'inherit',
|
||||
cwd: SOURCE_DIR // <- wichtig
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
// ✅ Cleanup läuft IMMER nach jedem Test
|
||||
afterEach(() => {
|
||||
if (!fs.existsSync(TARGET_DIR)) return;
|
||||
|
||||
fs.readdirSync(TARGET_DIR).forEach(file => {
|
||||
fs.rmSync(path.join(TARGET_DIR, file), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
});
|
||||
45
test/data/0_testSetup.json
Normal file
45
test/data/0_testSetup.json
Normal file
@@ -0,0 +1,45 @@
|
||||
[
|
||||
{
|
||||
"name":"Test 0",
|
||||
"robot":["TEST_PATH","data","robot","robot.json"],
|
||||
"image":[
|
||||
{
|
||||
"timestamp":11778819665744,
|
||||
"file":["TEST_PATH","data","screenShots","snapshot_video0_1778819665744.jpg"],
|
||||
"camera":"c310",
|
||||
"callibration":["PROJECT_PATH", "data", "settings","callibration_cam0.npz"]
|
||||
},
|
||||
{
|
||||
"timestamp":11778819665744,
|
||||
"file":["TEST_PATH","data","screenShots","snapshot_video1_1778819665744.jpg"],
|
||||
"camera":"c310",
|
||||
"callibration":["PROJECT_PATH", "data", "settings","callibration_cam0.npz"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"Test 1: 45° unterarm",
|
||||
"robot":["TEST_PATH","data","robot","robot.json"],
|
||||
"timestamp":1779690911822,
|
||||
"image":[
|
||||
{
|
||||
"timestamp":1779690911822,
|
||||
"file":["TEST_PATH","data","screenShots","snapshot_video0_1779690911822.jpg"],
|
||||
"camera":"c310",
|
||||
|
||||
"callibration":["PROJECT_PATH", "data", "settings","callibration_cam0.npz"]
|
||||
} ,
|
||||
{
|
||||
"timestamp":1779690911822,
|
||||
"file":["TEST_PATH","data","screenShots","snapshot_video1_1779690911822.jpg"],
|
||||
"camera":"c310",
|
||||
"callibration":["PROJECT_PATH", "data", "settings","callibration_cam0.npz"] },
|
||||
{
|
||||
"timestamp":1779690911822,
|
||||
"file":["TEST_PATH","data","screenShots","1779690911822_DSCF1382.JPG"],
|
||||
"camera":"XT1",
|
||||
"callibration":["PROJECT_PATH", "data", "XT1-16mm28-1mFokus_f8","callibration_XT1-16mm_1m_f8.npz"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"vision_config":{
|
||||
"MarkerType":"DICT_4X4_250",
|
||||
"MarkerSize":0.025
|
||||
},
|
||||
"recognized":{"x":null, "y":null, "z": null, "a":null, "b":null, "c":null, "e": null},
|
||||
"Elements":["Board","Base","Arm1","Joint1","Arm2","Finger1","Finger2"],
|
||||
"ElementLength":{"Arm1":250, "Arm2":250, "Finger1":100, "Finger2":100},
|
||||
@@ -8,7 +12,6 @@
|
||||
"jointC":{"name":"EllbowLift","type":"revolute","axis":[1,0,0],"parent":"Arm1","child":"Joint1", "origin":[null, null, null]},
|
||||
"jointD":{"name":"EllbowTwist","type":"revolute","axis":[0,1,0],"parent":"Joint1","child":"Arm2", "origin":[null, null, null]}
|
||||
},
|
||||
"MarkerType":"DICT_4X4_250",
|
||||
"Marker":[
|
||||
{"id":205,"on":"Board","position":[0.80, -0.090, 0.0]},
|
||||
{"id":207,"on":"Board","position":[0.80, 0.0, 0.0]},
|
||||
|
||||
Reference in New Issue
Block a user