I’m sure this is a very simple solution, but I can’t figure it out for the life of me. I’m training a rag doll to walk based on the WalkerAgent training from Unity and I changed a couple things around to better fit my purposes. Now every time any body part from the rag doll collides with the ground, agent is null, preventing any rewards from being applied.
I have double checked my code multiple times and it doesn’t look like there are any problems. The project also appears to be correctly set up. The original error that sent me down this rabbit hole was
“nullreferenceexception: Object reference not set to an instance of an objectUnity.MLAgentsExamples.ObjectContact.OnCollisionStay (UnityEngine.Collision col)
(at Assets/Scripts/ObjectContact.cs:55)UnityEngine.Physics:OnSceneContact(PhysicsScene, IntPtr, Int32) (at /Users/bokken/build/output/unity/unity/Modules/Physics/ScriptBindings/PhysicsContact.bindings.cs:49)”.
I’m pretty sure everything is happening in the correct order and that the agent should be initialized before it is called. Thank you all for your help.
As far as I can tell, these are the relevant portions of code.
From WalkerAgent (the main script):
public override void Initialize()
{
m_OrientationCube = GetComponentInChildren<OrientationCubeController>();
//Setup each body part
m_JdController = GetComponent<JointDriveController>();
m_JdController.SetupBodyPart(hips);
m_JdController.SetupBodyPart(spine);
m_JdController.SetupBodyPart(head);
m_JdController.SetupBodyPart(legrotateL);
m_JdController.SetupBodyPart(thighL);
m_JdController.SetupBodyPart(kneerotateL);
m_JdController.SetupBodyPart(shinL);
m_JdController.SetupBodyPart(footL);
m_JdController.SetupBodyPart(legrotateR);
m_JdController.SetupBodyPart(thighR);
m_JdController.SetupBodyPart(kneerotateR);
m_JdController.SetupBodyPart(shinR);
m_JdController.SetupBodyPart(footR);
m_JdController.SetupBodyPart(armrotateL);
m_JdController.SetupBodyPart(armL);
m_JdController.SetupBodyPart(forearmrotateL);
m_JdController.SetupBodyPart(forearmL);
m_JdController.SetupBodyPart(handL);
m_JdController.SetupBodyPart(armrotateR);
m_JdController.SetupBodyPart(armR);
m_JdController.SetupBodyPart(forearmrotateR);
m_JdController.SetupBodyPart(forearmR);
m_JdController.SetupBodyPart(handR);
}
From JointDriveController:
public void SetupBodyPart(Transform t)
{
var bp = new BodyPart
{
rb = t.GetComponent<Rigidbody>(),
joint = t.GetComponent<CharacterJoint>(),
startingPos = t.position,
startingRot = t.rotation
};
bp.rb.maxAngularVelocity = k_MaxAngularVelocity;
// Add & setup the ground contact script
bp.objectContact = t.GetComponent<ObjectContact>();
var agent = gameObject.GetComponent<Agent>();
if (agent == null)
{
agent = gameObject.AddComponent<Agent>();
}
bp.objectContact.agent = agent;
if (!bp.objectContact)
{
bp.objectContact = t.gameObject.AddComponent<ObjectContact>();
bp.objectContact.agent = gameObject.GetComponent<Agent>();
}
else
{
bp.objectContact.agent = gameObject.GetComponent<Agent>();
}
if (bp.objectContact.agent == null)
{
Debug.LogError($"Agent not found for {t.name}");
}
bp.thisJdController = this;
bodyPartsDict.Add(t, bp);
bodyPartsList.Add(bp);
}
From ObjectContact:
void OnCollisionEnter(Collision col)
{
if (agent == null)
{
Debug.LogError($"Agent is null on {gameObject.name} during OnCollisionEnter with {col.gameObject.name}");
return;
}
if (col.transform.CompareTag(k_Ground))
{
touchingGround = true;
}
if (col.transform.CompareTag(k_Wall))
{
touchingWall = true;
}
if (col.transform.CompareTag(k_Target))
{
touchingTarget = true;
agent.AddReward(targetReward);
}
Matt Clarke is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.