Tendons
A RaiSim tendon defines one scalar transmission coordinate called its length. A spatial tendon obtains that coordinate from a routed path through attachment sites and wrapping guides. A fixed tendon obtains it from a weighted sum of joint coordinates. Springs, damping, actuation, friction, inertia, limits, and couplings all act through this same coordinate.
The public types are raisim::Tendon and raisim::TendonCoupling, available
through <raisim/World.hpp>. The world owns them and advances their physics
with the contact solver. Spatial tendons are drawn automatically by Rayrai and
by the TCP viewer connected to RaisimServer.
Straight length constraints use this same tendon API with two sites. The former wire classes have been removed; see Constraints for migration mappings and legacy XML import behavior.
- Tendon code examples
- Build and run the recipes
- Limit the maximum separation
- Lock the current length
- Suspend a load with a slack spring
- Apply a bounded tension command
- Control the length with a servo
- Route over a cylinder and add a pulley branch
- Drive a weighted joint coordinate
- Couple two visible cable lengths
- Inspect, style, export, and reload
- Straight connections through the tendon API
- Python uses the same model
- Tendon physics
- Length, velocity, and virtual work
- Straight segments and via-points
- Sphere and cylinder wrapping
- Pulley branches and mechanical advantage
- Fixed tendons and units
- Spring, slack interval, and damping
- Actuator and activation dynamics
- Armature and route curvature
- Shared impulse solver
- Length bounds, margin, and compliance
- Dry friction and stiction
- Polynomial tendon couplings
- Energy interpretation
- Tendon API and model files
- Tendon examples and Rayrai
What the model represents
Use spatial tendons for cables, belts, ligaments, routed elastic elements, or other mechanisms whose force depends on a path length. Sites can attach to rigid bodies, articulated links, individual deformable or granular particles, or the world. One tendon can span multiple objects and articulated systems.
Use fixed tendons for differential transmissions or coordinated joint actuation.
For example, shoulder + 0.65 * elbow is a valid tendon coordinate. A fixed
tendon does not lock its joints: the word fixed describes constant transmission
coefficients. Locking a length requires a length limit or a coupling.
Both types share the following features:
Feature |
Physical role |
|---|---|
Spring and damping |
Elastic force around a rest length or outside a slack interval; viscous resistance to length change. Integrated implicitly. |
Drive |
Signed feedforward force, position/velocity feedback, optional first-order force activation, and limits on the combined actuator force. |
Length bounds |
Independent lower and upper constraints, or a bilateral length lock, with position correction and optional compliance. |
Dry friction |
A bounded impulse opposes transmission motion and can hold it at rest. |
Armature |
Additional inertia along the length coordinate, including curvature effects for a spatial route. |
Coupling |
A polynomial equality between changes in two tendon lengths, or a constraint on one tendon relative to its initial reference length. |
The Tendon physics chapter derives these behaviors and their discrete solver equations. Tendon API and model files lists every property, its default, and the native XML and MJCF interfaces.
Massless routing and its limits
The routed geometry is massless. It has no particles of its own, sag under its
own weight, bending stiffness, torsional stiffness, cable thickness in collision
detection, or finite-speed wave propagation. armature adds transmission
inertia; it does not distribute material mass along the drawn cable.
A spatial tendon interacts with the sites and guides explicitly listed in its
path. It does not discover arbitrary obstacles, collide with other tendons, or
wrap around meshes or cylinder end caps. Sphere and infinite-cylinder guides
are frictionless. frictionLoss resists the scalar transmission; it does not
implement capstan friction or different tensions on opposite sides of a guide.
The drawing radius is a visualization parameter. To keep a cable visibly outside a collision surface, set the wrapping radius to the desired cable centerline radius, accounting for visual thickness yourself.
A short working example
This complete program suspends a sphere from a world anchor. The spring is slack up to 1 m, the hard maximum length is 1.5 m, and a small feedforward tension pulls upward in addition to the spring. Normal RaiSim license discovery applies; an optional first argument supplies an activation-key path.
#include <raisim/World.hpp>
#include <cmath>
#include <iostream>
#include <stdexcept>
int main(int argc, char** argv) {
try {
if (argc > 1) raisim::World::setActivationKey(argv[1]);
raisim::World world;
world.setTimeStep(0.001);
world.addGround();
auto* load = world.addSphere(0.1, 1.0);
load->setName("load");
load->setPosition(0.0, 0.0, 0.8);
using Path = raisim::Tendon::PathElement;
raisim::Tendon::Properties p;
p.springLower = 0.0;
p.springUpper = 1.0;
p.stiffness = 500.0;
p.damping = 8.0;
p.upperLimit = 1.5;
p.width = 0.008;
auto* cable = world.addSpatialTendon("suspension", {
Path::via({nullptr, 0, {0.0, 0.0, 2.0}}),
Path::via({load})}, p);
cable->setTension(2.0); // Negative signed feedforward force.
for (int step = 0; step < 2000; ++step) world.integrate();
cable->updateGeometry(); // Inspect the final integrated configuration.
if (!std::isfinite(cable->getLength()) ||
std::abs(cable->getLength() - 1.01562) > 0.001)
throw std::runtime_error("unexpected suspended-load equilibrium");
std::cout << "length=" << cable->getLength()
<< " total_tension=" << cable->getTension()
<< " actuator_force=" << cable->getActuationForce() << '\n';
return 0;
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}
}
Download the complete source.
For focused, tested C++ recipes, including current-length locks and wire API
comparisons, see Tendon code examples.
Build and run the larger tendon_elastic, tendon_pulleys,
tendon_coupling, and rayrai_tendons programs using
Tendon examples and Rayrai.
Three lengths with different meanings
Keep the following quantities distinct when configuring a mechanism:
getLength()is the current geometric or weighted-joint coordinate.getReferenceLength()is captured when the tendon is created. Polynomial couplings use changes relative to this reference.springLowerandspringUpperdefine the spring’s rest interval. They default to the initial reference length, but can be set independently.
Likewise, Drive::targetLength is an actuator command, and
lowerLimit/upperLimit are constraint bounds. Changing one does not move
the others. Setting the spring endpoints to NaN later restores the spring
interval to the original reference, rather than capturing a new configuration.
Create a tendon after setting its objects’ initial poses and joint coordinates.
Force signs and diagnostics
getForce() is signed: positive force acts to increase length.
getTension() is exactly its negative. setTension(5.0) writes a feedforward
actuation command of -5.0; it does not prescribe the total solved tension.
Other configured force components and actuator limits still apply.
setTension() and setActuationForce() retain the current servo gains,
targets, and activation time. To switch to a pure force command, explicitly set
both servo gains to zero. A negative reported tension is possible because the
scalar model can transmit forces in either direction.
A spring interval [0, restLength] makes the spring term pull-only for a
nonnegative spatial length. Damping, friction, armature, drives, and lower
limits can still generate forces of either sign. A shortening-only actuator
uses actuationUpper = 0 with a nonpositive lower force bound; that bound
clamps only the actuator contribution.
Getter |
Meaning and timing |
|---|---|
|
Cached length at the last geometry refresh. Geometry is refreshed before solving a step; refresh again to inspect the newly integrated pose. |
|
Final solved transmission velocity after a step, evaluated with that
step’s Jacobian. After |
|
Last-step total force, including passive, actuator, armature, friction, limit, and coupling contributions. Force equals solved impulse / timestep. |
|
Last-step actuator contribution after filtering, implicit feedback, and actuator-force saturation. |
|
Signed sums of the corresponding last-step constraint contributions. |
|
Spring energy at the cached length; excludes bodies, actuators, and compliant constraint rows. |
|
Armature energy at the cached velocity; excludes body kinetic energy. |
|
Current transmission derivatives and application points/indices. Point gradients include guide reactions and pulley scaling. |
Use updateGeometry() after manually assigning poses or after integration
when current geometric measurements are needed. It updates length, velocity,
and gradients without advancing the simulation or changing last-step forces.
updateGeometry(true) also refreshes getVisualSegments(). A refresh with
false does not rebuild the stored drawing segments.
Ownership and runtime changes
Create, look up, enumerate, and remove tendons through World. The returned
pointers are borrowed; do not delete them. Tendon names must be nonempty and
unique among tendons. Coupling names must be nonempty and unique among couplings.
Removing a tendon removes its dependent couplings. Removing an object removes tendons that reference it, including references through wrapping guides or side sites, and removes their dependent couplings. Discard borrowed pointers after such removals. A path and its joint-term list are immutable through the public API: remove and recreate a tendon to change its topology.
For particle sites, localIndex identifies one particle. Keep particle indices
stable while attached. Remove/recreate the tendon before deleting or reordering
particles. World ownership does not turn particle indices into stable handles.
setEnabled(false) disables the tendon’s solver contributions and, after
scene synchronization, its drawing. Couplings involving that tendon also stop
contributing. Geometry remains inspectable. The next simulated step clears its
reported force components; disabling does not retroactively change previous
step results. The force-activation state is retained and is not advanced while
disabled. Re-enabling resumes from that state.
Enabled attachments are kept awake. Participating articulated systems use semi-implicit position integration for the constrained step so their positions advance consistently with the solved end-step velocities.
Make tendon topology changes between complete steps. Adding/removing tendons or
couplings between integrate1() and integrate2() is rejected. Apply
configuration/control changes before a complete step as well. In a server
application, protect edits with the world/server mutex and use
integrateWorldThreadSafe for stepping and control updates. The examples
show this pattern; the tendon physics itself introduces no simulation threads.
Checkpoint capture/restore preserves tendon properties, enable state, drive commands, references, and activation state along with simulation state. Topology changes invalidate earlier checkpoints. See World for the surrounding world workflow and Tendon API and model files for XML persistence.
Choosing and tuning a model
Start with a rest interval and a spring when elastic deflection is part of the mechanism. Use a length bound when the mechanism must prevent extension or compression. Use a coupling when a relationship between transmission coordinates must be enforced. Multiple effects can coexist, but incompatible locks, joint limits, contacts, and couplings can create an unsatisfiable system.
Choose a timestep that resolves the mechanism’s motion, especially contact and wrap/release transitions. Implicit springs improve stiffness stability but do not guarantee accurate motion at arbitrary timesteps. Increase solver iterations or tighten the solver tolerance when interacting contacts and tendon rows have not converged. Check current length errors, actuator saturation, and separate force components before changing physical parameters.
Worlds with no tendons allocate no tendon-system storage and use the ordinary contact-solver specialization. Removing the last tendon releases that optional storage. Enabled tendons add work for geometry, participating body dynamics, constraint rows, and solver iterations. Spatial armature also evaluates a curvature bias. Visual tessellation is requested by rendering/streaming, rather than generated during ordinary physics integration. Measure representative scenes with the serial headless commands in Tendon examples and Rayrai.