jaxsim 0.4.3.dev143__py3-none-any.whl → 0.4.3.dev155__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
jaxsim/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.4.3.dev143'
16
- __version_tuple__ = version_tuple = (0, 4, 3, 'dev143')
15
+ __version__ = version = '0.4.3.dev155'
16
+ __version_tuple__ = version_tuple = (0, 4, 3, 'dev155')
jaxsim/api/contact.py CHANGED
@@ -144,7 +144,8 @@ def collidable_point_dynamics(
144
144
  The joint force references to apply to the joints.
145
145
 
146
146
  Returns:
147
- The 6D force applied to each collidable point and additional data based on the contact model configured:
147
+ The 6D force applied to each collidable point and additional data based
148
+ on the contact model configured:
148
149
  - Soft: the material deformation rate.
149
150
  - Rigid: no additional data.
150
151
  - QuasiRigid: no additional data.
@@ -156,21 +157,13 @@ def collidable_point_dynamics(
156
157
  """
157
158
 
158
159
  # Import privately the contacts classes.
159
- from jaxsim.rbda.contacts import (
160
- RelaxedRigidContacts,
161
- RelaxedRigidContactsState,
162
- RigidContacts,
163
- RigidContactsState,
164
- SoftContacts,
165
- SoftContactsState,
166
- )
160
+ from jaxsim.rbda.contacts import RelaxedRigidContacts, RigidContacts, SoftContacts
167
161
 
168
162
  # Build the soft contact model.
169
163
  match model.contact_model:
170
164
 
171
165
  case SoftContacts():
172
166
  assert isinstance(model.contact_model, SoftContacts)
173
- assert isinstance(data.state.contact, SoftContactsState)
174
167
 
175
168
  # Compute the 6D force expressed in the inertial frame and applied to each
176
169
  # collidable point, and the corresponding material deformation rate.
@@ -187,7 +180,6 @@ def collidable_point_dynamics(
187
180
 
188
181
  case RigidContacts():
189
182
  assert isinstance(model.contact_model, RigidContacts)
190
- assert isinstance(data.state.contact, RigidContactsState)
191
183
 
192
184
  # Compute the 6D force expressed in the inertial frame and applied to each
193
185
  # collidable point.
@@ -203,7 +195,6 @@ def collidable_point_dynamics(
203
195
 
204
196
  case RelaxedRigidContacts():
205
197
  assert isinstance(model.contact_model, RelaxedRigidContacts)
206
- assert isinstance(data.state.contact, RelaxedRigidContactsState)
207
198
 
208
199
  # Compute the 6D force expressed in the inertial frame and applied to each
209
200
  # collidable point.
jaxsim/api/data.py CHANGED
@@ -13,7 +13,6 @@ import jaxsim.api as js
13
13
  import jaxsim.math
14
14
  import jaxsim.rbda
15
15
  import jaxsim.typing as jtp
16
- from jaxsim.rbda.contacts import SoftContacts
17
16
  from jaxsim.utils import Mutability
18
17
  from jaxsim.utils.tracing import not_tracing
19
18
 
@@ -107,17 +106,17 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
107
106
  @staticmethod
108
107
  def build(
109
108
  model: js.model.JaxSimModel,
110
- base_position: jtp.Vector | None = None,
111
- base_quaternion: jtp.Vector | None = None,
112
- joint_positions: jtp.Vector | None = None,
113
- base_linear_velocity: jtp.Vector | None = None,
114
- base_angular_velocity: jtp.Vector | None = None,
115
- joint_velocities: jtp.Vector | None = None,
109
+ base_position: jtp.VectorLike | None = None,
110
+ base_quaternion: jtp.VectorLike | None = None,
111
+ joint_positions: jtp.VectorLike | None = None,
112
+ base_linear_velocity: jtp.VectorLike | None = None,
113
+ base_angular_velocity: jtp.VectorLike | None = None,
114
+ joint_velocities: jtp.VectorLike | None = None,
116
115
  standard_gravity: jtp.FloatLike = jaxsim.math.StandardGravity,
117
- contact: jaxsim.rbda.contacts.ContactsState | None = None,
118
116
  contacts_params: jaxsim.rbda.contacts.ContactsParams | None = None,
119
117
  velocity_representation: VelRepr = VelRepr.Inertial,
120
118
  time: jtp.FloatLike | None = None,
119
+ extended_ode_state: dict[str, jtp.PyTree] | None = None,
121
120
  ) -> JaxSimModelData:
122
121
  """
123
122
  Create a `JaxSimModelData` object with the given state.
@@ -133,56 +132,73 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
133
132
  The base angular velocity in the selected representation.
134
133
  joint_velocities: The joint velocities.
135
134
  standard_gravity: The standard gravity constant.
136
- contact: The state of the soft contacts.
137
135
  contacts_params: The parameters of the soft contacts.
138
136
  velocity_representation: The velocity representation to use.
139
137
  time: The time at which the state is created.
138
+ extended_ode_state:
139
+ Additional user-defined state variables that are not part of the
140
+ standard `ODEState` object. Useful to extend the system dynamics
141
+ considered by default in JaxSim.
140
142
 
141
143
  Returns:
142
- A `JaxSimModelData` object with the given state.
144
+ A `JaxSimModelData` initialized with the given state.
143
145
  """
144
146
 
145
147
  base_position = jnp.array(
146
- base_position if base_position is not None else jnp.zeros(3)
148
+ base_position if base_position is not None else jnp.zeros(3),
149
+ dtype=float,
147
150
  ).squeeze()
148
151
 
149
152
  base_quaternion = jnp.array(
150
- base_quaternion
151
- if base_quaternion is not None
152
- else jnp.array([1.0, 0, 0, 0])
153
+ (
154
+ base_quaternion
155
+ if base_quaternion is not None
156
+ else jnp.array([1.0, 0, 0, 0])
157
+ ),
158
+ dtype=float,
153
159
  ).squeeze()
154
160
 
155
161
  base_linear_velocity = jnp.array(
156
- base_linear_velocity if base_linear_velocity is not None else jnp.zeros(3)
162
+ base_linear_velocity if base_linear_velocity is not None else jnp.zeros(3),
163
+ dtype=float,
157
164
  ).squeeze()
158
165
 
159
166
  base_angular_velocity = jnp.array(
160
- base_angular_velocity if base_angular_velocity is not None else jnp.zeros(3)
167
+ (
168
+ base_angular_velocity
169
+ if base_angular_velocity is not None
170
+ else jnp.zeros(3)
171
+ ),
172
+ dtype=float,
161
173
  ).squeeze()
162
174
 
163
175
  gravity = jnp.zeros(3).at[2].set(-standard_gravity)
164
176
 
165
177
  joint_positions = jnp.atleast_1d(
166
- joint_positions.squeeze()
167
- if joint_positions is not None
168
- else jnp.zeros(model.dofs())
178
+ jnp.array(
179
+ (
180
+ joint_positions
181
+ if joint_positions is not None
182
+ else jnp.zeros(model.dofs())
183
+ ),
184
+ dtype=float,
185
+ ).squeeze()
169
186
  )
170
187
 
171
188
  joint_velocities = jnp.atleast_1d(
172
- joint_velocities.squeeze()
173
- if joint_velocities is not None
174
- else jnp.zeros(model.dofs())
189
+ jnp.array(
190
+ (
191
+ joint_velocities
192
+ if joint_velocities is not None
193
+ else jnp.zeros(model.dofs())
194
+ ),
195
+ dtype=float,
196
+ ).squeeze()
175
197
  )
176
198
 
177
- time_ns = (
178
- jnp.array(
179
- time * 1e9,
180
- dtype=jnp.uint64 if jax.config.read("jax_enable_x64") else jnp.uint32,
181
- )
182
- if time is not None
183
- else jnp.array(
184
- 0, dtype=jnp.uint64 if jax.config.read("jax_enable_x64") else jnp.uint32
185
- )
199
+ time_ns = jnp.array(
200
+ time * 1e9 if time is not None else 0.0,
201
+ dtype=jnp.uint64 if jax.config.read("jax_enable_x64") else jnp.uint32,
186
202
  )
187
203
 
188
204
  W_H_B = jaxsim.math.Transform.from_quaternion_and_translation(
@@ -194,21 +210,22 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
194
210
  other_representation=velocity_representation,
195
211
  transform=W_H_B,
196
212
  is_force=False,
197
- )
213
+ ).astype(float)
198
214
 
199
215
  ode_state = ODEState.build_from_jaxsim_model(
200
216
  model=model,
201
- base_position=base_position.astype(float),
202
- base_quaternion=base_quaternion.astype(float),
203
- joint_positions=joint_positions.astype(float),
204
- base_linear_velocity=v_WB[0:3].astype(float),
205
- base_angular_velocity=v_WB[3:6].astype(float),
206
- joint_velocities=joint_velocities.astype(float),
207
- tangential_deformation=(
208
- contact.tangential_deformation
209
- if contact is not None and isinstance(model.contact_model, SoftContacts)
210
- else None
211
- ),
217
+ base_position=base_position,
218
+ base_quaternion=base_quaternion,
219
+ joint_positions=joint_positions,
220
+ base_linear_velocity=v_WB[0:3],
221
+ base_angular_velocity=v_WB[3:6],
222
+ joint_velocities=joint_velocities,
223
+ # Unpack all the additional ODE states. If the contact model requires an
224
+ # additional state that is not explicitly passed to this builder, ODEState
225
+ # automatically populates that state with zeroed variables.
226
+ # This is not true for any other custom state that the user might want to
227
+ # pass to the integrator.
228
+ **(extended_ode_state if extended_ode_state else {}),
212
229
  )
213
230
 
214
231
  if not ode_state.valid(model=model):
@@ -220,13 +237,14 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
220
237
  contacts_params = js.contact.estimate_good_soft_contacts_parameters(
221
238
  model=model, standard_gravity=standard_gravity
222
239
  )
240
+
223
241
  else:
224
242
  contacts_params = model.contact_model.parameters
225
243
 
226
244
  return JaxSimModelData(
227
245
  time_ns=time_ns,
228
246
  state=ode_state,
229
- gravity=gravity.astype(float),
247
+ gravity=gravity,
230
248
  contacts_params=contacts_params,
231
249
  velocity_representation=velocity_representation,
232
250
  )
jaxsim/api/model.py CHANGED
@@ -33,7 +33,7 @@ class JaxSimModel(JaxsimDataclass):
33
33
  model_name: Static[str]
34
34
 
35
35
  terrain: Static[jaxsim.terrain.Terrain] = dataclasses.field(
36
- default=jaxsim.terrain.FlatTerrain(), repr=False
36
+ default_factory=jaxsim.terrain.FlatTerrain.build, repr=False
37
37
  )
38
38
 
39
39
  contact_model: jaxsim.rbda.contacts.ContactModel | None = dataclasses.field(
@@ -101,13 +101,14 @@ class JaxSimModel(JaxsimDataclass):
101
101
  A path to an SDF/URDF file, a string containing
102
102
  its content, or a pre-parsed/pre-built rod model.
103
103
  model_name:
104
- The optional name of the model that overrides the one in
105
- the description.
106
- terrain:
107
- The optional terrain to consider.
104
+ The name of the model. If not specified, it is read from the description.
105
+ terrain: The terrain to consider (the default is a flat infinite plane).
106
+ contact_model:
107
+ The contact model to consider.
108
+ If not specified, a soft contacts model is used.
108
109
  is_urdf:
109
- The optional flag to force the model description to be parsed as a
110
- URDF or a SDF. This is otherwise automatically inferred.
110
+ The optional flag to force the model description to be parsed as a URDF.
111
+ This is usually automatically inferred.
111
112
  considered_joints:
112
113
  The list of joints to consider. If None, all joints are considered.
113
114
 
@@ -120,7 +121,7 @@ class JaxSimModel(JaxsimDataclass):
120
121
  # Parse the input resource (either a path to file or a string with the URDF/SDF)
121
122
  # and build the -intermediate- model description.
122
123
  intermediate_description = jaxsim.parsers.rod.build_model_description(
123
- model_description=model_description
124
+ model_description=model_description, is_urdf=is_urdf
124
125
  )
125
126
 
126
127
  # Lump links together if not all joints are considered.
@@ -160,11 +161,11 @@ class JaxSimModel(JaxsimDataclass):
160
161
  The intermediate model description defining the kinematics and dynamics
161
162
  of the model.
162
163
  model_name:
163
- The optional name of the model overriding the physics model name.
164
- terrain:
165
- The optional terrain to consider.
164
+ The name of the model. If not specified, it is read from the description.
165
+ terrain: The terrain to consider (the default is a flat infinite plane).
166
166
  contact_model:
167
- The optional contact model to consider. If None, the soft contact model is used.
167
+ The contact model to consider.
168
+ If not specified, a soft contacts model is used.
168
169
 
169
170
  Returns:
170
171
  The built Model object.
@@ -173,21 +174,31 @@ class JaxSimModel(JaxsimDataclass):
173
174
  # Set the model name (if not provided, use the one from the model description).
174
175
  model_name = model_name if model_name is not None else model_description.name
175
176
 
176
- # Set the terrain (if not provided, use the default flat terrain).
177
- terrain = terrain or JaxSimModel.__dataclass_fields__["terrain"].default
178
- contact_model = contact_model or jaxsim.rbda.contacts.SoftContacts(
179
- terrain=terrain
177
+ # Consider the default terrain (a flat infinite plane) if not specified.
178
+ terrain = (
179
+ terrain or JaxSimModel.__dataclass_fields__["terrain"].default_factory()
180
+ )
181
+
182
+ # Create the default contact model.
183
+ # It will be populated with an initial estimation of good parameters.
184
+ # While these might not be the best, they are a good starting point.
185
+ contact_model = contact_model or jaxsim.rbda.contacts.SoftContacts.build(
186
+ terrain=terrain, parameters=None
180
187
  )
181
188
 
182
189
  # Build the model.
183
190
  model = JaxSimModel(
184
191
  model_name=model_name,
185
- _description=wrappers.HashlessObject(obj=model_description),
186
192
  kin_dyn_parameters=js.kin_dyn_parameters.KynDynParameters.build(
187
193
  model_description=model_description
188
194
  ),
189
195
  terrain=terrain,
190
196
  contact_model=contact_model,
197
+ # The following is wrapped as hashless since it's a static argument, and we
198
+ # don't want to trigger recompilation if it changes. All relevant parameters
199
+ # needed to compute kinematics and dynamics quantities are stored in the
200
+ # kin_dyn_parameters attribute.
201
+ _description=wrappers.HashlessObject(obj=model_description),
191
202
  )
192
203
 
193
204
  return model
jaxsim/api/ode.py CHANGED
@@ -370,9 +370,8 @@ def system_dynamics(
370
370
  corresponding derivative, and the dictionary of auxiliary data returned
371
371
  by the system dynamics evaluation.
372
372
  """
373
- from jaxsim.rbda.contacts.relaxed_rigid import RelaxedRigidContacts
374
- from jaxsim.rbda.contacts.rigid import RigidContacts
375
- from jaxsim.rbda.contacts.soft import SoftContacts
373
+
374
+ from jaxsim.rbda.contacts import RelaxedRigidContacts, RigidContacts, SoftContacts
376
375
 
377
376
  # Compute the accelerations and the material deformation rate.
378
377
  W_v̇_WB, s̈, aux_dict = system_velocity_dynamics(
@@ -382,17 +381,20 @@ def system_dynamics(
382
381
  link_forces=link_forces,
383
382
  )
384
383
 
385
- ode_state_kwargs = {}
384
+ # Initialize the dictionary storing the derivative of the additional state variables
385
+ # that extend the state vector of the integrated ODE system.
386
+ extended_ode_state = {}
386
387
 
387
388
  match model.contact_model:
389
+
388
390
  case SoftContacts():
389
- ode_state_kwargs["tangential_deformation"] = aux_dict["m_dot"]
391
+ extended_ode_state["tangential_deformation"] = aux_dict["m_dot"]
390
392
 
391
393
  case RigidContacts() | RelaxedRigidContacts():
392
394
  pass
393
395
 
394
396
  case _:
395
- raise ValueError("Unable to determine contact state class prefix.")
397
+ raise ValueError(f"Invalid contact model {model.contact_model}")
396
398
 
397
399
  # Extract the velocities.
398
400
  W_ṗ_B, W_Q̇_B, ṡ = system_position_dynamics(
@@ -412,7 +414,7 @@ def system_dynamics(
412
414
  base_linear_velocity=W_v̇_WB[0:3],
413
415
  base_angular_velocity=W_v̇_WB[3:6],
414
416
  joint_velocities=s̈,
415
- **ode_state_kwargs,
417
+ **extended_ode_state,
416
418
  )
417
419
 
418
420
  return ode_state_derivative, aux_dict
jaxsim/api/ode_data.py CHANGED
@@ -1,19 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import dataclasses
4
+
5
+ import jax
3
6
  import jax.numpy as jnp
4
7
  import jax_dataclasses
5
8
 
6
9
  import jaxsim.api as js
7
10
  import jaxsim.typing as jtp
8
- from jaxsim.rbda.contacts import (
9
- ContactsState,
10
- RelaxedRigidContacts,
11
- RelaxedRigidContactsState,
12
- RigidContacts,
13
- RigidContactsState,
14
- SoftContacts,
15
- SoftContactsState,
16
- )
17
11
  from jaxsim.utils import JaxsimDataclass
18
12
 
19
13
  # =============================================================================
@@ -125,15 +119,18 @@ class ODEState(JaxsimDataclass):
125
119
 
126
120
  Attributes:
127
121
  physics_model: The state of the physics model.
128
- contact: The state of the contacts model.
122
+ extended:
123
+ Additional state variables extending the state vector corresponding to
124
+ equations of motion. These extended variables are passed to the integrator.
129
125
  """
130
126
 
131
127
  physics_model: PhysicsModelState
132
- contact: ContactsState
128
+
129
+ extended: dict[str, jtp.PyTree] = dataclasses.field(default_factory=dict)
133
130
 
134
131
  @staticmethod
135
132
  def build_from_jaxsim_model(
136
- model: js.model.JaxSimModel | None = None,
133
+ model: js.model.JaxSimModel,
137
134
  joint_positions: jtp.Vector | None = None,
138
135
  joint_velocities: jtp.Vector | None = None,
139
136
  base_position: jtp.Vector | None = None,
@@ -155,7 +152,15 @@ class ODEState(JaxsimDataclass):
155
152
  The linear velocity of the base link in inertial-fixed representation.
156
153
  base_angular_velocity:
157
154
  The angular velocity of the base link in inertial-fixed representation.
158
- kwargs: Additional arguments needed to build the contact state.
155
+ kwargs:
156
+ Additional arguments corresponding variables extending the default
157
+ state vector of the physics model.
158
+
159
+ Note:
160
+ Kwargs can be used to supply any additional state variables that are passed
161
+ to the integrator. This is useful to extend the default system dynamics,
162
+ for example if the contact model requires additional state variables or to
163
+ simulate additional dynamics like actuators or muscoloskeletal models.
159
164
 
160
165
  Returns:
161
166
  The `ODEState` built from the `JaxSimModel`.
@@ -165,29 +170,11 @@ class ODEState(JaxsimDataclass):
165
170
  `JaxSimModel` and initialized to zero.
166
171
  """
167
172
 
168
- # Get the contact model from the `JaxSimModel`.
169
- match model.contact_model:
170
-
171
- case SoftContacts():
172
-
173
- tangential_deformation = kwargs.get("tangential_deformation", None)
174
-
175
- contact = SoftContactsState.build_from_jaxsim_model(
176
- model=model,
177
- **(
178
- dict(tangential_deformation=tangential_deformation)
179
- if tangential_deformation is not None
180
- else dict()
181
- ),
182
- )
183
- case RigidContacts():
184
- contact = RigidContactsState.build()
173
+ # Initialize the extended state with the optional contact state.
174
+ extended_state = model.contact_model.zero_state_variables(model=model)
185
175
 
186
- case RelaxedRigidContacts():
187
- contact = RelaxedRigidContactsState.build()
188
-
189
- case _:
190
- raise ValueError("Unsupported contact model.")
176
+ # Override the default extended state with optional kwargs.
177
+ extended_state |= kwargs
191
178
 
192
179
  return ODEState.build(
193
180
  model=model,
@@ -200,13 +187,13 @@ class ODEState(JaxsimDataclass):
200
187
  base_linear_velocity=base_linear_velocity,
201
188
  base_angular_velocity=base_angular_velocity,
202
189
  ),
203
- contact=contact,
190
+ extended_state=extended_state,
204
191
  )
205
192
 
206
193
  @staticmethod
207
194
  def build(
208
195
  physics_model_state: PhysicsModelState | None = None,
209
- contact: ContactsState | None = None,
196
+ extended_state: dict[str, jtp.PyTree] | None = None,
210
197
  model: js.model.JaxSimModel | None = None,
211
198
  ) -> ODEState:
212
199
  """
@@ -214,62 +201,60 @@ class ODEState(JaxsimDataclass):
214
201
 
215
202
  Args:
216
203
  physics_model_state: The state of the physics model.
217
- contact: The state of the contacts model.
204
+ extended_state: Additional state variables extending the state vector.
218
205
  model: The `JaxSimModel` associated with the ODE state.
219
206
 
220
207
  Returns:
221
208
  A `ODEState` instance.
222
209
  """
223
210
 
211
+ # Build a zero state for the physics model if not provided.
224
212
  physics_model_state = (
225
213
  physics_model_state
226
214
  if physics_model_state is not None
227
215
  else PhysicsModelState.zero(model=model)
228
216
  )
229
217
 
230
- # Get the contact model from the `JaxSimModel`.
231
- match contact:
232
- case (
233
- SoftContactsState() | RigidContactsState() | RelaxedRigidContactsState()
234
- ):
235
- pass
236
- case None:
237
- contact = SoftContactsState.zero(model=model)
238
- case _:
239
- raise ValueError("Unable to determine contact state class prefix.")
240
-
241
- return ODEState(physics_model=physics_model_state, contact=contact)
218
+ return ODEState(
219
+ physics_model=physics_model_state,
220
+ extended=extended_state,
221
+ )
242
222
 
243
223
  @staticmethod
244
224
  def zero(model: js.model.JaxSimModel, data: js.data.JaxSimModelData) -> ODEState:
245
225
  """
246
- Build a zero `ODEState` from a `JaxSimModel`.
226
+ Build a zero `ODEState` corresponding to a `JaxSimModel`.
247
227
 
248
228
  Args:
249
- model: The `JaxSimModel` associated with the ODE state.
229
+ model: The model to consider.
230
+ data: The data of the considered model.
250
231
 
251
232
  Returns:
252
233
  A zero `ODEState` instance.
253
234
  """
254
235
 
255
- model_state = ODEState.build(
256
- model=model, contact=data.state.contact.zero(model=model)
236
+ ode_state = ODEState.build(
237
+ model=model,
238
+ extended_state=jax.tree.map(
239
+ lambda x: jnp.zeros_like(x), data.state.extended
240
+ ),
257
241
  )
258
242
 
259
- return model_state
243
+ return ode_state
260
244
 
261
245
  def valid(self, model: js.model.JaxSimModel) -> bool:
262
246
  """
263
247
  Check if the `ODEState` is valid for a given `JaxSimModel`.
264
248
 
265
249
  Args:
266
- model: The `JaxSimModel` to validate the `ODEState` against.
250
+ model: The model to validate this `ODEState` against.
267
251
 
268
252
  Returns:
269
253
  `True` if the ODE state is valid for the given model, `False` otherwise.
270
254
  """
271
255
 
272
- return self.physics_model.valid(model=model) and self.contact.valid(model=model)
256
+ # TODO: should we validate the extended state?
257
+ return self.physics_model.valid(model=model)
273
258
 
274
259
 
275
260
  # ==================================================
@@ -1,9 +1,5 @@
1
1
  from . import relaxed_rigid, rigid, soft
2
- from .common import ContactModel, ContactsParams, ContactsState
3
- from .relaxed_rigid import (
4
- RelaxedRigidContacts,
5
- RelaxedRigidContactsParams,
6
- RelaxedRigidContactsState,
7
- )
8
- from .rigid import RigidContacts, RigidContactsParams, RigidContactsState
9
- from .soft import SoftContacts, SoftContactsParams, SoftContactsState
2
+ from .common import ContactModel, ContactsParams
3
+ from .relaxed_rigid import RelaxedRigidContacts, RelaxedRigidContactsParams
4
+ from .rigid import RigidContacts, RigidContactsParams
5
+ from .soft import SoftContacts, SoftContactsParams
@@ -14,41 +14,6 @@ except ImportError:
14
14
  from typing_extensions import Self
15
15
 
16
16
 
17
- class ContactsState(JaxsimDataclass):
18
- """
19
- Abstract class storing the state of the contacts model.
20
- """
21
-
22
- @classmethod
23
- @abc.abstractmethod
24
- def build(cls: type[Self], **kwargs) -> Self:
25
- """
26
- Build the contact state object.
27
-
28
- Returns:
29
- The contact state object.
30
- """
31
- pass
32
-
33
- @classmethod
34
- @abc.abstractmethod
35
- def zero(cls: type[Self], **kwargs) -> Self:
36
- """
37
- Build a zero contact state.
38
-
39
- Returns:
40
- The zero contact state.
41
- """
42
- pass
43
-
44
- @abc.abstractmethod
45
- def valid(self, **kwargs) -> jtp.BoolLike:
46
- """
47
- Check if the contacts state is valid.
48
- """
49
- pass
50
-
51
-
52
17
  class ContactsParams(JaxsimDataclass):
53
18
  """
54
19
  Abstract class representing the parameters of a contact model.
@@ -88,6 +53,27 @@ class ContactModel(JaxsimDataclass):
88
53
  parameters: ContactsParams
89
54
  terrain: jaxsim.terrain.Terrain
90
55
 
56
+ @classmethod
57
+ @abc.abstractmethod
58
+ def build(
59
+ cls: type[Self],
60
+ parameters: ContactsParams,
61
+ terrain: jaxsim.terrain.Terrain,
62
+ **kwargs,
63
+ ) -> Self:
64
+ """
65
+ Create a `ContactModel` instance with specified parameters.
66
+
67
+ Args:
68
+ parameters: The parameters of the contact model.
69
+ terrain: The considered terrain.
70
+
71
+ Returns:
72
+ The `ContactModel` instance.
73
+ """
74
+
75
+ pass
76
+
91
77
  @abc.abstractmethod
92
78
  def compute_contact_forces(
93
79
  self,
@@ -109,6 +95,27 @@ class ContactModel(JaxsimDataclass):
109
95
 
110
96
  pass
111
97
 
98
+ @classmethod
99
+ def zero_state_variables(cls, model: js.model.JaxSimModel) -> dict[str, jtp.Array]:
100
+ """
101
+ Build zero state variables of the contact model.
102
+
103
+ Args:
104
+ model: The robot model considered by the contact model.
105
+
106
+ Note:
107
+ There are contact models that require to extend the state vector of the
108
+ integrated ODE system with additional variables. Our integrators are
109
+ capable of operating on a generic state, as long as it is a PyTree.
110
+ This method builds the zero state variables of the contact model as a
111
+ dictionary of JAX arrays.
112
+
113
+ Returns:
114
+ A dictionary storing the zero state variables of the contact model.
115
+ """
116
+
117
+ return {}
118
+
112
119
  def initialize_model_and_data(
113
120
  self,
114
121
  model: js.model.JaxSimModel,
@@ -11,11 +11,12 @@ import optax
11
11
 
12
12
  import jaxsim.api as js
13
13
  import jaxsim.typing as jtp
14
+ from jaxsim import logging
14
15
  from jaxsim.api.common import VelRepr
15
16
  from jaxsim.math import Adjoint
16
17
  from jaxsim.terrain.terrain import FlatTerrain, Terrain
17
18
 
18
- from .common import ContactModel, ContactsParams, ContactsState
19
+ from .common import ContactModel, ContactsParams
19
20
 
20
21
  try:
21
22
  from typing import Self
@@ -156,41 +157,46 @@ class RelaxedRigidContactsParams(ContactsParams):
156
157
  )
157
158
 
158
159
 
159
- @jax_dataclasses.pytree_dataclass
160
- class RelaxedRigidContactsState(ContactsState):
161
- """Class storing the state of the relaxed rigid contacts model."""
162
-
163
- def __eq__(self, other: RelaxedRigidContactsState) -> bool:
164
- return hash(self) == hash(other)
165
-
166
- @classmethod
167
- def build(cls: type[Self]) -> Self:
168
- """Create a `RelaxedRigidContactsState` instance"""
169
-
170
- return cls()
171
-
172
- @classmethod
173
- def zero(cls: type[Self], **kwargs) -> Self:
174
- """Build a zero `RelaxedRigidContactsState` instance from a `JaxSimModel`."""
175
-
176
- return cls.build()
177
-
178
- def valid(self, **kwargs) -> jtp.BoolLike:
179
- return True
180
-
181
-
182
160
  @jax_dataclasses.pytree_dataclass
183
161
  class RelaxedRigidContacts(ContactModel):
184
162
  """Relaxed rigid contacts model."""
185
163
 
186
164
  parameters: RelaxedRigidContactsParams = dataclasses.field(
187
- default_factory=RelaxedRigidContactsParams
165
+ default_factory=RelaxedRigidContactsParams.build
188
166
  )
189
167
 
190
168
  terrain: jax_dataclasses.Static[Terrain] = dataclasses.field(
191
- default_factory=FlatTerrain
169
+ default_factory=FlatTerrain.build
192
170
  )
193
171
 
172
+ @classmethod
173
+ def build(
174
+ cls: type[Self],
175
+ parameters: RelaxedRigidContactsParams | None = None,
176
+ terrain: Terrain | None = None,
177
+ **kwargs,
178
+ ) -> Self:
179
+ """
180
+ Create a `RelaxedRigidContacts` instance with specified parameters.
181
+
182
+ Args:
183
+ parameters: The parameters of the rigid contacts model.
184
+ terrain: The considered terrain.
185
+
186
+ Returns:
187
+ The `RelaxedRigidContacts` instance.
188
+ """
189
+
190
+ if len(kwargs) != 0:
191
+ logging.debug(msg=f"Ignoring extra arguments: {kwargs}")
192
+
193
+ return cls(
194
+ parameters=(
195
+ parameters or cls.__dataclass_fields__["parameters"].default_factory()
196
+ ),
197
+ terrain=terrain or cls.__dataclass_fields__["terrain"].default_factory(),
198
+ )
199
+
194
200
  @jax.jit
195
201
  def compute_contact_forces(
196
202
  self,
@@ -9,10 +9,11 @@ import jax_dataclasses
9
9
 
10
10
  import jaxsim.api as js
11
11
  import jaxsim.typing as jtp
12
+ from jaxsim import logging
12
13
  from jaxsim.api.common import ModelDataWithVelocityRepresentation, VelRepr
13
14
  from jaxsim.terrain import FlatTerrain, Terrain
14
15
 
15
- from .common import ContactModel, ContactsParams, ContactsState
16
+ from .common import ContactModel, ContactsParams
16
17
 
17
18
  try:
18
19
  from typing import Self
@@ -78,29 +79,6 @@ class RigidContactsParams(ContactsParams):
78
79
  )
79
80
 
80
81
 
81
- @jax_dataclasses.pytree_dataclass
82
- class RigidContactsState(ContactsState):
83
- """Class storing the state of the rigid contacts model."""
84
-
85
- def __eq__(self, other: RigidContactsState) -> bool:
86
- return hash(self) == hash(other)
87
-
88
- @classmethod
89
- def build(cls: type[Self]) -> Self:
90
- """Create a `RigidContactsState` instance"""
91
-
92
- return cls()
93
-
94
- @classmethod
95
- def zero(cls: type[Self], **kwargs) -> Self:
96
- """Build a zero `RigidContactsState` instance from a `JaxSimModel`."""
97
-
98
- return cls.build()
99
-
100
- def valid(self, **kwargs) -> jtp.BoolLike:
101
- return True
102
-
103
-
104
82
  @jax_dataclasses.pytree_dataclass
105
83
  class RigidContacts(ContactModel):
106
84
  """Rigid contacts model."""
@@ -110,9 +88,37 @@ class RigidContacts(ContactModel):
110
88
  )
111
89
 
112
90
  terrain: jax_dataclasses.Static[Terrain] = dataclasses.field(
113
- default_factory=FlatTerrain
91
+ default_factory=FlatTerrain.build
114
92
  )
115
93
 
94
+ @classmethod
95
+ def build(
96
+ cls: type[Self],
97
+ parameters: RigidContactsParams | None = None,
98
+ terrain: Terrain | None = None,
99
+ **kwargs,
100
+ ) -> Self:
101
+ """
102
+ Create a `RigidContacts` instance with specified parameters.
103
+
104
+ Args:
105
+ parameters: The parameters of the rigid contacts model.
106
+ terrain: The considered terrain.
107
+
108
+ Returns:
109
+ The `RigidContacts` instance.
110
+ """
111
+
112
+ if len(kwargs) != 0:
113
+ logging.debug(msg=f"Ignoring extra arguments: {kwargs}")
114
+
115
+ return cls(
116
+ parameters=(
117
+ parameters or cls.__dataclass_fields__["parameters"].default_factory()
118
+ ),
119
+ terrain=terrain or cls.__dataclass_fields__["terrain"].default_factory(),
120
+ )
121
+
116
122
  @staticmethod
117
123
  def detect_contacts(
118
124
  W_p_C: jtp.ArrayLike,
@@ -10,10 +10,11 @@ import jax_dataclasses
10
10
  import jaxsim.api as js
11
11
  import jaxsim.math
12
12
  import jaxsim.typing as jtp
13
+ from jaxsim import logging
13
14
  from jaxsim.math import StandardGravity
14
15
  from jaxsim.terrain import FlatTerrain, Terrain
15
16
 
16
- from .common import ContactModel, ContactsParams, ContactsState
17
+ from .common import ContactModel, ContactsParams
17
18
 
18
19
  try:
19
20
  from typing import Self
@@ -192,13 +193,67 @@ class SoftContacts(ContactModel):
192
193
  """Soft contacts model."""
193
194
 
194
195
  parameters: SoftContactsParams = dataclasses.field(
195
- default_factory=SoftContactsParams
196
+ default_factory=SoftContactsParams.build
196
197
  )
197
198
 
198
199
  terrain: jax_dataclasses.Static[Terrain] = dataclasses.field(
199
- default_factory=FlatTerrain
200
+ default_factory=FlatTerrain.build
200
201
  )
201
202
 
203
+ @classmethod
204
+ def build(
205
+ cls: type[Self],
206
+ parameters: SoftContactsParams | None = None,
207
+ terrain: Terrain | None = None,
208
+ model: js.model.JaxSimModel | None = None,
209
+ **kwargs,
210
+ ) -> Self:
211
+ """
212
+ Create a `SoftContacts` instance with specified parameters.
213
+
214
+ Args:
215
+ parameters: The parameters of the soft contacts model.
216
+ terrain: The considered terrain.
217
+ model:
218
+ The robot model considered by the contact model.
219
+ If passed, it is used to estimate good default parameters.
220
+
221
+ Returns:
222
+ The `SoftContacts` instance.
223
+ """
224
+
225
+ if len(kwargs) != 0:
226
+ logging.debug(msg=f"Ignoring extra arguments: {kwargs}")
227
+
228
+ # Build the contact parameters if not provided. Use the model to estimate
229
+ # good default parameters, if passed. Users can later override these default
230
+ # parameters with their own values -- possibly tuned better.
231
+ if parameters is None:
232
+ parameters = (
233
+ SoftContactsParams.build_default_from_jaxsim_model(model=model)
234
+ if model is not None
235
+ else cls.__dataclass_fields__["parameters"].default_factory()
236
+ )
237
+
238
+ return SoftContacts(
239
+ parameters=parameters,
240
+ terrain=terrain or cls.__dataclass_fields__["terrain"].default_factory(),
241
+ )
242
+
243
+ @classmethod
244
+ def zero_state_variables(cls, model: js.model.JaxSimModel) -> dict[str, jtp.Array]:
245
+ """
246
+ Build zero state variables of the contact model.
247
+ """
248
+
249
+ # Initialize the material deformation to zero.
250
+ tangential_deformation = jnp.zeros(
251
+ shape=(len(model.kin_dyn_parameters.contact_parameters.body), 3),
252
+ dtype=float,
253
+ )
254
+
255
+ return {"tangential_deformation": tangential_deformation}
256
+
202
257
  @staticmethod
203
258
  @functools.partial(jax.jit, static_argnames=("terrain",))
204
259
  def hunt_crossley_contact_model(
@@ -380,8 +435,7 @@ class SoftContacts(ContactModel):
380
435
  W_p_C, W_ṗ_C = js.contact.collidable_point_kinematics(model=model, data=data)
381
436
 
382
437
  # Extract the material deformation corresponding to the collidable points.
383
- assert isinstance(data.state.contact, SoftContactsState)
384
- m = data.state.contact.tangential_deformation
438
+ m = data.state.extended["tangential_deformation"]
385
439
 
386
440
  # Compute the contact forces for all collidable points.
387
441
  # Since we treat them as independent, we can vmap the computation.
@@ -423,131 +477,3 @@ class SoftContacts(ContactModel):
423
477
  δ̇ = jnp.where(δ > 0, δ̇, 0.0)
424
478
 
425
479
  return δ, δ̇, n̂
426
-
427
-
428
- @jax_dataclasses.pytree_dataclass
429
- class SoftContactsState(ContactsState):
430
- """
431
- Class storing the state of the soft contacts model.
432
-
433
- Attributes:
434
- tangential_deformation:
435
- The matrix of 3D tangential material deformations corresponding to
436
- each collidable point.
437
- """
438
-
439
- tangential_deformation: jtp.Matrix
440
-
441
- def __hash__(self) -> int:
442
-
443
- return hash(
444
- tuple(jnp.atleast_1d(self.tangential_deformation.flatten()).tolist())
445
- )
446
-
447
- def __eq__(self: Self, other: Self) -> bool:
448
-
449
- if not isinstance(other, type(self)):
450
- return False
451
-
452
- return hash(self) == hash(other)
453
-
454
- @classmethod
455
- def build_from_jaxsim_model(
456
- cls: type[Self],
457
- model: js.model.JaxSimModel | None = None,
458
- tangential_deformation: jtp.MatrixLike | None = None,
459
- ) -> Self:
460
- """
461
- Build a `SoftContactsState` from a `JaxSimModel`.
462
-
463
- Args:
464
- model: The `JaxSimModel` associated with the soft contacts state.
465
- tangential_deformation: The matrix of 3D tangential material deformations.
466
-
467
- Returns:
468
- The `SoftContactsState` built from the `JaxSimModel`.
469
-
470
- Note:
471
- If any of the state components are not provided, they are built from the
472
- `JaxSimModel` and initialized to zero.
473
- """
474
-
475
- return cls.build(
476
- tangential_deformation=tangential_deformation,
477
- number_of_collidable_points=len(
478
- model.kin_dyn_parameters.contact_parameters.body
479
- ),
480
- )
481
-
482
- @classmethod
483
- def build(
484
- cls: type[Self],
485
- *,
486
- tangential_deformation: jtp.MatrixLike | None = None,
487
- number_of_collidable_points: int | None = None,
488
- ) -> Self:
489
- """
490
- Create a `SoftContactsState`.
491
-
492
- Args:
493
- tangential_deformation:
494
- The matrix of 3D tangential material deformations corresponding to
495
- each collidable point.
496
- number_of_collidable_points: The number of collidable points.
497
-
498
- Returns:
499
- A `SoftContactsState` instance.
500
- """
501
-
502
- tangential_deformation = (
503
- jnp.atleast_2d(tangential_deformation)
504
- if tangential_deformation is not None
505
- else jnp.zeros(shape=(number_of_collidable_points, 3))
506
- ).astype(float)
507
-
508
- if tangential_deformation.shape[1] != 3:
509
- raise RuntimeError("The tangential deformation matrix must have 3 columns.")
510
-
511
- if (
512
- number_of_collidable_points is not None
513
- and tangential_deformation.shape[0] != number_of_collidable_points
514
- ):
515
- msg = "The number of collidable points must match the number of rows "
516
- msg += "in the tangential deformation matrix."
517
- raise RuntimeError(msg)
518
-
519
- return cls(tangential_deformation=tangential_deformation)
520
-
521
- @classmethod
522
- def zero(cls: type[Self], *, model: js.model.JaxSimModel) -> Self:
523
- """
524
- Build a zero `SoftContactsState` from a `JaxSimModel`.
525
-
526
- Args:
527
- model: The `JaxSimModel` associated with the soft contacts state.
528
-
529
- Returns:
530
- A zero `SoftContactsState` instance.
531
- """
532
-
533
- return cls.build_from_jaxsim_model(model=model)
534
-
535
- def valid(self, *, model: js.model.JaxSimModel) -> jtp.BoolLike:
536
- """
537
- Check if the `SoftContactsState` is valid for a given `JaxSimModel`.
538
-
539
- Args:
540
- model: The `JaxSimModel` to validate the `SoftContactsState` against.
541
-
542
- Returns:
543
- `True` if the soft contacts state is valid for the given `JaxSimModel`,
544
- `False` otherwise.
545
- """
546
-
547
- shape = self.tangential_deformation.shape
548
- expected = (len(model.kin_dyn_parameters.contact_parameters.body), 3)
549
-
550
- if shape != expected:
551
- return False
552
-
553
- return True
jaxsim/terrain/terrain.py CHANGED
@@ -49,7 +49,7 @@ class FlatTerrain(Terrain):
49
49
  _height: float = dataclasses.field(default=0.0, kw_only=True)
50
50
 
51
51
  @staticmethod
52
- def build(height: jtp.FloatLike) -> FlatTerrain:
52
+ def build(height: jtp.FloatLike = 0.0) -> FlatTerrain:
53
53
 
54
54
  return FlatTerrain(_height=float(height))
55
55
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaxsim
3
- Version: 0.4.3.dev143
3
+ Version: 0.4.3.dev155
4
4
  Summary: A differentiable physics engine and multibody dynamics library for control and robot learning.
5
5
  Author-email: Diego Ferigo <dgferigo@gmail.com>
6
6
  Maintainer-email: Diego Ferigo <dgferigo@gmail.com>, Filippo Luca Ferretti <filippo.ferretti@iit.it>
@@ -1,20 +1,20 @@
1
1
  jaxsim/__init__.py,sha256=bSbpggIz5aG6QuGZLa0V2EfHjAOeucMxi-vIYxzLmN8,2788
2
- jaxsim/_version.py,sha256=AUMtPwp-9k4PBssfGUg1S2TuNzVQkbYfnNIjR31wCZY,428
2
+ jaxsim/_version.py,sha256=WSWbOCEqJEvWRVjlIX5RELDmw5i2N3-iPI-UwySVbMI,428
3
3
  jaxsim/exceptions.py,sha256=8_h8iqL8DgNR754dR8SZiQ7361GR5V1sUk3ZuZCHw1Q,2069
4
4
  jaxsim/logging.py,sha256=STI-D_upXZYX-ZezLrlJJ0UlD5YspST0vZ_DcIwkzO4,1553
5
5
  jaxsim/typing.py,sha256=2HXy9hgazPXjofi1vLQ09ZubPtgVmg80U9NKmZ6NYiI,761
6
6
  jaxsim/api/__init__.py,sha256=8eV22t2S3UwNyCg8karPetG1dmX1VDBXkyv28_FwNQA,210
7
7
  jaxsim/api/com.py,sha256=m-p3EJDhpnMTlXKplfbZE_aH9NqX_VyLlAE3vUhc6l4,13642
8
8
  jaxsim/api/common.py,sha256=SNgxq42r6eF_-aPszvOjUYkGwXOzz4hKmhDwEUkscFQ,6650
9
- jaxsim/api/contact.py,sha256=ktol-c2UHDqt3Hd6NpMhK86NlyadIyB5eY7chA5GhkY,22568
10
- jaxsim/api/data.py,sha256=bSuBVKKksYtANLnxCkMQ3u2JGbn5mud7g8G5aLZawls,28988
9
+ jaxsim/api/contact.py,sha256=P4Z_nuhz0Js6iK3lywbnpR3hfBgM2IXzwx9cHJL9W2g,22237
10
+ jaxsim/api/data.py,sha256=kDP1s5mm8F-LpIqKrdaCmHhJEMyigFDyuaAXdMukhWY,29588
11
11
  jaxsim/api/frame.py,sha256=KS8A5wRfjxhe9NgcVo2QA516iP5zky7UVnWxG7nTa7c,12911
12
12
  jaxsim/api/joint.py,sha256=lksT1Doxz2jknHyhb4ls20z6f6dofpZSzBJtVacZXAE,7129
13
13
  jaxsim/api/kin_dyn_parameters.py,sha256=ElahFk_RCcLvjTidH2qDOsY-m1gN1hXitCv4SvfgGYY,29260
14
14
  jaxsim/api/link.py,sha256=LAA6ZMQXkWomXeptURBtc7z3_xDZ2BBnBMhVrohh0bE,18621
15
- jaxsim/api/model.py,sha256=Y0A9p7uKpfBdZLC9o_pTw7WQrmAaNJJBK1G97YkDRjQ,68260
16
- jaxsim/api/ode.py,sha256=B9CANQGLbrKAkmTxvWvkb0UGKC__r1nlHf-bGw963q0,13999
17
- jaxsim/api/ode_data.py,sha256=6q3IECaA351hLSGRovrOSKLo_P8IhJrW-p2-ZDlzGG8,20436
15
+ jaxsim/api/model.py,sha256=IcJhFdVjswSncurVpQXoa7uXVqSsvAuZVs-DXDsXi08,69021
16
+ jaxsim/api/ode.py,sha256=_rTgDVNLQWbZ-E8ApKbq4JQ6ctCcQeDvCzAf6d35hY8,14061
17
+ jaxsim/api/ode_data.py,sha256=1SD-x-lYk_YSEnVpxTLd69uOKC0mFUj44ZqpSmEDOxw,20190
18
18
  jaxsim/api/references.py,sha256=fW77LitZ8DYgT6ZmUInJfm5luBV1mTcqcNRiC_i79og,20862
19
19
  jaxsim/integrators/__init__.py,sha256=hxvOD-VK_mmd6v31wtC-nb28AYve1gLuZCNLV9wS-Kg,103
20
20
  jaxsim/integrators/common.py,sha256=78MBs89GxsL0wU2yAexjvBZt3HEtfZoGVIN9f0a8yTc,20305
@@ -52,19 +52,19 @@ jaxsim/rbda/forward_kinematics.py,sha256=2GmEoWsrioVl_SAbKRKfhOLz57pY4aR81PKRdul
52
52
  jaxsim/rbda/jacobian.py,sha256=p0EV_8cLzLVV-93VKznT7VPuRj8W7h7rQWkPlWJXfCA,11023
53
53
  jaxsim/rbda/rnea.py,sha256=CLfqs9XFVaD-hvkLABshDAfdw5bm_AMV3UVAQ_IvURQ,7542
54
54
  jaxsim/rbda/utils.py,sha256=eeT21Y4DiiyhrdF0lUE_VvRuwru5-rR7yOlOlWzCCWE,5381
55
- jaxsim/rbda/contacts/__init__.py,sha256=0UnO9ZR3BwdjQa276jOFbPi90pporr32LSc0qa9UUm4,369
56
- jaxsim/rbda/contacts/common.py,sha256=-eM8d1kvJ2E_2_kAgZJk4s3x8vDZHNSyOAinwPmRmEk,3469
57
- jaxsim/rbda/contacts/relaxed_rigid.py,sha256=G3NoFrIGqzr_hrScLtsbmliTSqcVxDxheA1w2HRcU7A,15794
58
- jaxsim/rbda/contacts/rigid.py,sha256=WzPPo_UACOo_7olv_R1PelRjdjGqdWHkQ6hkSSfdBZk,15689
59
- jaxsim/rbda/contacts/soft.py,sha256=NzzCYw5rvK8Fx_qH3fiMzPgey-KoxmRe9xkF3fluidE,18866
55
+ jaxsim/rbda/contacts/__init__.py,sha256=Vqtk2GeSAXh6YxiqadY-fe4PY__IUYiOwnLgSdpLqW0,271
56
+ jaxsim/rbda/contacts/common.py,sha256=N8iP8Ey2ljsLPn0fjGwoJxm4DDkMzSIRvKjgR2Eek6Y,4000
57
+ jaxsim/rbda/contacts/relaxed_rigid.py,sha256=3xGxKGXSH9UMpHPlU5M7daAFgT0KefV6UaMfMVSDrEw,15999
58
+ jaxsim/rbda/contacts/rigid.py,sha256=YsHt5P2S45ZkaXG1xwqU8He3gMuy4-EPY3LrxxWd8xA,15903
59
+ jaxsim/rbda/contacts/soft.py,sha256=TMCUDtFmNIae04LCla57iXMjdt9F5qTFjYEnP5NdLFg,16809
60
60
  jaxsim/terrain/__init__.py,sha256=f7lVX-iNpH_wkkjef9Qpjh19TTAUOQw76EiLYJDVizc,78
61
- jaxsim/terrain/terrain.py,sha256=Y0TGnUAGPuaeeSN8vbaSFjMXP5GYy3nxMCETjpUIMSA,5009
61
+ jaxsim/terrain/terrain.py,sha256=K91HEzPqTSyNrc_j1KfAAEF_5oDeuk_-jnnZGrcMEcY,5015
62
62
  jaxsim/utils/__init__.py,sha256=Y5zyoRevl3EMVQadhZ4EtSwTEkDt2vcnFoRhPJjKTZ0,215
63
63
  jaxsim/utils/jaxsim_dataclass.py,sha256=TGmTQV2Lq7Q-2nLoAEaeNtkPa_qj0IKkdBm4COj46Os,11312
64
64
  jaxsim/utils/tracing.py,sha256=KDMoyVPlu2NJvFkhtZwq5AkqMMgajt3munvJom-vEjQ,650
65
65
  jaxsim/utils/wrappers.py,sha256=Fh82ZcaFi5fUnByyFLnmumaobsu1hJIvFdopUVzJ1ps,4052
66
- jaxsim-0.4.3.dev143.dist-info/LICENSE,sha256=eaYdFmdeMbiIoIiPzEK0MjP1S9wtFXjXNR5er49uLR0,1546
67
- jaxsim-0.4.3.dev143.dist-info/METADATA,sha256=jZMIz7kCovjDtiHxhrp18oWpaYUhdX8t056wtbTv1us,17276
68
- jaxsim-0.4.3.dev143.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
69
- jaxsim-0.4.3.dev143.dist-info/top_level.txt,sha256=LxGMA8FLtXjQ6oI7N5gd_R_oSUHxpXxUEOfT1xS_ni0,7
70
- jaxsim-0.4.3.dev143.dist-info/RECORD,,
66
+ jaxsim-0.4.3.dev155.dist-info/LICENSE,sha256=eaYdFmdeMbiIoIiPzEK0MjP1S9wtFXjXNR5er49uLR0,1546
67
+ jaxsim-0.4.3.dev155.dist-info/METADATA,sha256=hodSp7KB07WWEmArLaUgmaXo7m1koUARPS8fhlzztj8,17276
68
+ jaxsim-0.4.3.dev155.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
69
+ jaxsim-0.4.3.dev155.dist-info/top_level.txt,sha256=LxGMA8FLtXjQ6oI7N5gd_R_oSUHxpXxUEOfT1xS_ni0,7
70
+ jaxsim-0.4.3.dev155.dist-info/RECORD,,