-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[dart] Compute Inverse Dynamics for all skeletons to populate joint forces #143
Conversation
Signed-off-by: Diego Ferigo <[email protected]>
If the goal of this PR is just to make sure that the joint forces aren't being cleared between simulation steps, then we should simply change line 54 to |
One thing that If the default joint force should always be zero, then we'll want to do what @azeey suggested and use |
Thanks @mxgrey for the explanation, now I got what @azeey meant. It's not clear to me the rationale behind clearing the joint forces when stepping the world. Can any of the developers shed some light on this need? If the physics would provide joint forces, ign-gazebo's |
The question is this: If the user does not explicitly set a joint force command between the last simulation step and the next one, then what should its fallback value be? The most obvious choices are:
If every joint force is guaranteed to get set between every simulation step, then the question is irrelevant in terms of the simulation outcome (although option 1 might be marginally more efficient for performance). But in my experience it's pretty common to have simulations where some joints simply stop receiving force commands, with the expectation that the joint will start exhibiting its passive dynamics of swinging freely. For that reason, option 2 is likely to be the most intuitive for users. But then if the user needs to know the most recent joint force commands, then option 2 would interfere with that. So I'd suggest not having DART clear the joint forces, and instead have the ignition-physics save the forces in a separate container and then clear the forces in DART at each step. Unless there's some desire for a behavior where the simulation should use the last joint force command that was given, even if no new command have come in. That's ultimately up to the ignition-gazebo architects to decide what the appropriate default behavior is. |
I dag a bit more in the APIs, to be more clear, "clearing joint forces" with /// Calculate the dynamics and integrate the world for one step
/// \param[in] _resetCommand True if you want to reset to zero the joint
/// command after simulation step.
void step(bool _resetCommand = true); If I got it, using
I think what you described here is what I would expect as well. Although, I fear that using the same APIs to handle both the "measurement" (let's assume we consider the joint forces as the output of perfect joint torque sensors) and the command could not be the optimal solution. Why not separating the two things? Would it make sense? Staying in the ign-physics layer, I would expect that the exposed joint force is always the current joint force of the model. If there was a joint force command and this command bypasses friction (some more detail in gazebosim/gz-sim#407), the returned force would match the command. If, instead, there was no command, I'd expect the joint force to be the passive one. This way, who reads the joint forces always has the right value, regardless of what was done before the step. Then, if the last command has to be retrieved, both ign-physics and ign-gazebo could handle it. In the ign-physics case, maybe one way to go would be adding a new API that gathers the last command. In the ign-gazebo side, instead, the content of the last
To repeat, if I understood, this approach would allow to clear out the forces and exposing the commands. It's not yet clear to me how to deal with the passive dynamics. |
Okay, I think I understand where the disconnect was. I wasn't accounting for joint axis friction when talking about the passive dynamics. I believe joint axis friction is accounted for in the constraint solver, so it's kept separate from the joint force command. You're right that it wouldn't show up in the joint forces that get reported by copying the joint force command fields the way that I suggested. And I believe you're also right that, without making some changes to the internals of DART, computing the inverse dynamics after the simulation step would be the most straightforward way to obtain the joint forces that account for friction. However, computing the inverse dynamics is not a free lunch. Since DART uses Featherstone's ABA, it's not outrageously costly, but it's still not free. Since many users will care more about performance than they do about getting this information, I don't think we should always compute the inverse dynamics. I think I would propose adding a feature to |
In general, I find confusing if a physics engine for some operation takes into account friction and for some other doesn't. There are commonly used engines out there that work like that, unfortunately. I'm noticing some recent activity in the implementation of the bullet engine. Standing on the Python API that I'm more familiar with, it seems that it just provides the last command:
And also calling ID would not take friction into account:
I'm not sure if the C / C++ APIs would provide more information.
I totally agree with you, especially for large words, calling ID on all models would not be worth if the data is not necessary.
Awesome, thanks! Just to put another option on the table, instead of creating new APIs, what about enabling the ID computation lazily? And I mean, the first call to I think that from the ign-gazebo point of view, it is not completely clear what the |
I just realized that the Edit: I was wrong. Af first sight I thought that |
I haven't had a chance to look at this in a while. I noticed you mentioned |
I still haven't wrapped my head around this. I think what I wrote in #143 (comment) could be useful to take two birds with one stone:
It seems to me that these two cases could be mapped exactly to what described in Modeling a Real Force/Torque Sensor and could share the implementation (and maybe tested against ID?). Gazebo Classic's I don't have anything against a new PR superseding this one that ports Gazebo Classic's approach to the DART plugin. My only doubt is how the optional presence of joint friction would affect the resulting value. In this moment, reading again gazebosim/gz-sim#407 and the linked resources still does not create a clear picture in my mind, further discussion might be necessary. xref gazebosim/gazebo-classic#1321 robotology/gazebo-yarp-plugins#471 |
I started looking into this yesterday and I think there's a piece missing from this needed to implement Force/Torque sensors, namely, the constraint forces on the joint. For example, to implement a 6 axis Force/Torque sensor, we would use a fixed joint between two links and get the constraint forces on the joint. But the approach in this PR gives the forces only in the non-constrained DOF of the joint and calling I'm going to see if we can use |
I've created #283, which exposes joint constraint forces. @diegoferigo If we just want the applied force minus joint friction, spring stiffness, etc, I'm not sure inverse dynamics is what we need. I tested this on a pendulum without any applied force and no joint friction, etc. and I get non-zero values. This is because the inverse dynamics algorithm gives you the torque necessary to create joint acceleration, so if the pendulum is swinging due to gravity, we get non-zero values because the joint is accelerating. Is that what you expect from calling |
Thanks @azeey for having a look at this! I think that a practical example could help in this case. Let's assume we want to design a joint torque controller, i.e. something that sends joint torque references and closes the loop on joint torque measurements (something similar to what discussed in robotology/gazebo-yarp-plugins#471). Practically, the joint torque references could be stored by the user in the In the current status of Ignition, there's no way to populate
This should match what discussed above in in #143 (comment) (please correct me if I'm either wrong or misunderstood), particularly in option 2:
Then, if we want to also provide the user the last applied command, a new component could be created ( |
Hi all, RecapTL;DR: I feel that joint input force and joint mechanical force (see later for strict definitions) are different concepts and for this reason it make sense to have separate methods to read them. If DetailsNaming clarificationAs a first step, I feel that the first thing that we may need to do is to clarify naming w.r.t. to this variables we are discussing about, as I feel that "Joint Force" is hopefully overloaded with different meanings across different discussion, source code and documentation to be useful. : ) Quoting from the related discussion robotology/gazebo-yarp-plugins#471 :
To avoid confusion, I propose at least in the rest of the discussion to refer to this two quantities as:
I would be happy to change or bikeshed this names, but I feel that is fundamental to use separate names for these two concepts to avoid confusion. Additional required featuresI think that now that if we agree that joint input force and joint mechanical force are both interesting quantities, I think we should clarify how this two quantities are already exposed or how we want them to be exposed. From what understand (but please correct me if this is not the case), How to compute joint mechanical force in DARTOnce we added a new method for exposing the joint mechanical force as discussed in the previous section, we need a way to compute it with the support physics engines, in particular (as this is the topic for this PR). For this, I don't think it is necessary to call any InverseDynamics call. In particular, if you check how a simulation step in DART works, you can see that in the jointMechanicalForce = joint->getRelativeJacobianStatic().transpose() * joint->getChildBodyNode->getBodyForce(); |
@azeey if you think that a quick chat on this over a virtual whiteboard can be useful for you, feel free to propose a time, thanks! |
The time slot is fine for me! I think on our side @diegoferigo may be interested as well on joining. |
Interested! Though, I might have to leave around 4:30pm / 4:45pm UTC. |
I can join at 4pm UTC |
So just to follow up on the topic: did the chat happened or is there any consensus on how joint forces should be calculated yet? I see most of Force Torque sensor and related PRs merged, but if I am not mistaken they should not work without this and gazebosim/gz-sim#952. |
Yeah, we had a consensus and the feature is implemented in #283. That and gazebosim/gz-sim#989 was used to implement Force/Torque sensors. We also discussed that the |
From @azeey's #124 (comment):
I'm not sure I got what you meant in the alternative option. Contrarily to what I initially proposed in #124 (comment), this PR computes ID for all simulated models in the
SimulationFeatures::WorldForwardStep
function. This prevents computing ID every timeJointFeatures::GetJointForce
is called.Fixes #124.