17
17
18
18
from . import math
19
19
from . import support
20
+ from .types import MJ_MINVAL
20
21
from .types import Data
21
22
from .types import DisableBit
22
23
from .types import JointType
23
24
from .types import Model
25
+ from .types import Option
24
26
from .warp_util import event_scope
25
27
26
28
@@ -94,25 +96,6 @@ def _spring_passive(
94
96
qfrc_spring_out [worldid , dofid ] = - stiffness * fdif
95
97
96
98
97
- @wp .kernel
98
- def _damper_passive (
99
- # Model:
100
- dof_damping : wp .array (dtype = float ),
101
- # Data in:
102
- qvel_in : wp .array2d (dtype = float ),
103
- qfrc_spring_in : wp .array2d (dtype = float ),
104
- # Data out:
105
- qfrc_damper_out : wp .array2d (dtype = float ),
106
- qfrc_passive_out : wp .array2d (dtype = float ),
107
- ):
108
- worldid , dofid = wp .tid ()
109
-
110
- qfrc_damper = - dof_damping [dofid ] * qvel_in [worldid , dofid ]
111
-
112
- qfrc_damper_out [worldid , dofid ] = qfrc_damper
113
- qfrc_passive_out [worldid , dofid ] = qfrc_damper + qfrc_spring_in [worldid , dofid ]
114
-
115
-
116
99
@wp .kernel
117
100
def _gravity_force (
118
101
# Model:
@@ -143,50 +126,187 @@ def _gravity_force(
143
126
144
127
145
128
@wp .kernel
146
- def _qfrc_passive_gravcomp (
129
+ def _box_fluid (
130
+ # Model:
131
+ opt_wind : wp .vec3 ,
132
+ opt_density : float ,
133
+ opt_viscosity : float ,
134
+ body_rootid : wp .array (dtype = int ),
135
+ body_mass : wp .array (dtype = float ),
136
+ body_inertia : wp .array (dtype = wp .vec3 ),
137
+ # Data in:
138
+ xipos_in : wp .array2d (dtype = wp .vec3 ),
139
+ ximat_in : wp .array2d (dtype = wp .mat33 ),
140
+ subtree_com_in : wp .array2d (dtype = wp .vec3 ),
141
+ cvel_in : wp .array2d (dtype = wp .spatial_vector ),
142
+ # Data out:
143
+ fluid_applied_out : wp .array2d (dtype = wp .spatial_vector ),
144
+ ):
145
+ """Fluid forces based on inertia-box approximation."""
146
+
147
+ worldid , bodyid = wp .tid ()
148
+
149
+ # map from CoM-centered to local body-centered 6D velocity
150
+
151
+ # body-inertial
152
+ pos = xipos_in [worldid , bodyid ]
153
+ rot = ximat_in [worldid , bodyid ]
154
+ rotT = wp .transpose (rot )
155
+
156
+ # transform velocity
157
+ cvel = cvel_in [worldid , bodyid ]
158
+ torque = wp .spatial_top (cvel )
159
+ force = wp .spatial_bottom (cvel )
160
+ subtree_com = subtree_com_in [worldid , body_rootid [bodyid ]]
161
+ dif = pos - subtree_com
162
+ force -= wp .cross (dif , torque )
163
+
164
+ lvel_torque = rotT @ torque
165
+ lvel_force = rotT @ force
166
+
167
+ if opt_wind [0 ] or opt_wind [1 ] or opt_wind [2 ]:
168
+ # subtract translational component from body velocity
169
+ lvel_force -= rotT @ opt_wind
170
+
171
+ lfrc_torque = wp .vec3 (0.0 )
172
+ lfrc_force = wp .vec3 (0.0 )
173
+
174
+ viscosity = opt_viscosity > 0.0
175
+ density = opt_density > 0.0
176
+
177
+ if viscosity or density :
178
+ inertia = body_inertia [bodyid ]
179
+ mass = body_mass [bodyid ]
180
+ scl = 6.0 / mass
181
+ box0 = wp .sqrt (wp .max (MJ_MINVAL , inertia [1 ] + inertia [2 ] - inertia [0 ]) * scl )
182
+ box1 = wp .sqrt (wp .max (MJ_MINVAL , inertia [0 ] + inertia [2 ] - inertia [1 ]) * scl )
183
+ box2 = wp .sqrt (wp .max (MJ_MINVAL , inertia [0 ] + inertia [1 ] - inertia [2 ]) * scl )
184
+
185
+ if viscosity :
186
+ # diameter of sphere approximation
187
+ diam = (box0 + box1 + box2 ) / 3.0
188
+
189
+ # angular viscosity
190
+ lfrc_torque = - lvel_torque * wp .pow (diam , 3.0 ) * wp .pi * opt_viscosity
191
+
192
+ # linear viscosity
193
+ lfrc_force = - 3.0 * lvel_force * diam * wp .pi * opt_viscosity
194
+
195
+ if density :
196
+ # force
197
+ lfrc_force -= wp .vec3 (
198
+ 0.5 * opt_density * box1 * box2 * wp .abs (lvel_force [0 ]) * lvel_force [0 ],
199
+ 0.5 * opt_density * box0 * box2 * wp .abs (lvel_force [1 ]) * lvel_force [1 ],
200
+ 0.5 * opt_density * box0 * box1 * wp .abs (lvel_force [2 ]) * lvel_force [2 ],
201
+ )
202
+
203
+ # torque
204
+ scl = opt_density / 64.0
205
+ box0_pow4 = wp .pow (box0 , 4.0 )
206
+ box1_pow4 = wp .pow (box1 , 4.0 )
207
+ box2_pow4 = wp .pow (box2 , 4.0 )
208
+ lfrc_torque -= wp .vec3 (
209
+ box0 * (box1_pow4 + box2_pow4 ) * wp .abs (lvel_torque [0 ]) * lvel_torque [0 ] * scl ,
210
+ box1 * (box0_pow4 + box2_pow4 ) * wp .abs (lvel_torque [1 ]) * lvel_torque [1 ] * scl ,
211
+ box2 * (box0_pow4 + box1_pow4 ) * wp .abs (lvel_torque [2 ]) * lvel_torque [2 ] * scl ,
212
+ )
213
+
214
+ # rotate to global orientation: lfrc -> bfrc
215
+ torque = rot @ lfrc_torque
216
+ force = rot @ lfrc_force
217
+
218
+ fluid_applied_out [worldid , bodyid ] = wp .spatial_vector (force , torque )
219
+
220
+
221
+ def _fluid (m : Model , d : Data ):
222
+ wp .launch (
223
+ _box_fluid ,
224
+ dim = (d .nworld , m .nbody ),
225
+ inputs = [
226
+ m .opt .wind ,
227
+ m .opt .density ,
228
+ m .opt .viscosity ,
229
+ m .body_rootid ,
230
+ m .body_mass ,
231
+ m .body_inertia ,
232
+ d .xipos ,
233
+ d .ximat ,
234
+ d .subtree_com ,
235
+ d .cvel ,
236
+ ],
237
+ outputs = [
238
+ d .fluid_applied ,
239
+ ],
240
+ )
241
+
242
+ # TODO(team): ellipsoid fluid model
243
+
244
+ support .apply_ft (m , d , d .fluid_applied , d .qfrc_fluid )
245
+
246
+
247
+ @wp .kernel
248
+ def _qfrc_passive (
147
249
# Model:
148
250
jnt_actgravcomp : wp .array (dtype = int ),
149
251
dof_jntid : wp .array (dtype = int ),
252
+ dof_damping : wp .array (dtype = float ),
150
253
# Data in:
254
+ qvel_in : wp .array2d (dtype = float ),
255
+ qfrc_spring_in : wp .array2d (dtype = float ),
151
256
qfrc_gravcomp_in : wp .array2d (dtype = float ),
257
+ qfrc_fluid_in : wp .array2d (dtype = float ),
258
+ # In:
259
+ gravcomp : bool ,
260
+ fluid : bool ,
152
261
# Data out:
262
+ qfrc_damper_out : wp .array2d (dtype = float ),
153
263
qfrc_passive_out : wp .array2d (dtype = float ),
154
264
):
155
265
worldid , dofid = wp .tid ()
156
266
267
+ # spring
268
+ qfrc_passive = qfrc_spring_in [worldid , dofid ]
269
+
270
+ # damper
271
+ qfrc_damper = - dof_damping [dofid ] * qvel_in [worldid , dofid ]
272
+ qfrc_damper_out [worldid , dofid ] = qfrc_damper
273
+
274
+ qfrc_passive += qfrc_damper
275
+
157
276
# add gravcomp unless added by actuators
158
- if jnt_actgravcomp [dof_jntid [dofid ]]:
159
- return
277
+ if gravcomp and not jnt_actgravcomp [dof_jntid [dofid ]]:
278
+ qfrc_passive += qfrc_gravcomp_in [ worldid , dofid ]
160
279
161
- qfrc_passive_out [worldid , dofid ] += qfrc_gravcomp_in [worldid , dofid ]
280
+ # add fluid force
281
+ if fluid :
282
+ qfrc_passive += qfrc_fluid_in [worldid , dofid ]
283
+
284
+ qfrc_passive_out [worldid , dofid ] = qfrc_passive
162
285
163
286
164
287
@event_scope
165
288
def passive (m : Model , d : Data ):
166
289
"""Adds all passive forces."""
167
290
if m .opt .disableflags & DisableBit .PASSIVE :
168
- d .qfrc_passive .zero_ ()
291
+ d .qfrc_spring .zero_ ()
292
+ d .qfrc_damper .zero_ ()
169
293
d .qfrc_gravcomp .zero_ ()
294
+ d .qfrc_fluid .zero_ ()
295
+ d .qfrc_passive .zero_ ()
170
296
return
171
297
172
- # TODO(team): mj_ellipsoidFluidModel
173
- # TODO(team): mj_inertiaBoxFluidModell
174
-
175
298
d .qfrc_spring .zero_ ()
176
299
wp .launch (
177
300
_spring_passive ,
178
301
dim = (d .nworld , m .njnt ),
179
302
inputs = [m .qpos_spring , m .jnt_type , m .jnt_qposadr , m .jnt_dofadr , m .jnt_stiffness , d .qpos ],
180
303
outputs = [d .qfrc_spring ],
181
304
)
182
- wp .launch (
183
- _damper_passive ,
184
- dim = (d .nworld , m .nv ),
185
- inputs = [m .dof_damping , d .qvel , d .qfrc_spring ],
186
- outputs = [d .qfrc_damper , d .qfrc_passive ],
187
- )
188
- if m .ngravcomp and not (m .opt .disableflags & DisableBit .GRAVITY ):
189
- d .qfrc_gravcomp .zero_ ()
305
+
306
+ gravcomp = m .ngravcomp and not (m .opt .disableflags & DisableBit .GRAVITY )
307
+ d .qfrc_gravcomp .zero_ ()
308
+
309
+ if gravcomp :
190
310
wp .launch (
191
311
_gravity_force ,
192
312
dim = (d .nworld , m .nbody - 1 , m .nv ),
@@ -203,9 +323,24 @@ def passive(m: Model, d: Data):
203
323
],
204
324
outputs = [d .qfrc_gravcomp ],
205
325
)
206
- wp .launch (
207
- _qfrc_passive_gravcomp ,
208
- dim = (d .nworld , m .nv ),
209
- inputs = [m .jnt_actgravcomp , m .dof_jntid , d .qfrc_gravcomp ],
210
- outputs = [d .qfrc_passive ],
211
- )
326
+
327
+ fluid = m .opt .density or m .opt .viscosity or m .opt .wind [0 ] or m .opt .wind [1 ] or m .opt .wind [2 ]
328
+ if fluid :
329
+ _fluid (m , d )
330
+
331
+ wp .launch (
332
+ _qfrc_passive ,
333
+ dim = (d .nworld , m .nv ),
334
+ inputs = [
335
+ m .jnt_actgravcomp ,
336
+ m .dof_jntid ,
337
+ m .dof_damping ,
338
+ d .qvel ,
339
+ d .qfrc_spring ,
340
+ d .qfrc_gravcomp ,
341
+ d .qfrc_fluid ,
342
+ gravcomp ,
343
+ fluid ,
344
+ ],
345
+ outputs = [d .qfrc_damper , d .qfrc_passive ],
346
+ )
0 commit comments