gz-sim icon indicating copy to clipboard operation
gz-sim copied to clipboard

Clearing pending commands - unexpected behavior

Open unjambonakap opened this issue 1 year ago • 8 comments

Hi,

Issue summary:

  • Set LinearVelocityCmd to non zero vector (for instance to give the system an initial velocity)
  • This velocity is used on first integration step
  • LinearVelocityCmd gets cleared to zero vector
  • The model stops moving on all subsequent steps (while we don't ecm.RemoveComponent(...))

When specify attaching a command to an entity (such as JointForceCmd, AngularVelocityCmd), these commands get cleared after a physic step (physics.cc)

This clearing has, I'd say, an unexpected behavior for some commands. Most notably, the velocity commands (angular and linear) get set to the zero vector. This zero vector is then used on later steps to overwrite the velocities.

I suppose the clearing of commands after an integration step means that these commands are considered as impulses - meaning a command should only alter one step and then be no-op. While clearing a force to the zero vector achieves that, doing the same for the velocity is not correct.

Possibles solutions:

  1. deleting the commands instead of clearing them to zero
  2. modifying the content of the velocity commands to have an optional

I'd favor (1) but I've just started using gazebo so I don't know much :)

Edit: I could do the PR once we've settled on a direction

Thanks

unjambonakap avatar Mar 11 '23 19:03 unjambonakap

While clearing a force to the zero vector achieves that, doing the same for the velocity is not correct.

Ah, yes, I think clearing to zero only makes sense for force components.

deleting the commands instead of clearing them to zero

I'd favor this too. I think in the past we had performance issues with repeatedly creating and deleting components, but I believe that has been fixed as of #856. The only caveat is I think this would be considered a behavior change since a system that assumes that keeps updating a velocity command now needs to recreate the component in every step, so at best, we'd have to target a PR against main, but we might have to live with the current behavior if too many systems depend on the old behavior.

azeey avatar Mar 13 '23 16:03 azeey

Looking throughout the codebase, there are a few systems and tests that rely on the current behavior so it might be a good option to go with the approach of creating a new vel cmd component for the different behavior. For the Link API, We can also add an optional arg to indicate whether the vel cmd should persist or not, e.g. SetLinearVelocity(EntityComponentManager &_ecm, const math::Vector3d &_vel, bool _persist = false)

iche033 avatar Mar 13 '23 20:03 iche033

Could you point to places that rely on this behavior? I'm interested in seeing a situation where the current behavior is useful because I really can't conceive a situation where it makes sense (nor reconcile it semantically to the function's name)

We have 3 behavior: logical persist: link.SetV(v, persist=true) -> link.v = v, integrate(1), link.v = v, ... logical dirac: link.SetV(v, persist=false) -> link.v = v, integrate(1) ... actual behavior: link.SetV(v) -> link.v = v, integrate(1) ,link.v = 0, integrate(1), link.v = 0, ...

I agree that a _persist flag would be a nice feature. A new command for it is fine though the current command's behavior needs to be changed (either through a second new command or through a delete of the component).

unjambonakap avatar Mar 13 '23 22:03 unjambonakap

I noticed that most of the systems and tests inside gz-sim had to send the cmd continuously, e.g. velocity_control system and a test helper class. The behavior change here is that if one of our users had code to move a model for a fixed period of time, e.g. by sending vel cmds for 5 seconds then expect the model to stop moving once they stop sending the cmd, the new proposed change would break this behavior.

iche033 avatar Mar 14 '23 18:03 iche033

Fair point for user code (though I hope they do not do that :) ). Those systems sending the command continuously wouldn't be affected by this, so that's good.

How do you want to proceed: should I stop bothering you and leave you people to it (I don't know much about the organization, if you're full time on gazebo or not) or we settle on a direction and I write a PR? That direction could be to introduce a sidekick to LinearVelocityCmd with a persisted and dirac version with the appropriate helpers

unjambonakap avatar Mar 14 '23 22:03 unjambonakap

PRs are welcome :) I think we just need to agree on the design and what's to be implemented. @azeey what do you think adding a new component or do you have other ideas?

iche033 avatar Mar 15 '23 20:03 iche033

Those systems sending the command continuously wouldn't be affected by this, so that's good.

I don't think that's quite right because those systems assume the component is there and just update the value. If we remove the component, those systems would have to be updated to recreate the component in every time step.

We could create new components (eg. *VelocityImpulseCmd and *VelocityPersistedCmd) and leave the current components unchanged so we are backward compatible, but how would these new components interact with each other and with the existing *VelocityCmd components. How should the Physics system prioritize the components? And how would multiple systems that each use one of these components coexist? I don't have a good answer for these. It seems a lot cleaner and easier to reason about to have one set of *VelocityCmd components. Systems that need persisted velocities can just create and set the component in each time step. Systems that need the the robot to stop would just set the component to 0.

So my proposal would be to change the current behavior in the main branch and have the Physics system remove *VelocityCmd components. Now that we have EntityComponentManager::SetComponentData, which creates a component if it doesn't exist, it wouldn't be a difficult transition for users to make. For multiple system interactions, perhaps we can create a EntityComponentManager::AddComponentData, so they don't clobber each other's data.

BTW, I also see the same problem with JointVelocityCmd, so the decision we make here should be applied for all *VelocityCmd components.

azeey avatar Mar 16 '23 14:03 azeey

It seems a lot cleaner and easier to reason about to have one set of *VelocityCmd components. Systems that need persisted velocities can just create and set the component in each time step. Systems that need the the robot to stop would just set the component to 0.

So my proposal would be to change the current behavior in the main branch and have the Physics system remove *VelocityCmd components. Now that we have EntityComponentManager::SetComponentData, which creates a component if it doesn't exist, it wouldn't be a difficult transition for users to make. For multiple system interactions, perhaps we can create a EntityComponentManager::AddComponentData, so they don't clobber each other's data.

BTW, I also see the same problem with JointVelocityCmd, so the decision we make here should be applied for all *VelocityCmd components.

I've started work on this suggestion in https://github.com/gazebosim/gz-sim/pull/2228

scpeters avatar Nov 04 '23 08:11 scpeters

all *VelocityCmd components are now removed at each timestep as of #2228, so I will close this issue. Please reopen if there is still something remaining to be done

scpeters avatar Apr 09 '24 19:04 scpeters