How to work with configurable articulation chains?

Hello,

I am working on a Unity project that allows the user to assemble a custom robot cell. From my observations I noticed that whenever a non-zero target articulation chain is changed (eg. an ArticulationBody is added or removed) all linked articulation bodies do a quick reset to their zero targets which results in the robot suddenly moving from reset position back to its set target position. Since key features of my project are to add/remove/replace robot tools and save/load a configured robot cell, the issue described happens often.

I have tried numerous ways to mitigate this reset such as waiting on fixed frame before enable/disable and setting ArticulationBody jointPosition and drive target from code, however, this still results in a sudden reset followed by a sudden set back into place.

So my questions would be what are the best practices for working with an articulation chain that changes the number of bodies in chain during runtime? Is the reset I described above intentional/necessary? What is the recommended way to instantaneously position the robot (setting ArticulationBody.jointPosition, ArticulationBody.SetJointPositions(), both, other)?

In order to reproduce my issue it should be enough to open any Unity robot tutorial (eg. Pick'n'place), then using the controller scripts to move joints out of target zero and finally using the Inspector to enable/disable one of the bodies in the chain. Below I have attached a gif of me enabling/disabling one of the grippers on Niryo One robot from Pick and Place tutorial.

Looking forward to any feedback regarding my issues, since at times it can cause the robot to get into "unsolvable" collisions.

Best regards,
Jani

7581877--939790--picknplace.gif

Hello @AirnamicsJaniZ , it is great to hear from you and this is an interesting question. By design in the PhysX, the articulation chain should not be changed after being created, because it is hard to imagine that we could take off or add a new link when a robot is running. Therefore, the best practice we would recommend is to avoid this type of manipulation on the articulation chain if possible.

If you really need to add/remove/replace/save/load articulation bodies with configurations at runtime, we would recommend recreating the whole hierarchy, which will re-create joint anchor frames, etc. We have put quite an effort into making some changes possible, but it’s still far from perfect. Generally speaking, you may need to update a few attributes of the articulation bodies when you add/remove one from the chain, including the joint positions, anchors, and some other tricks. In addition, you may need to make sure that setting joint positions should happen in the same frame when you enable/disable the articulation body component so that the link won't teleport back and forth.

The following code works for us to update articulation bodies at runtime.

        private void UpdateJoint(ArticulationBody body)
        {
            body.transform.localPosition = initialTransform.localPosition.ToUnity();
            body.transform.localRotation = initialTransform.localRotation.ToUnity();

            body.anchorPosition = this.anchorPosition;
            body.anchorRotation = this.anchorRotation;

            List<float> dof = new List<float>();
            body.GetJointPositions(dof);
            if (dof.Count == jointPositions.Count)
            {
                body.gameObject.SetActive(false);
                body.gameObject.SetActive(true);

                body.SetJointPositions(jointPositions);
                body.SetJointVelocities(jointVelocities);
                body.SetJointAccelerations(jointAccelerations);
                body.SetJointForces(jointForces);
            }
        }

Hello @peifeng-unity , thank you for the reply.

I've done some more tests with SetJointPositions and it seems to have solved the sudden movement issue when enabling/disabling an object. It still happens sometimes during runtime project load but that is likely an issue somewhere in my code, I need to figure out the main difference between simple enable and instantiate procedures (I've already tried loading a disabled gameObject prefab so that set active is called just before get/set joint positions, I tried waiting for fixed frame in coroutine during load procedure and I tried setting drive target + SetJointPositions/Velocities... + transform rotations - and I have "compute parent anchor" turned off so that shouldn't matter I think).

Quick note, during tests I noticed that the error "Articulation cache size(total degrees of freedom of all joints + 6 if root body is not immovable) does not match supplied list size!" prints even when the supplied list size is correct - I noticed that the correct way of using SetJointPositions is to first call GetJointPositions and modify the provided list. Creating a new List instance resulted in the error I mentioned regardless of list count being correct.

My main question though is what exactly is meant by "recreating the whole hierarchy" in case of adding/removing ArticulationBody objects? Would it be enough to simply disable all objects in chain, attach a new object and then re-enable the chain? Or do I perhaps need to create brand new instances of articulation objects and combine them before their Awake/Start?

Hey, my quick two cents on the error you are experiencing, this is a bug on the physics side. It's fixed in Unity version 2022.1.0a8. If your List size is correct, this is a misleading error even though nothing is wrong. Link to the Issue Tracker.


Hey, funnily enough I was actually the one to submit that bug and reproduce project. Though the issue there was not being able to use Get->Set (ArticulationBody.Get/SetJointPositions) after changing articulation length. Here though I was surprised that I cannot use Set without using Get first. I expected that I can pass any list to Set, so long as it matches articulation size, but that doesn't seem to be the case. And though the error is misleading I do also think that the Set did not finish execution, though I cannot confirm at this time.

For now though my main question remains as to what steps are needed to (re-)create a new articulation chain during runtime without running into known issues.

Quick follow up on SetJointPositions function. I did test 2022.1.X version and it seems both these issues have been resolved.

1 Like

It's great to know that the issues are resolved in the 2022.1 version.