feat: integrate SimpleCADAPI 2.0.2 CAD workflows

This commit is contained in:
Jerry
2026-08-03 11:17:05 +08:00
parent b5738e9109
commit c3a0f269b7
481 changed files with 110229 additions and 12826 deletions
@@ -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.
@@ -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"
}
]
}