Unity-Technologies / URDF-Importer

URDF importer
Apache License 2.0
230 stars 71 forks source link

Importing URDF from using script w/o using the editor #222

Open Kai-X-Org opened 1 year ago

Kai-X-Org commented 1 year ago

Does the current importer support importing urdf with code? i.e. is there a function I can call in a script that can just import the urdf? I am currently working on interfacing Unity to a Python-based scenario description language and would like to be able to rapidly spawn/delete robots across scenes directly from code without the user having to touch the editor. Thank you so much!

bv-radiusmedia commented 2 months ago

using System.Collections; using System.IO; using System.IO.Compression; using UnityEngine; using Unity.Robotics.UrdfImporter; using UnityEngine.Networking; using Unity.Robotics.UrdfImporter.Control; using TMPro;

public class UrdfRuntimeLoader : MonoBehaviour { public TextMeshPro DebugText; public string zipUrl = ""; // URL to download the zip file public string localZipFileName = "urdf_ue5.zip"; // Name of the local zip file public string urdfFileName = "ur5e.urdf"; // Name of the URDF file inside the zip public bool setImmovableLink = true; public bool useVHACD = false; public bool showProgress = false; public bool clearOnLoad = true;

private GameObject currentRobot = null;
private bool isLoading = false;

private IEnumerator LoadUrdf()
{
    isLoading = true;

    string localZipPath = Path.Combine(Application.persistentDataPath, localZipFileName);

    UnityWebRequest zipRequest = UnityWebRequest.Get(zipUrl);
    zipRequest.downloadHandler = new DownloadHandlerFile(localZipPath);
    yield return zipRequest.SendWebRequest();

    if (zipRequest.result != UnityWebRequest.Result.Success)
    {
        Debug.LogError("Failed to download zip file: " + zipRequest.error);
        isLoading = false;
        yield break;
    }

    string extractPath = Path.Combine(Application.persistentDataPath, "ExtractedURDF");

    if (Directory.Exists(extractPath))
    {
        Directory.Delete(extractPath, true);  // Clear any existing extracted content
    }
    Directory.CreateDirectory(extractPath);

    ZipFile.ExtractToDirectory(localZipPath, extractPath);
    Debug.Log("Extracted to: " + extractPath);

    string urdfFilePath = Path.Combine(extractPath + "/URDF ur5e", urdfFileName);
    if (!File.Exists(urdfFilePath))
    {
        Debug.LogError("URDF file not found in the extracted content!");
        isLoading = false;
        yield break;
    }

    if (clearOnLoad && currentRobot != null)
    {
        currentRobot.SetActive(false);
        Destroy(currentRobot);
    }
    yield return null;

    ImportSettings settings = new ImportSettings
    {
        chosenAxis = ImportSettings.axisType.yAxis,
        convexMethod = useVHACD ? ImportSettings.convexDecomposer.vHACD : ImportSettings.convexDecomposer.unity,
    };

    GameObject robotObject = null;
    try
    {
        DebugText.text = $"Loading URDF from: {urdfFilePath}";
        robotObject = UrdfRobotExtensions.CreateRuntime(urdfFilePath, settings);
        DebugText.text = "12 - Robot creation completed";
    }
    catch (System.Exception ex)
    {
        Debug.LogError("Error during URDF creation: " + ex.Message);
        //DebugText.text = "Error during URDF creation: " + ex.Message;
        isLoading = false;
        yield break;
    }

    if (robotObject != null && robotObject.transform != null)
    {
        robotObject.transform.SetParent(transform);
        SetControllerParameters(robotObject);
        Debug.Log("Successfully Loaded URDF: " + robotObject.name);
    }

    currentRobot = robotObject;
    isLoading = false;
}

void SetControllerParameters(GameObject robot)
{
    robot.GetComponent<UrdfRobot>().SetRigidbodiesUseGravity();

    if (robot.TryGetComponent<Controller>(out Controller controller))
    {
        controller.stiffness = 10000;
        controller.damping = 100;
        controller.forceLimit = 10;
        controller.speed = 30;
        controller.acceleration = 10;
        controller.enabled = true;
    }

    if (setImmovableLink)
    {
        Transform baseNode = robot.transform.GetChild(robot.transform.childCount - 1);
        if (baseNode)
        {
            ArticulationBody baseNodeAB = baseNode.GetComponent<ArticulationBody>();
            if (baseNodeAB == null)
            {
                baseNodeAB = baseNode.gameObject.AddComponent<ArticulationBody>();
            }
            baseNodeAB.immovable = true;
        }
        else
        {
            Debug.LogWarning($"The specified immovable link was not found in the robot hierarchy.");
        }
    }
}

public void LoadModel()
{
    StartCoroutine(LoadUrdf());
}

}

I am using this script and it works in the editor to download and load the URDF models at runtime. Hope this helps