Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ The default implementations are `openarm_describe_config_component` and `openarm

Interface files declare macros; implementation and third-party model includes belong inside those macros. Each interface is loaded in a local scope, so its definitions do not affect other components. Presets need no implementation selector or product registry.

Component topology uses stable `link1`, `link2`, ... and `joint1`, `joint2`, ... keys. An optional `name` on each topology entry defines its local URDF name; otherwise the key is used. The instance prefix is added once. Geometry, inertia, joint parameters, parent/child links, mimic targets, references, reflection selections and overrides use the stable keys. Changing `name` preserves these config references. Component descriptors expose resolved `link_name_map` and `joint_name_map` entries for emitters and control generation.

## Related links

- 📚 Read the [documentation](https://docs.openarm.dev/software/description)
Expand Down
2 changes: 1 addition & 1 deletion assets/body/v2.0/config/inertials/nominal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

body_link0:
link1:
origin:
x: -0.01627169562
y: 0.0
Expand Down
2 changes: 1 addition & 1 deletion assets/body/v2.0/config/link/collisions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

body_link0:
link1:
origin:
x: 0.0
y: 0.0
Expand Down
2 changes: 1 addition & 1 deletion assets/body/v2.0/config/link/visuals.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

body_link0:
link1:
origin:
x: 0.0
y: 0.0
Expand Down
10 changes: 5 additions & 5 deletions assets/body/v2.0/config/struct/reference_points.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

left_arm_mount_point:
parent: body_link0
parent: link1
origin:
x: 0.0
y: 0.030
Expand All @@ -29,13 +29,13 @@ left_arm_mount_point:
type: fixed
parent_link:
original_name: body_link0
canonical_name: body_link0
canonical_name: link1
child_link:
original_name: body_left_arm_mount_point
canonical_name: null

right_arm_mount_point:
parent: body_link0
parent: link1
origin:
x: 0.0
y: -0.030
Expand All @@ -51,13 +51,13 @@ right_arm_mount_point:
type: fixed
parent_link:
original_name: body_link0
canonical_name: body_link0
canonical_name: link1
child_link:
original_name: body_right_arm_mount_point
canonical_name: null

arm_origin:
parent: body_link0
parent: link1
emit: true
origin:
x: 0.0
Expand Down
3 changes: 2 additions & 1 deletion assets/body/v2.0/config/struct/topology.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
# limitations under the License.

links:
- body_link0
link1:
name: body_link0
joints: {}
8 changes: 4 additions & 4 deletions assets/common/assembly.xacro
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ limitations under the License.
<xacro:if value="${parent_ref_should_reflect}">
<xacro:openarm_reflect_pose origin="${reference_origin}" reflect_x="${parent_reflect_cfg['x']}" reflect_y="${parent_reflect_cfg['y']}" reflect_z="${parent_reflect_cfg['z']}" out_name="reference_origin" />
</xacro:if>
<xacro:if value="${parent_ref_canonical_link == parent_desc['topology']['links'][0] and parent_desc.get('base_frame_shift', 'none') != 'none'}">
<xacro:if value="${parent_ref_canonical_link == list(parent_desc['topology']['links'])[0] and parent_desc.get('base_frame_shift', 'none') != 'none'}">
<xacro:openarm_compose_pose first="${parent_desc['base_frame_shift']}" second="${reference_origin}" out_name="reference_origin" />
</xacro:if>
<xacro:openarm_compose_pose first="${reference_origin}" second="${connection_origin}" out_name="reference_mount_origin" />
Expand All @@ -111,9 +111,9 @@ limitations under the License.
<!-- reference point child empty links are already absorbed into config; runtime collapse only targets the parent's terminal empty link -->
<xacro:property
name="parent_terminal_link_empty"
value="${has_parent_desc and parent_desc['collapse_empty_end'] and parent_desc['topology']['links'][-1] not in parent_desc['inertials'] and parent_desc['topology']['links'][-1] not in parent_desc['visuals'] and parent_desc['topology']['links'][-1] not in parent_desc['collisions']}"
value="${has_parent_desc and parent_desc['collapse_empty_end'] and list(parent_desc['topology']['links'])[-1] not in parent_desc['inertials'] and list(parent_desc['topology']['links'])[-1] not in parent_desc['visuals'] and list(parent_desc['topology']['links'])[-1] not in parent_desc['collisions']}"
lazy_eval="false" />
<xacro:if value="${has_parent_reference_key and not has_parent_override and parent_terminal_link_empty and parent_ref_canonical_link == parent_desc['topology']['links'][-1] and component_desc.get('supports_frame_shift', False)}">
<xacro:if value="${has_parent_reference_key and not has_parent_override and parent_terminal_link_empty and parent_ref_canonical_link == list(parent_desc['topology']['links'])[-1] and component_desc.get('supports_frame_shift', False)}">
<xacro:property name="skip_mount_joint" value="${True}" lazy_eval="false" />
<xacro:property name="base_frame_shift" value="${reference_mount_origin}" lazy_eval="false" />
</xacro:if>
Expand All @@ -123,7 +123,7 @@ limitations under the License.
name="attached_children"
value="${[name for name in components if name in robot_preset and robot_preset[name]['enabled'] and 'connection' in robot_preset[name] and 'attach_to' in robot_preset[name]['connection'] and robot_preset[name]['connection']['attach_to'] == component_name]}"
lazy_eval="false" />
<xacro:property name="component_terminal_link" value="${component_desc['topology']['links'][-1]}" lazy_eval="false" />
<xacro:property name="component_terminal_link" value="${list(component_desc['topology']['links'])[-1]}" lazy_eval="false" />
<xacro:property
name="component_terminal_link_empty"
value="${component_desc['collapse_empty_end'] and component_terminal_link not in component_desc['inertials'] and component_terminal_link not in component_desc['visuals'] and component_terminal_link not in component_desc['collisions']}"
Expand Down
14 changes: 9 additions & 5 deletions assets/common/components.xacro
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ limitations under the License.
<xacro:property name="component_inertials" value="${xacro.load_yaml(component_cfg_root + '/inertials/' + component_cfg['inertials'] + '.yaml')}" lazy_eval="false" />
<xacro:property name="component_visuals" value="${xacro.load_yaml(component_cfg_root + '/link/visuals.yaml')}" lazy_eval="false" />
<xacro:property name="component_collisions" value="${xacro.load_yaml(component_cfg_root + '/link/collisions.yaml')}" lazy_eval="false" />
<xacro:property name="component_link_name_map" value="${empty_dict}" lazy_eval="false" />
<xacro:property name="component_root_link_actual" value="${component_prefix + component_topology['links'][0]}" lazy_eval="false" />
<xacro:property name="component_default_mount_parent" value="${component_prefix + (component_topology['links'][0] if component_type == 'body' else component_topology['links'][-1])}" lazy_eval="false" />
<xacro:property name="component_collapse_empty_end" value="${component_topology.get('collapse_empty_end', False) and len([j for j in component_topology['joints'] if component_topology['joints'][j]['parent'] == component_topology['links'][-1]]) == 0}" lazy_eval="false" />
<xacro:property name="component_link_name_map" value="${dict([(key, component_prefix + cfg.get('name', key)) for key, cfg in component_topology['links'].items()])}" lazy_eval="false" />
<xacro:property name="component_joint_name_map" value="${dict([(key, component_prefix + cfg.get('name', key)) for key, cfg in component_topology['joints'].items()])}" lazy_eval="false" />
<xacro:property name="component_root_link_actual" value="${component_link_name_map[list(component_topology['links'])[0]]}" lazy_eval="false" />
<xacro:property name="component_default_mount_parent" value="${component_link_name_map[list(component_topology['links'])[0] if component_type == 'body' else list(component_topology['links'])[-1]]}" lazy_eval="false" />
<xacro:property name="component_collapse_empty_end" value="${component_topology.get('collapse_empty_end', False) and len([j for j in component_topology['joints'] if component_topology['joints'][j]['parent'] == list(component_topology['links'])[-1]]) == 0}" lazy_eval="false" />

<xacro:property
name="${out_name}"
Expand All @@ -71,6 +72,7 @@ limitations under the License.
visuals=component_visuals,
collisions=component_collisions,
link_name_map=component_link_name_map,
joint_name_map=component_joint_name_map,
default_mount_parent=component_default_mount_parent,
collapse_empty_end=component_collapse_empty_end,
supports_frame_shift=True)}"
Expand Down Expand Up @@ -99,6 +101,8 @@ limitations under the License.
<xacro:if value="${component_desc['topology']['joints']}">
<xacro:openarm_emit_kinematic_component
prefix="${component_desc['prefix']}"
link_name_map="${component_desc['link_name_map']}"
joint_name_map="${component_desc['joint_name_map']}"
connected_to="${component_runtime['resolved_connected_to']}"
mount_origin="${component_runtime['resolved_mount_origin']}"
topology="${component_desc['topology']}"
Expand Down Expand Up @@ -126,7 +130,7 @@ limitations under the License.
reference_points="${component_desc['reference_points']}"
prefix="${component_desc['prefix']}"
link_name_map="${component_desc['link_name_map']}"
base_link_name="${component_desc['topology']['links'][0]}"
base_link_name="${list(component_desc['topology']['links'])[0]}"
reflect_x="${component_runtime['reflect_x']}"
reflect_y="${component_runtime['reflect_y']}"
reflect_z="${component_runtime['reflect_z']}"
Expand Down
24 changes: 13 additions & 11 deletions assets/common/kinematic_chain.xacro
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
<xacro:include filename="$(find openarm_description)/assets/common/validation.xacro" />

<xacro:macro name="openarm_emit_chain"
params="index joint_names topology prefix joint_origins joint_axes joint_limits joint_mimics inertials visuals collisions reflect_x reflect_y reflect_z reflect_include_links reflect_include_joints origin_override_joints limit_override_joints tip_collapse_source_link tip_collapse_child_link base_frame_shift">
params="index joint_names topology prefix link_name_map joint_name_map joint_origins joint_axes joint_limits joint_mimics inertials visuals collisions reflect_x reflect_y reflect_z reflect_include_links reflect_include_joints origin_override_joints limit_override_joints tip_collapse_source_link tip_collapse_child_link base_frame_shift">
<xacro:if value="${index &lt; len(joint_names)}">
<xacro:property name="name" value="${joint_names[index]}" />
<xacro:property name="joint" value="${topology['joints'][name]}" />
Expand All @@ -26,20 +26,21 @@ limitations under the License.
<xacro:property name="joint_reflects" value="${name in reflect_include_joints}" />
<xacro:property name="collapse_child" value="${child == tip_collapse_source_link}" />
<xacro:unless value="${collapse_child}">
<xacro:openarm_emit_link link_name="${prefix + child}" source_name="${child}"
<xacro:openarm_emit_link link_name="${link_name_map[child]}" source_name="${child}"
inertials="${inertials}" visuals="${visuals}" collisions="${collisions}"
reflect_x="${reflect_x if link_reflects else 1}" reflect_y="${reflect_y if link_reflects else 1}" reflect_z="${reflect_z if link_reflects else 1}" />
</xacro:unless>
<xacro:property name="mimic" value="${joint_mimics[name] if name in joint_mimics else 'none'}" />
<xacro:openarm_emit_joint joint_name="${prefix + name}" joint_type="${joint['type']}"
parent_link="${prefix + joint['parent']}" child_link="${tip_collapse_child_link if collapse_child else prefix + child}"
<xacro:openarm_emit_joint joint_name="${joint_name_map[name]}" joint_type="${joint['type']}"
parent_link="${link_name_map[joint['parent']]}" child_link="${tip_collapse_child_link if collapse_child else link_name_map[child]}"
joint_origins="${joint_origins}" joint_axes="${joint_axes}" joint_limits="${joint_limits}" source_name="${name}"
origin_override="${origin_override_joints.get(name, 'none')}" limit_override="${limit_override_joints.get(name, 'none')}"
mimic_override="${dict(joint=prefix + mimic['joint'], multiplier=mimic['multiplier'], offset=mimic['offset']) if mimic != 'none' else 'none'}"
mimic_override="${dict(joint=joint_name_map[mimic['joint']], multiplier=mimic['multiplier'], offset=mimic['offset']) if mimic != 'none' else 'none'}"
reflect_x="${reflect_x if joint_reflects else 1}" reflect_y="${reflect_y if joint_reflects else 1}" reflect_z="${reflect_z if joint_reflects else 1}"
reflect_rotation="${True}" mirror_limit_sign="${joint_reflects and (reflect_x == -1 or reflect_y == -1 or reflect_z == -1)}"
frame_shift="${base_frame_shift if joint['parent'] == topology['links'][0] else 'none'}" />
frame_shift="${base_frame_shift if joint['parent'] == list(topology['links'])[0] else 'none'}" />
<xacro:openarm_emit_chain index="${index + 1}" joint_names="${joint_names}" topology="${topology}" prefix="${prefix}"
link_name_map="${link_name_map}" joint_name_map="${joint_name_map}"
joint_origins="${joint_origins}" joint_axes="${joint_axes}" joint_limits="${joint_limits}" joint_mimics="${joint_mimics}"
inertials="${inertials}" visuals="${visuals}" collisions="${collisions}"
reflect_x="${reflect_x}" reflect_y="${reflect_y}" reflect_z="${reflect_z}"
Expand All @@ -50,21 +51,22 @@ limitations under the License.
</xacro:macro>

<xacro:macro name="openarm_emit_kinematic_component"
params="connected_to mount_origin topology prefix joint_origins joint_axes joint_limits joint_mimics:=${dict()} inertials visuals collisions reflect_x:=1 reflect_y:=1 reflect_z:=1 reflect_include_links:=${[]} reflect_include_joints:=${[]} origin_override_joints:=${dict()} limit_override_joints:=${dict()} tip_collapse_source_link:=none tip_collapse_child_link:=none skip_mount_joint:=${False} base_frame_shift:=none">
params="connected_to mount_origin topology prefix link_name_map joint_name_map joint_origins joint_axes joint_limits joint_mimics:=${dict()} inertials visuals collisions reflect_x:=1 reflect_y:=1 reflect_z:=1 reflect_include_links:=${[]} reflect_include_joints:=${[]} origin_override_joints:=${dict()} limit_override_joints:=${dict()} tip_collapse_source_link:=none tip_collapse_child_link:=none skip_mount_joint:=${False} base_frame_shift:=none">
<xacro:openarm_validate_topology topology="${topology}" component="${prefix}" />
<xacro:property name="base" value="${topology['links'][0]}" />
<xacro:property name="base" value="${list(topology['links'])[0]}" />
<xacro:property name="base_reflects" value="${base in reflect_include_links}" />
<xacro:openarm_emit_link link_name="${prefix + base}" source_name="${base}"
<xacro:openarm_emit_link link_name="${link_name_map[base]}" source_name="${base}"
inertials="${inertials}" visuals="${visuals}" collisions="${collisions}"
reflect_x="${reflect_x if base_reflects else 1}" reflect_y="${reflect_y if base_reflects else 1}" reflect_z="${reflect_z if base_reflects else 1}"
frame_shift="${base_frame_shift}" />
<xacro:unless value="${skip_mount_joint}">
<joint name="${prefix + base}_mount_joint" type="fixed">
<joint name="${link_name_map[base]}_mount_joint" type="fixed">
<xacro:openarm_emit_origin origin="${mount_origin}" />
<parent link="${connected_to}" /><child link="${prefix + base}" />
<parent link="${connected_to}" /><child link="${link_name_map[base]}" />
</joint>
</xacro:unless>
<xacro:openarm_emit_chain index="0" joint_names="${list(topology['joints'].keys())}" topology="${topology}" prefix="${prefix}"
link_name_map="${link_name_map}" joint_name_map="${joint_name_map}"
joint_origins="${joint_origins}" joint_axes="${joint_axes}" joint_limits="${joint_limits}" joint_mimics="${joint_mimics}"
inertials="${inertials}" visuals="${visuals}" collisions="${collisions}"
reflect_x="${reflect_x}" reflect_y="${reflect_y}" reflect_z="${reflect_z}"
Expand Down
2 changes: 1 addition & 1 deletion assets/common/links.xacro
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ limitations under the License.
<xacro:macro name="openarm_emit_rigid_component"
params="link_name connected_to mount_origin topology inertials visuals collisions reflect_x:=1 reflect_y:=1 reflect_z:=1 reflect_include_links:=^ skip_mount_joint:=false base_frame_shift:=none">

<xacro:property name="base_link_name" value="${topology['links'][0]}" lazy_eval="false" />
<xacro:property name="base_link_name" value="${list(topology['links'])[0]}" lazy_eval="false" />
<xacro:property name="resolved_base_frame_shift" value="${base_frame_shift if base_frame_shift != 'none' else 'none'}" lazy_eval="false" />
<xacro:property name="base_link_reflects" value="${base_link_name in reflect_include_links}" lazy_eval="false" />

Expand Down
12 changes: 9 additions & 3 deletions assets/common/validation.xacro
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ limitations under the License.
</xacro:macro>

<xacro:macro name="openarm_validate_link_ancestry" params="name topology component depth:=0">
<xacro:if value="${name != topology['links'][0]}">
<xacro:if value="${name != list(topology['links'])[0]}">
<xacro:openarm_require condition="${depth &lt; len(topology['links'])}" message="${'Component `%s` has a cycle at link `%s`.' % (component, name)}" />
<xacro:property name="incoming" value="${[j for j in topology['joints'] if topology['joints'][j]['child'] == name]}" lazy_eval="false" />
<xacro:openarm_require condition="${len(incoming) == 1}" message="${'Link `%s` in `%s` must have one parent joint.' % (name, component)}" />
Expand All @@ -146,10 +146,16 @@ limitations under the License.
</xacro:macro>

<xacro:macro name="openarm_validate_topology" params="topology component index:=0">
<xacro:property name="links" value="${topology['links']}" lazy_eval="false" />
<xacro:property name="links" value="${list(topology['links'])}" lazy_eval="false" />
<xacro:property name="joints" value="${topology['joints']}" lazy_eval="false" />
<xacro:if value="${index == 0}">
<xacro:openarm_require condition="${len(links) > 0 and len([link for link in links if links.count(link) != 1]) == 0}" message="${'Component `%s` must have nonempty, unique links.' % component}" />
<xacro:openarm_require condition="${len(links) > 0}" message="${'Component `%s` must have nonempty links.' % component}" />
<xacro:property name="link_names" value="${[cfg.get('name', key) for key, cfg in topology['links'].items()]}" lazy_eval="false" />
<xacro:property name="joint_names" value="${[cfg.get('name', key) for key, cfg in joints.items()]}" lazy_eval="false" />
<xacro:openarm_require condition="${python.all(python.isinstance(name, str) and name for name in link_names + joint_names)}"
message="${'Component `%s` requires nonempty string names.' % component}" />
<xacro:openarm_require condition="${len(python.set(link_names)) == len(link_names) and len(python.set(joint_names)) == len(joint_names)}"
message="${'Component `%s` has duplicate output names.' % component}" />
<xacro:openarm_require condition="${len([j for j in joints if joints[j]['parent'] not in links or joints[j]['child'] not in links]) == 0}" message="${'Component `%s` has a joint referencing an unknown link.' % component}" />
<xacro:openarm_require condition="${len([j for j in joints if joints[j]['child'] == links[0]]) == 0}" message="${'Root link of `%s` cannot have an internal parent joint.' % component}" />
<xacro:openarm_require condition="${len([j for j in joints if joints[j]['type'] not in ['fixed', 'revolute', 'continuous', 'prismatic']]) == 0}" message="${'Component `%s` has an unsupported joint type.' % component}" />
Expand Down
Loading
Loading