Quick answer: Enable the drive (Angular Orientation or Linear Position) with a non-zero Stiffness and MaxForce, then call SetAngularOrientationTarget or SetLinearPositionTarget. Both constrained components must SetSimulatePhysics(true) for the drive to have anything to push.
Here is how to fix Unreal PhysicsConstraintComponent drive not working. You set up a door hinge, a ragdoll joint, or a motorized crane arm. You call SetAngularOrientationTarget, expect the body to rotate toward it, and nothing moves. Or the constraint holds the body in place but ignores drive commands. PhysicsConstraintComponent has a half-dozen interacting flags, and all of them matter.
The Symptom
A PhysicsConstraintComponent keeps two bodies connected (the position and rotation limits work) but the drive target has no effect. You call SetAngularOrientationTarget with a 90-degree rotation and the body stays at 0. SetLinearVelocityDrive produces no motion. No errors in the log.
Variant: drive works once then stops. Or it produces oscillation and never settles.
What Causes This
Drive disabled. PhysicsConstraintComponent has separate flags for each drive axis. bAngularOrientationDrive, bAngularVelocityDrive, bLinearPositionDrive, bLinearVelocityDrive. All default to false. Setting a target on a disabled drive is a no-op.
Stiffness or MaxForce is zero. The drive spring equation is force = stiffness * (target - current) - damping * velocity, capped at MaxForce. If stiffness is 0, no force is applied. If MaxForce is 0, the cap clips to zero and nothing moves.
Bodies not simulating physics. If either constrained component has bSimulatePhysics = false, the drive cannot apply impulses. Kinematic bodies ignore drive forces. A common setup pattern is to keep one side kinematic (the “anchor”) and let the other side simulate.
Wrong API for the drive type. SetAngularOrientationTarget affects Position Drive. For Velocity Drive, use SetAngularVelocityTarget. Calling the wrong setter silently does nothing because the other drive is disabled.
Constraint not initialized at runtime. If you spawn the constraint in code, you must call SetConstrainedComponents with both components. Editor-placed constraints do this automatically.
Angular drive mode mismatch. SetAngularDriveMode chooses SLERP (single drive toward quaternion target) vs Twist and Swing (separate drives). Your drive parameters only affect the mode you selected.
The Fix
Step 1: Enable the drive and set parameters.
// In constructor or BeginPlay
UPhysicsConstraintComponent* Joint = GetConstraint();
// Enable angular orientation drive with SLERP
Joint->SetAngularDriveMode(EAngularDriveMode::SLERP);
Joint->SetAngularDriveParams(
1500.0f, // Spring stiffness
80.0f, // Damping
0.0f // ForceLimit - 0 means unlimited
);
// Enable the drive
Joint->SetOrientationDriveSLERP(true);
For twist/swing mode, use SetOrientationDriveTwistAndSwing(bEnableTwist, bEnableSwing) instead. Twist is rotation around the constraint’s primary axis; swing is off-axis rotation.
Step 2: Verify both bodies simulate physics.
ChildMesh->SetSimulatePhysics(true);
ParentMesh->SetSimulatePhysics(true);
// Or for an anchored joint: parent kinematic, child dynamic
ParentMesh->SetSimulatePhysics(false);
ChildMesh->SetSimulatePhysics(true);
If the parent is kinematic, it provides a stable anchor that the child can be driven relative to. This is the correct setup for a motorized arm whose base is bolted to the world.
Step 3: Set a target and it moves.
// Target the child to be rotated 90 degrees around the constraint axis
FQuat Target = FQuat(FVector::UpVector, FMath::DegreesToRadians(90.0f));
Joint->SetAngularOrientationTarget(Target.Rotator());
For continuous motion (a motor), use velocity drive:
Joint->SetAngularVelocityDriveTwistAndSwing(true, false);
Joint->SetAngularDriveParams(0, 100, 2000); // No stiffness, just damping + force
Joint->SetAngularVelocityTarget(FVector(360.0f, 0, 0)); // deg/sec around twist
Tuning Stiffness and Damping
The relationship is:
- Stiffness (spring) — how hard the drive pulls toward the target. Higher = faster, but overshoots.
- Damping — resists motion, prevents oscillation. Higher = slower but more stable.
- ForceLimit — maximum force applied. 0 means unlimited.
For a critically damped drive (fastest without overshoot):
damping = 2 * sqrt(mass * stiffness)
For a 100 kg body with stiffness 2000: damping = 2 * sqrt(100 * 2000) = 2 * 447 = 894. Start there and tune.
SetConstrainedComponents at Runtime
If you spawn the constraint programmatically:
UPhysicsConstraintComponent* NewJoint = NewObject<UPhysicsConstraintComponent>(this);
NewJoint->RegisterComponent();
NewJoint->AttachToComponent(RootComponent,
FAttachmentTransformRules::KeepRelativeTransform);
NewJoint->SetConstrainedComponents(
ParentMesh, NAME_None,
ChildMesh, NAME_None
);
Without SetConstrainedComponents, the joint has no bodies to drive. Editor-placed constraints with ComponentName1/2 set do this automatically during InitializeComponent.
Debug with p.VisualizeConstraints
In the console, run p.VisualizeConstraints 1. Constraints draw as gizmos in the world. You can see which bodies are connected, current angles, and limit arcs. If the constraint is not where you expect, the constrained components are wrong.
“Enable drive, set stiffness and damping, give it bodies to move. All three or nothing happens.”
Related Issues
For related physics setup, see Actor Replication Not Working. For animation integration, AnimNotify Not Firing at Playback Rate covers related timing questions.
Enable drive, non-zero stiffness, simulate physics on both sides. Drive starts moving.