motornet.plants#
Module contents#
This package contains the classes and subclasses used to create the plants that a model will be trained to control.
Plants are implemented as subclasses of the motornet.plants.plants.Plant
object. They all contain a single
motornet.plants.skeletons.Skeleton
and motornet.plants.muscles.Muscle
subclass defining the
biomechanical properties of that Plant object. The Plant object itself implements the numerical integration
routines, some of the geometry state calculation routines (in conjunction with the Skeleton object), applies moment
arms to produce generalized forces, and generally handles communication between the Skeleton and Muscle objects.
Note
While Plant objects are technically implemented in the motornet.plants.plants
module, it is possible
(and recommended) to call them using the motornet.plants.Plant
path, which is more concise and strictly
equivalent.
motornet.plants.muscles#
motornet.plants.skeletons#
motornet.plants#
- class motornet_tf.plants.plants.CompliantTendonArm26(timestep=0.0002, skeleton=None, **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:
timestep – Float, size of a single timestep (in sec).
skeleton – A
motornet.plants.skeletons.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 parentRigidTendonArm26
class.**kwargs – All contents are passed to the parent
RigidTendonArm26
class. This also allows for some backward compatibility.
- class motornet_tf.plants.plants.Plant(skeleton, muscle_type, timestep: float = 0.01, integration_method: str = 'euler', excitation_noise_sd: float = 0.0, proprioceptive_delay: float | None = None, visual_delay: float | None = None, 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, name: str = 'Plant')#
Bases:
object
Base class for Plant objects.
- Parameters:
skeleton – A
motornet.plants.skeletons.Skeleton
object class or subclass. This defines the type of skeleton that the muscles will wrap around.muscle_type – A
motornet.plants.muscles.Muscle
object class or subclass. This defines the type of muscle that will be added each time theadd_muscle()
method is called.name – String, the name of the object instance.
timestep – Float, size of a single timestep (in sec).
integration_method – String, “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.
excitation_noise_sd – Float, defines the amount of stochastic noise that will be added to the excitation input during the
call()
. Specifically, this value represents the standard deviation of a gaussian distribution centred around zero, from which a noise term is drawn randomly at every timestep.proprioceptive_delay – Float, the delay between a proprioceptive signal being produced by the plant and the network receiving it as input. If this is not a multiple of the timestep size, this will be rounded up to match the closest multiple value. What qualifies as “proprioceptive feedback” is defined at the network level.
visual_delay – Float, the delay between a visual signal being produced by the plant and the network receiving it as input. If this is not a multiple of the timestep size, this will be rounded up to match the closest multiple value. What qualifies as “visual feedback” is defined at the network level.
pos_upper_bound – Float, 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_bound – Float, 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_bound – Float, 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_bound – Float, 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 plant.
- Parameters:
path_fixation_body – List, 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.
name – String, 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(position, velocity=None, batch_size=1)#
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_size – Integer, the desired batch size.
- Returns:
A tensor containing batch_size joint states.
- draw_random_uniform_states(batch_size: int = 1)#
Draws joint states according to a random uniform distribution, bounded by the position and velocity boundary attributes defined at initialization.
- Parameters:
batch_size – Integer, the desired batch size.
- Returns:
A tensor containing batch_size joint states.
- get_geometry(joint_state)#
Computes the geometry state from the 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 plant) plus two for musculotendon length and musculotendon velocity. However, note that how many states and what they represent may vary depending on the
Plant
subclass. This should be available via thegeometry_state_names
attribute.- Parameters:
joint_state – Tensor, the joint state from which the geometry state is computed.
- Returns:
The geometry state corresponding to the joint state provided.
- get_initial_state(batch_size=1, joint_state=None)#
Gets initial states (joint, cartesian, muscle, geometry) that are biomechanically compatible with each other.
- Parameters:
batch_size – Integer, the desired batch size.
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.
- Returns:
A list containing the joint state, and cartesian, muscle, and geometry states, in that order. If a joint_state input was provided, the joint state in the returned list will be the same as the input.
- Raises:
ValueError – If the batch_size value is not specified and either the joint_state input is None or the size of joint_state input’s first dimension is equal to 1.
- 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 plant object’s configuration as a dictionary.
- Returns:
A dictionary containing the skeleton and muscle configurations as nested dictionary objects, and parameters of the plant’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 byget_muscle_cfg()
.
- integrate(muscle_input, joint_state, muscle_state, geometry_state, endpoint_load, joint_load)#
Integrates the plant 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 theintegration_step()
method.- Parameters:
muscle_input – Tensor, the input to the muscles (motor command). Typically, this should be the output of the controller network’s forward pass.
joint_state – Tensor, the initial state for joint configuration.
muscle_state – Tensor, the initial state for muscle configuration.
geometry_state – Tensor, the initial state for geometry configuration.
endpoint_load – Tensor, the load(s) to apply at the skeleton’s endpoint.
joint_load – Tensor, the load(s) to apply at the joints.
- Returns:
A list containing the new joint, muscle, and geometry states following integration, in that order.
- integration_step(dt, state_derivative, states)#
Performs one numerical integration step for the
motornet.plants.muscles.Muscle
object class or subclass, and then for themotornet.plants.skeletons.Skeleton
object class or subclass.- Parameters:
dt – Float, size of a single timestep (in sec).
state_derivative – Dictionary, 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)#
Computes the cartesian state given the joint state.
- Parameters:
joint_state – Tensor, the current joint configuration.
- Returns:
The current cartesian configuration (position, velocity) as a tensor.
- print_muscle_wrappings()#
Prints the wrapping configuration of the muscles added using the
add_muscle()
method in a readable format.
- setattr(name: str, value)#
Changes the value of an attribute held by this object.
- Parameters:
name – String, attribute to set to a new value.
value – Value that the attribute should take.
- state2target(state, n_timesteps: int = 1)#
Converts a tensor formatted as a state to a tensor formatted as a target that can be passed to a
tensorflow.keras.Model.fit()
call.- Parameters:
state – Tensor, the state to be converted to a target.
n_timesteps – Integer, the number of timesteps desired for creating the target tensor.
- Returns:
A tensor that can be used as a target input to the
tensorflow.keras.Model.fit()
method.
- update_ode(excitation, states, endpoint_load, joint_load)#
Computes state derivatives by evaluating the Ordinary Differential Equations of the
motornet.plants.muscles.Muscle
object class or subclass, and then of themotornet.plants.skeletons.Skeleton
object class or subclass.- Parameters:
excitation – Tensor, the input to the muscles (motor command). Typically, this should be the output of the controller network’s forward pass.
states – Dictionary, contains the joint, muscle, and geometry states as tensor arrays, mapped to a “joint”, “muscle”, and “geometry” key, respectively.
endpoint_load – Tensor, the load(s) to apply at the skeleton’s endpoint.
joint_load – Tensor, the load(s) to apply at the joints.
- Returns:
A list containing the new joint, muscle, and geometry states following integration, in that order.
- class motornet_tf.plants.plants.ReluPointMass24(timestep: float = 0.01, max_isometric_force: float = 500, mass: float = 1, **kwargs)#
Bases:
Plant
This object implements a 2D point-mass skeleton attached to 4
motornet.plants.muscles.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:
timestep – Float, size of a single timestep (in sec).
max_isometic_force – Float, the maximum force (N) that each muscle can produce.
mass – Float, the mass (kg) of the point-mass.
**kwargs – The kwargs inputs are passed as-is to the parent
motornet.plants.Plant
class.
- class motornet_tf.plants.plants.RigidTendonArm26(muscle_type, skeleton=None, timestep=0.01, **kwargs)#
Bases:
Plant
This pre-built plant 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.plants.skeletons.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
Plant
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_type – A
motornet.plants.muscles.Muscle
object class or subclass. This defines the type of muscle that will be added each time theadd_muscle()
method is called.skeleton – A
motornet.plants.skeletons.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.timestep – Float, size of a single timestep (in sec).
**kwargs – All contents are passed to the parent
Plant
class. Also allows for some backward compatibility.