URAEUS  SMBD
Symbolic MultiBody Dynamics in Python  A python package for symbolic creation and analysis of constrained multibody systems
Description
uraeus.smbd is a python package developed for the symbolic creation and analysis of constrained multibody systems.
A multibody system is hereby defined as a finite number of material bodies connected in an arbitrary fashion by mechanical joints that limit the relative motion between pairs of bodies. Practitioners of multibody dynamics study the generation and solution of the equations governing the motion of such systems [1].
Audience and Fields of Application
Initially, the main targeted audience was the Formula Student community. The motive was encouraging a deeper understanding of the modelling processes and the underlying theories used in other commercial software packages, which is a way of giving back to the community, and supporting the concept of "knowledge share" adopted there by exposing it to the opensource community as well.
Currently, the tool aims to serve a wider domain of users with different usage goals and different backgrounds, such as students, academic researchers and industry professionals.
Fields of application include any domain that deals with the study of interconnected bodies, such as:
 Ground Vehicles' Systems.
 Construction Equipment.
 Industrial Mechanisms.
 Robotics.
 Biomechanics.
 .. etc.
Features
Currently, the tool provides:
 Creation of symbolic templatebased and standalone multibody systems using minimal API via python scripting.
 Convenient and easy creation of complex multibody assemblies.
 Convenient visualization of the system topology as a network graph.
 Viewing the system's symbolic equations in a natural mathematical format using Latex printing.
 Optimization of the system symbolic equations by performing common subexpressions elimination.
 Creation of symbolic configuration files to facilitate the process of numerical simulation data entry.
Installation
Colab
Using the tool onColaboratory is a free Jupyter notebook environment that requires no setup and runs entirely in the cloud [2]. So, if you do not have an up and running python environment, you still can check out the tool and create multibody systems seamlessly.
The examples section below, has several readytouse Colab notebooks that walks you through a typical modelling process flow.
Using the tool on your machine.
The tool needs a valid python 3.6+ environment. If new to scientific computing in python, Anaconda is a recommended free python distribution from Continuum Analytics that includes SymPy, SciPy, NumPy, Matplotlib, and many more useful packages for scientific computing, which provides a nice coherent platform with most of the tools needed.
Git
As the tool is still under continuous development, cloning this repository is a more versatile way to test and play with it, until a more stable first release is released. This can be done via the following git commands from the command line.
$ git clone https://github.com/khaledghobashy/uraeus.git
$ git pull origin master
Or alternatively, download the repository as a zip file and extract it on your machine.
To install the package locally and use it as other python packages, open a terminal or a powershell and cd
to the package location, then run
$ cd path/to/package
$ pip install e .
Pip
The package can be also installed from PyPi using
$ pip install uraeus.smbd
Conda
To Do
Background
What is the problem to be solved?
The primary interest in multibody dynamics is to analyze the system behaviour for given inputs. In analogy with control systems; a multibody system can be thought as a system subjected to some inputs producing some outputs. These three parts of the problem are dependent on the analyst end goal of the analysis and simulation.
How is the system physics abstracted mathematically?
An unconstrained body in space is normally defined using 6 generalized coordinates defining its location and orientation. For example, a system of 10 bodies requires 60 generalized coordinates to be fully defined, which in turn requires 60 independent equations to be solved for these unknown generalized coordinates.
The way we achieve a solution for the system is dependent on the type of study we are performing. Mainly we have four types of analysis that are of interest for a given multibody system. These are:

Kinematic Analysis
"How does the whole system move if we moved this particular body ?" 
Inverse Dynamic Analysis
"What are the forces needed to achieve this motion we just did ?" 
Equilibrium Analysis
"How does the system look if we did nothing ?" 
Dynamic Analysis
"Now we gave it a force, how does it behave ?"
Each analysis type or question can be modelled by a set of algebraic and/or differential equations that can be solved for the system generalized states (positions, velocities and accelerations). A more detailed discussion of each analysis type will be provided in another documentation.
Approach
The philosophy of the tool is to isolate the model creation process form the actual numerical and computational representation of the system that will be used in the simulation process. This is done through the ideas of symbolic computing and codegeneration as well be shown below.
Model Creation
The topology of the system is represented as a multidirected graph, where each node represents a body and each edge represents a connection between the end nodes, where this connection may represents a joint, actuator or a force element. This serves mainly two aspects:
 A natural way to create and represent the topology of a given multibody system.
 A convenient way to abstract the system programmatically, where all the topological data of the system are stored in a graph.
The tool achieves this by making heavy use the NetworkX python package to create topology graphs and to construct the governing equations of the system. The equations themselves are represented symbolically using SymPy, which is a Python library for symbolic mathematics.
The combination of both, NetworkX and SymPy, provides the tool with a very simple, easytouse and convenient interface for the process of model creation and topology design, where the user only focuses on the validity of the system topology in hand, as he thinks only in terms of the topological components  bodies, joints, actuators and forces, without the burden of frequent numerical inputs for each component, or how the actual system is configured in space. In short, the tool divide the typical model creation process in halves, the system topology design and the system configuration assignment.
Code Generation and Model Simulation
The process of performing actual simulations on the created model requires the generation of a valid numerical and computational code of the created model. This is done by taking in the symbolic model and create a valid code files written in the desired programming language with the desired programming paradigm and structure.
These numerical environments are decoupled from this package and developed fairly independently, as each numerical environment is responsible for the translation of the developed symbolic models into valid numerical code and what features it aims to provide for the users.
The development of such environments in different languages requires a good grasp of several aspects such as :
 Good knowledge of the symbolic models' interfaces and structure.
 Good knowledge of the target language.
 Appropriate environment architecture/structure that serves the intended usage requirements.
 Good knowledge of the available linear algebra and math libraries for that language.
 Design for minimal dependencies on 3rd parties libraries.
 Simple API for usage and simple build process for compiled languages.
Note: The development of such environments is discussed in a separate documentation for those interested in developing their own.
Conclusion
Several benefits of the adopted approach can be stated here, but the major theme here is the flexibility and modularity, in both software usage and software development. These can be summarized as follows:
 The distinction between the topology design phase and the configuration assignment phase, which gives proper focus for each at its' own.
 Natural adoption of the templatebased modelling theme that emerges from the use of networkgraphs to represent the system, which allows convenient assemblage of several graphs to form a new system.
 Uncoupled simulation environment, where the symbolic equations generated form the designed topology is free to be written in any programming language with any desired numerical libraries.
Usage Examples & Tutorials
ReadytoUse Notebooks & Tutorials
This is a list of readytouse jupyter notebooks that walks you through the typical flow of the tool modelling process. The examples directory in this repository is planned to include updated versions of working models that can be statically viewed on github, downloaded on your machine or to be ran directly on Colab.
Standalone Studies
 Spatial Fourbar. (GitHub  Colab)
 Spatial SliderCrank. (GitHub Colab)
 DoubleWishbone Suspension. (GitHub Colab)
 DoubleFourbar Mechanism. (GitHub Colab)
 Simple Pendulum. (GitHub Colab)
 Double Pendulum. (GitHub Colab)
TemplateBased Projects
To be discussed ...
Detailed Example  Spatial Fourbar Mechanism
Below is code sample that walks you through the process of building a standalone symbolic topology and configuration as well as the generation of numerical simulation environments.
This model will be created as a standalone topology and project. What this means is that model topological data is fully encapsulated in one topology graph and no need for any topological data from other external systems, which is the case for templatebased topologies. This also means that the project files/database is selfcontained, unlike the templatebased topologies that need to be organized in a shared database.
Initializing Project Structure
Currently, a standalone project is structured using three toplevel directories inside a given parent_dir
; these are

/symenv
:
Directory of symbolic model data. 
/numenv
:
Directory of the numerical environments to be generated. 
/visenv
:
Directory of the 3D visualization environments to be generated.
To create a standalone project :
from uraeus.smbd.systems import standalone_project
parent_dir = '' # current working directory
project = standalone_project(parent_dir)
project.create()
Building the Symbolic Topology.
We start by importing the standalone_topology
class from the systems
module to create our symbolic model instance.
from uraeus.smbd.systems import standalone_topology
model_name = 'fourbar'
sym_model = standalone_topology(model_name)
We then start constructing our system by adding the bodies, joints, actuators and forces.
# Adding Bodies
sym_model.add_body('l1')
sym_model.add_body('l2')
sym_model.add_body('l3')
# Adding Joints
sym_model.add_joint.revolute('a', 'ground', 'rbs_l1')
sym_model.add_joint.spherical('b', 'rbs_l1', 'rbs_l2')
sym_model.add_joint.universal('c', 'rbs_l2', 'rbs_l3')
sym_model.add_joint.revolute('d', 'rbs_l3', 'ground')
# Adding Actuators
sym_model.add_actuator.rotational_actuator('act', 'jcs_a')
And that's it; we have just created a symbolic topology that represents our fourbar mechanism. The topology graph of the system can be visualized by the method sym_model.topology.draw_constraints_topology()
Also we can check the number of constraint equations, generalized coordinates and the estimated degrees of freedom of the system.
To finalize this step, we call the assemble()
method to construct the governing equations symbolically then save
the model.
sym_model.assemble()
sym_model.save('symenv')
We can check the system equations by accessing the appropriate topology attributes.
# Position level constraint equations.
sym_model.topology.pos_equations
# System Jacobian of the position level constraint equations.
sym_model.topology.jac_equations
Building the symbolic configuration.
The next step is to create a symbolic configuration of our symbolic model, but what is this symbolic configuration?
You may have noticed that we did not care explicitly about how our system is configured in space, we did not care about how our bodies or joints are located or oriented or how we can define these configuration parameters, all we cared about is only the topological connectivity. These configuration parameters already got generated automatically based on the used components. For example, the creation of a symbolic body body l1 for example generates automatically the following symbolic parameters:

m_rbs_l1
: body mass. 
Jbar_rbs_l1
: inertia tensor. 
R_rbs_l1
: body reference point location. 
Rd_rbs_l1
: body translational velocity. 
Rdd_rbs_l1
: body translational acceleration. 
P_rbs_l1
: body orientation. 
Pd_rbs_l1
: body orientation 1st rate of change. 
Pdd_rbs_l1
: body orientation 2nd rate of change.
where the rbs_
initial is short for rigid body single. If the body is mirrored, the system will create two bodies with the initials rbr_
and rbl_
for right and left respectively.
The same happens for edges' components joints, actuators and forces where each component is responsible for creating its own configuration symbolic parameters.
These parameters are extracted from the symbolic topology to form the primary configuration layer that represents the needed user inputs for any given simulation. The benefit of the symbolic configuration is that we can construct our own layer of inputs that we desire to use in the numerical simulation and define the relations between these inputs and the primary parameters extracted from the topology components. This is best shown by example.
Our fourbar mechanism is simply visualized as three links and a ground that are connected at four distinct points, a, b, c and d. We can simply get directly the numerical values of these points in space much easier than for example getting directly the orientation of the two axes used to define the universal joint used to connect l2 with l3.
The idea is to construct a directed relational graph that maps the required primary configuration to a set of new configuration parameters that may be easier and more convenient to specify directly.
We start by creating our configuration instance
from uraeus.smbd.systems import configuration
sym_config = configuration('%s_cfg'%model_name, sym_model)
Now we can check the primary configuration parameters extracted the from the symbolic topology by sym_config.config.input_nodes
which returns a list of strings containing the inputs' parameters names.
Now, we create our desired user inputs.
# Adding the desired set of UserInputs
# ====================================
sym_config.add_point.UserInput('a')
sym_config.add_point.UserInput('b')
sym_config.add_point.UserInput('c')
sym_config.add_point.UserInput('d')
sym_config.add_vector.UserInput('x')
sym_config.add_vector.UserInput('y')
sym_config.add_vector.UserInput('z')
After that, we set the relations between the primary configuration parameters and our custom configuration inputs.
# Defining Relations between original topology inputs
# and our desired UserInputs.
# ===================================================
# Revolute Joint (a) location and orientation
sym_config.add_relation.Equal_to('pt1_jcs_a', ('hps_a',))
sym_config.add_relation.Equal_to('ax1_jcs_a', ('vcs_x',))
# Spherical Joint (b) location and orientation
sym_config.add_relation.Equal_to('pt1_jcs_b', ('hps_b',))
sym_config.add_relation.Equal_to('ax1_jcs_b', ('vcs_z',))
# Universal Joint (c) location and orientation
sym_config.add_relation.Equal_to('pt1_jcs_c', ('hps_c',))
sym_config.add_relation.Oriented('ax1_jcs_c', ('hps_b', 'hps_c'))
sym_config.add_relation.Oriented('ax2_jcs_c', ('hps_c', 'hps_b'))
# Revolute Joint (d) location and orientation
sym_config.add_relation.Equal_to('pt1_jcs_d', ('hps_d',))
sym_config.add_relation.Equal_to('ax1_jcs_d', ('vcs_y',))
Note: The set of configuration parameters of each component and their naming convention will be discussed in a separate documentation
The first line of the above codeblock adds a relation that sets the location of joint pt1_jsc_a
to be Equal_to
the userinput location point hps_a
, where the fifth line adds a relation that sets the orientation of the first axis of the universal joint ax1_jsc_c
to be Oriented
along the userinput location points hps_b
and hps_c
. The rest of the statements follows the same convention.
An optional and recommended step is to create symbolic geometries and assign these geometries to topology bodies to automatically evaluate the bodies configuration parameters stated earlier. Also this will be used to generate a pythonblender script that can be used in blender to create 3D visualizations in blender later.
# links radius
sym_config.add_scalar.UserInput('links_ro')
# Link 1 geometry
sym_config.add_geometry.Cylinder_Geometry('l1', ('hps_a','hps_b','s_links_ro'))
sym_config.assign_geometry_to_body('rbs_l1', 'gms_l1')
# Link 2 geometry
sym_config.add_geometry.Cylinder_Geometry('l2', ('hps_b','hps_c','s_links_ro'))
sym_config.assign_geometry_to_body('rbs_l2', 'gms_l2')
# Link 3 geometry
sym_config.add_geometry.Cylinder_Geometry('l3', ('hps_c','hps_d','s_links_ro'))
sym_config.assign_geometry_to_body('rbs_l3', 'gms_l3')
The last step is to export the configuration data into a JSON file that can be used then by other numerical and visualization environments.
sym_config.export_JSON_file('symenv')
Roadmap
To be discussed ...
Implementation Details
The Implementation Details will be provided in a separate documentation and linked here
Theoretical Basis
The Theoretical Basis will be provided in a separate documentation and linked here
Support
As the tool is developed and maintained by one developer for now, if you have any inquiries, do not hesitate to contact me at khaled.ghobashy@live.com or kh.ghobashy@gmail.com
References
[1] : McPhee, J.J. Nonlinear Dyn (1996) 9: 73. https://doi.org/10.1007/BF01833294
[2] : https://colab.research.google.com/notebooks/welcome.ipynb
License
uraeus.smbd is distributed under the 3clause BSD license. See the LICENSE file for details.