Prerequisites
Bug summary
Context: Reactive control (optimize_next_action) on a 6-DOF non-redundant arm (Doosan M1013), calling update_goal_tool_poses(goal, run_ik=True) once per goal-set/retarget.
Observed: In solver_mpc.py, update_goal_tool_poses's run_ik=True branch gates everything — including the plain Cartesian goal update — behind IK success:
if run_ik:
ik_result = self._solve_ik_for_goal(goal_tool_poses, robot_ids)
if ik_result is not None:
if use_best_effort_ik or torch.all(ik_result.success):
goal_joint_state = JointState.from_position(
ik_result.solution.view(-1, self.action_dim), joint_names=self.joint_names
)
log_info("IK succeeded, updated target joint configuration with IK solution")
if use_ik_goal:
self.update_goal_state(goal_joint_state)
current_state = self.core._goal_buffer.current_js.clone()
self.enable_joint_position_tracking()
new_goal_buffer = self.goal_registry_manager.update_goal_tool_poses(goal_tool_poses)
self._goal_tool_poses = goal_tool_poses
self._update_rollout_params(new_goal_buffer)
return True
return False
_solve_ik_for_goal seeds IKSolver.solve_pose with a single seed (the current joint state, return_seeds=1). With use_best_effort_ik=False (the default), if that single seed doesn't converge — which we hit in practice near a kinematic singularity — the whole call returns False and the Cartesian goal is silently never set, even though setting it doesn't actually require IK to succeed (the else branch proves that).
Steps to reproduce
curobo/curobo/_src/solver/solver_mpc.py l415-l431
Expected behavior
Question: Is this coupling intentional? It seems like IK failure should only skip the joint-position-tracking anchor (use_ik_goal's effect), not the Cartesian goal update itself — i.e. run_ik=True + failed IK could still fall through to the same Cartesian-only update the else branch does, rather than a hard no-op. Right now the only way to get a Cartesian goal applied and a best-effort joint anchor is use_best_effort_ik=True, which accepts a possibly-far-off, non-converged IK solution as a hard joint-tracking target — there doesn't seem to be a middle ground ("try to anchor joint-space, but always at least apply the Cartesian goal").
Secondary question: is a single current-state seed (return_seeds=1) expected to be reliable near a singularity, or would multiple seeds be recommended there even for a non-redundant 6-DOF arm? We're using the joint-position-tracking anchor specifically to damp null-space drift (J4/J6 co-rotating with no cost pushing back until a joint limit engages) near a wrist singularity, and want to understand whether single-seed IK is a good fit for that use case or if we should be seeding differently.
Actual behavior / error output
something like that (but cleanner)
if run_ik:
ik_result = self._solve_ik_for_goal(goal_tool_poses, robot_ids)
if ik_result is not None:
if use_best_effort_ik or torch.all(ik_result.success):
goal_joint_state = JointState.from_position(
ik_result.solution.view(-1, self.action_dim), joint_names=self.joint_names
)
log_info("IK succeeded, updated target joint configuration with IK solution")
if use_ik_goal:
self.update_goal_state(goal_joint_state)
current_state = self.core._goal_buffer.current_js.clone()
self.enable_joint_position_tracking()
new_goal_buffer = self.goal_registry_manager.update_goal_tool_poses(goal_tool_poses)
self._goal_tool_poses = goal_tool_poses
self._update_rollout_params(new_goal_buffer)
return True
else:
self.disable_joint_position_tracking()
new_goal_buffer = self.goal_registry_manager.update_goal_tool_poses(goal_tool_poses)
self._goal_tool_poses = goal_tool_poses
self._update_rollout_params(new_goal_buffer)
return False
else:
self.disable_joint_position_tracking()
new_goal_buffer = self.goal_registry_manager.update_goal_tool_poses(goal_tool_poses)
self._goal_tool_poses = goal_tool_poses
self._update_rollout_params(new_goal_buffer)
return True
cuRobo version + commit SHA
cuRobo v0.8.0.post1.dev42 (commit 8e734f3)
Installation method
Source — CUDA 12 + PyTorch (uv pip install .[cu12-torch])
Kernel backend
cuda_core (default, runtime compilation)
Python version
Python 3.12.3
PyTorch version (if installed)
2.8.0+cu128 12.8
GPU / driver / CUDA toolkit
cuda_12.0.r12.0/compiler.32267302_0
Operating system
ubuntu 24
Isaac Sim version (if applicable)
none
Additional context
No response
Prerequisites
main(or the most recent release).Bug summary
Context: Reactive control (
optimize_next_action) on a 6-DOF non-redundant arm (Doosan M1013), callingupdate_goal_tool_poses(goal, run_ik=True)once per goal-set/retarget.Observed: In
solver_mpc.py,update_goal_tool_poses'srun_ik=Truebranch gates everything — including the plain Cartesian goal update — behind IK success:_solve_ik_for_goalseedsIKSolver.solve_posewith a single seed (the current joint state,return_seeds=1). Withuse_best_effort_ik=False(the default), if that single seed doesn't converge — which we hit in practice near a kinematic singularity — the whole call returnsFalseand the Cartesian goal is silently never set, even though setting it doesn't actually require IK to succeed (theelsebranch proves that).Steps to reproduce
Expected behavior
Question: Is this coupling intentional? It seems like IK failure should only skip the joint-position-tracking anchor (
use_ik_goal's effect), not the Cartesian goal update itself — i.e.run_ik=True+ failed IK could still fall through to the same Cartesian-only update theelsebranch does, rather than a hard no-op. Right now the only way to get a Cartesian goal applied and a best-effort joint anchor isuse_best_effort_ik=True, which accepts a possibly-far-off, non-converged IK solution as a hard joint-tracking target — there doesn't seem to be a middle ground ("try to anchor joint-space, but always at least apply the Cartesian goal").Secondary question: is a single current-state seed (
return_seeds=1) expected to be reliable near a singularity, or would multiple seeds be recommended there even for a non-redundant 6-DOF arm? We're using the joint-position-tracking anchor specifically to damp null-space drift (J4/J6 co-rotating with no cost pushing back until a joint limit engages) near a wrist singularity, and want to understand whether single-seed IK is a good fit for that use case or if we should be seeding differently.Actual behavior / error output
something like that (but cleanner) if run_ik: ik_result = self._solve_ik_for_goal(goal_tool_poses, robot_ids) if ik_result is not None: if use_best_effort_ik or torch.all(ik_result.success): goal_joint_state = JointState.from_position( ik_result.solution.view(-1, self.action_dim), joint_names=self.joint_names ) log_info("IK succeeded, updated target joint configuration with IK solution") if use_ik_goal: self.update_goal_state(goal_joint_state) current_state = self.core._goal_buffer.current_js.clone() self.enable_joint_position_tracking() new_goal_buffer = self.goal_registry_manager.update_goal_tool_poses(goal_tool_poses) self._goal_tool_poses = goal_tool_poses self._update_rollout_params(new_goal_buffer) return True else: self.disable_joint_position_tracking() new_goal_buffer = self.goal_registry_manager.update_goal_tool_poses(goal_tool_poses) self._goal_tool_poses = goal_tool_poses self._update_rollout_params(new_goal_buffer) return False else: self.disable_joint_position_tracking() new_goal_buffer = self.goal_registry_manager.update_goal_tool_poses(goal_tool_poses) self._goal_tool_poses = goal_tool_poses self._update_rollout_params(new_goal_buffer) return TruecuRobo version + commit SHA
cuRobo v0.8.0.post1.dev42 (commit
8e734f3)Installation method
Source — CUDA 12 + PyTorch (
uv pip install .[cu12-torch])Kernel backend
cuda_core (default, runtime compilation)
Python version
Python 3.12.3
PyTorch version (if installed)
2.8.0+cu128 12.8
GPU / driver / CUDA toolkit
cuda_12.0.r12.0/compiler.32267302_0
Operating system
ubuntu 24
Isaac Sim version (if applicable)
none
Additional context
No response