Search Unity

Environment reset on episodebegin.

Discussion in 'ML-Agents' started by m4l4, Sep 11, 2020.

  1. m4l4

    m4l4

    Joined:
    Jul 28, 2020
    Posts:
    81
    Hi everyone, i'm working on a self driving car, and i'm having troubles with the environment reset.

    I've always kept my simulation quite small, so i've been able to easily store position and rotation of every object and use them for the reset.
    now the scene is full of stuff, tires barriers, barrels, street cones and so on.
    needless to say that after every episode, there's ton of stuff scattered around.

    is there a more efficient way of putting everything back in place, than storing every single object pos and rot?

    also, i don't like to use "search by tag", because if i make multiple training areas in the same scene, they will then interfere with each other.
     
  2. mbaske

    mbaske

    Joined:
    Dec 31, 2017
    Posts:
    473
    You can try a recursive approach.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3.  
    4. namespace MBaske
    5. {
    6.     public class ResettableItem
    7.     {
    8.         private Transform tf;
    9.         private Vector3 pos;
    10.         private Quaternion rot;
    11.         private Rigidbody rb;
    12.  
    13.         public ResettableItem(Transform tf)
    14.         {
    15.             this.tf = tf;
    16.             pos = tf.localPosition;
    17.             rot = tf.localRotation;
    18.             rb = tf.GetComponent<Rigidbody>();
    19.         }
    20.  
    21.         public void Reset()
    22.         {
    23.             if (rb != null)
    24.             {
    25.                 rb.velocity = Vector3.zero;
    26.                 rb.angularVelocity = Vector3.zero;
    27.                 rb.Sleep();
    28.             }
    29.  
    30.             tf.localPosition = pos;
    31.             tf.localRotation = rot;
    32.         }
    33.     }
    34.  
    35.     public class Resetter
    36.     {
    37.         private List<ResettableItem> items;
    38.  
    39.         public Resetter(Transform tf)
    40.         {
    41.             items = new List<ResettableItem>();
    42.             Add(tf);
    43.         }
    44.  
    45.         public void Reset()
    46.         {
    47.             foreach (ResettableItem item in items)
    48.             {
    49.                 item.Reset();
    50.             }
    51.         }
    52.  
    53.         private void Add(Transform tf)
    54.         {
    55.             items.Add(new ResettableItem(tf));
    56.  
    57.             for (int i = 0; i < tf.childCount; i++)
    58.             {
    59.                 Add(tf.GetChild(i));
    60.             }
    61.         }
    62.     }
    63. }
    Create a resetter field:
    Resetter resetter;

    On initialize you would call:
    resetter = new Resetter(environment_transform);

    On reset, call:
    resetter.Reset();
     
  3. m4l4

    m4l4

    Joined:
    Jul 28, 2020
    Posts:
    81
    Wow ty i'll try that immediately
     
  4. m4l4

    m4l4

    Joined:
    Jul 28, 2020
    Posts:
    81
    works like a charm, the only problem is that lots of obstacles have a fixed joint linked to the ground. on impact, the joint component doesn't get deactivated, but it gets removed from the gameObject.
    So now i have to find a way to identify which of them needs a fixed joint, add it on reset, and link it to the ground :(
     
  5. mbaske

    mbaske

    Joined:
    Dec 31, 2017
    Posts:
    473
    Should be easy to add to ResettableItem. Something like this (haven't tested it).

    Code (CSharp):
    1. ...
    2. private Rigidbody connected;
    3.  
    4. public ResettableItem(Transform tf)
    5. {
    6.     this.tf = tf;
    7.     pos = tf.localPosition;
    8.     rot = tf.localRotation;
    9.     rb = tf.GetComponent<Rigidbody>();
    10.  
    11.     var joint = tf.GetComponent<FixedJoint>();
    12.     if (joint != null)
    13.     {
    14.         connected = joint.connectedBody;
    15.     }
    16. }
    17.  
    18. public void Reset()
    19. {
    20.     if (rb != null)
    21.     {
    22.         rb.velocity = Vector3.zero;
    23.         rb.angularVelocity = Vector3.zero;
    24.         rb.Sleep();
    25.     }
    26.  
    27.     tf.localPosition = pos;
    28.     tf.localRotation = rot;
    29.  
    30.     if (connected != null)
    31.     {
    32.         var joint = tf.gameObject.AddComponent<FixedJoint>() as FixedJoint;
    33.         joint.connectedBody = connected;
    34.     }
    35. }
    36. ...
    EDIT: Probably should check in Reset() if the old joint still exists, before adding a new one.
    Code (CSharp):
    1. ...
    2. if (connected != null)
    3.     {
    4.         var joint = tf.GetComponent<FixedJoint>();
    5.         if (joint == null)
    6.         {
    7.             joint = tf.gameObject.AddComponent<FixedJoint>() as FixedJoint;
    8.             joint.connectedBody = connected;
    9.         }
    10.     }
    11. ...
     
    Last edited: Sep 12, 2020
  6. m4l4

    m4l4

    Joined:
    Jul 28, 2020
    Posts:
    81
    thanks again, and yes, i need to check first if the joint has been detached to avoid adding duplicates.
     
  7. m4l4

    m4l4

    Joined:
    Jul 28, 2020
    Posts:
    81
    ok, so i've tinkered a bit with the code because i'm a noob and i was getting too many errors using List<ResettableItems> , so i switched to List<Gameobject>.

    when i try to set the fixedJoint breakforce, i get a pretty weird behavior.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ResettableItem : MonoBehaviour
    6. {
    7.         private Vector3 pos;
    8.         private Quaternion rot;
    9.         private Rigidbody rb;
    10.         private Rigidbody connected;
    11.         public float connectionStrenght;
    12.  
    13.  
    14.         public void Awake(){
    15.             pos = transform.position;
    16.             rot = transform.rotation;
    17.             rb = GetComponent<Rigidbody>();
    18.  
    19.             var joint = GetComponent<FixedJoint>();
    20.             if (joint != null)
    21.             {
    22.                 connected = joint.connectedBody;
    23.                 connectionStrenght = joint.breakForce;
    24.                 Debug.Log(joint.breakForce);
    25.             }
    26.  
    27.         }
    28.         public void Reset()
    29.         {
    30.             gameObject.SetActive(true);
    31.  
    32.             if (rb != null)
    33.             {
    34.                 rb.velocity = Vector3.zero;
    35.                 rb.angularVelocity = Vector3.zero;
    36.                 rb.Sleep();
    37.             }
    38.             transform.position = pos;
    39.             transform.rotation = rot;    
    40.  
    41.             if (connected != null)
    42.             {
    43.                 var joint = GetComponent<FixedJoint>();
    44.                 if (joint == null)
    45.                 {
    46.                     joint = gameObject.AddComponent<FixedJoint>() as FixedJoint;
    47.                     joint.breakForce = connectionStrenght;
    48.                     joint.connectedBody = connected;
    49.                    
    50.                 }
    51.             }      
    52.            
    53.         }
    54.     }
    position, rotation and rigidbody work as intended, but the joint doesn't appear to be applied. If i remove, the line:
    joint.breakForce = connectionStrenght;
    the joint gets created, connected to the environment with a default breakForce/torqueForce = infinity

    tooltip says Joint.breakForce{ get; set; } but i don't know what does that mean.

    i've searched online but i haven't been able to figure out how to set the breakforce of a joint via script