forgecad 0.9.16 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AdminPage-CXvls4-J.js → AdminPage-DcCnj0qo.js} +1 -1
- package/dist/assets/{BenchmarkPage-B27zk8xL.js → BenchmarkPage-BVEpJSVk.js} +1 -1
- package/dist/assets/{BlogPage-CMAVvgQL.js → BlogPage-DHaGP50_.js} +1 -1
- package/dist/assets/{DocsPage-knf4I4h7.js → DocsPage-CDoxHkz8.js} +40 -859
- package/dist/assets/EditorApp-BJ0Dloyh.js +16446 -0
- package/dist/assets/{EmbedViewer-D7ZGlFjx.js → EmbedViewer-CRKZbY0y.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-CnevhTE8.js → LandingPageProofDriven-BxHkYRE7.js} +1 -1
- package/dist/assets/{LegalPage-BPTUmqeg.js → LegalPage-B-u6FrVv.js} +1 -1
- package/dist/assets/{PricingPage-B0D4goG_.js → PricingPage-CzpZ6-Ce.js} +1 -1
- package/dist/assets/{SettingsPage-CFF-UgjI.js → SettingsPage-CIZSSAd0.js} +1 -1
- package/dist/assets/{app-CE3sYcV7.css → app-CjsbDlb7.css} +143 -0
- package/dist/assets/{app-T0pDcSX4.js → app-DaTMg3nH.js} +1310 -290
- package/dist/assets/cli/{render-C5pcIISc.js → render-DPf4AYJK.js} +55 -60
- package/dist/assets/{constructionHistoryWorker-Ba2Hm58b.js → constructionHistoryWorker-AwMMWSxg.js} +1103 -349
- package/dist/assets/{evalWorker-vkx310U2.js → evalWorker-CjZZWRWW.js} +5209 -2643
- package/dist/assets/{inspectWorker-BuTJDVX6.js → inspectWorker-CZsCFtQT.js} +1163 -409
- package/dist/assets/{jointPose-B_Cgedn9.js → jointPose-DzQOViQH.js} +1 -1
- package/dist/assets/{manifold-BWgsjmAM.js → manifold-BYlzU521.js} +1 -1
- package/dist/assets/{manifold-D6IFSkhH.js → manifold-DgXo0T5P.js} +2 -2
- package/dist/assets/{manifold-rZexZI0G.js → manifold-K1SkarlQ.js} +1 -1
- package/dist/assets/{reportWorker-0AGij1Ru.js → reportWorker-B9nWwSrB.js} +8501 -3393
- package/dist/assets/{scalar-sampling-budget-J5cuzxT1.js → scalar-sampling-budget-prBw_s8t.js} +6067 -3479
- package/dist/assets/{scanProxyWorker-Vl4Wxa1y.js → scanProxyWorker-2GtDLk-R.js} +1 -1
- package/dist/assets/{javascript-1kQXfVaz.js → typescript-DBQ6RN5l.js} +874 -22
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +3 -3
- package/dist/docs-raw/AI/usage.md +1 -1
- package/dist/docs-raw/CLI.md +77 -240
- package/dist/docs-raw/README.md +6 -0
- package/dist/docs-raw/component-model.md +17 -150
- package/dist/docs-raw/generated/assembly.md +188 -582
- package/dist/docs-raw/generated/concepts.md +259 -3501
- package/dist/docs-raw/generated/core.md +283 -1250
- package/dist/docs-raw/generated/curves.md +387 -1608
- package/dist/docs-raw/generated/legacy.md +162 -0
- package/dist/docs-raw/generated/lib.md +227 -85
- package/dist/docs-raw/generated/output.md +35 -99
- package/dist/docs-raw/generated/runtime-names.md +23 -23
- package/dist/docs-raw/generated/sdf.md +68 -284
- package/dist/docs-raw/generated/sheet-metal.md +68 -335
- package/dist/docs-raw/generated/sketch.md +240 -1161
- package/dist/docs-raw/generated/viewport.md +75 -316
- package/dist/docs-raw/generated/wood.md +21 -49
- package/dist/docs-raw/guides/coordinate-system.md +4 -42
- package/dist/docs-raw/guides/inspection-bundles.md +44 -442
- package/dist/docs-raw/guides/joint-design.md +18 -79
- package/dist/docs-raw/guides/positioning.md +21 -143
- package/dist/docs-raw/guides/scene-presentation.md +89 -0
- package/dist/docs-raw/guides/simready-quickstart.md +171 -0
- package/dist/docs-raw/simulation-workflow.md +273 -0
- package/dist/docs-raw/skills/forgecad-3d-reconstruction.md +25 -111
- package/dist/docs-raw/skills/forgecad-blockout-model.md +20 -117
- package/dist/docs-raw/skills/forgecad-component-model.md +23 -107
- package/dist/docs-raw/skills/forgecad-high-level-spec.md +47 -155
- package/dist/docs-raw/skills/forgecad-image-replicator.md +26 -143
- package/dist/docs-raw/skills/forgecad-lld.md +19 -113
- package/dist/docs-raw/skills/forgecad-make-a-model.md +112 -532
- package/dist/docs-raw/skills/forgecad-model-grader.md +38 -108
- package/dist/docs-raw/skills/forgecad-prepare-prompt.md +24 -211
- package/dist/docs-raw/skills/forgecad-project.md +13 -131
- package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +42 -134
- package/dist/docs-raw/skills/forgecad-render-inspect.md +27 -174
- package/dist/docs-raw/skills/forgecad-visual-spec.md +32 -112
- package/dist/docs-raw/skills/forgecad.md +19 -18
- package/dist/docs-raw/skills/index.md +2 -0
- package/dist/docs-raw/welcome.md +2 -2
- package/dist/index.html +2 -2
- package/dist/llms.txt +1 -2
- package/dist/sitemap.xml +25 -13
- package/dist-cli/{check-compiler-SYQ2PWOB.js → check-compiler-II7NLPAB.js} +1 -1
- package/dist-cli/{check-query-propagation-HIAGV62W.js → check-query-propagation-7462TR3R.js} +1 -1
- package/dist-cli/{chunk-SPZE3DUY.js → chunk-UWTJCGXF.js} +5848 -2915
- package/dist-cli/forgecad.js +3496 -703
- package/dist-skill/CONTEXT.md +1797 -7963
- package/dist-skill/SKILL.md +15 -15
- package/dist-skill/docs/API/core/concepts.md +27 -157
- package/dist-skill/docs/CLI.md +77 -240
- package/dist-skill/docs/generated/assembly.md +182 -532
- package/dist-skill/docs/generated/core.md +283 -1250
- package/dist-skill/docs/generated/curves.md +387 -1609
- package/dist-skill/docs/generated/lib.md +227 -85
- package/dist-skill/docs/generated/output.md +35 -99
- package/dist-skill/docs/generated/runtime-names.md +16 -21
- package/dist-skill/docs/generated/sdf.md +68 -284
- package/dist-skill/docs/generated/sheet-metal.md +68 -335
- package/dist-skill/docs/generated/sketch.md +240 -1160
- package/dist-skill/docs/generated/viewport.md +75 -223
- package/dist-skill/docs/generated/wood.md +21 -49
- package/dist-skill/docs/guides/coordinate-system.md +4 -42
- package/dist-skill/docs/guides/inspection-bundles.md +44 -442
- package/dist-skill/docs/guides/joint-design.md +18 -79
- package/dist-skill/docs/guides/positioning.md +21 -143
- package/dist-skill/docs/guides/scene-presentation.md +89 -0
- package/dist-skill/docs/guides/surface-members.md +26 -0
- package/dist-skill/library/forgecad-3d-reconstruction/SKILL.md +23 -111
- package/dist-skill/library/forgecad-blockout-model/SKILL.md +18 -117
- package/dist-skill/library/forgecad-component-model/SKILL.md +21 -107
- package/dist-skill/library/forgecad-high-level-spec/SKILL.md +45 -155
- package/dist-skill/library/forgecad-image-replicator/SKILL.md +24 -143
- package/dist-skill/library/forgecad-lld/SKILL.md +17 -113
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +110 -532
- package/dist-skill/library/forgecad-model-grader/SKILL.md +36 -108
- package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +35 -224
- package/dist-skill/library/forgecad-prepare-prompt/references/default-profiles.md +43 -271
- package/dist-skill/library/forgecad-prepare-prompt/references/master-prompt.md +30 -99
- package/dist-skill/library/forgecad-project/SKILL.md +13 -133
- package/dist-skill/library/forgecad-reconstruction-benchmark/SKILL.md +29 -123
- package/dist-skill/library/forgecad-render-inspect/SKILL.md +25 -174
- package/dist-skill/library/forgecad-visual-spec/SKILL.md +30 -111
- package/dist-skill/website/skills/forgecad-3d-reconstruction.md +58 -0
- package/dist-skill/website/skills/forgecad-blockout-model.md +49 -0
- package/dist-skill/website/skills/forgecad-component-model.md +53 -0
- package/dist-skill/website/skills/forgecad-high-level-spec.md +101 -0
- package/dist-skill/website/skills/forgecad-image-replicator.md +63 -0
- package/dist-skill/website/skills/forgecad-lld.md +41 -0
- package/dist-skill/website/skills/forgecad-make-a-model.md +186 -0
- package/dist-skill/website/skills/forgecad-model-grader.md +82 -0
- package/dist-skill/website/skills/forgecad-prepare-prompt.md +63 -0
- package/dist-skill/website/skills/forgecad-project.md +26 -0
- package/dist-skill/website/skills/forgecad-reconstruction-benchmark.md +60 -0
- package/dist-skill/website/skills/forgecad-render-inspect.md +80 -0
- package/dist-skill/website/skills/forgecad-visual-spec.md +71 -0
- package/dist-skill/website/skills/forgecad.md +122 -0
- package/dist-skill/website/skills/index.md +26 -0
- package/examples/api/comparison-imported-sphere-candidate.forge.js +1 -1
- package/examples/api/conformal-product-ribbon.forge.js +1 -1
- package/examples/api/exact-sheet-shell-assembly.forge.js +1 -1
- package/examples/api/extrude-options.forge.js +4 -2
- package/examples/api/field-loft-drive-tip.forge.js +40 -0
- package/examples/api/guided-loft-olive-oil-bottle.forge.js +1 -1
- package/examples/api/highlight-debug.forge.js +10 -10
- package/examples/api/mesh-import-slats.forge.js +1 -1
- package/examples/api/real-product-curves.forge.js +1 -1
- package/examples/api/sculpt-box-circle-booleans.forge.js +1 -1
- package/examples/api/sdf-shapes.forge.js +2 -5
- package/examples/api/sketch-rounding-strategies.forge.js +6 -6
- package/examples/api/surface-member-bottle-cage.forge.js +3 -3
- package/examples/api/surface-member-conformal-product-ribbon.forge.js +3 -3
- package/examples/api/surface-member-razor-inlay.forge.js +1 -1
- package/examples/api/variable-sweep-test.forge.js +3 -3
- package/examples/mechanical/airplane-propeller.forge.js +74 -39
- package/examples/nurbs-surface.forge.js +1 -1
- package/examples/products/iphone.forge.js +1 -1
- package/examples/robotics/README.md +46 -0
- package/examples/robotics/scout-cam-rover-simready/README.md +119 -0
- package/examples/robotics/scout-cam-rover-simready/lib/dims.js +140 -0
- package/examples/robotics/scout-cam-rover-simready/main.forge.js +343 -0
- package/examples/robotics/scout-cam-rover-simready/parts/body.forge.js +304 -0
- package/examples/robotics/scout-cam-rover-simready/parts/chassis.forge.js +320 -0
- package/examples/robotics/scout-cam-rover-simready/parts/hardware.forge.js +21 -0
- package/examples/robotics/scout-cam-rover-simready/parts/turret.forge.js +70 -0
- package/examples/robotics/scout-cam-rover-simready/parts/wheel.forge.js +116 -0
- package/examples/robotics/simready-asset-crate.forge.js +79 -0
- package/examples/robotics/simready-diff-drive-rover.forge.js +141 -0
- package/examples/robotics/simready-parallel-gripper.forge.js +102 -0
- package/package.json +1 -1
- package/dist/assets/EditorApp-BHMQlJ-D.js +0 -14686
- package/dist/docs-raw/guides/geometry-conventions.md +0 -52
- package/dist/docs-raw/guides/modeling-recipes.md +0 -78
- package/dist-skill/docs/guides/geometry-conventions.md +0 -52
- package/dist-skill/docs/guides/modeling-recipes.md +0 -78
- package/dist-skill/library/forgecad-visual-spec/references/prompt-template.md +0 -79
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Pan turret of the scout cam rover (printed in black PLA).
|
|
2
|
+
// Rides the SG90 round horn through the neck bore: the central column reaches
|
|
3
|
+
// down through the neck, its socket ceiling rests on the horn top (M2 screw up
|
|
4
|
+
// through the horn into the spline retains it — purchased hardware, see BOM).
|
|
5
|
+
// Turret-local frame: base underside at z=0, +Z up, spline axis = Z.
|
|
6
|
+
|
|
7
|
+
const wallP = param('wall_thickness', 2.4, { min: 2.0, max: 3.0, step: 0.1, unit: 'mm' });
|
|
8
|
+
const wheelODP = param('wheel_od', 110, { min: 96, max: 130, step: 1, unit: 'mm' });
|
|
9
|
+
|
|
10
|
+
const dimsMod = require('../lib/dims.js');
|
|
11
|
+
|
|
12
|
+
const COL_BLACK = '#1f2023';
|
|
13
|
+
|
|
14
|
+
function buildTurret(D) {
|
|
15
|
+
const T = D.turret;
|
|
16
|
+
|
|
17
|
+
// base disc with 4 cosmetic lugs
|
|
18
|
+
let tr = cylinder(T.baseH, T.baseD / 2);
|
|
19
|
+
for (const pt of circularLayout(T.lugN, T.baseD / 2 + T.lugT / 2 - 0.3, { startDeg: 45 })) {
|
|
20
|
+
tr = tr.add(
|
|
21
|
+
box(T.lugW, T.lugT, T.lugH).translate(pt.x, pt.y, 0)
|
|
22
|
+
.rotate([0, 0, 1], (Math.atan2(pt.y, pt.x) * 180) / Math.PI, { pivot: [pt.x, pt.y, 0] })
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// barrel + cap
|
|
27
|
+
tr = tr.add(cylinder(T.barrelH, T.barrelD / 2).translate(0, 0, T.baseH));
|
|
28
|
+
tr = tr.add(cylinder(T.capH, T.capD / 2).translate(0, 0, T.baseH + T.barrelH));
|
|
29
|
+
|
|
30
|
+
// emblem on top: two engraved rings + a small dome
|
|
31
|
+
const capTop = T.baseH + T.barrelH + T.capH;
|
|
32
|
+
const ringCut = (rOut, rIn) =>
|
|
33
|
+
cylinder(1.0, rOut).subtract(cylinder(1.4, rIn).translate(0, 0, -0.2)).translate(0, 0, capTop - 0.8);
|
|
34
|
+
tr = tr.subtract(ringCut(10, 8), ringCut(5, 3.4));
|
|
35
|
+
tr = tr.add(sphere(2.2).scale([1, 1, 0.55]).translate(0, 0, capTop - 0.4));
|
|
36
|
+
|
|
37
|
+
// central column down through the neck to the servo horn
|
|
38
|
+
const colTop = 0.5; // weld into the base disc
|
|
39
|
+
let col = cylinder(T.colLen + colTop, T.colD / 2).translate(0, 0, -T.colLen);
|
|
40
|
+
col = col.add(cylinder(T.colHubH, T.colHubD / 2).translate(0, 0, -T.colLen));
|
|
41
|
+
// horn socket: open downward, ceiling rests on the horn top face
|
|
42
|
+
col = col.subtract(cylinder(T.socketDepth + 0.1, T.socketD / 2).translate(0, 0, -T.colLen - 0.1));
|
|
43
|
+
// clearance bore above the socket for the M2 retention screw head
|
|
44
|
+
col = col.subtract(cylinder(6, 2.6).translate(0, 0, -T.colLen + T.socketDepth - 0.1));
|
|
45
|
+
tr = tr.add(col);
|
|
46
|
+
|
|
47
|
+
return tr.color(COL_BLACK).material({ metalness: 0.15, roughness: 0.5, clearcoat: 0.3 })
|
|
48
|
+
.withConnectors({
|
|
49
|
+
hub: connector('axle', {
|
|
50
|
+
origin: [0, 0, -T.colLen + T.socketDepth], axis: [0, 0, -1], up: [0, 1, 0], kind: 'revolute',
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const D = dimsMod.compute({ wall: wallP, wheelOD: wheelODP });
|
|
56
|
+
|
|
57
|
+
if (require.main === module) {
|
|
58
|
+
scene({
|
|
59
|
+
camera: { position: [90, -100, 80], target: [0, 0, 8], fov: 40 },
|
|
60
|
+
environment: { preset: 'studio', intensity: 0.3, background: false },
|
|
61
|
+
lights: [
|
|
62
|
+
{ type: 'ambient', color: '#efe7dc', intensity: 0.25 },
|
|
63
|
+
{ type: 'directional', position: [80, -90, 130], color: '#ffe2bf', intensity: 2.4, castShadow: true },
|
|
64
|
+
{ type: 'directional', position: [-70, 60, 60], color: '#d4e6fb', intensity: 0.9 },
|
|
65
|
+
],
|
|
66
|
+
});
|
|
67
|
+
return { preview: [{ name: 'Turret', shape: buildTurret(D) }], make: { buildTurret } };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { make: { buildTurret } };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Wheel for the scout cam rover: printed rim (PLA) + printed tire (TPU).
|
|
2
|
+
// Wheel-local frame: z=0 is the hub bore mouth (faces the robot), +Z points outboard.
|
|
3
|
+
// The hub boss runs inside the motor-pod bore and grips the N20 D-shaft (press fit).
|
|
4
|
+
|
|
5
|
+
const wallP = param('wall_thickness', 2.4, { min: 2.0, max: 3.0, step: 0.1, unit: 'mm' });
|
|
6
|
+
const wheelODP = param('wheel_od', 110, { min: 96, max: 130, step: 1, unit: 'mm' });
|
|
7
|
+
|
|
8
|
+
const dimsMod = require('../lib/dims.js');
|
|
9
|
+
|
|
10
|
+
const COL_TEAL = '#2fb3b8';
|
|
11
|
+
const COL_TIRE = '#cfc8bc';
|
|
12
|
+
|
|
13
|
+
function buildRim(D) {
|
|
14
|
+
const hub = D.hub, web = D.web;
|
|
15
|
+
const rimOR = D.rimOD / 2, rimIR = D.rimID / 2;
|
|
16
|
+
|
|
17
|
+
// hub boss with D-bore for the N20 shaft
|
|
18
|
+
let boss = cylinder(hub.bossL, hub.bossD / 2);
|
|
19
|
+
const flatY = hub.boreFlat - hub.boreD / 2; // flat plane offset from center
|
|
20
|
+
const dProfile = circle2d(hub.boreD / 2)
|
|
21
|
+
.intersect(rect(hub.boreD + 0.4, hub.boreFlat).translate(0, (hub.boreFlat / 2) - hub.boreD / 2));
|
|
22
|
+
const dBore = dProfile.extrude(hub.boreDepth + 0.1).translate(0, 0, -0.1);
|
|
23
|
+
boss = boss.subtract(dBore);
|
|
24
|
+
verify.greaterThan('D-bore flat offset is positive', flatY + hub.boreD / 2, 0);
|
|
25
|
+
|
|
26
|
+
// spoke web: hub disc + crosshair spokes + mid ring, welded 1mm into the rim band
|
|
27
|
+
const webReach = rimIR + 1;
|
|
28
|
+
const webSk = circle2d(11)
|
|
29
|
+
.add(rect(webReach * 2, 8))
|
|
30
|
+
.add(rect(8, webReach * 2))
|
|
31
|
+
.add(circle2d(28).subtract(circle2d(24)));
|
|
32
|
+
let webSolid = webSk.extrude(web.t).translate(0, 0, web.z0);
|
|
33
|
+
|
|
34
|
+
// rim band
|
|
35
|
+
const rimBand = cylinder(D.rimW, rimOR).subtract(cylinder(D.rimW + 2, rimIR).translate(0, 0, -1))
|
|
36
|
+
.translate(0, 0, D.rim.z0);
|
|
37
|
+
|
|
38
|
+
let rimPart = union(boss, webSolid, rimBand);
|
|
39
|
+
|
|
40
|
+
// cosmetic hub-face dimples (visible on the outboard web face)
|
|
41
|
+
for (const pt of circularLayout(hub.faceHoleN, hub.faceHoleR, { startDeg: 90 })) {
|
|
42
|
+
rimPart = rimPart.subtract(
|
|
43
|
+
cylinder(1.6, hub.faceHoleD / 2).translate(pt.x, pt.y, web.z0 + web.t - 1.5)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return rimPart.color(COL_TEAL).material({ metalness: 0.05, roughness: 0.45 });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function buildTire(D) {
|
|
50
|
+
const rimOR = D.rimOD / 2, tireOR = D.tireOD / 2;
|
|
51
|
+
let prof = rect(tireOR - rimOR, D.tireW).translate(rimOR + (tireOR - rimOR) / 2, D.tireW / 2);
|
|
52
|
+
prof = prof.filletCorner([tireOR, 0], 2.5).filletCorner([tireOR, D.tireW], 2.5);
|
|
53
|
+
return prof.revolve()
|
|
54
|
+
.translate(0, 0, D.rim.z0)
|
|
55
|
+
.color(COL_TIRE).material({ metalness: 0.0, roughness: 0.85 });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function buildShaft(D) {
|
|
59
|
+
// The N20 D-shaft rides in the wheel's D-bore and turns WITH the wheel, so it
|
|
60
|
+
// is modeled as a child of the wheel part (the motor keeps a short stub).
|
|
61
|
+
const M = D.motor;
|
|
62
|
+
const prof = circle2d(M.shaftD / 2)
|
|
63
|
+
.intersect(rect(M.shaftD + 0.4, M.shaftFlat).translate(0, M.shaftFlat / 2 - M.shaftD / 2));
|
|
64
|
+
return prof.extrude(8.5).translate(0, 0, -0.1)
|
|
65
|
+
.color('#d8dbe0').material({ metalness: 0.9, roughness: 0.25 });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Returns the wheel as three separate single-body parts that share the same
|
|
69
|
+
// local frame: the rim carries the joint bore plus identity seats for the tire
|
|
70
|
+
// (stretch fit on the rim band) and the N20 D-shaft (turns with the wheel).
|
|
71
|
+
function buildWheel(D) {
|
|
72
|
+
const idSeat = () => connector('mount', { origin: [0, 0, 0], axis: [0, 0, 1], up: [0, 1, 0], kind: 'fixed' });
|
|
73
|
+
const idChild = () => connector('mount', { origin: [0, 0, 0], axis: [0, 0, -1], up: [0, 1, 0], kind: 'fixed' });
|
|
74
|
+
const rimPart = buildRim(D).withConnectors({
|
|
75
|
+
bore: connector('axle', { origin: [0, 0, 0], axis: [0, 0, -1], up: [0, 1, 0], kind: 'revolute' }),
|
|
76
|
+
tire_seat: idSeat(),
|
|
77
|
+
shaft_seat: idSeat(),
|
|
78
|
+
});
|
|
79
|
+
const tirePart = buildTire(D).withConnectors({
|
|
80
|
+
seat: idChild(),
|
|
81
|
+
tread: connector('contact', {
|
|
82
|
+
origin: [0, -D.tireOD / 2, D.rim.z0 + D.tireW / 2],
|
|
83
|
+
axis: [0, -1, 0],
|
|
84
|
+
up: [0, 0, 1],
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
const shaftPart = buildShaft(D).withConnectors({ seat: idChild() });
|
|
88
|
+
verify.clearanceBetween('tire seats on rim band', tirePart, rimPart, -0.01, 0.05);
|
|
89
|
+
verify.clearanceBetween('D-shaft rides in the D-bore', shaftPart, rimPart, 0.02, 0.15);
|
|
90
|
+
return { rim: rimPart, tire: tirePart, shaft: shaftPart };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const D = dimsMod.compute({ wall: wallP, wheelOD: wheelODP });
|
|
94
|
+
|
|
95
|
+
if (require.main === module) {
|
|
96
|
+
scene({
|
|
97
|
+
camera: { position: [160, -150, 120], target: [0, 0, 17], fov: 40 },
|
|
98
|
+
environment: { preset: 'studio', intensity: 0.25, background: false },
|
|
99
|
+
lights: [
|
|
100
|
+
{ type: 'ambient', color: '#efe7dc', intensity: 0.18 },
|
|
101
|
+
{ type: 'directional', position: [140, -160, 220], color: '#ffe2bf', intensity: 2.6, castShadow: true },
|
|
102
|
+
{ type: 'directional', position: [-130, 110, 110], color: '#d4e6fb', intensity: 0.8 },
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
const wp = buildWheel(D);
|
|
106
|
+
return {
|
|
107
|
+
preview: [
|
|
108
|
+
{ name: 'Rim', shape: wp.rim },
|
|
109
|
+
{ name: 'Tire', shape: wp.tire },
|
|
110
|
+
{ name: 'Drive Shaft', shape: wp.shaft },
|
|
111
|
+
],
|
|
112
|
+
make: { buildWheel },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { make: { buildWheel } };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const pine = Sim.material("pine crate", {
|
|
2
|
+
densityKgM3: 520,
|
|
3
|
+
staticFriction: 0.55,
|
|
4
|
+
dynamicFriction: 0.42,
|
|
5
|
+
restitution: 0.08,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const woodMaterial = { roughness: 0.78, metalness: 0.02 };
|
|
9
|
+
const darkEndgrain = { roughness: 0.86, metalness: 0.01 };
|
|
10
|
+
|
|
11
|
+
const rim = group(
|
|
12
|
+
{ name: "Front Top Rail", shape: box(132, 8, 8).translate(0, -50, 37).color("#6f4a25").material(darkEndgrain) },
|
|
13
|
+
{ name: "Back Top Rail", shape: box(132, 8, 8).translate(0, 50, 37).color("#6f4a25").material(darkEndgrain) },
|
|
14
|
+
{ name: "Left Top Rail", shape: box(8, 92, 8).translate(-66, 0, 37).color("#6f4a25").material(darkEndgrain) },
|
|
15
|
+
{ name: "Right Top Rail", shape: box(8, 92, 8).translate(66, 0, 37).color("#6f4a25").material(darkEndgrain) },
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const cornerPosts = group(
|
|
19
|
+
{ name: "Front Left Post", shape: box(10, 10, 78).translate(-64, -48, 0).color("#714d27").material(darkEndgrain) },
|
|
20
|
+
{ name: "Front Right Post", shape: box(10, 10, 78).translate(64, -48, 0).color("#714d27").material(darkEndgrain) },
|
|
21
|
+
{ name: "Back Left Post", shape: box(10, 10, 78).translate(-64, 48, 0).color("#714d27").material(darkEndgrain) },
|
|
22
|
+
{ name: "Back Right Post", shape: box(10, 10, 78).translate(64, 48, 0).color("#714d27").material(darkEndgrain) },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const sideSlats = group(
|
|
26
|
+
{ name: "Front Upper Slat", shape: box(118, 7, 12).translate(0, -52, 18).color("#81582c").material(woodMaterial) },
|
|
27
|
+
{ name: "Front Lower Slat", shape: box(118, 7, 12).translate(0, -52, -12).color("#9a6a38").material(woodMaterial) },
|
|
28
|
+
{ name: "Back Upper Slat", shape: box(118, 7, 12).translate(0, 52, 18).color("#81582c").material(woodMaterial) },
|
|
29
|
+
{ name: "Back Lower Slat", shape: box(118, 7, 12).translate(0, 52, -12).color("#9a6a38").material(woodMaterial) },
|
|
30
|
+
{ name: "Left Upper Slat", shape: box(7, 78, 12).translate(-70, 0, 18).color("#81582c").material(woodMaterial) },
|
|
31
|
+
{ name: "Left Lower Slat", shape: box(7, 78, 12).translate(-70, 0, -12).color("#9a6a38").material(woodMaterial) },
|
|
32
|
+
{ name: "Right Upper Slat", shape: box(7, 78, 12).translate(70, 0, 18).color("#81582c").material(woodMaterial) },
|
|
33
|
+
{ name: "Right Lower Slat", shape: box(7, 78, 12).translate(70, 0, -12).color("#9a6a38").material(woodMaterial) },
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const floorPlanks = group(
|
|
37
|
+
{ name: "Floor Left", shape: box(36, 86, 8).translate(-40, 0, -36).color("#a8733d").material(woodMaterial) },
|
|
38
|
+
{ name: "Floor Center", shape: box(36, 86, 8).translate(0, 0, -36).color("#b47b42").material(woodMaterial) },
|
|
39
|
+
{ name: "Floor Right", shape: box(36, 86, 8).translate(40, 0, -36).color("#a8733d").material(woodMaterial) },
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const forkliftSkids = group(
|
|
43
|
+
{ name: "Left Fork Pocket", shape: box(112, 10, 8).translate(0, -28, -50).color("#6f4a25").material(darkEndgrain) },
|
|
44
|
+
{ name: "Right Fork Pocket", shape: box(112, 10, 8).translate(0, 28, -50).color("#6f4a25").material(darkEndgrain) },
|
|
45
|
+
{ name: "Left Spacer", shape: box(14, 10, 18).translate(-46, -28, -42).color("#714d27").material(darkEndgrain) },
|
|
46
|
+
{ name: "Right Spacer", shape: box(14, 10, 18).translate(46, 28, -42).color("#714d27").material(darkEndgrain) },
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const handles = group(
|
|
50
|
+
{ name: "Front Handhold", shape: box(48, 5, 14).translate(0, -56, 3).color("#3f2a18").material({ roughness: 0.9 }) },
|
|
51
|
+
{ name: "Back Handhold", shape: box(48, 5, 14).translate(0, 56, 3).color("#3f2a18").material({ roughness: 0.9 }) },
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const crate = group(
|
|
55
|
+
{ name: "Rim", group: rim },
|
|
56
|
+
{ name: "Posts", group: cornerPosts },
|
|
57
|
+
{ name: "Side Slats", group: sideSlats },
|
|
58
|
+
{ name: "Floor Planks", group: floorPlanks },
|
|
59
|
+
{ name: "Forklift Skids", group: forkliftSkids },
|
|
60
|
+
{ name: "Handles", group: handles },
|
|
61
|
+
).withConnectors({
|
|
62
|
+
grip: connector({ origin: [0, -56, 3], axis: [0, -1, 0], up: [0, 0, 1] }),
|
|
63
|
+
floor_contact: connector({ origin: [0, 0, -54], axis: [0, 0, -1], up: [1, 0, 0] }),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return assembly("SimReady Asset Crate")
|
|
67
|
+
.addPart("Body", crate, {
|
|
68
|
+
sim: Sim.body({
|
|
69
|
+
massKg: 2.4,
|
|
70
|
+
material: pine,
|
|
71
|
+
collider: Sim.collider.convexHull(),
|
|
72
|
+
contacts: {
|
|
73
|
+
grip: Sim.contact.gripperSurface("grip"),
|
|
74
|
+
},
|
|
75
|
+
}),
|
|
76
|
+
})
|
|
77
|
+
.withSimulation({
|
|
78
|
+
profile: Sim.profile.roboticsAssetPhysx(),
|
|
79
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
const aluminum = Sim.material("6061 aluminum", {
|
|
2
|
+
densityKgM3: 2700,
|
|
3
|
+
staticFriction: 0.45,
|
|
4
|
+
dynamicFriction: 0.35,
|
|
5
|
+
restitution: 0.05,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const rubber = Sim.material("rubber tire", {
|
|
9
|
+
densityKgM3: 1100,
|
|
10
|
+
staticFriction: 0.9,
|
|
11
|
+
dynamicFriction: 0.75,
|
|
12
|
+
restitution: 0.12,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const darkPolymer = Sim.material("filled nylon", {
|
|
16
|
+
densityKgM3: 1250,
|
|
17
|
+
staticFriction: 0.42,
|
|
18
|
+
dynamicFriction: 0.32,
|
|
19
|
+
restitution: 0.04,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function wheel(axisY) {
|
|
23
|
+
const tireCore = cylinder(26, 34, undefined, 64).color("#171a1d").material({ roughness: 0.9 });
|
|
24
|
+
const treadBlocks = circularPattern(box(9, 5, 30).translate(0, 35, 0), 18).color("#24282c").material({ roughness: 0.95 });
|
|
25
|
+
const outerHub = cylinder(30, 14, undefined, 48).color("#a9b5bc").material({ metalness: 0.35, roughness: 0.42 });
|
|
26
|
+
const hubCap = cylinder(34, 7, undefined, 32).color("#3e4a52").material({ metalness: 0.25, roughness: 0.5 });
|
|
27
|
+
|
|
28
|
+
return group(
|
|
29
|
+
{ name: "Tire", shape: tireCore },
|
|
30
|
+
{ name: "Tread", shape: treadBlocks },
|
|
31
|
+
{ name: "Hub", shape: outerHub },
|
|
32
|
+
{ name: "Cap", shape: hubCap },
|
|
33
|
+
)
|
|
34
|
+
.rotateX(90)
|
|
35
|
+
.withConnectors({
|
|
36
|
+
bore: connector({ origin: [0, 0, 0], axis: [0, axisY, 0], up: [0, 0, 1], kind: "revolute" }),
|
|
37
|
+
tread: connector({ origin: [0, 0, -36], axis: [0, 0, -1], up: [1, 0, 0] }),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const chassis = group(
|
|
42
|
+
{ name: "Lower Pan", shape: box(228, 118, 26).translate(0, 0, 22).color("#46545d").material({ metalness: 0.18, roughness: 0.48 }) },
|
|
43
|
+
{ name: "Upper Deck", shape: box(164, 88, 16).translate(8, 0, 46).color("#62727b").material({ metalness: 0.22, roughness: 0.44 }) },
|
|
44
|
+
{ name: "Front Bumper", shape: box(18, 124, 20).translate(122, 0, 26).color("#262d33").material({ roughness: 0.72 }) },
|
|
45
|
+
{ name: "Rear Bumper", shape: box(14, 116, 16).translate(-122, 0, 24).color("#2d353b").material({ roughness: 0.7 }) },
|
|
46
|
+
{ name: "Left Rocker Guard", shape: box(194, 9, 16).translate(0, 68, 24).color("#252c31").material({ roughness: 0.72 }) },
|
|
47
|
+
{ name: "Right Rocker Guard", shape: box(194, 9, 16).translate(0, -68, 24).color("#252c31").material({ roughness: 0.72 }) },
|
|
48
|
+
{ name: "Sensor Mast", shape: cylinder(34, 5, undefined, 24).translate(58, 0, 72).color("#1c242b").material({ roughness: 0.58 }) },
|
|
49
|
+
{ name: "Lidar", shape: cylinder(16, 22, undefined, 48).translate(58, 0, 98).color("#c7d0d6").material({ metalness: 0.1, roughness: 0.35 }) },
|
|
50
|
+
{ name: "Camera Bar", shape: box(8, 52, 12).translate(129, 0, 44).color("#161b20").material({ roughness: 0.6 }) },
|
|
51
|
+
)
|
|
52
|
+
.withConnectors({
|
|
53
|
+
left_front_axle: connector({ origin: [72, 82, 30], axis: [0, 1, 0], up: [0, 0, 1], kind: "revolute" }),
|
|
54
|
+
left_rear_axle: connector({ origin: [-72, 82, 30], axis: [0, 1, 0], up: [0, 0, 1], kind: "revolute" }),
|
|
55
|
+
right_front_axle: connector({ origin: [72, -82, 30], axis: [0, -1, 0], up: [0, 0, 1], kind: "revolute" }),
|
|
56
|
+
right_rear_axle: connector({ origin: [-72, -82, 30], axis: [0, -1, 0], up: [0, 0, 1], kind: "revolute" }),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const leftWheel = wheel(-1);
|
|
60
|
+
const rightWheel = wheel(1);
|
|
61
|
+
|
|
62
|
+
const rover = assembly("SimReady Diff Drive Rover")
|
|
63
|
+
.addPart("Chassis", chassis, {
|
|
64
|
+
sim: Sim.body({
|
|
65
|
+
massKg: 4.2,
|
|
66
|
+
material: aluminum,
|
|
67
|
+
collider: Sim.collider.convexHull(),
|
|
68
|
+
}),
|
|
69
|
+
})
|
|
70
|
+
.addPart("Left Front Wheel", leftWheel, {
|
|
71
|
+
sim: Sim.body({
|
|
72
|
+
massKg: 0.32,
|
|
73
|
+
material: rubber,
|
|
74
|
+
collider: Sim.collider.convexHull(),
|
|
75
|
+
contacts: { tread: Sim.contact.wheelSurface("tread") },
|
|
76
|
+
}),
|
|
77
|
+
})
|
|
78
|
+
.addPart("Left Rear Wheel", leftWheel, {
|
|
79
|
+
sim: Sim.body({
|
|
80
|
+
massKg: 0.32,
|
|
81
|
+
material: rubber,
|
|
82
|
+
collider: Sim.collider.convexHull(),
|
|
83
|
+
contacts: { tread: Sim.contact.wheelSurface("tread") },
|
|
84
|
+
}),
|
|
85
|
+
})
|
|
86
|
+
.addPart("Right Front Wheel", rightWheel, {
|
|
87
|
+
sim: Sim.body({
|
|
88
|
+
massKg: 0.32,
|
|
89
|
+
material: rubber,
|
|
90
|
+
collider: Sim.collider.convexHull(),
|
|
91
|
+
contacts: { tread: Sim.contact.wheelSurface("tread") },
|
|
92
|
+
}),
|
|
93
|
+
})
|
|
94
|
+
.addPart("Right Rear Wheel", rightWheel, {
|
|
95
|
+
sim: Sim.body({
|
|
96
|
+
massKg: 0.32,
|
|
97
|
+
material: rubber,
|
|
98
|
+
collider: Sim.collider.convexHull(),
|
|
99
|
+
contacts: { tread: Sim.contact.wheelSurface("tread") },
|
|
100
|
+
}),
|
|
101
|
+
})
|
|
102
|
+
.connect("Chassis.left_front_axle", "Left Front Wheel.bore", {
|
|
103
|
+
as: "leftFrontWheel",
|
|
104
|
+
type: "revolute",
|
|
105
|
+
drive: Sim.drive.velocity({ maxTorqueNm: 1.8, maxSpeedRpm: 220, damping: 0.02, friction: 0.01 }),
|
|
106
|
+
})
|
|
107
|
+
.connect("Chassis.left_rear_axle", "Left Rear Wheel.bore", {
|
|
108
|
+
as: "leftRearWheel",
|
|
109
|
+
type: "revolute",
|
|
110
|
+
drive: Sim.drive.velocity({ maxTorqueNm: 1.8, maxSpeedRpm: 220, damping: 0.02, friction: 0.01 }),
|
|
111
|
+
})
|
|
112
|
+
.connect("Chassis.right_front_axle", "Right Front Wheel.bore", {
|
|
113
|
+
as: "rightFrontWheel",
|
|
114
|
+
type: "revolute",
|
|
115
|
+
drive: Sim.drive.velocity({ maxTorqueNm: 1.8, maxSpeedRpm: 220, damping: 0.02, friction: 0.01 }),
|
|
116
|
+
})
|
|
117
|
+
.connect("Chassis.right_rear_axle", "Right Rear Wheel.bore", {
|
|
118
|
+
as: "rightRearWheel",
|
|
119
|
+
type: "revolute",
|
|
120
|
+
drive: Sim.drive.velocity({ maxTorqueNm: 1.8, maxSpeedRpm: 220, damping: 0.02, friction: 0.01 }),
|
|
121
|
+
})
|
|
122
|
+
.withSimulation({
|
|
123
|
+
rootPart: "Chassis",
|
|
124
|
+
profile: Sim.profile.robotBodyRunnable(),
|
|
125
|
+
controllers: [
|
|
126
|
+
Sim.controller.diffDrive({
|
|
127
|
+
leftJoints: ["leftFrontWheel", "leftRearWheel"],
|
|
128
|
+
rightJoints: ["rightFrontWheel", "rightRearWheel"],
|
|
129
|
+
wheelRadiusMm: 34,
|
|
130
|
+
wheelSeparationMm: 164,
|
|
131
|
+
}),
|
|
132
|
+
],
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
verify.that("rover has five physical bodies", () => rover.describe().parts.length === 5);
|
|
136
|
+
verify.that("rover has four driven wheel joints", () => rover.describe().joints.length === 4);
|
|
137
|
+
verify.that("rover keeps wheel contact metadata on every wheel", () => {
|
|
138
|
+
return rover.describe().parts.filter((part) => part.sim?.contacts?.tread).length === 4;
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return rover;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const aluminum = Sim.material("anodized aluminum", {
|
|
2
|
+
densityKgM3: 2700,
|
|
3
|
+
staticFriction: 0.44,
|
|
4
|
+
dynamicFriction: 0.32,
|
|
5
|
+
restitution: 0.04,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const urethane = Sim.material("urethane pad", {
|
|
9
|
+
densityKgM3: 1250,
|
|
10
|
+
staticFriction: 0.95,
|
|
11
|
+
dynamicFriction: 0.8,
|
|
12
|
+
restitution: 0.08,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const palm = group(
|
|
16
|
+
{ name: "Palm Body", shape: box(36, 72, 24).translate(-28, 0, 8).color("#596872").material({ metalness: 0.2, roughness: 0.42 }) },
|
|
17
|
+
{ name: "Top Cover", shape: box(44, 64, 5).translate(-28, 0, 23).color("#75858e").material({ metalness: 0.18, roughness: 0.38 }) },
|
|
18
|
+
{ name: "Front Slide Rail", shape: cylinder(74, 3.2, undefined, 24).pointAlong([0, 1, 0]).translate(0, 0, 13).color("#c2c9cc").material({ metalness: 0.55, roughness: 0.32 }) },
|
|
19
|
+
{ name: "Rear Slide Rail", shape: cylinder(74, 3.2, undefined, 24).pointAlong([0, 1, 0]).translate(-38, 0, 13).color("#c2c9cc").material({ metalness: 0.55, roughness: 0.32 }) },
|
|
20
|
+
{ name: "Lead Screw", shape: cylinder(80, 2.2, undefined, 20).pointAlong([0, 1, 0]).translate(-19, 0, 5).color("#2f363b").material({ metalness: 0.4, roughness: 0.38 }) },
|
|
21
|
+
{ name: "Motor Cap", shape: cylinder(16, 11, undefined, 36).pointAlong([0, 1, 0]).translate(-28, -46, 8).color("#222a2f").material({ roughness: 0.56 }) },
|
|
22
|
+
)
|
|
23
|
+
.withConnectors({
|
|
24
|
+
left_slide: connector({ origin: [0, 27, 13], axis: [0, 1, 0], up: [0, 0, 1], kind: "prismatic", min: 0, max: 18 }),
|
|
25
|
+
right_slide: connector({ origin: [0, -27, 13], axis: [0, -1, 0], up: [0, 0, 1], kind: "prismatic", min: 0, max: 18 }),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function finger(axisY, color) {
|
|
29
|
+
const carriage = box(28, 15, 16).translate(-14, 0, 0).color("#39464e").material({ metalness: 0.12, roughness: 0.48 });
|
|
30
|
+
const upperFinger = box(78, 8, 9).translate(38, 0, 5).color(color).material({ metalness: 0.08, roughness: 0.44 });
|
|
31
|
+
const lowerFinger = box(62, 7, 8).translate(48, 0, -13).color(color).material({ metalness: 0.08, roughness: 0.48 });
|
|
32
|
+
const frontBridge = box(9, 8, 24).translate(76, 0, -4).color(color).material({ metalness: 0.08, roughness: 0.46 });
|
|
33
|
+
const pad = box(30, 3, 16).translate(60, -axisY * 6, -8).color("#20252a").material({ roughness: 0.9 });
|
|
34
|
+
const padRibA = box(26, 1, 2).translate(60, -axisY * 8, -13).color("#121619").material({ roughness: 0.95 });
|
|
35
|
+
const padRibB = box(26, 1, 2).translate(60, -axisY * 8, -8).color("#121619").material({ roughness: 0.95 });
|
|
36
|
+
const padRibC = box(26, 1, 2).translate(60, -axisY * 8, -3).color("#121619").material({ roughness: 0.95 });
|
|
37
|
+
|
|
38
|
+
return group(
|
|
39
|
+
{ name: "Carriage", shape: carriage },
|
|
40
|
+
{ name: "Upper Finger", shape: upperFinger },
|
|
41
|
+
{ name: "Lower Finger", shape: lowerFinger },
|
|
42
|
+
{ name: "Front Bridge", shape: frontBridge },
|
|
43
|
+
{ name: "Pad", shape: pad },
|
|
44
|
+
{ name: "Pad Rib A", shape: padRibA },
|
|
45
|
+
{ name: "Pad Rib B", shape: padRibB },
|
|
46
|
+
{ name: "Pad Rib C", shape: padRibC },
|
|
47
|
+
).withConnectors({
|
|
48
|
+
slide: connector({ origin: [0, 0, 0], axis: [0, -axisY, 0], up: [0, 0, 1], kind: "prismatic", min: 0, max: 18 }),
|
|
49
|
+
pad: connector({ origin: [60, -axisY * 8, -8], axis: [0, -axisY, 0], up: [0, 0, 1] }),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const gripper = assembly("SimReady Parallel Gripper")
|
|
54
|
+
.addPart("Palm", palm, {
|
|
55
|
+
sim: Sim.body({
|
|
56
|
+
massKg: 0.42,
|
|
57
|
+
material: aluminum,
|
|
58
|
+
collider: Sim.collider.boundingBox(),
|
|
59
|
+
}),
|
|
60
|
+
})
|
|
61
|
+
.addPart("Left Finger", finger(1, "#d66b4f"), {
|
|
62
|
+
sim: Sim.body({
|
|
63
|
+
massKg: 0.11,
|
|
64
|
+
material: urethane,
|
|
65
|
+
collider: Sim.collider.convexHull(),
|
|
66
|
+
contacts: { pad: Sim.contact.gripperSurface("pad") },
|
|
67
|
+
}),
|
|
68
|
+
})
|
|
69
|
+
.addPart("Right Finger", finger(-1, "#d66b4f"), {
|
|
70
|
+
sim: Sim.body({
|
|
71
|
+
massKg: 0.11,
|
|
72
|
+
material: urethane,
|
|
73
|
+
collider: Sim.collider.convexHull(),
|
|
74
|
+
contacts: { pad: Sim.contact.gripperSurface("pad") },
|
|
75
|
+
}),
|
|
76
|
+
})
|
|
77
|
+
.connect("Palm.left_slide", "Left Finger.slide", {
|
|
78
|
+
as: "leftFingerOpen",
|
|
79
|
+
type: "prismatic",
|
|
80
|
+
min: 0,
|
|
81
|
+
max: 18,
|
|
82
|
+
drive: Sim.drive.passive({ damping: 0.04, friction: 0.02 }),
|
|
83
|
+
})
|
|
84
|
+
.connect("Palm.right_slide", "Right Finger.slide", {
|
|
85
|
+
as: "rightFingerOpen",
|
|
86
|
+
type: "prismatic",
|
|
87
|
+
min: 0,
|
|
88
|
+
max: 18,
|
|
89
|
+
drive: Sim.drive.passive({ damping: 0.04, friction: 0.02 }),
|
|
90
|
+
})
|
|
91
|
+
.withSimulation({
|
|
92
|
+
rootPart: "Palm",
|
|
93
|
+
profile: Sim.profile.robotBodyRunnable(),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
verify.that("gripper exposes grasp surfaces", () => {
|
|
97
|
+
const parts = gripper.describe().parts;
|
|
98
|
+
return parts.filter((part) => part.sim?.contacts?.pad).length === 2;
|
|
99
|
+
});
|
|
100
|
+
verify.that("gripper has a compact three-body simulation contract", () => gripper.describe().parts.length === 3);
|
|
101
|
+
|
|
102
|
+
return gripper;
|
package/package.json
CHANGED