Skip to content
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

feat: interactive mode for rviz npcs #132

8 changes: 4 additions & 4 deletions Assets/AWSIM/Scenes/Main/AutowareSimulation.unity
Original file line number Diff line number Diff line change
Expand Up @@ -1559,7 +1559,7 @@ MonoBehaviour:
- {fileID: 6850358619771218631, guid: 9bc315af95865dd4bbf4a8f716791609, type: 3}
npcPedestrianParent: {fileID: 1822423795}
npcVehicleParent: {fileID: 10387859}
despawnTime: 20
despawnTime: 30
--- !u!1 &221280047
GameObject:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -1658,8 +1658,8 @@ MonoBehaviour:
m_TargetGraphic: {fileID: 1743169424}
m_HandleRect: {fileID: 1743169422}
m_Direction: 2
m_Value: 0.9999898
m_Size: 0.77988505
m_Value: 1.0000012
m_Size: 0.9126437
m_NumberOfSteps: 0
m_OnValueChanged:
m_PersistentCalls:
Expand Down Expand Up @@ -10222,7 +10222,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -3.75, y: -39.999035}
m_AnchoredPosition: {x: -3.75, y: -40.000027}
m_SizeDelta: {x: -27.5, y: 0}
m_Pivot: {x: 0.5, y: 1}
--- !u!114 &2100303027
Expand Down
212 changes: 178 additions & 34 deletions Assets/AWSIM/Scripts/NPCs/RvizNPCSpawner/RVIZNPCSpawner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,18 @@ public class RVIZNPCSpawner : MonoBehaviour

private bool _willSpawnNpc = false;
private bool _willDespawnAllNPCs = false;
private int _npcLabel;
private bool _willDespawnInteractiveNPCs = false;
private bool _allNPCsDespawned = false;
private float _npcVelocity;
private int _npcLabel;
private int _interactiveAction = 0;
private int _activeNPCCount = 0;
private GameObject interactiveVehicle;
private List<GameObject> _spawnedNPCs = new List<GameObject>();
private Quaternion _npcSpawnRotation;
private Vector3 _npcSpawnPosition;
private List<GameObject> _spawnedNPCs = new List<GameObject>();
private Vector3 _previousPosition;
private float _raycastStart = 1.33f;

// Subscriber
ISubscription<dummy_perception_publisher.msg.Object> dummyPerceptionSubscriber;
Expand All @@ -50,36 +57,42 @@ void Start()

private void FixedUpdate()
{
// clear the _spawnedNPCs array if all the npcs are despawned
if (_allNPCsDespawned)
{
DespawnAllNPCs();
_allNPCsDespawned = false;
return;
}

// spawn a new NPC
if (_willSpawnNpc)
{
// check where the ground collider is and spawn the NPC above the ground
Vector3 rayOrigin = new Vector3(_npcSpawnPosition.x, 1000.0f, _npcSpawnPosition.z);
Vector3 rayDirection = Vector3.down;
SpawnNewNPC();
}

if (Physics.Raycast(rayOrigin, rayDirection, out RaycastHit hit, Mathf.Infinity))
{
_npcSpawnPosition = new Vector3(_npcSpawnPosition.x, hit.point.y + 1.33f, _npcSpawnPosition.z);
if (_npcLabel == 7)
{
SpawnPedestrians(_npcSpawnPosition, _npcSpawnRotation);
}
else
{
SpawnVehicles(_npcSpawnPosition, _npcSpawnRotation, _npcLabel);
}
}
else

// interactive action = 1: update the position of the last spawned interactive NPC
if (_interactiveAction == 1 && _spawnedNPCs != null && _spawnedNPCs.Count > 0)
{
if (Mathf.Abs(_previousPosition.x - _npcSpawnPosition.x) >= 0.1f || Mathf.Abs(_previousPosition.z - _npcSpawnPosition.z) >= 0.1f)
{
Debug.LogWarning("No mesh or collider detected on target location. Please ensure that the target location is on a mesh or collider.");
MoveNPC();
}

_willSpawnNpc = false;
}


if (_willDespawnAllNPCs)
{
DespawnAllNPCs();
_willDespawnAllNPCs = false;
return;
}
if (_willDespawnInteractiveNPCs)
{
DespawnInteractiveNPCs();
_willDespawnInteractiveNPCs = false;
return;
}
}

Expand All @@ -89,18 +102,69 @@ private void FixedUpdate()
/// <param name="msg">Received Object message</param>
void OnObjectInfoReceived(dummy_perception_publisher.msg.Object msg)
{
if (msg.Classification.Label == 0)
_npcLabel = msg.Classification.Label; // Label: 0 = delete All Npcs, 7 = Spawn pedestrians, 3 = spawn vehicle
_interactiveAction = msg.Action; // Action: 0 = uninteractive mode, 1 = interactive mode, 2 = delete interactive NPCs
_npcSpawnPosition = ROS2Utility.RosMGRSToUnityPosition(msg.Initial_state.Pose_covariance.Pose.Position);
_npcSpawnRotation = ROS2Utility.RosToUnityRotation(msg.Initial_state.Pose_covariance.Pose.Orientation);
_npcVelocity = (float)msg.Initial_state.Twist_covariance.Twist.Linear.X;

// interactive mode;
if (_interactiveAction == 1)
{
return;
}

if (_npcLabel == 0)
{
// despawn all the rviz NPCs
Debug.Log("delete spawned NPCs");
_willDespawnAllNPCs = true;
return;
}
_willSpawnNpc = true;
_npcSpawnPosition = ROS2Utility.RosMGRSToUnityPosition(msg.Initial_state.Pose_covariance.Pose.Position);
_npcSpawnRotation = ROS2Utility.RosToUnityRotation(msg.Initial_state.Pose_covariance.Pose.Orientation);
_npcLabel = msg.Classification.Label;
_npcVelocity = (float)msg.Initial_state.Twist_covariance.Twist.Linear.X;


// spawn normal npcs
if (_interactiveAction == 0)
{
_willSpawnNpc = true;
return;
}

// delete only interactive npcs
if (_interactiveAction == 2)
{
_willDespawnInteractiveNPCs = true;
return;
}

}

private void SpawnNewNPC()
{
{
// check where the ground collider is and spawn the NPC above the ground
Vector3 rayOrigin = new Vector3(_npcSpawnPosition.x, _raycastStart, _npcSpawnPosition.z);
Vector3 rayDirection = Vector3.down;

if (Physics.Raycast(rayOrigin, rayDirection, out RaycastHit hit, Mathf.Infinity))
{
_npcSpawnPosition = new Vector3(_npcSpawnPosition.x, hit.point.y + _raycastStart, _npcSpawnPosition.z);
if (_npcLabel == 7)
{
SpawnPedestrians(_npcSpawnPosition, _npcSpawnRotation);
}
else
{
SpawnVehicles(_npcSpawnPosition, _npcSpawnRotation, _npcLabel);
}
_activeNPCCount++;
}
else
{
Debug.LogWarning("No mesh or collider detected on target location. Please ensure that the target location is on a mesh or collider.");
}

_willSpawnNpc = false;
return;
}
}

/// <summary>
Expand All @@ -109,11 +173,23 @@ void OnObjectInfoReceived(dummy_perception_publisher.msg.Object msg)
private void SpawnPedestrians(Vector3 spawnPoint, Quaternion spawnOrientation)
{
GameObject npcPedestrian = Instantiate(npcPedestrianPrefab, new Vector3(spawnPoint.x, spawnPoint.y, spawnPoint.z), spawnOrientation, npcPedestrianParent);
SimplePedestrianWalkerController walker = npcPedestrian.AddComponent<SimplePedestrianWalkerController>();
_spawnedNPCs.Add(npcPedestrian);

// in interactive mode I don't need the following, but I need it in normal mode
SimplePedestrianWalkerController walker = npcPedestrian.AddComponent<SimplePedestrianWalkerController>();
walker.GetType().GetField("duration", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(walker, 30);
walker.GetType().GetField("speed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(walker, _npcVelocity);
walker.GetType().GetField("speed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(walker, _interactiveAction == 1 ? 0 : _npcVelocity);

if (_interactiveAction == 1)
{
NPCPedestrian pedestrianScript = npcPedestrian.GetComponent<NPCPedestrian>();
if (pedestrianScript != null)
{
Destroy(walker);
Destroy(pedestrianScript);
}
}

_spawnedNPCs.Add(npcPedestrian);
StartCoroutine(DespawnNPC(npcPedestrian, despawnTime));
}

Expand All @@ -122,7 +198,10 @@ private void SpawnPedestrians(Vector3 spawnPoint, Quaternion spawnOrientation)
/// </summary>
private void SpawnVehicles(Vector3 spawnPoint, Quaternion spawnOrientation, int vehicleType)
{
// default vehicle is car
GameObject vehiclePrefab = npcCarPrefabs[Random.Range(0, npcCarPrefabs.Length - 1)];

// change the vehicle to bus
if (vehicleType == 3)
{
vehiclePrefab = npcBusPrefabs[Random.Range(0, npcBusPrefabs.Length)];
Expand All @@ -137,16 +216,53 @@ private void SpawnVehicles(Vector3 spawnPoint, Quaternion spawnOrientation, int
NPCMovement npcMovement = npcVehicle.AddComponent<NPCMovement>();
npcMovement.Initialize(_npcVelocity);

// despawn automatically after some time.
StartCoroutine(DespawnNPC(npcVehicle, despawnTime));
}

private void MoveNPC()
{
int groundLayerMask = LayerMask.GetMask("Ground");

Vector3 rayOrigin = new Vector3(_npcSpawnPosition.x, _raycastStart, _npcSpawnPosition.z);
Vector3 rayDirection = Vector3.down;

if (Physics.Raycast(rayOrigin, rayDirection, out RaycastHit hit, Mathf.Infinity, groundLayerMask))
{
interactiveVehicle = _spawnedNPCs[_spawnedNPCs.Count - 1];
interactiveVehicle.tag = "InteractiveNpcs";
if (interactiveVehicle != null)
{
if (_npcLabel == 7)
{
// remove unwanted components for interactive pedestrians
NPCPedestrian pedestrianScript = interactiveVehicle.GetComponent<NPCPedestrian>();
SimplePedestrianWalkerController walker = interactiveVehicle.GetComponent<SimplePedestrianWalkerController>();
if (walker != null)
{
Destroy(walker); // Destroy the SimplePedestrianWalkerController script
}

if (pedestrianScript != null)
{
Destroy(pedestrianScript); // Destroy the NPCPedestrian script
}
}

interactiveVehicle.transform.position = new Vector3(_npcSpawnPosition.x, hit.point.y, _npcSpawnPosition.z);
_previousPosition = interactiveVehicle.transform.position;
interactiveVehicle.transform.rotation = _npcSpawnRotation;
}
return;
}
}

/// <summary>
/// Recursively set layer of the NPC and its children to layer 12: "NPC Vehicle"
/// </summary>
private void SetNPCLayer(GameObject obj, int newLayer)
{
obj.layer = newLayer;

foreach (Transform child in obj.transform)
{
SetNPCLayer(child.gameObject, newLayer);
Expand All @@ -160,23 +276,51 @@ private IEnumerator DespawnNPC(GameObject npc, float delay)
{
yield return new WaitForSeconds(delay);
Destroy(npc);
_activeNPCCount--;

if (_activeNPCCount == 0)
{
_allNPCsDespawned = true; // Set flag to trigger despawn check in FixedUpdate
}
}

/// <summary>
/// Despawn all NPCs
/// </summary>
private void DespawnAllNPCs()
{
_activeNPCCount = 0;
foreach (var npc in _spawnedNPCs)
{
Destroy(npc);
}
DespawnInteractiveNPCs();
_spawnedNPCs.Clear();
}

/// <summary>
/// Despawn only interactive NPCs
/// </summary>
private void DespawnInteractiveNPCs()
{
GameObject[] npcs = GameObject.FindGameObjectsWithTag("InteractiveNpcs");
foreach (GameObject npc in npcs)
{
_activeNPCCount--;
Destroy(npc);
}
if (_activeNPCCount == 0)
{
_allNPCsDespawned = true;
}
}


/// <summary>
/// Clean up the subscription when the GameObject is destroyed
/// </summary>
void OnDestroy()
{
// Clean up the subscription when the GameObject is destroyed
SimulatorROS2Node.RemoveSubscription<dummy_perception_publisher.msg.Object>(dummyPerceptionSubscriber);
}
}
Expand Down
1 change: 1 addition & 0 deletions ProjectSettings/TagManager.asset
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ TagManager:
- OdometrySensor
- MainCanvas
- CameraOutputCanvas
- InteractiveNpcs
layers:
- Default
- TransparentFX
Expand Down
Loading