google / brax

Massively parallel rigidbody physics simulation on accelerator hardware.
Apache License 2.0
2.27k stars 249 forks source link

Support for drag force to implement gym swimmer environment #86

Closed benelot closed 2 years ago

benelot commented 2 years ago

I was trying to get drag force into my simulation in order to get the swimmer environment running (and possibly simple underwater simulations!) because ther rest of the swimmer env is just simple to port over to brax.

The drag force can be described as follows:

$F_d = - 1/2 \rho ||v||^2 A C_d unit_vector(v)$

where:

\rho and C_d as well as the 1/2 could easily be merged into one constant as they initially play a minor role of determining the properties of the interaction.

This can in principle added easily to the location in code where the forces are applied to the different bodies. I got stuck with two problems:

benelot commented 2 years ago

As soon as we defined this, I can make a PR to get this into the code.

cdfreeman-google commented 2 years ago

Hello!

The Force primitive will appear in the next github sync, and I think the most natural place to slot this is as a new kind of Force. We can collect the necessary metadata about colliders for different bodies there, and feed it into the Force calculation in a similar way to how we do this for collision calculations.

I think we will need some kind of get_cross_sectional_area fn call for each primitive (is it really surface area in the direction of motion, or is it cross sectional area?). I don't think such a function is too hard to write down for our existing primitives, but if it requires thinking about occlusion, then it may take some additional work. We could get a beta version up and running pretty quickly without it, though, I think.

I'll ping this thread again once we sync Forces in!

benelot commented 2 years ago

Perfect!

benelot commented 2 years ago

@erwincoumans

benelot commented 2 years ago

I think we will need some kind of get_cross_sectional_area fn call for each primitive

It seems pretty confusing on the net as I just find out, but most descriptions of the area is the area some body covers when you look at it from the direction of motion. So cross-section would be correct only for a few edge-cases, but for instance for a tilted capsule, you do not just want a slice like an ellipsoid from the cylinder part, but area of the whole object projected flat. So the correct wording seems to be projected area in the direction of motion or something.

cdfreeman-google commented 2 years ago

That makes sense. Thankfully swimmer is only in 2d, which makes this a bit simpler.

cdfreeman-google commented 2 years ago

Alright, check out https://github.com/google/brax/blob/main/brax/physics/forces.py for the implementation of our simplest force. It's used to power the cart in the new inverted_pendulum and inverted_double_pendulum environments

erwincoumans commented 2 years ago

MuJoCo implements a heavily simplified viscosity model, based on the inertial box and its bounding sphere as far as I can tell, not on the actual collision geometry.

benelot commented 2 years ago

Alright, check out https://github.com/google/brax/blob/main/brax/physics/forces.py for the implementation of our simplest force. It's used to power the cart in the new inverted_pendulum and inverted_double_pendulum environments

I see how you define the thruster to the system config and that you apply a step in the pendulum env. Is the truster then just added as an action in step? Because in the swimmer's case, the force is not an action, but a reaction to the limb velocity and is applied to the COMs of the limbs. I am trying to get how this is done, but any hint could be helpful.

cdfreeman-google commented 2 years ago

Alright, check out https://github.com/google/brax/blob/main/brax/physics/forces.py for the implementation of our simplest force. It's used to power the cart in the new inverted_pendulum and inverted_double_pendulum environments

I see how you define the thruster to the system config and that you apply a step in the pendulum env. Is the truster then just added as an action in step? Because in the swimmer's case, the force is not an action, but a reaction to the limb velocity and is applied to the COMs of the limbs. I am trying to get how this is done, but any hint could be helpful.

Two possible paths forward here: 1) Put the details of the force calculations in the env step and pipe the relevant action value directly into the step function of the brax system. 2) Create a "passive" force class that does the requisite calculation, but which doesn't depend on user input in any way. This would need to be added to the config too, just like thruster is, now.

Pros for way 1) is that it could be easily accomplished right now by attaching thrusters to each body, and putting a little extra logic in the env step function. Cons for way 1) is that that force would be replicated across physics substeps instead of calculated different at each substep, so there might be a small accuracy penalty.

Pros for way 2) is that it removes all of the complexity from the env step, and puts it directly in a configurable widget that we can just attach to different bodies. Cons for way 2) is that it introduces a lot of complexity for a single configurable widget used by only one environment ;) .

It's probably worth trying way 1) for now, just because it's easier. Basically, all you'd need to do is pass in the requisite force values into the right indices of action of the system step. The force and actuator objects can report which indices correspond to which controllable objects, but, generically, forces come after actuators in the list. Let me know if that makes sense--happy to hop on a video call if it would be helpful.

benelot commented 2 years ago

We implemented a first version that is going to be in the repo soon.