Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resolved New Input System Unity Robotics - Tutorial

Discussion in 'Robotics' started by medinafb01, May 30, 2022.

  1. medinafb01

    medinafb01

    Joined:
    Feb 1, 2021
    Posts:
    14
    First of all thanks to the entire Unity Robotics team for this amazing package.

    The purpose of this post is to highlight how to implement Unity's new input system

    # Current SetUp
    # Let's START
    # Let's solve a minor BUG in URDF-Importer 0.5.2
    Issue:

    Controller doesn't highlight the link that it selects to be moved.

    Context:
    Checking my old project using URDF Importer V 0.5.0. I noticed that when importing the Robot from the URDF file the structure of the Game Objects in the herarchy had changed. This structure is critical because this is the way Unity understands your robot.


    So, in some part the `Controller` script uses this structure to highlight the link that is going to be moved.

    How to solve it:

    1. In the search bar of the project window search for Controller. Note: Change the search from "Assets" to "All". Once found open it.


    2. In the controller there is a Highlight function (line 88). In this function on line 102. All materials that are part of the selected link are stored to change its color.

    Code (CSharp):
    1. Renderer[] rendererList = articulationChain[selectedIndex].transform.GetChild(0).GetComponentsInChildren<Renderer>();
    As you can see it tries to take the component "Renderer" from the child 0, but in the new structure the child 0 is "Collision", the correct way would be to take the materials from the child 1 "Visuals".

    So we will change to child 1 in:
    • Line 102
    • Line 165
    • Line 179
    Do not forget to save the changes, Now everything is working



    # Now we are ready to go
    Input Action


    1. Download the new input system.
    Window → Package Manager → Packages: Unity Resgistry → Search: input system them Click en Install !


    YES, the project will be restarted



    2. Create a new folder and name it "InputAction" then right click and at the bottom click InputAtions and name it "RobotController".



    3. Double click on "RobotController. Create the control map for the robot and the actions in this case are two: SelectJoint and MoveJoint.



    Do the same for MoveJoint, but in 2D Vector select right and left.



    ## Create the new Controller

    In the folder "Scripts" create a new script and name it "RobotController"

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using Unity.Robotics;
    4. using Unity.Robotics.UrdfImporter.Control;
    5. using UrdfControlRobot = Unity.Robotics.UrdfImporter.Control;
    6. using UnityEngine.InputSystem;
    7. public class RobotController : MonoBehaviour
    8. {
    9.     public enum RotationDirection { None = 0, Positive = 1, Negative = -1 };
    10.     public enum ControlType { PositionControl };
    11.     //Fields for inputs
    12.     [Header("Robot Control References")]
    13.     [SerializeField] private InputActionProperty moveJointInput;
    14.     [SerializeField] private InputActionProperty selectJointInput;
    15.     //Robot properties
    16.     private ArticulationBody[] articulationChain;
    17.     private Color[] prevColor;
    18.     private int previousIndex;
    19.     [InspectorReadOnly(hideInEditMode: true)]
    20.     public string selectedJoint;
    21.     [HideInInspector]
    22.     public int selectedIndex;
    23.     [Header("Robot properties")]
    24.     public ControlType control = ControlType.PositionControl;
    25.     public float stiffness;
    26.     public float damping;
    27.     public float forceLimit;
    28.     public float speed = 5f; // Units: degree/s
    29.     public float torque = 100f; // Units: Nm or N
    30.     public float acceleration = 5f;// Units: m/s^2 / degree/s^2
    31.     [Tooltip("Color to highlight the currently selected Join")]
    32.     public Color highLightColor = new Color(1, 0, 0, 1);
    33.     //The old controller
    34.     private Controller controller;
    35.     private void OnEnable()
    36.     {
    37.         this.gameObject.AddComponent(typeof(Controller));
    38.         controller = GetComponent<Controller>();
    39.         SetControllerValues();
    40.     }
    41.     void Start()
    42.     {
    43.         previousIndex = selectedIndex = 1;
    44.         this.gameObject.AddComponent<FKRobot>();
    45.         articulationChain = this.GetComponentsInChildren<ArticulationBody>();
    46.         int defDyanmicVal = 10;
    47.         foreach (ArticulationBody joint in articulationChain)
    48.         {
    49.             joint.gameObject.AddComponent<JointControl>();
    50.             joint.jointFriction = defDyanmicVal;
    51.             joint.angularDamping = defDyanmicVal;
    52.             ArticulationDrive currentDrive = joint.xDrive;
    53.             currentDrive.forceLimit = forceLimit;
    54.             joint.xDrive = currentDrive;
    55.         }
    56.         DisplaySelectedJoint(selectedIndex);
    57.         StoreJointColors(selectedIndex);
    58.         //Enable to read new inputs
    59.         selectJointInput.action.Enable();
    60.         moveJointInput.action.Enable();
    61.     }
    62.     private void Update()
    63.     {
    64.         SetSelectedJointIndex(selectedIndex);
    65.         UpdateDirection(selectedIndex);
    66.         //If one key has been triggered to selectJointInput
    67.         if (selectJointInput.action.triggered)
    68.         {
    69.             //Read the value: Up =  (0.0, 1.0) // Down = (0.0, -1.0)
    70.             Vector2 inputValue = selectJointInput.action.ReadValue<Vector2>();
    71.             if (inputValue.y > 0)
    72.             {
    73.                 SetSelectedJointIndex(selectedIndex + 1);
    74.                 Highlight(selectedIndex);
    75.             }
    76.             else
    77.             {
    78.                 SetSelectedJointIndex(selectedIndex - 1);
    79.                 Highlight(selectedIndex);
    80.             }
    81.         }
    82.         UpdateDirection(selectedIndex);
    83.     }
    84.     private void SetSelectedJointIndex(int index)
    85.     {
    86.         if (articulationChain.Length > 0)
    87.         {
    88.             selectedIndex = (index + articulationChain.Length) % articulationChain.Length;
    89.         }
    90.     }
    91.     private void Highlight(int selectedIndex)
    92.     {
    93.         if (selectedIndex == previousIndex || selectedIndex < 0 || selectedIndex >= articulationChain.Length)
    94.         {
    95.             return;
    96.         }
    97.         ResetJointColors(previousIndex);
    98.         StoreJointColors(selectedIndex);
    99.         DisplaySelectedJoint(selectedIndex);
    100.         Renderer[] rendererList = articulationChain[selectedIndex].transform.GetChild(1).GetComponentsInChildren<Renderer>();
    101.         foreach (var mesh in rendererList)
    102.         {
    103.             MaterialExtensions.SetMaterialColor(mesh.material, highLightColor);
    104.         }
    105.     }
    106.     private void UpdateDirection(int jointIndex)
    107.     {
    108.         if (jointIndex < 0 || jointIndex >= articulationChain.Length)
    109.             return;
    110.         //Read the current value from moveJointInput
    111.         Vector2 inputValue = moveJointInput.action.ReadValue<Vector2>();
    112.         JointControl current = articulationChain[jointIndex].GetComponent<JointControl>();
    113.         if (previousIndex != jointIndex)
    114.         {
    115.             JointControl previous = articulationChain[previousIndex].GetComponent<JointControl>();
    116.             previous.direction = UrdfControlRobot.RotationDirection.None;
    117.             previousIndex = jointIndex;
    118.         }
    119.         if (current.controltype != UrdfControlRobot.ControlType.PositionControl)
    120.         {
    121.             UpdateControlType(current);
    122.         }
    123.         // Move Positive = (1.0, 0.0)
    124.         if (inputValue.x > 0)
    125.         {
    126.             current.direction = UrdfControlRobot.RotationDirection.Positive;
    127.             Debug.Log(inputValue);
    128.         }
    129.         // Move Negative = (1.0, 0.0)
    130.         else if (inputValue.x < 0)
    131.         {
    132.             Debug.Log(inputValue);
    133.             current.direction = UrdfControlRobot.RotationDirection.Negative;
    134.         }
    135.         else
    136.         {
    137.             current.direction = UrdfControlRobot.RotationDirection.None;
    138.         }
    139.     }
    140.     private void StoreJointColors(int index)
    141.     {
    142.         Renderer[] materialLists = articulationChain[index].transform.GetChild(1).GetComponentsInChildren<Renderer>();
    143.         prevColor = new Color[materialLists.Length];
    144.         for (int counter = 0; counter < materialLists.Length; counter++)
    145.         {
    146.             prevColor[counter] = MaterialExtensions.GetMaterialColor(materialLists[counter]);
    147.         }
    148.     }
    149.     private void ResetJointColors(int index)
    150.     {
    151.         Renderer[] previousRendererList = articulationChain[index].transform.GetChild(1).GetComponentsInChildren<Renderer>();
    152.         for (int counter = 0; counter < previousRendererList.Length; counter++)
    153.         {
    154.             MaterialExtensions.SetMaterialColor(previousRendererList[counter].material, prevColor[counter]);
    155.         }
    156.     }
    157.     void DisplaySelectedJoint(int selectedIndex)
    158.     {
    159.         if (selectedIndex < 0 || selectedIndex >= articulationChain.Length)
    160.         {
    161.             return;
    162.         }
    163.         selectedJoint = articulationChain[selectedIndex].name + " (" + selectedIndex + ")";
    164.     }
    165.     public void UpdateControlType(JointControl joint)
    166.     {
    167.         joint.controltype = UrdfControlRobot.ControlType.PositionControl;
    168.         if (control == ControlType.PositionControl)
    169.         {
    170.             ArticulationDrive drive = joint.joint.xDrive;
    171.             drive.stiffness = stiffness;
    172.             drive.damping = damping;
    173.             joint.joint.xDrive = drive;
    174.         }
    175.     }
    176.     private void SetControllerValues()
    177.     {
    178.         controller.stiffness = stiffness;
    179.         controller.damping = damping;
    180.         controller.forceLimit = forceLimit;
    181.         controller.speed = speed;
    182.         controller.torque = torque;
    183.         controller.acceleration = acceleration;
    184.     }
    185.     private void FixedUpdate()
    186.     {
    187.         SetControllerValues();
    188.     }
    189. }
    190.  
    NOTE
    If you notice in OnEnable, I am getting the old control, and then I am assigning the properties in SetControllerValues() and referencing the values in FixedUpdate(). I do this because within the package there are other scripts that use the Controller so to avoid breaking it was the quickest solution.

    Now to avoid further conflicts, we are going to modify the old controller.

    Code (CSharp):
    1. using System;
    2. using Unity.Robotics;
    3. using UnityEngine;
    4.  
    5. namespace Unity.Robotics.UrdfImporter.Control
    6. {
    7.     public enum RotationDirection { None = 0, Positive = 1, Negative = -1 };
    8.     public enum ControlType { PositionControl };
    9.  
    10.     public class Controller : MonoBehaviour
    11.     {
    12.         [HideInInspector]
    13.         public ControlType control = ControlType.PositionControl;
    14.         [HideInInspector]
    15.         public float stiffness;
    16.         [HideInInspector]
    17.         public float damping;
    18.         [HideInInspector]
    19.         public float forceLimit;
    20.         [HideInInspector]
    21.         public float speed = 5f; // Units: degree/s
    22.         [HideInInspector]
    23.         public float torque = 100f; // Units: Nm or N
    24.         [HideInInspector]
    25.         public float acceleration = 5f;// Units: m/s^2 / degree/s^2
    26.         [HideInInspector]
    27.  
    28.  
    29.         public void UpdateControlType(JointControl joint)
    30.         {
    31.             joint.controltype = control;
    32.             if (control == ControlType.PositionControl)
    33.             {
    34.                 ArticulationDrive drive = joint.joint.xDrive;
    35.                 drive.stiffness = stiffness;
    36.                 drive.damping = damping;
    37.                 joint.joint.xDrive = drive;
    38.             }
    39.         }
    40.     }
    41. }
    I have removed almost everything, I have only kept the properties, I do this because as I said before scripts like JointController use Controller to get the properties.
    (I know a bit dirty).

    Delete the old controller, add the new one and reference the fields.



    It's done, now you can use your robot.



    If you have any questions I am happy to answer

    Greetings,
     
    Envilon, ClementVirat and Ivan_br like this.
  2. Envilon

    Envilon

    Joined:
    Aug 8, 2020
    Posts:
    55
    Does anyone know why the 'highlighting problem' has not been resolved in the repository yet? I haven't found any Issue about this in the URDF-Importer or Unity-Robotics-Hub repository either.

    Also, is there any information about why the URDF-Importer is still using the old Input Manager? I feel like this workaround is only temporary.
     
    RendergonPolygons likes this.