How to set ArticulationBody motion to "limited" in C#

I’m adding the ArticulationBody component to a GameObject at runtime, and I’m trying to figure out how to set the “Motion” type from Free to Limited.

The unity docs are really sparse and I can’t figure out how to implement it. The closest thing I’ve found is Unity - Scripting API: ArticulationBody.linearLockX. Through trial and error, I’ve implemented the following script which builds without errors, but “Motion” still shows up as “Free”. If I manually set motion to “limited” in play mode, then the drive.lowerLimit and drive.upperLimit actually have an effect.

This script should work as-is, just attach to an empty GameObject.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
	void Start()
	{
		for (int i = 0; i < 3; i++)
		{
			// spawn ArticulationBody root
			GameObject root = GameObject.CreatePrimitive(PrimitiveType.Sphere);
			root.transform.position = new Vector3(0, 2f, 2f * i);
			root.AddComponent<ArticulationBody>();
			ArticulationBody abRoot = root.GetComponent<ArticulationBody>();
			abRoot.mass = 20f;

			// link
			GameObject link = GameObject.CreatePrimitive(PrimitiveType.Cube);

			float randomX = Random.Range(2f, 6f);
			link.transform.localScale = new Vector3(randomX, 0.5f, 0.5f);

			float pivotPoint = (randomX / 2) + (root.transform.localScale.x / 2);
			link.transform.position = new Vector3(pivotPoint, 2f, 2f * i);
			link.transform.SetParent(root.transform);
			link.AddComponent<ArticulationBody>();

			ArticulationBody ablink = link.GetComponent<ArticulationBody>();
			ablink.mass = 0.25f;
			ablink.anchorRotation = Quaternion.Euler(0, 180, 90);
			ablink.anchorPosition = Vector3.left / 2;
			ablink.jointType = ArticulationJointType.RevoluteJoint;

			ArticulationDofLock limit = ArticulationDofLock.LimitedMotion;
			ablink.linearLockX = limit;

			var drive = ablink.xDrive;
			drive.stiffness = 10000;
			drive.damping = 100;
			drive.lowerLimit = -90f; // has no effect unless "Motion" is set to "Limited" in the editor manually
			drive.upperLimit = 90f; // has no effect unless "Motion" is set to "Limited" in the editor manually
			drive.target = 0f;
			ablink.xDrive = drive;
		}

	}
}

Instead of lines 35 and 36, try the following:

ablink.linearLockX = ArticulationDofLock.LimitedMotion;
ablink.linearLockY = ArticulationDofLock.LockedMotion;
ablink.linearLockZ= ArticulationDofLock.LockedMotion;
ablink.twistLock = ArticulationDofLock.LimitedMotion;

I am NOT an expert at this, but this works for me.

See UnityCsReference/Modules/PhysicsEditor/ArticulationBodyEditor.cs at master · Unity-Technologies/UnityCsReference · GitHub from line 315 onwards - it seems that the value of twistLock is important to making this code work. Sorry for the lack of tech-y language. I hope this works!

If it doesn’t, Unity have made a Robotics-URDF importer project which was a reference material for me doing this