© Copyright, 2025 G. Schaer.
SPDX-License-Identifier: GPL-3.0-only
Tutorial 1: External Forces and Torques
Tutorial Description
This tutorial covers creating a condynsate Project in which external forces are applied to the center of mass of a a cube. We will cover:
Appling forces and torques to the center of mass of an object.
Measuring the position, orientation, velocity, and rotational velocity of the center of mass of that object.
Imports
To begin, we import the same modules for the same reasons as Tutorial 0.
[1]:
from condynsate import Project
from condynsate import __assets__ as assets
Initializing the Project Class
Here we initialize the Project in the same way as Tutorial 0.
[2]:
# Create the project
proj = Project()
You can open the visualizer by visiting the following URL:
http://127.0.0.1:7028/static/
[3]:
# Turn off the grid and axes
proj.visualizer.set_axes(False) # Returns 0 on success
proj.visualizer.set_grid(False) # Returns 0 on success
[3]:
0
[4]:
# Load a fixed plane as the ground object
ground = proj.load_urdf(assets['plane_medium.urdf'], fixed=True)
[5]:
# Load a cube object that is resting on the ground plane
cube = proj.load_urdf(assets['cube.urdf'])
cube.set_initial_state(position=(0, 0, 0.5))
[5]:
0
[6]:
# Refresh the visualizer to show changes to the cube's position
proj.refresh_visualizer() # Returns 0 on success
[6]:
0
Running a Simulation Loop
Similary to Tutorial 0, we start the simulation loop by calling condynsate.Project.reset.
[7]:
proj.reset() # Returns 0 on success
[7]:
0
In each step of the loop we take 4 steps
Calculate the cube’s height above the ground
Apply an upward force (in the +z world direction) to the center of mass of the cube proportional to the cube’s height
Apply an external torque to the cube
Take a single simulation step
To get state information about the cube, we access the cube’s state attribute. The cube’s state attribute has the following child attributes:
-----------------------------------------------------------------------------
| condynsate.simulator.dataclasses.BodyState |
-----------------------------------------------------------------------------
Attributes
----------
position : 3 tuple of floats
The (x,y,z) position in world coordinates.
orientation : 4 tuple of floats
The wxyz quaternion representation of the orientation in world
coordinates.
ypr : 3 tuple of floats
The (z-y'-x' Tait–Bryan) Euler angles in radians ordered as
(yaw, pitch, roll).
velocity : 3 tuple of floats
The (x,y,z) velocity in world coordinates.
omega : 3 tuple of floats
The (x,y,z) angular velocity in world coordinates.
velocity_in_body : 3 tuple of floats
The (x,y,z) velocity in body coordinates.
omega_in_body : 3 tuple of floats
The (x,y,z) angular velocity in body coordinates.
To get the cube’s position in world coordinates, we access the position child attribute. Based on this position and the length of the cube, we can then calculate how high the cube is above the ground plane.
External forces are applied to simulator objects with the condynsate.simulator.objects.Body.apply_force function
-----------------------------------------------------------------------------
| condynsate.simulator.objects.Body.apply_force |
-----------------------------------------------------------------------------
Applies force to the center of mass of the body.
Parameters
----------
force : 3 tuple of floats
The force being applied to the center of mass.
**kwargs
Keyword Args
------------
body : bool, optional
A Boolean flag that indicates if the force argument is in
body coordinates (True), or in world coordinates (False).
The default is False.
draw_arrow : bool, optional
A Boolean flag that indicates if an arrow should be drawn
to represent the applied force. The default is False.
arrow_scale : float, optional
The scaling factor, relative to the size of the applied force,
that is used to size the force arrow. The default is 1.0.
Returns
-------
ret_code : int
0 if successful, -1 if something went wrong.
External torques are applied to simulator objects with the condynsate.simulator.objects.Body.apply_torque function
-----------------------------------------------------------------------------
| condynsate.simulator.objects.Body.apply_torque |
-----------------------------------------------------------------------------
Applies external torque to the body.
Parameters
----------
torque : 3 tuple of floats
The torque being applied.
**kwargs
Keyword Args
------------
body : bool, optional
A Boolean flag that indicates if the torque argument is in
body coordinates (True), or in world coordinates (False).
The default is False.
draw_arrow : bool, optional
A Boolean flag that indicates if an arrow should be drawn
to represent the applied torque. The default is False.
arrow_scale : float, optional
The scaling factor, relative to the size of the applied torque,
that is used to size the torque arrow. The default is 1.0.
Returns
-------
ret_code : int
0 if successful, -1 if something went wrong.
[8]:
# Run a 10 second simulation
while proj.simtime <= 10.:
# Get the cube's height above the ground
position = cube.state.position
height = position[2] - 0.5
# Calculate an upward force proportional to the cube's height and apply it to the cube
upward_force = 9.81 + (1.0-height) * 0.1
cube.apply_force((0, 0, upward_force), body=False, draw_arrow=True, arrow_scale=0.15)
# Apply a small external torque to the cube
cube.apply_torque((0.02, 0.02, 0.02), body=False, draw_arrow=True, arrow_scale=55.0)
# Take a single simulation step
proj.step(real_time=True, # Run the simulation in real time
stable_step=False # Dynamically adjust the refresh rate for best total run time
)
Note that after condynsate.Project.step is called, the forces and torques applied in the previous simulation step will not be applied in the next step. Therefore, we must call the apply_force and apply_torque functions before every time step in which we want to apply external inputs
Finally, we ensure all children threads exit gracefully.
[9]:
proj.terminate() # Returns 0 on success
[9]:
0
Challenge
This tutorial is now complete. For an added challenge, think of how you would modify the simulation loop so that the force applied is also porportional to the magnitude of the velocity of the cube.
[ ]: