feat: integrate SimpleCADAPI 2.0.2 CAD workflows
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# Coordinate-free semantic assembly
|
||||
|
||||
This directory defines the LCD25 reducer as a reusable mechanical design rather
|
||||
than a list of STEP filenames and placement matrices.
|
||||
|
||||
## Authority
|
||||
|
||||
`lcd25-harmonic-reducer.assembly-designir.json` is the editable assembly
|
||||
authority. It contains:
|
||||
|
||||
- product parameters and expressions;
|
||||
- replaceable component archetypes;
|
||||
- semantic interfaces constructed from generated geometry;
|
||||
- mating and support relations;
|
||||
- rigid groups, joints and harmonic transmission behavior;
|
||||
- edit operations and interfaces that must remain stable.
|
||||
|
||||
It intentionally contains no XYZ position, rotation, transform matrix, source
|
||||
STEP path, or occurrence coordinate. A backend generates each component,
|
||||
discovers its declared interfaces and solves the constraint graph. Numeric
|
||||
placements are compiler output and may be cached separately, but never become
|
||||
design authority.
|
||||
|
||||
## Generality
|
||||
|
||||
The contract is not specific to LCD25. Component identities describe functional
|
||||
roles such as `fixed_tooth_member`, `combined_load_support`, and
|
||||
`external_output_interface`. Each role selects a replaceable generation family.
|
||||
The same contract can express harmonic, planetary, cycloidal, belt, chain and
|
||||
screw transmissions by changing archetypes, relations and the transmission
|
||||
block.
|
||||
|
||||
## Structural modification
|
||||
|
||||
`variants/add-output-shaft.patch.json` demonstrates a structural edit. It adds:
|
||||
|
||||
- editable shaft diameter and length;
|
||||
- a generated stepped-shaft component;
|
||||
- coaxial, shoulder-mate, insert and torque-lock relations;
|
||||
- output rigid-group membership;
|
||||
- a new public shaft-end interface.
|
||||
|
||||
No coordinate is supplied. The assembly solver must position the shaft from its
|
||||
relations to the output flange.
|
||||
|
||||
## Validation
|
||||
|
||||
Validate the base model:
|
||||
|
||||
```bash
|
||||
python3 models/lcd25-reducer/semantic-assembly/validate_assembly_design.py \
|
||||
models/lcd25-reducer/semantic-assembly/lcd25-harmonic-reducer.assembly-designir.json \
|
||||
--schema designir-pipeline/contracts/assembly-designir-1.0.schema.json
|
||||
```
|
||||
|
||||
Apply and validate the shaft variant:
|
||||
|
||||
```bash
|
||||
python3 models/lcd25-reducer/semantic-assembly/validate_assembly_design.py \
|
||||
models/lcd25-reducer/semantic-assembly/lcd25-harmonic-reducer.assembly-designir.json \
|
||||
--schema designir-pipeline/contracts/assembly-designir-1.0.schema.json \
|
||||
--patch models/lcd25-reducer/semantic-assembly/variants/add-output-shaft.patch.json \
|
||||
--resolved-output models/lcd25-reducer/semantic-assembly/generated/lcd25-with-output-shaft.assembly-designir.json
|
||||
```
|
||||
|
||||
## Compiler boundary
|
||||
|
||||
The next compiler stage must:
|
||||
|
||||
1. generate or select geometry for each component archetype;
|
||||
2. resolve every semantic interface against generated topology;
|
||||
3. solve relations from a scrambled initial state;
|
||||
4. emit STEP occurrence placements only as derived output;
|
||||
5. compile joints and transmissions to URDF/MJCF;
|
||||
6. reject underconstrained, overconstrained or interfering assemblies.
|
||||
|
||||
The current validator proves schema integrity, coordinate independence,
|
||||
reference integrity and graph connectivity. It does not yet solve B-Rep
|
||||
constraints or generate the final reducer STEP.
|
||||
+967
@@ -0,0 +1,967 @@
|
||||
{
|
||||
"schema_version": "assembly-1.0",
|
||||
"designir_kind": "coordinate_free_semantic_assembly",
|
||||
"model_id": "lcd25_harmonic_reducer_with_output_shaft",
|
||||
"family": "harmonic_reducer_module",
|
||||
"units": "mm",
|
||||
"design_intent": "A compact coaxial harmonic reducer whose geometry, assembly and motion are regenerated from functional interfaces rather than stored placements.",
|
||||
"parameters": {
|
||||
"nominal_size": {
|
||||
"kind": "length",
|
||||
"value": 25.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
20.0,
|
||||
40.0
|
||||
],
|
||||
"status": "inferred",
|
||||
"description": "Nominal transmission size controlling the scalable component family."
|
||||
},
|
||||
"reduction_ratio": {
|
||||
"kind": "ratio",
|
||||
"value": 100.0,
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
50.0,
|
||||
160.0
|
||||
],
|
||||
"status": "inferred",
|
||||
"description": "Input rotations per output rotation."
|
||||
},
|
||||
"outer_envelope_diameter": {
|
||||
"kind": "length",
|
||||
"value": 110.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
90.0,
|
||||
140.0
|
||||
],
|
||||
"status": "specified",
|
||||
"description": "Maximum housing envelope."
|
||||
},
|
||||
"axial_envelope": {
|
||||
"kind": "length",
|
||||
"value": 32.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
25.0,
|
||||
50.0
|
||||
],
|
||||
"status": "specified",
|
||||
"description": "Maximum reducer axial package length."
|
||||
},
|
||||
"output_bore_diameter": {
|
||||
"kind": "length",
|
||||
"value": 14.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
8.0,
|
||||
25.0
|
||||
],
|
||||
"status": "estimated",
|
||||
"description": "Central output interface bore."
|
||||
},
|
||||
"housing_wall": {
|
||||
"kind": "length",
|
||||
"value": 3.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
2.0,
|
||||
6.0
|
||||
],
|
||||
"status": "estimated",
|
||||
"description": "Minimum structural housing wall."
|
||||
},
|
||||
"output_bolt_count": {
|
||||
"kind": "count",
|
||||
"value": 4,
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
3,
|
||||
8
|
||||
],
|
||||
"status": "inferred",
|
||||
"description": "Output flange fastener pattern count."
|
||||
},
|
||||
"housing_bolt_count": {
|
||||
"kind": "count",
|
||||
"value": 10,
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
6,
|
||||
16
|
||||
],
|
||||
"status": "inferred",
|
||||
"description": "Housing closure fastener count."
|
||||
},
|
||||
"output_torque_limit": {
|
||||
"kind": "torque",
|
||||
"value": 25.0,
|
||||
"unit": "N*m",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
5.0,
|
||||
60.0
|
||||
],
|
||||
"status": "estimated",
|
||||
"description": "Initial simulation effort limit."
|
||||
},
|
||||
"output_speed_limit": {
|
||||
"kind": "speed",
|
||||
"value": 2.5,
|
||||
"unit": "rad/s",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
0.5,
|
||||
5.0
|
||||
],
|
||||
"status": "estimated",
|
||||
"description": "Initial simulation output speed limit."
|
||||
},
|
||||
"output_shaft_diameter": {
|
||||
"kind": "length",
|
||||
"value": 14.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
10.0,
|
||||
20.0
|
||||
],
|
||||
"status": "specified",
|
||||
"description": "Output shaft journal diameter."
|
||||
},
|
||||
"output_shaft_length": {
|
||||
"kind": "length",
|
||||
"value": 45.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [
|
||||
25.0,
|
||||
80.0
|
||||
],
|
||||
"status": "specified",
|
||||
"description": "Usable shaft extension measured from the output mounting face."
|
||||
}
|
||||
},
|
||||
"expressions": {
|
||||
"flexspline_tooth_count": "2 * round(reduction_ratio / 2)",
|
||||
"circular_spline_tooth_count": "flexspline_tooth_count + 2",
|
||||
"bearing_nominal_diameter": "0.72 * outer_envelope_diameter",
|
||||
"output_flange_diameter": "0.48 * outer_envelope_diameter",
|
||||
"housing_fastener_pitch_diameter": "0.82 * outer_envelope_diameter"
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"id": "structure_module",
|
||||
"purpose": "Carry external loads and provide all mounting seats.",
|
||||
"members": [
|
||||
"housing",
|
||||
"rear_cover",
|
||||
"front_cover"
|
||||
],
|
||||
"replaceable_as_unit": true
|
||||
},
|
||||
{
|
||||
"id": "harmonic_stage",
|
||||
"purpose": "Generate the harmonic reduction between input and output.",
|
||||
"members": [
|
||||
"circular_spline",
|
||||
"flexspline",
|
||||
"wave_generator"
|
||||
],
|
||||
"replaceable_as_unit": true
|
||||
},
|
||||
{
|
||||
"id": "output_support_module",
|
||||
"purpose": "Support and locate the rotating output.",
|
||||
"members": [
|
||||
"output_bearing",
|
||||
"output_flange"
|
||||
],
|
||||
"replaceable_as_unit": true
|
||||
},
|
||||
{
|
||||
"id": "retention_module",
|
||||
"purpose": "Close and fasten structural interfaces.",
|
||||
"members": [
|
||||
"housing_fasteners",
|
||||
"output_fasteners"
|
||||
],
|
||||
"replaceable_as_unit": false
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"id": "housing",
|
||||
"role": "fixed_structure",
|
||||
"archetype": "coaxial_reducer_housing",
|
||||
"lifecycle": "required",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "annular_housing_with_mounting_flange",
|
||||
"parameter_bindings": {
|
||||
"outer_diameter": "outer_envelope_diameter",
|
||||
"axial_length": "axial_envelope",
|
||||
"minimum_wall": "housing_wall"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "main_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "front_closure_seat",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "rear_closure_seat",
|
||||
"type": "plane",
|
||||
"construction": "rear_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "circular_spline_seat",
|
||||
"type": "cylinder",
|
||||
"construction": "inner_cylindrical_surface",
|
||||
"qualifiers": [
|
||||
"largest_internal_transmission_seat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "output_bearing_seat",
|
||||
"type": "bearing_seat",
|
||||
"construction": "inner_cylindrical_surface",
|
||||
"qualifiers": [
|
||||
"frontmost_bearing_seat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "closure_pattern",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": [
|
||||
"housing_bolt_count"
|
||||
]
|
||||
}
|
||||
],
|
||||
"material_class": "aluminum_alloy",
|
||||
"tags": [
|
||||
"fixed",
|
||||
"structural",
|
||||
"thermal_path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "circular_spline",
|
||||
"role": "fixed_tooth_member",
|
||||
"archetype": "internal_spline_ring",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "harmonic_circular_spline",
|
||||
"parameter_bindings": {
|
||||
"nominal_size": "nominal_size",
|
||||
"tooth_count": "circular_spline_tooth_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "tooth_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "housing_fit",
|
||||
"type": "cylinder",
|
||||
"construction": "outer_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "anti_rotation",
|
||||
"type": "torque_interface",
|
||||
"construction": "generated_feature"
|
||||
}
|
||||
],
|
||||
"material_class": "hardened_steel",
|
||||
"tags": [
|
||||
"fixed",
|
||||
"transmission"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flexspline",
|
||||
"role": "compliant_tooth_member",
|
||||
"archetype": "cup_flexspline",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "harmonic_flexspline",
|
||||
"parameter_bindings": {
|
||||
"nominal_size": "nominal_size",
|
||||
"tooth_count": "flexspline_tooth_count",
|
||||
"output_bore": "output_bore_diameter"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "tooth_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "wave_generator_seat",
|
||||
"type": "bearing_seat",
|
||||
"construction": "inner_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "output_face",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "output_torque_interface",
|
||||
"type": "torque_interface",
|
||||
"construction": "generated_feature"
|
||||
}
|
||||
],
|
||||
"material_class": "spring_steel",
|
||||
"tags": [
|
||||
"rotating",
|
||||
"compliant",
|
||||
"transmission"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "wave_generator",
|
||||
"role": "input_deformation_member",
|
||||
"archetype": "elliptical_wave_generator",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "subassembly_template",
|
||||
"family": "elliptical_cam_with_flexible_bearing",
|
||||
"parameter_bindings": {
|
||||
"nominal_size": "nominal_size"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "rotation_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "input_torque_interface",
|
||||
"type": "torque_interface",
|
||||
"construction": "inner_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_contact",
|
||||
"type": "contact_envelope",
|
||||
"construction": "outer_cylindrical_surface",
|
||||
"qualifiers": [
|
||||
"elliptical_compliant_contact"
|
||||
]
|
||||
}
|
||||
],
|
||||
"material_class": "bearing_steel",
|
||||
"tags": [
|
||||
"rotating",
|
||||
"input",
|
||||
"transmission"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "output_bearing",
|
||||
"role": "combined_load_support",
|
||||
"archetype": "cross_roller_bearing",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "cross_roller_bearing",
|
||||
"parameter_bindings": {
|
||||
"nominal_diameter": "bearing_nominal_diameter"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "bearing_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "outer_ring_seat",
|
||||
"type": "bearing_seat",
|
||||
"construction": "outer_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "inner_ring_seat",
|
||||
"type": "bearing_seat",
|
||||
"construction": "inner_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "axial_reference",
|
||||
"type": "plane",
|
||||
"construction": "center_plane"
|
||||
}
|
||||
],
|
||||
"material_class": "bearing_steel",
|
||||
"tags": [
|
||||
"support",
|
||||
"split_kinematic_membership"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "output_flange",
|
||||
"role": "external_output_interface",
|
||||
"archetype": "bolted_output_flange",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "annular_output_flange",
|
||||
"parameter_bindings": {
|
||||
"diameter": "output_flange_diameter",
|
||||
"bore_diameter": "output_bore_diameter",
|
||||
"bolt_count": "output_bolt_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "rotation_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_mate",
|
||||
"type": "plane",
|
||||
"construction": "rear_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "bearing_fit",
|
||||
"type": "bearing_seat",
|
||||
"construction": "outer_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "external_mount_face",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "external_bolt_pattern",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": [
|
||||
"output_bolt_count"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "output_bore",
|
||||
"type": "shaft_seat",
|
||||
"construction": "inner_cylindrical_surface",
|
||||
"parameter_refs": [
|
||||
"output_bore_diameter"
|
||||
]
|
||||
}
|
||||
],
|
||||
"material_class": "alloy_steel",
|
||||
"tags": [
|
||||
"rotating",
|
||||
"output",
|
||||
"public_interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "front_cover",
|
||||
"role": "front_axial_retainer",
|
||||
"archetype": "annular_cover",
|
||||
"lifecycle": "required",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "bolted_annular_cover",
|
||||
"parameter_bindings": {
|
||||
"outer_diameter": "outer_envelope_diameter",
|
||||
"bolt_count": "housing_bolt_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "housing_mate",
|
||||
"type": "plane",
|
||||
"construction": "rear_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "main_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "fastener_pattern",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": [
|
||||
"housing_bolt_count"
|
||||
]
|
||||
}
|
||||
],
|
||||
"material_class": "aluminum_alloy",
|
||||
"tags": [
|
||||
"fixed",
|
||||
"structural"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rear_cover",
|
||||
"role": "rear_axial_retainer",
|
||||
"archetype": "annular_cover",
|
||||
"lifecycle": "required",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "bolted_annular_cover",
|
||||
"parameter_bindings": {
|
||||
"outer_diameter": "outer_envelope_diameter"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "housing_mate",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "main_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
}
|
||||
],
|
||||
"material_class": "aluminum_alloy",
|
||||
"tags": [
|
||||
"fixed",
|
||||
"structural"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "housing_fasteners",
|
||||
"role": "housing_closure_fasteners",
|
||||
"archetype": "socket_head_screw_pattern",
|
||||
"lifecycle": "generated_pattern",
|
||||
"quantity": "housing_bolt_count",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "metric_socket_head_screw",
|
||||
"parameter_bindings": {
|
||||
"nominal_thread": "M5",
|
||||
"count": "housing_bolt_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "fastener_axes",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": [
|
||||
"housing_bolt_count"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "head_seats",
|
||||
"type": "fastener_seat",
|
||||
"construction": "generated_feature"
|
||||
}
|
||||
],
|
||||
"material_class": "steel",
|
||||
"tags": [
|
||||
"fixed",
|
||||
"fastener_pattern"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "output_fasteners",
|
||||
"role": "output_interface_fasteners",
|
||||
"archetype": "countersunk_screw_pattern",
|
||||
"lifecycle": "generated_pattern",
|
||||
"quantity": "output_bolt_count",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "metric_countersunk_screw",
|
||||
"parameter_bindings": {
|
||||
"nominal_thread": "M2_5",
|
||||
"count": "output_bolt_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "fastener_axes",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": [
|
||||
"output_bolt_count"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "head_seats",
|
||||
"type": "fastener_seat",
|
||||
"construction": "generated_feature"
|
||||
}
|
||||
],
|
||||
"material_class": "steel",
|
||||
"tags": [
|
||||
"rotating",
|
||||
"fastener_pattern"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "output_shaft",
|
||||
"role": "external_torque_shaft",
|
||||
"archetype": "stepped_keyed_shaft",
|
||||
"lifecycle": "optional",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "stepped_output_shaft",
|
||||
"parameter_bindings": {
|
||||
"journal_diameter": "output_shaft_diameter",
|
||||
"extension_length": "output_shaft_length",
|
||||
"mating_bore": "output_bore_diameter"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "shaft_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "mounting_shoulder",
|
||||
"type": "plane",
|
||||
"construction": "rear_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "flange_fit",
|
||||
"type": "shaft_seat",
|
||||
"construction": "outer_cylindrical_surface",
|
||||
"parameter_refs": [
|
||||
"output_shaft_diameter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "torque_drive",
|
||||
"type": "torque_interface",
|
||||
"construction": "generated_feature",
|
||||
"qualifiers": [
|
||||
"key_or_spline_selected_by_load"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "external_shaft_end",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
}
|
||||
],
|
||||
"material_class": "alloy_steel",
|
||||
"tags": [
|
||||
"rotating",
|
||||
"output",
|
||||
"public_interface"
|
||||
]
|
||||
}
|
||||
],
|
||||
"relations": [
|
||||
{
|
||||
"id": "circular_spline_centering",
|
||||
"type": "coaxial",
|
||||
"a": "housing.main_axis",
|
||||
"b": "circular_spline.tooth_axis",
|
||||
"intent": "Center the fixed tooth member in the housing.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "circular_spline_fixing",
|
||||
"type": "torque_lock",
|
||||
"a": "housing.circular_spline_seat",
|
||||
"b": "circular_spline.anti_rotation",
|
||||
"intent": "Prevent rotation of the circular spline relative to the housing.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_centering",
|
||||
"type": "coaxial",
|
||||
"a": "circular_spline.tooth_axis",
|
||||
"b": "flexspline.tooth_axis",
|
||||
"intent": "Keep both spline members on the reducer axis.",
|
||||
"mobility": "allow_rotation"
|
||||
},
|
||||
{
|
||||
"id": "wave_generator_centering",
|
||||
"type": "coaxial",
|
||||
"a": "flexspline.tooth_axis",
|
||||
"b": "wave_generator.rotation_axis",
|
||||
"intent": "Place the wave generator on the transmission axis.",
|
||||
"mobility": "allow_rotation"
|
||||
},
|
||||
{
|
||||
"id": "wave_generator_contact",
|
||||
"type": "bearing_support",
|
||||
"a": "flexspline.wave_generator_seat",
|
||||
"b": "wave_generator.flexspline_contact",
|
||||
"intent": "Transfer the elliptical deformation while allowing relative rotation.",
|
||||
"mobility": "allow_rotation",
|
||||
"confidence": 0.82,
|
||||
"evidence": [
|
||||
"harmonic_stage_topology",
|
||||
"nested_flexible_bearing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "output_bearing_housing_fit",
|
||||
"type": "bearing_support",
|
||||
"a": "housing.output_bearing_seat",
|
||||
"b": "output_bearing.outer_ring_seat",
|
||||
"intent": "Fix and support the bearing outer ring in the housing.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "output_bearing_flange_fit",
|
||||
"type": "bearing_support",
|
||||
"a": "output_flange.bearing_fit",
|
||||
"b": "output_bearing.inner_ring_seat",
|
||||
"intent": "Support output flange rotation through the bearing inner ring.",
|
||||
"mobility": "allow_rotation"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_output_face",
|
||||
"type": "face_mate",
|
||||
"a": "flexspline.output_face",
|
||||
"b": "output_flange.flexspline_mate",
|
||||
"intent": "Locate the flexspline axially against the output flange.",
|
||||
"value": 0.0,
|
||||
"tolerance": 0.01,
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_output_torque",
|
||||
"type": "torque_lock",
|
||||
"a": "flexspline.output_torque_interface",
|
||||
"b": "output_flange.external_bolt_pattern",
|
||||
"intent": "Transmit flexspline torque to the output flange.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "front_cover_centering",
|
||||
"type": "coaxial",
|
||||
"a": "housing.main_axis",
|
||||
"b": "front_cover.main_axis",
|
||||
"intent": "Center the front closure.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "front_cover_seating",
|
||||
"type": "face_mate",
|
||||
"a": "housing.front_closure_seat",
|
||||
"b": "front_cover.housing_mate",
|
||||
"intent": "Close the front housing interface.",
|
||||
"value": 0.0,
|
||||
"tolerance": 0.02,
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "rear_cover_centering",
|
||||
"type": "coaxial",
|
||||
"a": "housing.main_axis",
|
||||
"b": "rear_cover.main_axis",
|
||||
"intent": "Center the rear closure.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "rear_cover_seating",
|
||||
"type": "face_mate",
|
||||
"a": "housing.rear_closure_seat",
|
||||
"b": "rear_cover.housing_mate",
|
||||
"intent": "Close the rear housing interface.",
|
||||
"value": 0.0,
|
||||
"tolerance": 0.02,
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "housing_fastener_alignment",
|
||||
"type": "fasten_pattern",
|
||||
"a": "housing.closure_pattern",
|
||||
"b": "housing_fasteners.fastener_axes",
|
||||
"intent": "Instantiate and align the housing closure screws.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "output_fastener_alignment",
|
||||
"type": "fasten_pattern",
|
||||
"a": "output_flange.external_bolt_pattern",
|
||||
"b": "output_fasteners.fastener_axes",
|
||||
"intent": "Instantiate and align output flange screws.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "output_shaft_centering",
|
||||
"type": "coaxial",
|
||||
"a": "output_flange.rotation_axis",
|
||||
"b": "output_shaft.shaft_axis",
|
||||
"intent": "Center the new shaft on the solved output axis.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "output_shaft_seating",
|
||||
"type": "face_mate",
|
||||
"a": "output_flange.external_mount_face",
|
||||
"b": "output_shaft.mounting_shoulder",
|
||||
"intent": "Locate the shaft shoulder from the output flange mounting face.",
|
||||
"value": 0.0,
|
||||
"tolerance": 0.01,
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "output_shaft_fit",
|
||||
"type": "insert",
|
||||
"a": "output_flange.output_bore",
|
||||
"b": "output_shaft.flange_fit",
|
||||
"intent": "Fit the shaft journal into the output flange bore.",
|
||||
"tolerance": 0.01,
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "output_shaft_torque_lock",
|
||||
"type": "torque_lock",
|
||||
"a": "output_flange.output_bore",
|
||||
"b": "output_shaft.torque_drive",
|
||||
"intent": "Transfer output torque through a keyed or splined interface.",
|
||||
"mobility": "fixed"
|
||||
}
|
||||
],
|
||||
"kinematics": {
|
||||
"anchor_component": "housing",
|
||||
"rigid_groups": [
|
||||
{
|
||||
"id": "fixed_group",
|
||||
"members": [
|
||||
"housing",
|
||||
"circular_spline",
|
||||
"front_cover",
|
||||
"rear_cover",
|
||||
"housing_fasteners"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "output_group",
|
||||
"members": [
|
||||
"flexspline",
|
||||
"output_flange",
|
||||
"output_fasteners",
|
||||
"output_shaft"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "input_group",
|
||||
"members": [
|
||||
"wave_generator"
|
||||
]
|
||||
}
|
||||
],
|
||||
"joints": [
|
||||
{
|
||||
"id": "input_joint",
|
||||
"type": "continuous",
|
||||
"parent_group": "fixed_group",
|
||||
"child_group": "input_group",
|
||||
"axis_ref": "wave_generator.rotation_axis",
|
||||
"station_ref": "flexspline.wave_generator_seat",
|
||||
"dynamics": {
|
||||
"damping": 0.002,
|
||||
"friction": 0.003,
|
||||
"parameter_status": "estimated"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "output_joint",
|
||||
"type": "continuous",
|
||||
"parent_group": "fixed_group",
|
||||
"child_group": "output_group",
|
||||
"axis_ref": "output_flange.rotation_axis",
|
||||
"station_ref": "output_bearing.axial_reference",
|
||||
"dynamics": {
|
||||
"damping": 0.08,
|
||||
"friction": 0.12,
|
||||
"effort_limit": "output_torque_limit",
|
||||
"velocity_limit": "output_speed_limit",
|
||||
"parameter_status": "estimated"
|
||||
}
|
||||
}
|
||||
],
|
||||
"transmissions": [
|
||||
{
|
||||
"id": "harmonic_stage_transmission",
|
||||
"type": "harmonic",
|
||||
"input_joint": "input_joint",
|
||||
"output_joint": "output_joint",
|
||||
"ratio_expression": "output_angle = -input_angle / reduction_ratio",
|
||||
"fixed_member": "circular_spline",
|
||||
"compliance_model": "reduced_order_torsional_compliance"
|
||||
}
|
||||
]
|
||||
},
|
||||
"edit_interface": {
|
||||
"editable_parameters": [
|
||||
"nominal_size",
|
||||
"reduction_ratio",
|
||||
"outer_envelope_diameter",
|
||||
"axial_envelope",
|
||||
"output_bore_diameter",
|
||||
"housing_wall",
|
||||
"output_bolt_count",
|
||||
"housing_bolt_count",
|
||||
"output_torque_limit",
|
||||
"output_speed_limit",
|
||||
"output_shaft_diameter",
|
||||
"output_shaft_length"
|
||||
],
|
||||
"structural_operations": [
|
||||
"add_component",
|
||||
"remove_component",
|
||||
"replace_component",
|
||||
"change_relation",
|
||||
"change_transmission",
|
||||
"add_module"
|
||||
],
|
||||
"preserved_interfaces": [
|
||||
"housing.main_axis",
|
||||
"housing.front_closure_seat",
|
||||
"output_flange.external_mount_face",
|
||||
"output_flange.external_bolt_pattern",
|
||||
"output_flange.output_bore",
|
||||
"output_shaft.external_shaft_end"
|
||||
]
|
||||
},
|
||||
"validation_contract": {
|
||||
"coordinate_free_source": true,
|
||||
"required_checks": [
|
||||
"schema_valid",
|
||||
"reference_integrity",
|
||||
"constraint_graph_connected",
|
||||
"assembly_solvable_from_scrambled_state",
|
||||
"no_overconstraint",
|
||||
"interface_compatibility",
|
||||
"clearance",
|
||||
"interference",
|
||||
"joint_mobility",
|
||||
"parameter_perturbation",
|
||||
"preserved_interface",
|
||||
"urdf_load",
|
||||
"mjcf_load"
|
||||
],
|
||||
"acceptance_rules": [
|
||||
"No component placement may be authored as a coordinate or transform.",
|
||||
"The solver must recover a unique assembly from semantic interfaces and relations.",
|
||||
"Changing an editable parameter must rebuild affected components and re-solve all relations.",
|
||||
"Structural edits must preserve declared public interfaces unless the patch explicitly changes the contract."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,739 @@
|
||||
{
|
||||
"schema_version": "assembly-1.0",
|
||||
"designir_kind": "coordinate_free_semantic_assembly",
|
||||
"model_id": "lcd25_harmonic_reducer",
|
||||
"family": "harmonic_reducer_module",
|
||||
"units": "mm",
|
||||
"design_intent": "A compact coaxial harmonic reducer whose geometry, assembly and motion are regenerated from functional interfaces rather than stored placements.",
|
||||
"parameters": {
|
||||
"nominal_size": {
|
||||
"kind": "length",
|
||||
"value": 25.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [20.0, 40.0],
|
||||
"status": "inferred",
|
||||
"description": "Nominal transmission size controlling the scalable component family."
|
||||
},
|
||||
"reduction_ratio": {
|
||||
"kind": "ratio",
|
||||
"value": 100.0,
|
||||
"editable": true,
|
||||
"bounds": [50.0, 160.0],
|
||||
"status": "inferred",
|
||||
"description": "Input rotations per output rotation."
|
||||
},
|
||||
"outer_envelope_diameter": {
|
||||
"kind": "length",
|
||||
"value": 110.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [90.0, 140.0],
|
||||
"status": "specified",
|
||||
"description": "Maximum housing envelope."
|
||||
},
|
||||
"axial_envelope": {
|
||||
"kind": "length",
|
||||
"value": 32.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [25.0, 50.0],
|
||||
"status": "specified",
|
||||
"description": "Maximum reducer axial package length."
|
||||
},
|
||||
"output_bore_diameter": {
|
||||
"kind": "length",
|
||||
"value": 14.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [8.0, 25.0],
|
||||
"status": "estimated",
|
||||
"description": "Central output interface bore."
|
||||
},
|
||||
"housing_wall": {
|
||||
"kind": "length",
|
||||
"value": 3.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [2.0, 6.0],
|
||||
"status": "estimated",
|
||||
"description": "Minimum structural housing wall."
|
||||
},
|
||||
"output_bolt_count": {
|
||||
"kind": "count",
|
||||
"value": 4,
|
||||
"editable": true,
|
||||
"bounds": [3, 8],
|
||||
"status": "inferred",
|
||||
"description": "Output flange fastener pattern count."
|
||||
},
|
||||
"housing_bolt_count": {
|
||||
"kind": "count",
|
||||
"value": 10,
|
||||
"editable": true,
|
||||
"bounds": [6, 16],
|
||||
"status": "inferred",
|
||||
"description": "Housing closure fastener count."
|
||||
},
|
||||
"output_torque_limit": {
|
||||
"kind": "torque",
|
||||
"value": 25.0,
|
||||
"unit": "N*m",
|
||||
"editable": true,
|
||||
"bounds": [5.0, 60.0],
|
||||
"status": "estimated",
|
||||
"description": "Initial simulation effort limit."
|
||||
},
|
||||
"output_speed_limit": {
|
||||
"kind": "speed",
|
||||
"value": 2.5,
|
||||
"unit": "rad/s",
|
||||
"editable": true,
|
||||
"bounds": [0.5, 5.0],
|
||||
"status": "estimated",
|
||||
"description": "Initial simulation output speed limit."
|
||||
}
|
||||
},
|
||||
"expressions": {
|
||||
"flexspline_tooth_count": "2 * round(reduction_ratio / 2)",
|
||||
"circular_spline_tooth_count": "flexspline_tooth_count + 2",
|
||||
"bearing_nominal_diameter": "0.72 * outer_envelope_diameter",
|
||||
"output_flange_diameter": "0.48 * outer_envelope_diameter",
|
||||
"housing_fastener_pitch_diameter": "0.82 * outer_envelope_diameter"
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"id": "structure_module",
|
||||
"purpose": "Carry external loads and provide all mounting seats.",
|
||||
"members": ["housing", "rear_cover", "front_cover"],
|
||||
"replaceable_as_unit": true
|
||||
},
|
||||
{
|
||||
"id": "harmonic_stage",
|
||||
"purpose": "Generate the harmonic reduction between input and output.",
|
||||
"members": ["circular_spline", "flexspline", "wave_generator"],
|
||||
"replaceable_as_unit": true
|
||||
},
|
||||
{
|
||||
"id": "output_support_module",
|
||||
"purpose": "Support and locate the rotating output.",
|
||||
"members": ["output_bearing", "output_flange"],
|
||||
"replaceable_as_unit": true
|
||||
},
|
||||
{
|
||||
"id": "retention_module",
|
||||
"purpose": "Close and fasten structural interfaces.",
|
||||
"members": ["housing_fasteners", "output_fasteners"],
|
||||
"replaceable_as_unit": false
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"id": "housing",
|
||||
"role": "fixed_structure",
|
||||
"archetype": "coaxial_reducer_housing",
|
||||
"lifecycle": "required",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "annular_housing_with_mounting_flange",
|
||||
"parameter_bindings": {
|
||||
"outer_diameter": "outer_envelope_diameter",
|
||||
"axial_length": "axial_envelope",
|
||||
"minimum_wall": "housing_wall"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "main_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "front_closure_seat",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "rear_closure_seat",
|
||||
"type": "plane",
|
||||
"construction": "rear_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "circular_spline_seat",
|
||||
"type": "cylinder",
|
||||
"construction": "inner_cylindrical_surface",
|
||||
"qualifiers": ["largest_internal_transmission_seat"]
|
||||
},
|
||||
{
|
||||
"id": "output_bearing_seat",
|
||||
"type": "bearing_seat",
|
||||
"construction": "inner_cylindrical_surface",
|
||||
"qualifiers": ["frontmost_bearing_seat"]
|
||||
},
|
||||
{
|
||||
"id": "closure_pattern",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": ["housing_bolt_count"]
|
||||
}
|
||||
],
|
||||
"material_class": "aluminum_alloy",
|
||||
"tags": ["fixed", "structural", "thermal_path"]
|
||||
},
|
||||
{
|
||||
"id": "circular_spline",
|
||||
"role": "fixed_tooth_member",
|
||||
"archetype": "internal_spline_ring",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "harmonic_circular_spline",
|
||||
"parameter_bindings": {
|
||||
"nominal_size": "nominal_size",
|
||||
"tooth_count": "circular_spline_tooth_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "tooth_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "housing_fit",
|
||||
"type": "cylinder",
|
||||
"construction": "outer_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "anti_rotation",
|
||||
"type": "torque_interface",
|
||||
"construction": "generated_feature"
|
||||
}
|
||||
],
|
||||
"material_class": "hardened_steel",
|
||||
"tags": ["fixed", "transmission"]
|
||||
},
|
||||
{
|
||||
"id": "flexspline",
|
||||
"role": "compliant_tooth_member",
|
||||
"archetype": "cup_flexspline",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "harmonic_flexspline",
|
||||
"parameter_bindings": {
|
||||
"nominal_size": "nominal_size",
|
||||
"tooth_count": "flexspline_tooth_count",
|
||||
"output_bore": "output_bore_diameter"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "tooth_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "wave_generator_seat",
|
||||
"type": "bearing_seat",
|
||||
"construction": "inner_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "output_face",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "output_torque_interface",
|
||||
"type": "torque_interface",
|
||||
"construction": "generated_feature"
|
||||
}
|
||||
],
|
||||
"material_class": "spring_steel",
|
||||
"tags": ["rotating", "compliant", "transmission"]
|
||||
},
|
||||
{
|
||||
"id": "wave_generator",
|
||||
"role": "input_deformation_member",
|
||||
"archetype": "elliptical_wave_generator",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "subassembly_template",
|
||||
"family": "elliptical_cam_with_flexible_bearing",
|
||||
"parameter_bindings": {
|
||||
"nominal_size": "nominal_size"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "rotation_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "input_torque_interface",
|
||||
"type": "torque_interface",
|
||||
"construction": "inner_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_contact",
|
||||
"type": "contact_envelope",
|
||||
"construction": "outer_cylindrical_surface",
|
||||
"qualifiers": ["elliptical_compliant_contact"]
|
||||
}
|
||||
],
|
||||
"material_class": "bearing_steel",
|
||||
"tags": ["rotating", "input", "transmission"]
|
||||
},
|
||||
{
|
||||
"id": "output_bearing",
|
||||
"role": "combined_load_support",
|
||||
"archetype": "cross_roller_bearing",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "cross_roller_bearing",
|
||||
"parameter_bindings": {
|
||||
"nominal_diameter": "bearing_nominal_diameter"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "bearing_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "outer_ring_seat",
|
||||
"type": "bearing_seat",
|
||||
"construction": "outer_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "inner_ring_seat",
|
||||
"type": "bearing_seat",
|
||||
"construction": "inner_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "axial_reference",
|
||||
"type": "plane",
|
||||
"construction": "center_plane"
|
||||
}
|
||||
],
|
||||
"material_class": "bearing_steel",
|
||||
"tags": ["support", "split_kinematic_membership"]
|
||||
},
|
||||
{
|
||||
"id": "output_flange",
|
||||
"role": "external_output_interface",
|
||||
"archetype": "bolted_output_flange",
|
||||
"lifecycle": "replaceable",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "annular_output_flange",
|
||||
"parameter_bindings": {
|
||||
"diameter": "output_flange_diameter",
|
||||
"bore_diameter": "output_bore_diameter",
|
||||
"bolt_count": "output_bolt_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "rotation_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_mate",
|
||||
"type": "plane",
|
||||
"construction": "rear_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "bearing_fit",
|
||||
"type": "bearing_seat",
|
||||
"construction": "outer_cylindrical_surface"
|
||||
},
|
||||
{
|
||||
"id": "external_mount_face",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "external_bolt_pattern",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": ["output_bolt_count"]
|
||||
},
|
||||
{
|
||||
"id": "output_bore",
|
||||
"type": "shaft_seat",
|
||||
"construction": "inner_cylindrical_surface",
|
||||
"parameter_refs": ["output_bore_diameter"]
|
||||
}
|
||||
],
|
||||
"material_class": "alloy_steel",
|
||||
"tags": ["rotating", "output", "public_interface"]
|
||||
},
|
||||
{
|
||||
"id": "front_cover",
|
||||
"role": "front_axial_retainer",
|
||||
"archetype": "annular_cover",
|
||||
"lifecycle": "required",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "bolted_annular_cover",
|
||||
"parameter_bindings": {
|
||||
"outer_diameter": "outer_envelope_diameter",
|
||||
"bolt_count": "housing_bolt_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "housing_mate",
|
||||
"type": "plane",
|
||||
"construction": "rear_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "main_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "fastener_pattern",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": ["housing_bolt_count"]
|
||||
}
|
||||
],
|
||||
"material_class": "aluminum_alloy",
|
||||
"tags": ["fixed", "structural"]
|
||||
},
|
||||
{
|
||||
"id": "rear_cover",
|
||||
"role": "rear_axial_retainer",
|
||||
"archetype": "annular_cover",
|
||||
"lifecycle": "required",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "bolted_annular_cover",
|
||||
"parameter_bindings": {
|
||||
"outer_diameter": "outer_envelope_diameter"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "housing_mate",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "main_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
}
|
||||
],
|
||||
"material_class": "aluminum_alloy",
|
||||
"tags": ["fixed", "structural"]
|
||||
},
|
||||
{
|
||||
"id": "housing_fasteners",
|
||||
"role": "housing_closure_fasteners",
|
||||
"archetype": "socket_head_screw_pattern",
|
||||
"lifecycle": "generated_pattern",
|
||||
"quantity": "housing_bolt_count",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "metric_socket_head_screw",
|
||||
"parameter_bindings": {
|
||||
"nominal_thread": "M5",
|
||||
"count": "housing_bolt_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "fastener_axes",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": ["housing_bolt_count"]
|
||||
},
|
||||
{
|
||||
"id": "head_seats",
|
||||
"type": "fastener_seat",
|
||||
"construction": "generated_feature"
|
||||
}
|
||||
],
|
||||
"material_class": "steel",
|
||||
"tags": ["fixed", "fastener_pattern"]
|
||||
},
|
||||
{
|
||||
"id": "output_fasteners",
|
||||
"role": "output_interface_fasteners",
|
||||
"archetype": "countersunk_screw_pattern",
|
||||
"lifecycle": "generated_pattern",
|
||||
"quantity": "output_bolt_count",
|
||||
"generation": {
|
||||
"strategy": "standard_library",
|
||||
"family": "metric_countersunk_screw",
|
||||
"parameter_bindings": {
|
||||
"nominal_thread": "M2_5",
|
||||
"count": "output_bolt_count"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "fastener_axes",
|
||||
"type": "hole_pattern",
|
||||
"construction": "pitch_circle_pattern",
|
||||
"parameter_refs": ["output_bolt_count"]
|
||||
},
|
||||
{
|
||||
"id": "head_seats",
|
||||
"type": "fastener_seat",
|
||||
"construction": "generated_feature"
|
||||
}
|
||||
],
|
||||
"material_class": "steel",
|
||||
"tags": ["rotating", "fastener_pattern"]
|
||||
}
|
||||
],
|
||||
"relations": [
|
||||
{
|
||||
"id": "circular_spline_centering",
|
||||
"type": "coaxial",
|
||||
"a": "housing.main_axis",
|
||||
"b": "circular_spline.tooth_axis",
|
||||
"intent": "Center the fixed tooth member in the housing.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "circular_spline_fixing",
|
||||
"type": "torque_lock",
|
||||
"a": "housing.circular_spline_seat",
|
||||
"b": "circular_spline.anti_rotation",
|
||||
"intent": "Prevent rotation of the circular spline relative to the housing.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_centering",
|
||||
"type": "coaxial",
|
||||
"a": "circular_spline.tooth_axis",
|
||||
"b": "flexspline.tooth_axis",
|
||||
"intent": "Keep both spline members on the reducer axis.",
|
||||
"mobility": "allow_rotation"
|
||||
},
|
||||
{
|
||||
"id": "wave_generator_centering",
|
||||
"type": "coaxial",
|
||||
"a": "flexspline.tooth_axis",
|
||||
"b": "wave_generator.rotation_axis",
|
||||
"intent": "Place the wave generator on the transmission axis.",
|
||||
"mobility": "allow_rotation"
|
||||
},
|
||||
{
|
||||
"id": "wave_generator_contact",
|
||||
"type": "bearing_support",
|
||||
"a": "flexspline.wave_generator_seat",
|
||||
"b": "wave_generator.flexspline_contact",
|
||||
"intent": "Transfer the elliptical deformation while allowing relative rotation.",
|
||||
"mobility": "allow_rotation",
|
||||
"confidence": 0.82,
|
||||
"evidence": ["harmonic_stage_topology", "nested_flexible_bearing"]
|
||||
},
|
||||
{
|
||||
"id": "output_bearing_housing_fit",
|
||||
"type": "bearing_support",
|
||||
"a": "housing.output_bearing_seat",
|
||||
"b": "output_bearing.outer_ring_seat",
|
||||
"intent": "Fix and support the bearing outer ring in the housing.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "output_bearing_flange_fit",
|
||||
"type": "bearing_support",
|
||||
"a": "output_flange.bearing_fit",
|
||||
"b": "output_bearing.inner_ring_seat",
|
||||
"intent": "Support output flange rotation through the bearing inner ring.",
|
||||
"mobility": "allow_rotation"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_output_face",
|
||||
"type": "face_mate",
|
||||
"a": "flexspline.output_face",
|
||||
"b": "output_flange.flexspline_mate",
|
||||
"intent": "Locate the flexspline axially against the output flange.",
|
||||
"value": 0.0,
|
||||
"tolerance": 0.01,
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "flexspline_output_torque",
|
||||
"type": "torque_lock",
|
||||
"a": "flexspline.output_torque_interface",
|
||||
"b": "output_flange.external_bolt_pattern",
|
||||
"intent": "Transmit flexspline torque to the output flange.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "front_cover_centering",
|
||||
"type": "coaxial",
|
||||
"a": "housing.main_axis",
|
||||
"b": "front_cover.main_axis",
|
||||
"intent": "Center the front closure.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "front_cover_seating",
|
||||
"type": "face_mate",
|
||||
"a": "housing.front_closure_seat",
|
||||
"b": "front_cover.housing_mate",
|
||||
"intent": "Close the front housing interface.",
|
||||
"value": 0.0,
|
||||
"tolerance": 0.02,
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "rear_cover_centering",
|
||||
"type": "coaxial",
|
||||
"a": "housing.main_axis",
|
||||
"b": "rear_cover.main_axis",
|
||||
"intent": "Center the rear closure.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "rear_cover_seating",
|
||||
"type": "face_mate",
|
||||
"a": "housing.rear_closure_seat",
|
||||
"b": "rear_cover.housing_mate",
|
||||
"intent": "Close the rear housing interface.",
|
||||
"value": 0.0,
|
||||
"tolerance": 0.02,
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "housing_fastener_alignment",
|
||||
"type": "fasten_pattern",
|
||||
"a": "housing.closure_pattern",
|
||||
"b": "housing_fasteners.fastener_axes",
|
||||
"intent": "Instantiate and align the housing closure screws.",
|
||||
"mobility": "fixed"
|
||||
},
|
||||
{
|
||||
"id": "output_fastener_alignment",
|
||||
"type": "fasten_pattern",
|
||||
"a": "output_flange.external_bolt_pattern",
|
||||
"b": "output_fasteners.fastener_axes",
|
||||
"intent": "Instantiate and align output flange screws.",
|
||||
"mobility": "fixed"
|
||||
}
|
||||
],
|
||||
"kinematics": {
|
||||
"anchor_component": "housing",
|
||||
"rigid_groups": [
|
||||
{
|
||||
"id": "fixed_group",
|
||||
"members": ["housing", "circular_spline", "front_cover", "rear_cover", "housing_fasteners"]
|
||||
},
|
||||
{
|
||||
"id": "output_group",
|
||||
"members": ["flexspline", "output_flange", "output_fasteners"]
|
||||
},
|
||||
{
|
||||
"id": "input_group",
|
||||
"members": ["wave_generator"]
|
||||
}
|
||||
],
|
||||
"joints": [
|
||||
{
|
||||
"id": "input_joint",
|
||||
"type": "continuous",
|
||||
"parent_group": "fixed_group",
|
||||
"child_group": "input_group",
|
||||
"axis_ref": "wave_generator.rotation_axis",
|
||||
"station_ref": "flexspline.wave_generator_seat",
|
||||
"dynamics": {
|
||||
"damping": 0.002,
|
||||
"friction": 0.003,
|
||||
"parameter_status": "estimated"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "output_joint",
|
||||
"type": "continuous",
|
||||
"parent_group": "fixed_group",
|
||||
"child_group": "output_group",
|
||||
"axis_ref": "output_flange.rotation_axis",
|
||||
"station_ref": "output_bearing.axial_reference",
|
||||
"dynamics": {
|
||||
"damping": 0.08,
|
||||
"friction": 0.12,
|
||||
"effort_limit": "output_torque_limit",
|
||||
"velocity_limit": "output_speed_limit",
|
||||
"parameter_status": "estimated"
|
||||
}
|
||||
}
|
||||
],
|
||||
"transmissions": [
|
||||
{
|
||||
"id": "harmonic_stage_transmission",
|
||||
"type": "harmonic",
|
||||
"input_joint": "input_joint",
|
||||
"output_joint": "output_joint",
|
||||
"ratio_expression": "output_angle = -input_angle / reduction_ratio",
|
||||
"fixed_member": "circular_spline",
|
||||
"compliance_model": "reduced_order_torsional_compliance"
|
||||
}
|
||||
]
|
||||
},
|
||||
"edit_interface": {
|
||||
"editable_parameters": [
|
||||
"nominal_size",
|
||||
"reduction_ratio",
|
||||
"outer_envelope_diameter",
|
||||
"axial_envelope",
|
||||
"output_bore_diameter",
|
||||
"housing_wall",
|
||||
"output_bolt_count",
|
||||
"housing_bolt_count",
|
||||
"output_torque_limit",
|
||||
"output_speed_limit"
|
||||
],
|
||||
"structural_operations": [
|
||||
"add_component",
|
||||
"remove_component",
|
||||
"replace_component",
|
||||
"change_relation",
|
||||
"change_transmission",
|
||||
"add_module"
|
||||
],
|
||||
"preserved_interfaces": [
|
||||
"housing.main_axis",
|
||||
"housing.front_closure_seat",
|
||||
"output_flange.external_mount_face",
|
||||
"output_flange.external_bolt_pattern",
|
||||
"output_flange.output_bore"
|
||||
]
|
||||
},
|
||||
"validation_contract": {
|
||||
"coordinate_free_source": true,
|
||||
"required_checks": [
|
||||
"schema_valid",
|
||||
"reference_integrity",
|
||||
"constraint_graph_connected",
|
||||
"assembly_solvable_from_scrambled_state",
|
||||
"no_overconstraint",
|
||||
"interface_compatibility",
|
||||
"clearance",
|
||||
"interference",
|
||||
"joint_mobility",
|
||||
"parameter_perturbation",
|
||||
"preserved_interface",
|
||||
"urdf_load",
|
||||
"mjcf_load"
|
||||
],
|
||||
"acceptance_rules": [
|
||||
"No component placement may be authored as a coordinate or transform.",
|
||||
"The solver must recover a unique assembly from semantic interfaces and relations.",
|
||||
"Changing an editable parameter must rebuild affected components and re-solve all relations.",
|
||||
"Structural edits must preserve declared public interfaces unless the patch explicitly changes the contract."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate and semantically patch coordinate-free Assembly DesignIR."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import jsonschema
|
||||
|
||||
|
||||
FORBIDDEN_PLACEMENT_KEYS = {
|
||||
"transform",
|
||||
"transforms",
|
||||
"matrix",
|
||||
"matrices",
|
||||
"placement",
|
||||
"placements",
|
||||
"position",
|
||||
"positions",
|
||||
"location",
|
||||
"locations",
|
||||
"xyz",
|
||||
"rpy",
|
||||
"quaternion",
|
||||
"translation",
|
||||
}
|
||||
|
||||
|
||||
def walk_forbidden(value: Any, path: str = "$") -> list[str]:
|
||||
failures: list[str] = []
|
||||
if isinstance(value, dict):
|
||||
for key, child in value.items():
|
||||
child_path = f"{path}.{key}"
|
||||
if key.lower() in FORBIDDEN_PLACEMENT_KEYS:
|
||||
failures.append(child_path)
|
||||
failures.extend(walk_forbidden(child, child_path))
|
||||
elif isinstance(value, list):
|
||||
for index, child in enumerate(value):
|
||||
failures.extend(walk_forbidden(child, f"{path}[{index}]"))
|
||||
return failures
|
||||
|
||||
|
||||
def component_interfaces(payload: dict[str, Any]) -> dict[str, set[str]]:
|
||||
return {
|
||||
component["id"]: {interface["id"] for interface in component["interfaces"]}
|
||||
for component in payload["components"]
|
||||
}
|
||||
|
||||
|
||||
def validate_references(payload: dict[str, Any]) -> list[str]:
|
||||
failures: list[str] = []
|
||||
interfaces = component_interfaces(payload)
|
||||
component_ids = set(interfaces)
|
||||
if len(component_ids) != len(payload["components"]):
|
||||
failures.append("component ids are not unique")
|
||||
|
||||
relation_ids: set[str] = set()
|
||||
adjacency = {component_id: set() for component_id in component_ids}
|
||||
for relation in payload["relations"]:
|
||||
if relation["id"] in relation_ids:
|
||||
failures.append(f"duplicate relation id: {relation['id']}")
|
||||
relation_ids.add(relation["id"])
|
||||
endpoints: list[tuple[str, str]] = []
|
||||
for side in ("a", "b"):
|
||||
component_id, interface_id = relation[side].split(".", 1)
|
||||
endpoints.append((component_id, interface_id))
|
||||
if component_id not in interfaces:
|
||||
failures.append(
|
||||
f"{relation['id']}.{side}: unknown component {component_id}"
|
||||
)
|
||||
elif interface_id not in interfaces[component_id]:
|
||||
failures.append(
|
||||
f"{relation['id']}.{side}: unknown interface "
|
||||
f"{component_id}.{interface_id}"
|
||||
)
|
||||
if all(component_id in component_ids for component_id, _ in endpoints):
|
||||
adjacency[endpoints[0][0]].add(endpoints[1][0])
|
||||
adjacency[endpoints[1][0]].add(endpoints[0][0])
|
||||
|
||||
anchor = payload["kinematics"]["anchor_component"]
|
||||
if anchor not in component_ids:
|
||||
failures.append(f"unknown anchor component: {anchor}")
|
||||
elif component_ids:
|
||||
visited: set[str] = set()
|
||||
frontier = [anchor]
|
||||
while frontier:
|
||||
current = frontier.pop()
|
||||
if current in visited:
|
||||
continue
|
||||
visited.add(current)
|
||||
frontier.extend(adjacency[current] - visited)
|
||||
disconnected = sorted(component_ids - visited)
|
||||
if disconnected:
|
||||
failures.append(
|
||||
"constraint graph disconnected: " + ", ".join(disconnected)
|
||||
)
|
||||
|
||||
group_ids: set[str] = set()
|
||||
for group in payload["kinematics"]["rigid_groups"]:
|
||||
if group["id"] in group_ids:
|
||||
failures.append(f"duplicate rigid group id: {group['id']}")
|
||||
group_ids.add(group["id"])
|
||||
for member in group["members"]:
|
||||
if member not in component_ids:
|
||||
failures.append(
|
||||
f"rigid group {group['id']} has unknown member {member}"
|
||||
)
|
||||
|
||||
joint_ids: set[str] = set()
|
||||
for joint in payload["kinematics"]["joints"]:
|
||||
joint_ids.add(joint["id"])
|
||||
for side in ("parent_group", "child_group"):
|
||||
if joint[side] not in group_ids:
|
||||
failures.append(
|
||||
f"joint {joint['id']} has unknown {side} {joint[side]}"
|
||||
)
|
||||
for ref_key in ("axis_ref", "station_ref"):
|
||||
component_id, interface_id = joint[ref_key].split(".", 1)
|
||||
if (
|
||||
component_id not in interfaces
|
||||
or interface_id not in interfaces[component_id]
|
||||
):
|
||||
failures.append(
|
||||
f"joint {joint['id']} has unknown {ref_key} "
|
||||
f"{joint[ref_key]}"
|
||||
)
|
||||
|
||||
for transmission in payload["kinematics"]["transmissions"]:
|
||||
for key in ("input_joint", "output_joint"):
|
||||
if transmission[key] not in joint_ids:
|
||||
failures.append(
|
||||
f"transmission {transmission['id']} has unknown "
|
||||
f"{key} {transmission[key]}"
|
||||
)
|
||||
fixed_member = transmission.get("fixed_member")
|
||||
if fixed_member and fixed_member not in component_ids:
|
||||
failures.append(
|
||||
f"transmission {transmission['id']} has unknown fixed member "
|
||||
f"{fixed_member}"
|
||||
)
|
||||
|
||||
parameter_ids = set(payload["parameters"])
|
||||
for parameter_id in payload["edit_interface"]["editable_parameters"]:
|
||||
if parameter_id not in parameter_ids:
|
||||
failures.append(f"unknown editable parameter: {parameter_id}")
|
||||
elif not payload["parameters"][parameter_id]["editable"]:
|
||||
failures.append(f"parameter is not editable: {parameter_id}")
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def apply_patch(payload: dict[str, Any], patch: dict[str, Any]) -> dict[str, Any]:
|
||||
if patch["target_model"] != payload["model_id"]:
|
||||
raise ValueError("Patch target_model does not match base model")
|
||||
result = copy.deepcopy(payload)
|
||||
groups = {
|
||||
group["id"]: group for group in result["kinematics"]["rigid_groups"]
|
||||
}
|
||||
for operation in patch["operations"]:
|
||||
kind = operation["op"]
|
||||
if kind == "add_parameter":
|
||||
result["parameters"][operation["id"]] = operation["value"]
|
||||
result["edit_interface"]["editable_parameters"].append(
|
||||
operation["id"]
|
||||
)
|
||||
elif kind == "add_component":
|
||||
result["components"].append(operation["value"])
|
||||
elif kind == "add_relation":
|
||||
result["relations"].append(operation["value"])
|
||||
elif kind == "add_rigid_group_member":
|
||||
groups[operation["group"]]["members"].append(
|
||||
operation["component"]
|
||||
)
|
||||
elif kind == "add_preserved_interface":
|
||||
result["edit_interface"]["preserved_interfaces"].append(
|
||||
operation["value"]
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unsupported semantic patch operation: {kind}")
|
||||
result["model_id"] = f"{payload['model_id']}_with_output_shaft"
|
||||
return result
|
||||
|
||||
|
||||
def validate(
|
||||
payload: dict[str, Any], schema: dict[str, Any]
|
||||
) -> dict[str, Any]:
|
||||
schema_errors = sorted(
|
||||
jsonschema.Draft202012Validator(schema).iter_errors(payload),
|
||||
key=lambda error: list(error.absolute_path),
|
||||
)
|
||||
failures = [
|
||||
f"{'.'.join(map(str, error.absolute_path))}: {error.message}"
|
||||
for error in schema_errors
|
||||
]
|
||||
forbidden = walk_forbidden(payload)
|
||||
failures.extend(
|
||||
f"coordinate placement key is forbidden: {path}" for path in forbidden
|
||||
)
|
||||
if not schema_errors:
|
||||
failures.extend(validate_references(payload))
|
||||
return {
|
||||
"status": "pass" if not failures else "fail",
|
||||
"schema_version": payload.get("schema_version"),
|
||||
"model_id": payload.get("model_id"),
|
||||
"coordinate_free": not forbidden,
|
||||
"component_count": len(payload.get("components", [])),
|
||||
"relation_count": len(payload.get("relations", [])),
|
||||
"joint_count": len(payload.get("kinematics", {}).get("joints", [])),
|
||||
"transmission_count": len(
|
||||
payload.get("kinematics", {}).get("transmissions", [])
|
||||
),
|
||||
"failures": failures,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("model", type=Path)
|
||||
parser.add_argument("--schema", type=Path, required=True)
|
||||
parser.add_argument("--patch", type=Path)
|
||||
parser.add_argument("--resolved-output", type=Path)
|
||||
parser.add_argument("--report", type=Path)
|
||||
args = parser.parse_args()
|
||||
|
||||
payload = json.loads(args.model.read_text(encoding="utf-8"))
|
||||
schema = json.loads(args.schema.read_text(encoding="utf-8"))
|
||||
if args.patch:
|
||||
patch = json.loads(args.patch.read_text(encoding="utf-8"))
|
||||
payload = apply_patch(payload, patch)
|
||||
if args.resolved_output:
|
||||
args.resolved_output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.resolved_output.write_text(
|
||||
json.dumps(payload, ensure_ascii=False, indent=2),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
report = validate(payload, schema)
|
||||
if args.report:
|
||||
args.report.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.report.write_text(
|
||||
json.dumps(report, ensure_ascii=False, indent=2),
|
||||
encoding="utf-8",
|
||||
)
|
||||
print(json.dumps(report, ensure_ascii=False))
|
||||
raise SystemExit(0 if report["status"] == "pass" else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"status": "pass",
|
||||
"schema_version": "assembly-1.0",
|
||||
"model_id": "lcd25_harmonic_reducer_with_output_shaft",
|
||||
"coordinate_free": true,
|
||||
"component_count": 11,
|
||||
"relation_count": 19,
|
||||
"joint_count": 2,
|
||||
"transmission_count": 1,
|
||||
"failures": []
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"status": "pass",
|
||||
"schema_version": "assembly-1.0",
|
||||
"model_id": "lcd25_harmonic_reducer",
|
||||
"coordinate_free": true,
|
||||
"component_count": 10,
|
||||
"relation_count": 15,
|
||||
"joint_count": 2,
|
||||
"transmission_count": 1,
|
||||
"failures": []
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"patch_version": "1.0",
|
||||
"target_model": "lcd25_harmonic_reducer",
|
||||
"intent": "Add a coaxial keyed output shaft without authoring a placement transform.",
|
||||
"operations": [
|
||||
{
|
||||
"op": "add_parameter",
|
||||
"id": "output_shaft_diameter",
|
||||
"value": {
|
||||
"kind": "length",
|
||||
"value": 14.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [10.0, 20.0],
|
||||
"status": "specified",
|
||||
"description": "Output shaft journal diameter."
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add_parameter",
|
||||
"id": "output_shaft_length",
|
||||
"value": {
|
||||
"kind": "length",
|
||||
"value": 45.0,
|
||||
"unit": "mm",
|
||||
"editable": true,
|
||||
"bounds": [25.0, 80.0],
|
||||
"status": "specified",
|
||||
"description": "Usable shaft extension measured from the output mounting face."
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add_component",
|
||||
"value": {
|
||||
"id": "output_shaft",
|
||||
"role": "external_torque_shaft",
|
||||
"archetype": "stepped_keyed_shaft",
|
||||
"lifecycle": "optional",
|
||||
"generation": {
|
||||
"strategy": "semantic_feature_program",
|
||||
"family": "stepped_output_shaft",
|
||||
"parameter_bindings": {
|
||||
"journal_diameter": "output_shaft_diameter",
|
||||
"extension_length": "output_shaft_length",
|
||||
"mating_bore": "output_bore_diameter"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"id": "shaft_axis",
|
||||
"type": "axis",
|
||||
"construction": "primary_axis"
|
||||
},
|
||||
{
|
||||
"id": "mounting_shoulder",
|
||||
"type": "plane",
|
||||
"construction": "rear_axial_face"
|
||||
},
|
||||
{
|
||||
"id": "flange_fit",
|
||||
"type": "shaft_seat",
|
||||
"construction": "outer_cylindrical_surface",
|
||||
"parameter_refs": ["output_shaft_diameter"]
|
||||
},
|
||||
{
|
||||
"id": "torque_drive",
|
||||
"type": "torque_interface",
|
||||
"construction": "generated_feature",
|
||||
"qualifiers": ["key_or_spline_selected_by_load"]
|
||||
},
|
||||
{
|
||||
"id": "external_shaft_end",
|
||||
"type": "plane",
|
||||
"construction": "front_axial_face"
|
||||
}
|
||||
],
|
||||
"material_class": "alloy_steel",
|
||||
"tags": ["rotating", "output", "public_interface"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add_relation",
|
||||
"value": {
|
||||
"id": "output_shaft_centering",
|
||||
"type": "coaxial",
|
||||
"a": "output_flange.rotation_axis",
|
||||
"b": "output_shaft.shaft_axis",
|
||||
"intent": "Center the new shaft on the solved output axis.",
|
||||
"mobility": "fixed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add_relation",
|
||||
"value": {
|
||||
"id": "output_shaft_seating",
|
||||
"type": "face_mate",
|
||||
"a": "output_flange.external_mount_face",
|
||||
"b": "output_shaft.mounting_shoulder",
|
||||
"intent": "Locate the shaft shoulder from the output flange mounting face.",
|
||||
"value": 0.0,
|
||||
"tolerance": 0.01,
|
||||
"mobility": "fixed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add_relation",
|
||||
"value": {
|
||||
"id": "output_shaft_fit",
|
||||
"type": "insert",
|
||||
"a": "output_flange.output_bore",
|
||||
"b": "output_shaft.flange_fit",
|
||||
"intent": "Fit the shaft journal into the output flange bore.",
|
||||
"tolerance": 0.01,
|
||||
"mobility": "fixed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add_relation",
|
||||
"value": {
|
||||
"id": "output_shaft_torque_lock",
|
||||
"type": "torque_lock",
|
||||
"a": "output_flange.output_bore",
|
||||
"b": "output_shaft.torque_drive",
|
||||
"intent": "Transfer output torque through a keyed or splined interface.",
|
||||
"mobility": "fixed"
|
||||
}
|
||||
},
|
||||
{
|
||||
"op": "add_rigid_group_member",
|
||||
"group": "output_group",
|
||||
"component": "output_shaft"
|
||||
},
|
||||
{
|
||||
"op": "add_preserved_interface",
|
||||
"value": "output_shaft.external_shaft_end"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user