motornet.effectors#

class motornet.effector.CompliantTendonArm26(timestep=0.0002, skeleton=None, muscle_kwargs: dict = {}, **kwargs)#

Bases: RigidTendonArm26

This is the compliant-tendon version of the RigidTendonArm26 class. Note that the default integration method is Runge-Kutta 4, instead of Euler.

Parameters:
  • timestepFloat, size of a single timestep (in sec).

  • skeleton – A motornet.skeleton.Skeleton object class or subclass. This defines the type of skeleton that the muscles will wrap around. If no skeleton is passed, this will default to the skeleton used in the parent RigidTendonArm26 class.

  • **kwargs – All contents are passed to the parent RigidTendonArm26 class. This also allows for some backward compatibility.

class motornet.effector.Effector(skeleton, muscle, name: str = 'Effector', n_ministeps: int = 1, timestep: float = 0.01, integration_method: str = 'euler', damping: float = 0.0, pos_lower_bound: float | list | tuple | None = None, pos_upper_bound: float | list | tuple | None = None, vel_lower_bound: float | list | tuple | None = None, vel_upper_bound: float | list | tuple | None = None)#

Bases: Module

Base class for Effector objects.

Parameters:
  • skeleton – A motornet.skeleton.Skeleton object class or subclass. This defines the type of skeleton that the muscles will wrap around.

  • muscle – A motornet.muscle.Muscle object class or subclass. This defines the type of muscle that will be added each time the add_muscle() method is called.

  • nameString, the name of the object instance.

  • timestepFloat, size of a single timestep (in sec).

  • Integer (n_ministeps") – across ministeps.

  • constant (number of integration ministeps per timestep. This assumes the action input is) – across ministeps.

  • integration_methodString, “euler” to specify that numerical integration should be done using the Euler method, or “rk4”, “rungekutta4”, “runge-kutta4”, or “runge-kutta-4” to specify the Runge-Kutta 4 method instead. This argument is case-insensitive.

  • dampingFloat, the damping coefficient applied at each joint, proportional to joint velocity. This value should be positive to reduce joint torques proportionally to joint velocity.

  • pos_upper_boundFloat, list or tuple, indicating the upper boundary of the skeleton’s joint position. This should be a n-elements vector or list, with n the number of joints of the skeleton. For instance, for a two degrees-of-freedom arm, we would have n=2.

  • pos_lower_boundFloat, list or tuple, indicating the lower boundary of the skeleton’s joint position. This should be a n-elements vector or list, with n the number of joints of the skeleton. For instance, for a two degrees-of-freedom arm, we would have n=2.

  • vel_upper_boundFloat, list or tuple, indicating the upper boundary of the skeleton’s joint velocity. This should be a n-elements vector or list, with n the number of joints of the skeleton. For instance, for a two degrees-of-freedom arm, we would have n=2.

  • vel_lower_boundFloat, list or tuple, indicating the lower boundary of the skeleton’s joint velocity. This should be a n-elements vector or list, with n the number of joints of the skeleton. For instance, for a two degrees-of-freedom arm, we would have n=2.

add_muscle(path_fixation_body: list, path_coordinates: list, name: str | None = None, **kwargs)#

Adds a muscle to the effector.

Parameters:
  • path_fixation_bodyList, containing the index of the fixation body (or fixation bone) for each fixation point in the muscle. The index 0 always stands for the worldspace, i.e. a fixation point outside of the skeleton.

  • path_coordinates – A List of lists. There should be as many lists in the main list as there are fixation points for that muscle. Each nested list within the main list should contain a series of n coordinate float values, with n being the dimensionality of the worldspace. For instance, in a 2D environment, we would need two coordinate values. The coordinate system of each bone is centered on that bone’s origin point. Its first dimension is always alongside the length of the bone, and the next dimension(s) proceed(s) from there on orthogonally to that first dimension.

  • nameString, the name to give to the muscle being added. If None is given, the name defaults to “muscle_m”, with m being a counter for the number of muscles.

  • **kwargs – This is used to pass the set of properties required to build the type of muscle specified at initialization. What it should contain varies depending on the muscle type being used. A TypeError will be raised by this method if a muscle property pertaining to the muscle type specified is missing.

Raises:

TypeError – If an argument is missing to build the type of muscle specified at initialization.

draw_fixed_states(batch_size, position, velocity=None)#

Creates a joint state tensor corresponding to the specified position, tiled batch_size times.

Parameters:
  • position – The position to tile in the state tensor.

  • velocity – The velocity to tile in the state tensor. If None, this will default to 0 (null velocity).

  • batch_sizeInteger, the desired batch size.

Returns:

A tensor containing batch_size joint states.

draw_random_uniform_states(batch_size)#

Draws joint states according to a random uniform distribution, bounded by the position and velocity boundary attributes defined at initialization.

Parameters:

batch_sizeInteger, the desired batch size.

Returns:

A tensor containing batch_size joint states.

get_geometry(joint_state)#

Computes the geometry state from the joint state. Geometry state dimensionality is [n_batch, n_timesteps, n_states, n_muscles]. By default, there are as many states as there are moments (that is, one per degree of freedom in the effector) plus two for musculotendon length and musculotendon velocity. However, note that how many states and what they represent may vary depending on the Effector subclass. This should be available via the geometry_state_names attribute.

Parameters:

joint_stateTensor, the joint state from which the geometry state is computed.

Returns:

The geometry state corresponding to the joint state provided.

get_muscle_cfg()#

Gets the wrapping configuration of muscles added through the add_muscle() method.

Returns:

A dictionary containing a key for each muscle name, associated to a nested dictionary containing information fo that muscle.

get_save_config()#

Gets the effector object’s configuration as a dictionary.

Returns:

A dictionary containing the skeleton and muscle configurations as nested dictionary objects, and parameters of the effector’s configuration. Specifically, the size of the timestep (sec), the name of each muscle added via the add_muscle() method, the number of muscles, the visual and proprioceptive delay, the standard deviation of the excitation noise, and the muscle wrapping configuration as returned by get_muscle_cfg().

integrate(action, endpoint_load, joint_load)#

Integrates the effector over one timestep. To do so, it first calls the update_ode() method to obtain state derivatives from evaluation of the Ordinary Differential Equations. Then it performs the numerical integration over one timestep using the integration_step() method, and updates the states to the resulting values.

Parameters:
  • actionTensor, the input to the muscles (motor command). Typically, this should be the output of the controller or policy network’s forward pass.

  • endpoint_loadTensor, the load(s) to apply at the skeleton’s endpoint.

  • joint_loadTensor, the load(s) to apply at the joints.

integration_step(dt, state_derivative, states)#

Performs one numerical integration step for the motornet.muscle.Muscle object class or subclass, and then for the motornet.skeleton.Skeleton object class or subclass.

Parameters:
  • dtFloat, size of a single timestep (in sec).

  • state_derivativeDictionary, contains the derivatives of the joint, muscle, and geometry states as tensor arrays, mapped to a “joint”, “muscle”, and “geometry” key, respectively. This is usually obtained using the update_ode() method.

  • states – A Dictionary containing the joint, muscle, and geometry states as Tensor, mapped to a “joint”, “muscle”, and “geometry” key, respectively.

Returns:

A dictionary containing the updated joint, muscle, and geometry states following integration.

joint2cartesian(joint_state: Tensor) Tensor#

Computes the cartesian state given the joint state.

Parameters:

joint_stateTensor, the current joint configuration.

Returns:

The current cartesian configuration (position, velocity) as a tensor.

ode(action, states, endpoint_load, joint_load)#

Computes state derivatives by evaluating the Ordinary Differential Equations of the motornet.muscle.Muscle object class or subclass, and then of the motornet.skeleton.Skeleton object class or subclass.

Parameters:
  • actionTensor, the input to the muscles (motor command). Typically, this should be the output of the controller or policy network’s forward pass.

  • statesDictionary contains the joint, muscle, and geometry states as Tensor, mapped to a “joint”, “muscle”, and “geometry” key, respectively.

  • endpoint_loadTensor, the load(s) to apply at the skeleton’s endpoint.

  • joint_loadTensor, the load(s) to apply at the joints.

Returns:

A dictionary containing the derivatives of the the joint, muscle, and geometry states as Tensor, mapped to a “joint”, “muscle”, and “geometry” key, respectively.

print_muscle_wrappings()#

Prints the wrapping configuration of the muscles added using the add_muscle() method in a readable format.

reset(*, seed: int | None = None, options: dict[str, Any] | None = None)#

Sets initial states (joint, cartesian, muscle, geometry) that are biomechanically compatible with each other.

Parameters:
  • seedInteger, the seed that is used to initialize the environment’s PRNG (np_random). If the environment does not already have a PRNG and seed=None (the default option) is passed, a seed will be chosen from some source of entropy (e.g. timestamp or /dev/urandom). However, if the environment already has a PRNG and seed=None is passed, the PRNG will not be reset. If you pass an integer, the PRNG will be reset even if it already exists. Usually, you want to pass an integer right after the environment has been initialized and then never again.

  • optionsDictionary, optional kwargs. This is mainly useful to pass batch_size and joint_state kwargs if desired, as described below.

Options:
  • batch_size: Integer, the desired batch size. Default: 1.

  • joint_state: The joint state from which the other state values are inferred. If None, random initial joint states are drawn, from which the other state values are inferred. Default: None.

setattr(name: str, value)#

Changes the value of an attribute held by this object.

Parameters:
  • nameString, attribute to set to a new value.

  • value – Value that the attribute should take.

step(action, **kwargs)#
class motornet.effector.ReluPointMass24(timestep: float = 0.01, max_isometric_force: float = 500, mass: float = 1, **kwargs)#

Bases: Effector

This object implements a 2D point-mass skeleton attached to 4 motornet.muscle.ReluMuscle muscles in a “X” configuration. The outside attachement points are the corners of a (2, 2) -> (2, -2) -> (-2, -2) -> (-2, 2) frame, and the point-mass is constrained to a (1, 1) -> (1, -1) -> (-1, -1) -> (-1, 1) space.

Parameters:
  • timestepFloat, size of a single timestep (in sec).

  • max_isometic_forceFloat, the maximum force (N) that each muscle can produce.

  • massFloat, the mass (kg) of the point-mass.

  • **kwargs – The kwargs inputs are passed as-is to the parent motornet.Effector class.

class motornet.effector.RigidTendonArm26(muscle, skeleton=None, timestep=0.01, muscle_kwargs: dict = {}, **kwargs)#

Bases: Effector

This pre-built effector class is an implementation of a 6-muscles, “lumped-muscle” model from [1]. Because lumped-muscle models are functional approximations of biological reality, this class’ geometry does not rely on the default geometry methods, but on its own, custom-made geometry. The moment arm approximation is based on a set of polynomial functions. The default integration method is Euler.

If no skeleton input is provided, this object will use a motornet.skeleton.TwoDofArm skeleton, with the following parameters (from [1]):

  • m1 = 1.82

  • m2 = 1.43

  • l1g = 0.135

  • l2g = 0.165

  • i1 = 0.051

  • i2 = 0.057

  • l1 = 0.309

  • l2 = 0.333

The default shoulder and elbow lower limits are defined as 0, and their default upper limits as 135 and 155 degrees, respectively.

The kwargs inputs are passed as-is to the parent Effector class.

References

[1] Nijhof, E.-J., & Kouwenhoven, E. Simulation of Multijoint Arm Movements (2000). In J. M. Winters & P. E. Crago, Biomechanics and Neural Control of Posture and Movement (pp. 363–372). Springer New York. doi: 10.1007/978-1-4612-2104-3_29

Parameters:
  • muscle – A motornet.muscle.Muscle object class or subclass. This defines the type of muscle that will be added each time the add_muscle() method is called.

  • skeleton – A motornet.skeleton.Skeleton object class or subclass. This defines the type of skeleton that the muscles will wrap around. See above for details on what this argument defaults to if no argument is passed.

  • timestepFloat, size of a single timestep (in sec).

  • muscle_kwargsDictionary, contains the muscle parameters to be passed to the motornet.muscle.Muscle.build() method.()

  • **kwargs – All contents are passed to the parent Effector class. Also allows for some backward compatibility.