© 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:

  1. Applying torques to individual continuous joints of a .urdf object.

  2. 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

  1. Get the pendulum’s joint angle

  2. Apply a torque to the pendulum joint proportional to the joint angle

  3. 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.

[ ]: