Repository files navigation

OpenArm Control

Reusable kinematics and control utilities for OpenArm, backed by MuJoCo and mink.

Install

uv sync

Usage

Kinematics

Poses are float32[7] = [px, py, pz, qw, qx, qy, qz], expressed in the scene's arm_origin site frame by default (--origin-frame world restores world-frame poses).

fromopenarm_controlimportKinematics, IKParams, ArmSetup# FK onlykin=Kinematics(setup)
pose=kin.fk("right", joints) # float32[7]pose_r, pose_l=kin.fk_bimanual(r, l) # single mj_forward# IKkin=Kinematics(setup, IKParams())
kin.set_target("right", pose_r)
kin.set_target("left", pose_l)
result=kin.solve() # float32[16] right[8]+left[8]

IKParams

Solver configuration passed to Kinematics. Key fields are listed below; all fields have defaults.

FieldDefaultDescription
position_cost12.0Position task weight
orientation_cost1.5Orientation task weight
lm_damping0.01Per-task Levenberg-Marquardt damping
damping0.1Global Tikhonov regularization
solver"daqp"QP backend
posture_cost0.0Full home posture task weight (0 = disabled)
dt0.004Outer control period, divided across IK iterations
max_iters5IK sub-iterations per solve
velocity_limitsNoneJoint-name to velocity-cap mapping in rad/s; None keeps position-only limits
frame_position_error_limit0.02Total position-error request per outer IK solve
frame_orientation_error_limit0.25Total orientation-error request per outer IK solve
nullspace_cost8.5Fixed-home nullspace posture cost
nullspace_return_rate1.6Nullspace return rate in s⁻¹
joint_brakingTrueEnable preventive braking when velocity limits are active
joint_braking_distance0.2Joint-limit braking distance in radians
singularity_max_approach_rate0.25Maximum singularity-ratio approach rate
kinetic_energy_cost2e-5Kinetic-energy regularization cost

Build from CLI args with register_ik_args + ik_params_from_args:

python your_ik_node.py --tick-hz 250 --limit-velocity

Without --config, --limit-velocity uses the built-in per-arm caps [2, 2, 3.14, 3.14, 6.3, 6.3, 6.3] rad/s. An optional YAML override uses a seven-entry arm_velocity_limits list:

arm_velocity_limits: [2.0, 2.0, 3.14, 3.14, 6.3, 6.3, 6.3]
python your_ik_node.py --limit-velocity --config ./ik_limits.yaml

Constrained IK behavior

A bare IKParams() instance enables four complementary mechanisms:

  • Frame-error bounding limits the Cartesian correction requested by one outer solve while retaining the full target for subsequent cycles. Position bounding activates smoothly with target linear speed and remains latched while accumulated position lag is significant; orientation bounding is always active when configured.
  • Nullspace posture regulation guides the redundant arm motion toward the initial home posture without applying a full joint-space posture objective.
  • Singularity approach limiting slows only motion that moves the arm toward a poorly conditioned configuration.
  • Kinetic-energy regularization provides a weak mass-matrix-based tie-breaker between kinematically similar solutions. It is not inverse dynamics or gravity compensation.

Frame-error bounding limits accumulated feedback correction, not target velocity, and does not replace joint velocity limits. The full-joint home PostureTask is a separate optional objective controlled by posture_cost and is disabled by default.

The bare library default leaves hardware-specific per-joint velocity limits opt-in: provide velocity_limits directly or use --limit-velocity. The CLI flag selects the built-in caps unless --config overrides them. Enabling these limits replaces the position-only arm limit with one recoverable position/velocity envelope, so a command already slightly outside a position bound can return over multiple feasible steps. Preventive braking then reduces only the velocity approaching a nearby position bound; it is enabled by default with velocity limits and can be disabled with --no-joint-braking.

These limits constrain the QP solution. A downstream driver may apply its own independently configured execution-layer velocity envelope; the two sets of caps are not required to match.

Set both frame-error limits to zero to remove frame-error bounding. Set nullspace_cost, singularity_max_approach_rate, or kinetic_energy_cost to zero to disable the corresponding mechanism. These are kinematic command-layer mechanisms, not a certified whole-robot safety controller.

The remaining curve-shape and threshold parameters are regular IKParams fields but are intentionally not exposed as CLI flags. Call update_measured_state() with fresh driver qpos for state-aware limits; the caller owns freshness and should call clear_measured_state() when that state expires.

Related links

License

Licensed under the Apache License 2.0. See LICENSE.txt for details.

Copyright 2026 Enactic, Inc.

Code of Conduct

All participation in the OpenArm project is governed by our Code of Conduct.

About

OpenArm Control: Kinematics and Dynamics for OpenArm

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

OpenArm Control

Reusable kinematics and control utilities for OpenArm, backed by MuJoCo and mink.

Install

uv sync

Usage

Kinematics

Poses are float32[7] = [px, py, pz, qw, qx, qy, qz], expressed in the scene's arm_origin site frame by default (--origin-frame world restores world-frame poses).

fromopenarm_controlimportKinematics, IKParams, ArmSetup# FK onlykin=Kinematics(setup)
pose=kin.fk("right", joints) # float32[7]pose_r, pose_l=kin.fk_bimanual(r, l) # single mj_forward# IKkin=Kinematics(setup, IKParams())
kin.set_target("right", pose_r)
kin.set_target("left", pose_l)
result=kin.solve() # float32[16] right[8]+left[8]

IKParams

Solver configuration passed to Kinematics. Key fields are listed below; all fields have defaults.

FieldDefaultDescription
position_cost12.0Position task weight
orientation_cost1.5Orientation task weight
lm_damping0.01Per-task Levenberg-Marquardt damping
damping0.1Global Tikhonov regularization
solver"daqp"QP backend
posture_cost0.0Full home posture task weight (0 = disabled)
dt0.004Outer control period, divided across IK iterations
max_iters5IK sub-iterations per solve
velocity_limitsNoneJoint-name to velocity-cap mapping in rad/s; None keeps position-only limits
frame_position_error_limit0.02Total position-error request per outer IK solve
frame_orientation_error_limit0.25Total orientation-error request per outer IK solve
nullspace_cost8.5Fixed-home nullspace posture cost
nullspace_return_rate1.6Nullspace return rate in s⁻¹
joint_brakingTrueEnable preventive braking when velocity limits are active
joint_braking_distance0.2Joint-limit braking distance in radians
singularity_max_approach_rate0.25Maximum singularity-ratio approach rate
kinetic_energy_cost2e-5Kinetic-energy regularization cost

Build from CLI args with register_ik_args + ik_params_from_args:

python your_ik_node.py --tick-hz 250 --limit-velocity

Without --config, --limit-velocity uses the built-in per-arm caps [2, 2, 3.14, 3.14, 6.3, 6.3, 6.3] rad/s. An optional YAML override uses a seven-entry arm_velocity_limits list:

arm_velocity_limits: [2.0, 2.0, 3.14, 3.14, 6.3, 6.3, 6.3]
python your_ik_node.py --limit-velocity --config ./ik_limits.yaml

Constrained IK behavior

A bare IKParams() instance enables four complementary mechanisms:

  • Frame-error bounding limits the Cartesian correction requested by one outer solve while retaining the full target for subsequent cycles. Position bounding activates smoothly with target linear speed and remains latched while accumulated position lag is significant; orientation bounding is always active when configured.
  • Nullspace posture regulation guides the redundant arm motion toward the initial home posture without applying a full joint-space posture objective.
  • Singularity approach limiting slows only motion that moves the arm toward a poorly conditioned configuration.
  • Kinetic-energy regularization provides a weak mass-matrix-based tie-breaker between kinematically similar solutions. It is not inverse dynamics or gravity compensation.

Frame-error bounding limits accumulated feedback correction, not target velocity, and does not replace joint velocity limits. The full-joint home PostureTask is a separate optional objective controlled by posture_cost and is disabled by default.

The bare library default leaves hardware-specific per-joint velocity limits opt-in: provide velocity_limits directly or use --limit-velocity. The CLI flag selects the built-in caps unless --config overrides them. Enabling these limits replaces the position-only arm limit with one recoverable position/velocity envelope, so a command already slightly outside a position bound can return over multiple feasible steps. Preventive braking then reduces only the velocity approaching a nearby position bound; it is enabled by default with velocity limits and can be disabled with --no-joint-braking.

These limits constrain the QP solution. A downstream driver may apply its own independently configured execution-layer velocity envelope; the two sets of caps are not required to match.

Set both frame-error limits to zero to remove frame-error bounding. Set nullspace_cost, singularity_max_approach_rate, or kinetic_energy_cost to zero to disable the corresponding mechanism. These are kinematic command-layer mechanisms, not a certified whole-robot safety controller.

The remaining curve-shape and threshold parameters are regular IKParams fields but are intentionally not exposed as CLI flags. Call update_measured_state() with fresh driver qpos for state-aware limits; the caller owns freshness and should call clear_measured_state() when that state expires.

Related links

License

Licensed under the Apache License 2.0. See LICENSE.txt for details.

Copyright 2026 Enactic, Inc.

Code of Conduct

All participation in the OpenArm project is governed by our Code of Conduct.

About

OpenArm Control: Kinematics and Dynamics for OpenArm

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

OpenArm Control

Reusable kinematics and control utilities for OpenArm, backed by MuJoCo and mink.

Install

uv sync

Usage

Kinematics

Poses are float32[7] = [px, py, pz, qw, qx, qy, qz], expressed in the scene's arm_origin site frame by default (--origin-frame world restores world-frame poses).

fromopenarm_controlimportKinematics, IKParams, ArmSetup# FK onlykin=Kinematics(setup)
pose=kin.fk("right", joints) # float32[7]pose_r, pose_l=kin.fk_bimanual(r, l) # single mj_forward# IKkin=Kinematics(setup, IKParams())
kin.set_target("right", pose_r)
kin.set_target("left", pose_l)
result=kin.solve() # float32[16] right[8]+left[8]

IKParams

Solver configuration passed to Kinematics. Key fields are listed below; all fields have defaults.

FieldDefaultDescription
position_cost12.0Position task weight
orientation_cost1.5Orientation task weight
lm_damping0.01Per-task Levenberg-Marquardt damping
damping0.1Global Tikhonov regularization
solver"daqp"QP backend
posture_cost0.0Full home posture task weight (0 = disabled)
dt0.004Outer control period, divided across IK iterations
max_iters5IK sub-iterations per solve
velocity_limitsNoneJoint-name to velocity-cap mapping in rad/s; None keeps position-only limits
frame_position_error_limit0.02Total position-error request per outer IK solve
frame_orientation_error_limit0.25Total orientation-error request per outer IK solve
nullspace_cost8.5Fixed-home nullspace posture cost
nullspace_return_rate1.6Nullspace return rate in s⁻¹
joint_brakingTrueEnable preventive braking when velocity limits are active
joint_braking_distance0.2Joint-limit braking distance in radians
singularity_max_approach_rate0.25Maximum singularity-ratio approach rate
kinetic_energy_cost2e-5Kinetic-energy regularization cost

Build from CLI args with register_ik_args + ik_params_from_args:

python your_ik_node.py --tick-hz 250 --limit-velocity

Without --config, --limit-velocity uses the built-in per-arm caps [2, 2, 3.14, 3.14, 6.3, 6.3, 6.3] rad/s. An optional YAML override uses a seven-entry arm_velocity_limits list:

arm_velocity_limits: [2.0, 2.0, 3.14, 3.14, 6.3, 6.3, 6.3]
python your_ik_node.py --limit-velocity --config ./ik_limits.yaml

Constrained IK behavior

A bare IKParams() instance enables four complementary mechanisms:

  • Frame-error bounding limits the Cartesian correction requested by one outer solve while retaining the full target for subsequent cycles. Position bounding activates smoothly with target linear speed and remains latched while accumulated position lag is significant; orientation bounding is always active when configured.
  • Nullspace posture regulation guides the redundant arm motion toward the initial home posture without applying a full joint-space posture objective.
  • Singularity approach limiting slows only motion that moves the arm toward a poorly conditioned configuration.
  • Kinetic-energy regularization provides a weak mass-matrix-based tie-breaker between kinematically similar solutions. It is not inverse dynamics or gravity compensation.

Frame-error bounding limits accumulated feedback correction, not target velocity, and does not replace joint velocity limits. The full-joint home PostureTask is a separate optional objective controlled by posture_cost and is disabled by default.

The bare library default leaves hardware-specific per-joint velocity limits opt-in: provide velocity_limits directly or use --limit-velocity. The CLI flag selects the built-in caps unless --config overrides them. Enabling these limits replaces the position-only arm limit with one recoverable position/velocity envelope, so a command already slightly outside a position bound can return over multiple feasible steps. Preventive braking then reduces only the velocity approaching a nearby position bound; it is enabled by default with velocity limits and can be disabled with --no-joint-braking.

These limits constrain the QP solution. A downstream driver may apply its own independently configured execution-layer velocity envelope; the two sets of caps are not required to match.

Set both frame-error limits to zero to remove frame-error bounding. Set nullspace_cost, singularity_max_approach_rate, or kinetic_energy_cost to zero to disable the corresponding mechanism. These are kinematic command-layer mechanisms, not a certified whole-robot safety controller.

The remaining curve-shape and threshold parameters are regular IKParams fields but are intentionally not exposed as CLI flags. Call update_measured_state() with fresh driver qpos for state-aware limits; the caller owns freshness and should call clear_measured_state() when that state expires.

Related links

License

Licensed under the Apache License 2.0. See LICENSE.txt for details.

Copyright 2026 Enactic, Inc.

Code of Conduct

All participation in the OpenArm project is governed by our Code of Conduct.

About

OpenArm Control: Kinematics and Dynamics for OpenArm

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

OpenArm Control

Reusable kinematics and control utilities for OpenArm, backed by MuJoCo and mink.

Install

uv sync

Usage

Kinematics

Poses are float32[7] = [px, py, pz, qw, qx, qy, qz], expressed in the scene's arm_origin site frame by default (--origin-frame world restores world-frame poses).

fromopenarm_controlimportKinematics, IKParams, ArmSetup# FK onlykin=Kinematics(setup)
pose=kin.fk("right", joints) # float32[7]pose_r, pose_l=kin.fk_bimanual(r, l) # single mj_forward# IKkin=Kinematics(setup, IKParams())
kin.set_target("right", pose_r)
kin.set_target("left", pose_l)
result=kin.solve() # float32[16] right[8]+left[8]

IKParams

Solver configuration passed to Kinematics. Key fields are listed below; all fields have defaults.

FieldDefaultDescription
position_cost12.0Position task weight
orientation_cost1.5Orientation task weight
lm_damping0.01Per-task Levenberg-Marquardt damping
damping0.1Global Tikhonov regularization
solver"daqp"QP backend
posture_cost0.0Full home posture task weight (0 = disabled)
dt0.004Outer control period, divided across IK iterations
max_iters5IK sub-iterations per solve
velocity_limitsNoneJoint-name to velocity-cap mapping in rad/s; None keeps position-only limits
frame_position_error_limit0.02Total position-error request per outer IK solve
frame_orientation_error_limit0.25Total orientation-error request per outer IK solve
nullspace_cost8.5Fixed-home nullspace posture cost
nullspace_return_rate1.6Nullspace return rate in s⁻¹
joint_brakingTrueEnable preventive braking when velocity limits are active
joint_braking_distance0.2Joint-limit braking distance in radians
singularity_max_approach_rate0.25Maximum singularity-ratio approach rate
kinetic_energy_cost2e-5Kinetic-energy regularization cost

Build from CLI args with register_ik_args + ik_params_from_args:

python your_ik_node.py --tick-hz 250 --limit-velocity

Without --config, --limit-velocity uses the built-in per-arm caps [2, 2, 3.14, 3.14, 6.3, 6.3, 6.3] rad/s. An optional YAML override uses a seven-entry arm_velocity_limits list:

arm_velocity_limits: [2.0, 2.0, 3.14, 3.14, 6.3, 6.3, 6.3]
python your_ik_node.py --limit-velocity --config ./ik_limits.yaml

Constrained IK behavior

A bare IKParams() instance enables four complementary mechanisms:

  • Frame-error bounding limits the Cartesian correction requested by one outer solve while retaining the full target for subsequent cycles. Position bounding activates smoothly with target linear speed and remains latched while accumulated position lag is significant; orientation bounding is always active when configured.
  • Nullspace posture regulation guides the redundant arm motion toward the initial home posture without applying a full joint-space posture objective.
  • Singularity approach limiting slows only motion that moves the arm toward a poorly conditioned configuration.
  • Kinetic-energy regularization provides a weak mass-matrix-based tie-breaker between kinematically similar solutions. It is not inverse dynamics or gravity compensation.

Frame-error bounding limits accumulated feedback correction, not target velocity, and does not replace joint velocity limits. The full-joint home PostureTask is a separate optional objective controlled by posture_cost and is disabled by default.

The bare library default leaves hardware-specific per-joint velocity limits opt-in: provide velocity_limits directly or use --limit-velocity. The CLI flag selects the built-in caps unless --config overrides them. Enabling these limits replaces the position-only arm limit with one recoverable position/velocity envelope, so a command already slightly outside a position bound can return over multiple feasible steps. Preventive braking then reduces only the velocity approaching a nearby position bound; it is enabled by default with velocity limits and can be disabled with --no-joint-braking.

These limits constrain the QP solution. A downstream driver may apply its own independently configured execution-layer velocity envelope; the two sets of caps are not required to match.

Set both frame-error limits to zero to remove frame-error bounding. Set nullspace_cost, singularity_max_approach_rate, or kinetic_energy_cost to zero to disable the corresponding mechanism. These are kinematic command-layer mechanisms, not a certified whole-robot safety controller.

The remaining curve-shape and threshold parameters are regular IKParams fields but are intentionally not exposed as CLI flags. Call update_measured_state() with fresh driver qpos for state-aware limits; the caller owns freshness and should call clear_measured_state() when that state expires.

Related links

License

Licensed under the Apache License 2.0. See LICENSE.txt for details.

Copyright 2026 Enactic, Inc.

Code of Conduct

All participation in the OpenArm project is governed by our Code of Conduct.

About

OpenArm Control: Kinematics and Dynamics for OpenArm

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

OpenArm Control

Reusable kinematics and control utilities for OpenArm, backed by MuJoCo and mink.

Install

uv sync

Usage

Kinematics

Poses are float32[7] = [px, py, pz, qw, qx, qy, qz], expressed in the scene's arm_origin site frame by default (--origin-frame world restores world-frame poses).

fromopenarm_controlimportKinematics, IKParams, ArmSetup# FK onlykin=Kinematics(setup)
pose=kin.fk("right", joints) # float32[7]pose_r, pose_l=kin.fk_bimanual(r, l) # single mj_forward# IKkin=Kinematics(setup, IKParams())
kin.set_target("right", pose_r)
kin.set_target("left", pose_l)
result=kin.solve() # float32[16] right[8]+left[8]

IKParams

Solver configuration passed to Kinematics. Key fields are listed below; all fields have defaults.

FieldDefaultDescription
position_cost12.0Position task weight
orientation_cost1.5Orientation task weight
lm_damping0.01Per-task Levenberg-Marquardt damping
damping0.1Global Tikhonov regularization
solver"daqp"QP backend
posture_cost0.0Full home posture task weight (0 = disabled)
dt0.004Outer control period, divided across IK iterations
max_iters5IK sub-iterations per solve
velocity_limitsNoneJoint-name to velocity-cap mapping in rad/s; None keeps position-only limits
frame_position_error_limit0.02Total position-error request per outer IK solve
frame_orientation_error_limit0.25Total orientation-error request per outer IK solve
nullspace_cost8.5Fixed-home nullspace posture cost
nullspace_return_rate1.6Nullspace return rate in s⁻¹
joint_brakingTrueEnable preventive braking when velocity limits are active
joint_braking_distance0.2Joint-limit braking distance in radians
singularity_max_approach_rate0.25Maximum singularity-ratio approach rate
kinetic_energy_cost2e-5Kinetic-energy regularization cost

Build from CLI args with register_ik_args + ik_params_from_args:

python your_ik_node.py --tick-hz 250 --limit-velocity

Without --config, --limit-velocity uses the built-in per-arm caps [2, 2, 3.14, 3.14, 6.3, 6.3, 6.3] rad/s. An optional YAML override uses a seven-entry arm_velocity_limits list:

arm_velocity_limits: [2.0, 2.0, 3.14, 3.14, 6.3, 6.3, 6.3]
python your_ik_node.py --limit-velocity --config ./ik_limits.yaml

Constrained IK behavior

A bare IKParams() instance enables four complementary mechanisms:

  • Frame-error bounding limits the Cartesian correction requested by one outer solve while retaining the full target for subsequent cycles. Position bounding activates smoothly with target linear speed and remains latched while accumulated position lag is significant; orientation bounding is always active when configured.
  • Nullspace posture regulation guides the redundant arm motion toward the initial home posture without applying a full joint-space posture objective.
  • Singularity approach limiting slows only motion that moves the arm toward a poorly conditioned configuration.
  • Kinetic-energy regularization provides a weak mass-matrix-based tie-breaker between kinematically similar solutions. It is not inverse dynamics or gravity compensation.

Frame-error bounding limits accumulated feedback correction, not target velocity, and does not replace joint velocity limits. The full-joint home PostureTask is a separate optional objective controlled by posture_cost and is disabled by default.

The bare library default leaves hardware-specific per-joint velocity limits opt-in: provide velocity_limits directly or use --limit-velocity. The CLI flag selects the built-in caps unless --config overrides them. Enabling these limits replaces the position-only arm limit with one recoverable position/velocity envelope, so a command already slightly outside a position bound can return over multiple feasible steps. Preventive braking then reduces only the velocity approaching a nearby position bound; it is enabled by default with velocity limits and can be disabled with --no-joint-braking.

These limits constrain the QP solution. A downstream driver may apply its own independently configured execution-layer velocity envelope; the two sets of caps are not required to match.

Set both frame-error limits to zero to remove frame-error bounding. Set nullspace_cost, singularity_max_approach_rate, or kinetic_energy_cost to zero to disable the corresponding mechanism. These are kinematic command-layer mechanisms, not a certified whole-robot safety controller.

The remaining curve-shape and threshold parameters are regular IKParams fields but are intentionally not exposed as CLI flags. Call update_measured_state() with fresh driver qpos for state-aware limits; the caller owns freshness and should call clear_measured_state() when that state expires.

Related links

License

Licensed under the Apache License 2.0. See LICENSE.txt for details.

Copyright 2026 Enactic, Inc.

Code of Conduct

All participation in the OpenArm project is governed by our Code of Conduct.

About

OpenArm Control: Kinematics and Dynamics for OpenArm

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

OpenArm Control

Reusable kinematics and control utilities for OpenArm, backed by MuJoCo and mink.

Install

uv sync

Usage

Kinematics

Poses are float32[7] = [px, py, pz, qw, qx, qy, qz], expressed in the scene's arm_origin site frame by default (--origin-frame world restores world-frame poses).

fromopenarm_controlimportKinematics, IKParams, ArmSetup# FK onlykin=Kinematics(setup)
pose=kin.fk("right", joints) # float32[7]pose_r, pose_l=kin.fk_bimanual(r, l) # single mj_forward# IKkin=Kinematics(setup, IKParams())
kin.set_target("right", pose_r)
kin.set_target("left", pose_l)
result=kin.solve() # float32[16] right[8]+left[8]

IKParams

Solver configuration passed to Kinematics. Key fields are listed below; all fields have defaults.

FieldDefaultDescription
position_cost12.0Position task weight
orientation_cost1.5Orientation task weight
lm_damping0.01Per-task Levenberg-Marquardt damping
damping0.1Global Tikhonov regularization
solver"daqp"QP backend
posture_cost0.0Full home posture task weight (0 = disabled)
dt0.004Outer control period, divided across IK iterations
max_iters5IK sub-iterations per solve
velocity_limitsNoneJoint-name to velocity-cap mapping in rad/s; None keeps position-only limits
frame_position_error_limit0.02Total position-error request per outer IK solve
frame_orientation_error_limit0.25Total orientation-error request per outer IK solve
nullspace_cost8.5Fixed-home nullspace posture cost
nullspace_return_rate1.6Nullspace return rate in s⁻¹
joint_brakingTrueEnable preventive braking when velocity limits are active
joint_braking_distance0.2Joint-limit braking distance in radians
singularity_max_approach_rate0.25Maximum singularity-ratio approach rate
kinetic_energy_cost2e-5Kinetic-energy regularization cost

Build from CLI args with register_ik_args + ik_params_from_args:

python your_ik_node.py --tick-hz 250 --limit-velocity

Without --config, --limit-velocity uses the built-in per-arm caps [2, 2, 3.14, 3.14, 6.3, 6.3, 6.3] rad/s. An optional YAML override uses a seven-entry arm_velocity_limits list:

arm_velocity_limits: [2.0, 2.0, 3.14, 3.14, 6.3, 6.3, 6.3]
python your_ik_node.py --limit-velocity --config ./ik_limits.yaml

Constrained IK behavior

A bare IKParams() instance enables four complementary mechanisms:

  • Frame-error bounding limits the Cartesian correction requested by one outer solve while retaining the full target for subsequent cycles. Position bounding activates smoothly with target linear speed and remains latched while accumulated position lag is significant; orientation bounding is always active when configured.
  • Nullspace posture regulation guides the redundant arm motion toward the initial home posture without applying a full joint-space posture objective.
  • Singularity approach limiting slows only motion that moves the arm toward a poorly conditioned configuration.
  • Kinetic-energy regularization provides a weak mass-matrix-based tie-breaker between kinematically similar solutions. It is not inverse dynamics or gravity compensation.

Frame-error bounding limits accumulated feedback correction, not target velocity, and does not replace joint velocity limits. The full-joint home PostureTask is a separate optional objective controlled by posture_cost and is disabled by default.

The bare library default leaves hardware-specific per-joint velocity limits opt-in: provide velocity_limits directly or use --limit-velocity. The CLI flag selects the built-in caps unless --config overrides them. Enabling these limits replaces the position-only arm limit with one recoverable position/velocity envelope, so a command already slightly outside a position bound can return over multiple feasible steps. Preventive braking then reduces only the velocity approaching a nearby position bound; it is enabled by default with velocity limits and can be disabled with --no-joint-braking.

These limits constrain the QP solution. A downstream driver may apply its own independently configured execution-layer velocity envelope; the two sets of caps are not required to match.

Set both frame-error limits to zero to remove frame-error bounding. Set nullspace_cost, singularity_max_approach_rate, or kinetic_energy_cost to zero to disable the corresponding mechanism. These are kinematic command-layer mechanisms, not a certified whole-robot safety controller.

The remaining curve-shape and threshold parameters are regular IKParams fields but are intentionally not exposed as CLI flags. Call update_measured_state() with fresh driver qpos for state-aware limits; the caller owns freshness and should call clear_measured_state() when that state expires.

Related links

License

Licensed under the Apache License 2.0. See LICENSE.txt for details.

Copyright 2026 Enactic, Inc.

Code of Conduct

All participation in the OpenArm project is governed by our Code of Conduct.

About

OpenArm Control: Kinematics and Dynamics for OpenArm

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

OpenArm Control

Reusable kinematics and control utilities for OpenArm, backed by MuJoCo and mink.

Install

uv sync

Usage

Kinematics

Poses are float32[7] = [px, py, pz, qw, qx, qy, qz], expressed in the scene's arm_origin site frame by default (--origin-frame world restores world-frame poses).

fromopenarm_controlimportKinematics, IKParams, ArmSetup# FK onlykin=Kinematics(setup)
pose=kin.fk("right", joints) # float32[7]pose_r, pose_l=kin.fk_bimanual(r, l) # single mj_forward# IKkin=Kinematics(setup, IKParams())
kin.set_target("right", pose_r)
kin.set_target("left", pose_l)
result=kin.solve() # float32[16] right[8]+left[8]

IKParams

Solver configuration passed to Kinematics. Key fields are listed below; all fields have defaults.

FieldDefaultDescription
position_cost12.0Position task weight
orientation_cost1.5Orientation task weight
lm_damping0.01Per-task Levenberg-Marquardt damping
damping0.1Global Tikhonov regularization
solver"daqp"QP backend
posture_cost0.0Full home posture task weight (0 = disabled)
dt0.004Outer control period, divided across IK iterations
max_iters5IK sub-iterations per solve
velocity_limitsNoneJoint-name to velocity-cap mapping in rad/s; None keeps position-only limits
frame_position_error_limit0.02Total position-error request per outer IK solve
frame_orientation_error_limit0.25Total orientation-error request per outer IK solve
nullspace_cost8.5Fixed-home nullspace posture cost
nullspace_return_rate1.6Nullspace return rate in s⁻¹
joint_brakingTrueEnable preventive braking when velocity limits are active
joint_braking_distance0.2Joint-limit braking distance in radians
singularity_max_approach_rate0.25Maximum singularity-ratio approach rate
kinetic_energy_cost2e-5Kinetic-energy regularization cost

Build from CLI args with register_ik_args + ik_params_from_args:

python your_ik_node.py --tick-hz 250 --limit-velocity

Without --config, --limit-velocity uses the built-in per-arm caps [2, 2, 3.14, 3.14, 6.3, 6.3, 6.3] rad/s. An optional YAML override uses a seven-entry arm_velocity_limits list:

arm_velocity_limits: [2.0, 2.0, 3.14, 3.14, 6.3, 6.3, 6.3]
python your_ik_node.py --limit-velocity --config ./ik_limits.yaml

Constrained IK behavior

A bare IKParams() instance enables four complementary mechanisms:

  • Frame-error bounding limits the Cartesian correction requested by one outer solve while retaining the full target for subsequent cycles. Position bounding activates smoothly with target linear speed and remains latched while accumulated position lag is significant; orientation bounding is always active when configured.
  • Nullspace posture regulation guides the redundant arm motion toward the initial home posture without applying a full joint-space posture objective.
  • Singularity approach limiting slows only motion that moves the arm toward a poorly conditioned configuration.
  • Kinetic-energy regularization provides a weak mass-matrix-based tie-breaker between kinematically similar solutions. It is not inverse dynamics or gravity compensation.

Frame-error bounding limits accumulated feedback correction, not target velocity, and does not replace joint velocity limits. The full-joint home PostureTask is a separate optional objective controlled by posture_cost and is disabled by default.

The bare library default leaves hardware-specific per-joint velocity limits opt-in: provide velocity_limits directly or use --limit-velocity. The CLI flag selects the built-in caps unless --config overrides them. Enabling these limits replaces the position-only arm limit with one recoverable position/velocity envelope, so a command already slightly outside a position bound can return over multiple feasible steps. Preventive braking then reduces only the velocity approaching a nearby position bound; it is enabled by default with velocity limits and can be disabled with --no-joint-braking.

These limits constrain the QP solution. A downstream driver may apply its own independently configured execution-layer velocity envelope; the two sets of caps are not required to match.

Set both frame-error limits to zero to remove frame-error bounding. Set nullspace_cost, singularity_max_approach_rate, or kinetic_energy_cost to zero to disable the corresponding mechanism. These are kinematic command-layer mechanisms, not a certified whole-robot safety controller.

The remaining curve-shape and threshold parameters are regular IKParams fields but are intentionally not exposed as CLI flags. Call update_measured_state() with fresh driver qpos for state-aware limits; the caller owns freshness and should call clear_measured_state() when that state expires.

Related links

License

Licensed under the Apache License 2.0. See LICENSE.txt for details.

Copyright 2026 Enactic, Inc.

Code of Conduct

All participation in the OpenArm project is governed by our Code of Conduct.

About

OpenArm Control: Kinematics and Dynamics for OpenArm

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

OpenArm Control

Reusable kinematics and control utilities for OpenArm, backed by MuJoCo and mink.

Install

uv sync

Usage

Kinematics

Poses are float32[7] = [px, py, pz, qw, qx, qy, qz], expressed in the scene's arm_origin site frame by default (--origin-frame world restores world-frame poses).

fromopenarm_controlimportKinematics, IKParams, ArmSetup# FK onlykin=Kinematics(setup)
pose=kin.fk("right", joints) # float32[7]pose_r, pose_l=kin.fk_bimanual(r, l) # single mj_forward# IKkin=Kinematics(setup, IKParams())
kin.set_target("right", pose_r)
kin.set_target("left", pose_l)
result=kin.solve() # float32[16] right[8]+left[8]

IKParams

Solver configuration passed to Kinematics. Key fields are listed below; all fields have defaults.

FieldDefaultDescription
position_cost12.0Position task weight
orientation_cost1.5Orientation task weight
lm_damping0.01Per-task Levenberg-Marquardt damping
damping0.1Global Tikhonov regularization
solver"daqp"QP backend
posture_cost0.0Full home posture task weight (0 = disabled)
dt0.004Outer control period, divided across IK iterations
max_iters5IK sub-iterations per solve
velocity_limitsNoneJoint-name to velocity-cap mapping in rad/s; None keeps position-only limits
frame_position_error_limit0.02Total position-error request per outer IK solve
frame_orientation_error_limit0.25Total orientation-error request per outer IK solve
nullspace_cost8.5Fixed-home nullspace posture cost
nullspace_return_rate1.6Nullspace return rate in s⁻¹
joint_brakingTrueEnable preventive braking when velocity limits are active
joint_braking_distance0.2Joint-limit braking distance in radians
singularity_max_approach_rate0.25Maximum singularity-ratio approach rate
kinetic_energy_cost2e-5Kinetic-energy regularization cost

Build from CLI args with register_ik_args + ik_params_from_args:

python your_ik_node.py --tick-hz 250 --limit-velocity

Without --config, --limit-velocity uses the built-in per-arm caps [2, 2, 3.14, 3.14, 6.3, 6.3, 6.3] rad/s. An optional YAML override uses a seven-entry arm_velocity_limits list:

arm_velocity_limits: [2.0, 2.0, 3.14, 3.14, 6.3, 6.3, 6.3]
python your_ik_node.py --limit-velocity --config ./ik_limits.yaml

Constrained IK behavior

A bare IKParams() instance enables four complementary mechanisms:

  • Frame-error bounding limits the Cartesian correction requested by one outer solve while retaining the full target for subsequent cycles. Position bounding activates smoothly with target linear speed and remains latched while accumulated position lag is significant; orientation bounding is always active when configured.
  • Nullspace posture regulation guides the redundant arm motion toward the initial home posture without applying a full joint-space posture objective.
  • Singularity approach limiting slows only motion that moves the arm toward a poorly conditioned configuration.
  • Kinetic-energy regularization provides a weak mass-matrix-based tie-breaker between kinematically similar solutions. It is not inverse dynamics or gravity compensation.

Frame-error bounding limits accumulated feedback correction, not target velocity, and does not replace joint velocity limits. The full-joint home PostureTask is a separate optional objective controlled by posture_cost and is disabled by default.

The bare library default leaves hardware-specific per-joint velocity limits opt-in: provide velocity_limits directly or use --limit-velocity. The CLI flag selects the built-in caps unless --config overrides them. Enabling these limits replaces the position-only arm limit with one recoverable position/velocity envelope, so a command already slightly outside a position bound can return over multiple feasible steps. Preventive braking then reduces only the velocity approaching a nearby position bound; it is enabled by default with velocity limits and can be disabled with --no-joint-braking.

These limits constrain the QP solution. A downstream driver may apply its own independently configured execution-layer velocity envelope; the two sets of caps are not required to match.

Set both frame-error limits to zero to remove frame-error bounding. Set nullspace_cost, singularity_max_approach_rate, or kinetic_energy_cost to zero to disable the corresponding mechanism. These are kinematic command-layer mechanisms, not a certified whole-robot safety controller.

The remaining curve-shape and threshold parameters are regular IKParams fields but are intentionally not exposed as CLI flags. Call update_measured_state() with fresh driver qpos for state-aware limits; the caller owns freshness and should call clear_measured_state() when that state expires.

Related links

License

Licensed under the Apache License 2.0. See LICENSE.txt for details.

Copyright 2026 Enactic, Inc.

Code of Conduct

All participation in the OpenArm project is governed by our Code of Conduct.

About

OpenArm Control: Kinematics and Dynamics for OpenArm

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages