Skip to content

Conversation

@Dingry
Copy link
Contributor

@Dingry Dingry commented Dec 30, 2024

What this does

The exisiting joint controllers (JointPositionController, JointVelocityController, and JointTorqueController) would break under two conditions:

  • When the sequence of actuators didn't match the sequence of joints
  • When the number of joints didn't equal the number of actuators, which can occur due to joint constraints (like equality constraints or tendon mechanisms)

The PR fixes this with actuator-joint indexing and mapping in the control function.

Copy link
Contributor

@snasiriany snasiriany left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments and some questions!

Comment on lines +269 to +277
self._ref_actuator_to_joint_id = np.ones(self.sim.model.nu).astype(np.int32) * (-1)
for part_name, actuator_ids in self._ref_actuators_indexes_dict.items():
self._ref_actuator_to_joint_id[actuator_ids] = np.array(
[
self._ref_joints_indexes_dict[part_name].index(self.sim.model.actuator_trnid[i, 0])
for i in actuator_ids
]
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have the same code in fixed_base_robot.py as well, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.


self._ref_actuator_to_joint_id = np.ones(self.sim.model.nu).astype(np.int32) * (-1)
for part_name, actuator_ids in self._ref_actuators_indexes_dict.items():
self._ref_actuator_to_joint_id[actuator_ids] = np.array(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a very small comment in the code explaining how this mapping works (conceptually at a high level)

Comment on lines +192 to +202

part_controllers = self.composite_controller.get_controller(part_name)
if (
isinstance(part_controllers, JointPositionController)
or isinstance(part_controllers, JointVelocityController)
or isinstance(part_controllers, JointTorqueController)
):
# select only the joints that are actuated
actuated_joint_indexes = self._ref_actuator_to_joint_id[actuator_indexes]
applied_action = applied_action[actuated_joint_indexes]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this logic apply more generally to other robots? other than legged_robot.py

also, why is the logic only applied for JointPositionController/JointVelocityController/JointTorqueController? Is it because these are the controllers where we directly output joint targets?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this logic should apply to all robots.

Yes. The JointController generates control signals for all joints, while the GripperController only produces control signals for actuators. This difference explains why we need these conditional statements. I'm uncertain about the behavior of other controllers.
Also I was thinking that the GripperController seems essentially similar to JointController but focuses only on actuator-driven joints. If so, we could potentially unify their implementation since their fundamental problem if the same: align joint with actuator actions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants