© Copyright, 2025 G. Schaer.
SPDX-License-Identifier: GPL-3.0-only
Tutorial 2: Joint Torques
Tutorial Description
This tutorial covers creating a condynsate Project in which torques are applied to specific joints of an articulated body. We will cover:
Applying torques to individual continuous joints of a .urdf object.
Measuring the state of individual joints of a .urdf 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, but instead of loading a cube object, we load a pendulum. Additionally, we leave the ground grid on and do not load a ground plane.
[10]:
# Create the project
proj = Project()
You can open the visualizer by visiting the following URL:
http://127.0.0.1:7032/static/
[11]:
proj.visualizer.set_axes(False) # Returns 0 on success
[11]:
0
This time, we make the pendulum fixed. This ensures the base of the pendulum has 0 degrees of freedom. Setting the fixed flag doe not affect the degrees of freedom of the joints of the pendulum.
[12]:
# Load a pendulum object and set its initial position to resting on the ground
pendulum = proj.load_urdf(assets['pendulum.urdf'],
fixed=True
)
Additionally to setting the initial state of the body as a whole, we can also set the initial state of each joint of articulated bodies. Here we will set the initial angle of the pendulum arm to 10 degrees. To access the joints of a body, we use the joints attribute. The joints attribute is a dictionary that indexes joint names (as defined in the .urdf files from which bodies are loaded) to members of the condynsate.simulator.objects.Joint class.
The name of the pendulum joint is base_to_arm. This name is defined in the pendulum.urdf file.
We can then call the condynsate.simulator.objects.Joint.set_initial_state function to set the initial state of the arm.
-----------------------------------------------------------------------------
| condynsate.simulator.objects.Joint.set_initial_state |
-----------------------------------------------------------------------------
Sets the initial state of the joint. When the simulation is reset
the joint will be reset to this value
Parameters
----------
**kwargs
Keyword Args
------------
angle : float, optional
The (angle in radians) of the joint about the joint axis.
omega : float, optional
The angular velocity (angle in radians / second) of the joint
about the joint axis.
Returns
-------
ret_code : int
0 if successful, -1 if something went wrong.
[13]:
# Set the initial angle of the pendulum arm
pendulum.joints['base_to_arm'].set_initial_state(angle=0.1745) # All angles in condynsate are radians
[13]:
0
[14]:
# Refresh the visualizer to show changes to the pendulums's position and angle
proj.refresh_visualizer() # Returns 0 on success
[14]:
0
Running a Simulation Loop
Similary to Tutorial 0, we start the simulation loop by calling condynsate.Project.reset.
[15]:
proj.reset() # Returns 0 on success
[15]:
0
In each step of the loop we take 3 steps
Get the pendulum’s joint angle
Apply a torque to the pendulum joint proportional to the joint angle
Take a single simulation step
To get state information about joints, we access a joint’s state attribute. The state attribute has the following child attributes:
-----------------------------------------------------------------------------
| condynsate.simulator.dataclasses.JointState |
-----------------------------------------------------------------------------
Attributes
----------
angle : float
The angle of the joint about the joint axis.
omega : float
The angular velocity of the joint about the joint axis.
To get the pendulum’s joint angle, we access the angle child attribute.
To apply a torque to a joint, we call the condynsate.simulator.objects.Joint.apply_torque function
-----------------------------------------------------------------------------
| condynsate.simulator.objects.Joint.apply_torque |
-----------------------------------------------------------------------------
Applies torque to a joint for a single simulation step.
Parameters
----------
torque : float
The torque being applied about the joint's axis..
**kwargs
Keyword Args
------------
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.
arrow_offset : float, optional
The amount by which the drawn is offset from the center of the
joint's child link along the joint axis. The default is 0.0.
Returns
-------
ret_code : int
0 if successful, -1 if something went wrong.
[ ]:
# Run a 10 second simulation
while proj.simtime <= 10.:
# Get the pendulum's joint angle
joint_state = pendulum.joints['base_to_arm'].state
angle = joint_state.angle
# Apply a torque to the pendulum's joint
torque = -14.0 * angle
pendulum.joints['base_to_arm'].apply_torque(torque, draw_arrow=True, arrow_scale=0.25)
# 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 exactly like the previous tutorial, after condynsate.Project.step is called, the torques applied in the previous simulation step will not be applied in the next step. Therefore, we must call apply_torque function before every time step in which we want to apply joint torques.
Finally, we ensure all children threads exit gracefully.
[ ]:
proj.terminate() # Returns 0 on success
Challenge
This tutorial is now complete. For an added challenge, think of how you would modify the simulation loop to implement a PD controller.
[ ]: