Skip to content

RayPerceptionSensor: handle empty and invalid tags #4155

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions com.unity.ml-agents/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ and this project adheres to

### Bug Fixes
#### com.unity.ml-agents (C#)
- Fixed an issue where RayPerceptionSensor would raise an exception when the
list of tags was empty, or a tag in the list was invalid (unknown, null, or
empty string). (#4155)

#### ml-agents / ml-agents-envs / gym-unity (Python)

## [1.1.0-preview] - 2020-06-10
Expand Down
19 changes: 17 additions & 2 deletions com.unity.ml-agents/Runtime/Sensors/RayPerceptionSensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,24 @@ out DebugDisplayInfo.RayInfo debugRayOut
if (castHit)
{
// Find the index of the tag of the object that was hit.
for (var i = 0; i < input.DetectableTags.Count; i++)
var numTags = input.DetectableTags?.Count ?? 0;
for (var i = 0; i < numTags; i++)
{
if (hitObject.CompareTag(input.DetectableTags[i]))
var tagsEqual = false;
try
{
var tag = input.DetectableTags[i];
if (!string.IsNullOrEmpty(tag))
{
tagsEqual = hitObject.CompareTag(tag);
}
}
catch (UnityException e)
{
// If the tag is null, empty, or not a valid tag, just ignore it.
}

if (tagsEqual)
{
rayOutput.HitTaggedObject = true;
rayOutput.HitTagIndex = i;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@ void OnDrawGizmosSelected()
else
{
var rayInput = GetRayPerceptionInput();
// We don't actually need the tags here, since they don't affect the display of the rays.
// Additionally, the user might be in the middle of typing the tag name when this is called,
// and there's no way to turn off the "Tag ... is not defined" error logs.
// So just don't use any tags here.
rayInput.DetectableTags = null;
for (var rayIndex = 0; rayIndex < rayInput.Angles.Count; rayIndex++)
{
DebugDisplayInfo.RayInfo debugRay;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.MLAgents.Sensors;

namespace Unity.MLAgents.Tests
Expand Down Expand Up @@ -336,6 +337,69 @@ public void TestStaticPerceive()

// Expected to hit the cube
Assert.AreEqual("cube", castOutput.RayOutputs[0].HitGameObject.name);
Assert.AreEqual(0, castOutput.RayOutputs[0].HitTagIndex);
}
}

[Test]
public void TestStaticPerceiveInvalidTags()
{
SetupScene();
var obj = new GameObject("agent");
var perception = obj.AddComponent<RayPerceptionSensorComponent3D>();

perception.RaysPerDirection = 0; // single ray
perception.MaxRayDegrees = 45;
perception.RayLength = 20;
perception.DetectableTags = new List<string>();
perception.DetectableTags.Add("Bad tag");
perception.DetectableTags.Add(null);
perception.DetectableTags.Add("");
perception.DetectableTags.Add(k_CubeTag);

var radii = new[] { 0f, .5f };
foreach (var castRadius in radii)
{
perception.SphereCastRadius = castRadius;
var castInput = perception.GetRayPerceptionInput();

// There's no clean way that I can find to check for a defined tag without
// logging an error.
LogAssert.Expect(LogType.Error, "Tag: Bad tag is not defined.");
var castOutput = RayPerceptionSensor.Perceive(castInput);

Assert.AreEqual(1, castOutput.RayOutputs.Length);

// Expected to hit the cube
Assert.AreEqual("cube", castOutput.RayOutputs[0].HitGameObject.name);
Assert.AreEqual(3, castOutput.RayOutputs[0].HitTagIndex);
}
}

[Test]
public void TestStaticPerceiveNoTags()
{
SetupScene();
var obj = new GameObject("agent");
var perception = obj.AddComponent<RayPerceptionSensorComponent3D>();

perception.RaysPerDirection = 0; // single ray
perception.MaxRayDegrees = 45;
perception.RayLength = 20;
perception.DetectableTags = null;

var radii = new[] { 0f, .5f };
foreach (var castRadius in radii)
{
perception.SphereCastRadius = castRadius;
var castInput = perception.GetRayPerceptionInput();
var castOutput = RayPerceptionSensor.Perceive(castInput);

Assert.AreEqual(1, castOutput.RayOutputs.Length);

// Expected to hit the cube
Assert.AreEqual("cube", castOutput.RayOutputs[0].HitGameObject.name);
Assert.AreEqual(-1, castOutput.RayOutputs[0].HitTagIndex);
}
}
}
Expand Down