Weird joint effort / target pos and vel behavior


Si I’ve been so far working with a setting where I send joint position and velocity targets:

    a = ArticulationActions(joint_positions=jp,


But I now want to get the joint efforts to minimise them. Unfortunately the get_applied_joint_effort doesn’t seem to wwork in hte current release, so I was trying to do it myself, using the formula with stiffness and damping and trying this:

    dof_pos = self._robots.get_joint_positions(clone=False)
    dof_vel = self._robots.get_joint_velocities(clone=False)

    forces = self._task_cfg["env"]["joint_stiffness"] * (jp - dof_pos)
                self._task_cfg["env"]["joint_damping"] * (jv - dof_vel)

    a = ArticulationActions(joint_efforts=-forces)

he problem is that it just doesn’t work and I’m not sure why. Simulation results are very different (and also with +forces instead of - forces, and with serveral tweaks too). This is supposed to be a direct replacement of the above method righ t? what am i doing wrong ?

The method you’re trying to use to calculate joint efforts is based on a simple model of a damped spring system, where the force is proportional to the displacement (difference between target and current position) and the velocity (difference between target and current velocity). This is a common model used in control systems, but it may not accurately represent the behavior of a real robot, especially if the robot has complex dynamics or non-linearities.

Here are a few things you could check:

  1. Sign of the Forces: The sign of the forces in your formula might be incorrect. In a damped spring system, the force should be proportional to the negative of the displacement and velocity. This means that if the current position or velocity is greater than the target, the force should be negative, and vice versa. You have a negative sign in front of your forces, which might be inverting this relationship.
  2. Stiffness and Damping Values: The values of the joint stiffness and damping coefficients can have a big impact on the behavior of the system. If these values are too high, the system might become unstable. If they’re too low, the system might not respond quickly enough to changes in the target position or velocity. You might need to tune these values to get the desired behavior.
  3. Integration Method: The method you’re using to integrate the forces to get the new joint positions and velocities might be causing issues. If you’re using a simple Euler integration method, this can lead to instability or inaccuracies, especially if the time step is too large. You might want to try using a more accurate integration method, like Runge-Kutta.
  4. Non-Linearities and Complex Dynamics: If your robot has non-linearities or complex dynamics that are not captured by the simple damped spring model, this could cause the simulation results to be different. You might need to use a more complex model that takes these factors into account.
  5. Joint Limits: If your robot has joint limits, these could be causing the simulation results to be different. If a joint reaches its limit, the force applied to it will not have the expected effect. You might need to take joint limits into account in your calculations.

Hello, thanks for the comprehensive answer, but my problem is a little more specific.

I just want to know which formula is PhysX using exactly to compute the torque to be able to replace ArticulationActions(joint_positions=jp, joint_velocities=jv) with a formula that would directly give the torque such as (this one comes from the AnymalTerrain example) and get the exact same simulation.

torques = torch.clip(self.Kp*(self.action_scale*self.actions + self.default_dof_pos - self.dof_pos) - self.Kd*self.dof_vel, -80., 80.)

I have effectivly tried tried every flavor of formulas to replace it (testing all kind of signs, units etc) and none of it gives the same results on my simulations. Also there is very strong difference between different number of solver iterations with the formula where I compute torque directly, wrt a ArticulationAction approach. Is there a hidden trick somewhere where the ArticulationAction with velocity and position is taken as a constraint in the solver and not directly converted to torque ? Is there a trick with the units ?

Basically I really just want to be able to just change the ArticulationAction based on position and velocity, to a code that provide directly the in the AnymalTerrain example.


Hey @rthaker I was working as well with joint positions and noticed a weird behavior that you might want to investigatie/have some insight about.
In short I have a robot with various joints and an articulated root. Everything was working normally on 2021.2.1 but when I moved to 2022.2.1 the only working part was the velocity control.
Upon a full day of investigation I discovered that if the articulation root is enabled the maximum target joint position is 6 or somewhere around that value. 10 for example gets mapped to ~3.6XXX.

A fast way to check this for you is to open the franka example, disable the joint limits on the gripper and try to set the position of the fingers.

Can you help me out? I just opened another issue regarding this.

Another issue I noticed is that the maximum velocity is not taken into account when setting velocity targets. This makes working with Isaac really hard.

Hi @marc2002 /@rochmollero - I have forwarded your question to right PIC. They will review and get back to you.

Apologies for the delay in the response. We are currently busy working on the new release which is expected to come out next month.

For the record, we published the detailed joint drive implementation in Physx with the last release, see the link in the note box: Articulations — physx 5.3.0 documentation