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

Add actor alive interface #1919

Merged
merged 8 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
29 changes: 14 additions & 15 deletions envision/tests/test_data_formatter.py
Gamenot marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def covered_data():
actor_id="agent_007",
lane_id="NE-NW",
events=Events(
[], False, False, False, False, False, False, False, True
[], False, False, False, False, False, False, False, True, False
),
driven_path=[(4, 4), (2, 2)],
point_cloud=[[1, 3], [4, 2]],
Expand Down Expand Up @@ -119,17 +119,7 @@ def covered_data():
2, # z
-3.14, # heading
20, # speed
(
[],
0,
0,
0,
0,
0,
0,
0,
1,
), # events
([], 0, 0, 0, 0, 0, 0, 0, 1, 0), # events
[
[[4, 5, 3, 2.24, 1, 4, 10, 0, 4.96]],
[[9, 5, 3, 1.11, 2, 2, 1.2, 1, 9.96]],
Expand Down Expand Up @@ -167,7 +157,16 @@ def complex_data():
actor_id="agent_007",
lane_id="NE-NW",
events=Events(
[], False, False, False, False, False, False, False, True
[],
False,
False,
False,
False,
False,
False,
False,
True,
False,
),
)
for i in range(2)
Expand All @@ -193,7 +192,7 @@ def complex_data():
2,
-3.14,
20,
[[], 0, 0, 0, 0, 0, 0, 0, 1],
[[], 0, 0, 0, 0, 0, 0, 0, 1, 0],
[],
[],
[],
Expand All @@ -209,7 +208,7 @@ def complex_data():
2,
-3.14,
20,
[[], 0, 0, 0, 0, 0, 0, 0, 1],
[[], 0, 0, 0, 0, 0, 0, 0, 1, 0],
[],
[],
[],
Expand Down
15 changes: 15 additions & 0 deletions smarts/core/agent_interface.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could modify an exisiting test or add a new test to check for the actors alive done criteria.

Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,19 @@ class AgentsAliveDoneCriteria:
"""


@dataclass(frozen=True)
class ActorsAliveDoneCriteria:
"""Require actors to persist."""

actors_of_interest: str = r""
Copy link
Member

@Adaickalavan Adaickalavan Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we account for multiple vehicles of interest?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pattern string, so it would account based on pattern matching. I could break it up into multiple for ease of use I suppose.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broken up.

"""Actors that should exist to continue this agent."""

strict: bool = True
"""If strict the agent will be done instantly if an actor of interest is not available
immediately.
"""


@dataclass(frozen=True)
class EventConfiguration:
"""Configure the conditions in which an Event is triggered."""
Expand Down Expand Up @@ -225,6 +238,8 @@ class DoneCriteria:
"""
agents_alive: Optional[AgentsAliveDoneCriteria] = None
"""If set, triggers the ego agent to be done based on the number of active agents for multi-agent purposes."""
actors_alive: Optional[ActorsAliveDoneCriteria] = None
"""If set, triggers the ego agent to be done based on actors existing in the simulation."""
Comment on lines 239 to +242
Copy link
Member

@Adaickalavan Adaickalavan Mar 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, it might be better to combine or unify agents_alive and actors_alive options together into one event configuration, because separate agents_alive and actors_alive options might conflict.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you are considering is the difference between AND and OR causing termination. It is slightly difficult to satisfy these complex cases without introducing expressions.

I think we do not have the case for AND currently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we use a single env to cater to two types of scenarios, namely (i) one which uses and terminates with the social agent as the leader, and (ii) one which uses and terminates with the sumo vehicle as the leader, we end up with a code which looks like

[Assume lines 151 to 158 are uncommented]

# agents_alive=AgentsAliveDoneCriteria(
# agent_lists_alive=[
# AgentsListAlive(
# agents_list=["social-agent-leader-Leader-007"],
# minimum_agents_alive_in_list=1,
# )
# ]
# ),
actors_alive=ActorsAliveDoneCriteria(
actors_of_interest="Leader-007",
strict=True,
),
)

Here, the env will terminate immediately every time as one of the done criteria, namely actors_alive or agents_alive will become true immediately at the start of the every scenario.

Another issue here is the name of vehicle of interest differs in both scenarios, because social-agent-leader string gets prefixed to the agent name when using social agent as the leader.



@dataclass
Expand Down
2 changes: 2 additions & 0 deletions smarts/core/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ class Events(NamedTuple):
agents_alive_done: bool
"""True if all configured co-simulating agents are done (if any), else False.
This is useful for cases when the vehicle is related to other vehicles."""
actors_alive_done: bool
"""True if described actors have left the simulation."""
53 changes: 50 additions & 3 deletions smarts/core/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import logging
import re
import sys
import time
import weakref
Expand All @@ -28,7 +29,7 @@

import numpy as np

from smarts.core.agent_interface import AgentsAliveDoneCriteria
from smarts.core.agent_interface import ActorsAliveDoneCriteria, AgentsAliveDoneCriteria
from smarts.core.plan import Plan
from smarts.core.road_map import RoadMap, Waypoint
from smarts.core.signals import SignalState
Expand Down Expand Up @@ -295,9 +296,9 @@ def step(sim, sensor_state):

@classmethod
def _agents_alive_done_check(
cls, agent_manager, agents_alive: AgentsAliveDoneCriteria
cls, agent_manager, agents_alive: Optional[AgentsAliveDoneCriteria]
):
if not agents_alive:
if agents_alive is None:
return False

if (
Expand Down Expand Up @@ -333,6 +334,37 @@ def _agents_alive_done_check(

return False

@classmethod
def _actors_alive_done_check(
cls,
vehicle_index,
sensor_state,
actors_alive: Optional[ActorsAliveDoneCriteria],
):
if actors_alive is None:
return False

sensor_state: SensorState = sensor_state
from smarts.core.vehicle_index import VehicleIndex

vehicle_index: VehicleIndex = vehicle_index

pattern = re.compile(actors_alive.actors_of_interest)
## TODO optimization to get vehicles that were added and removed last step
## TODO second optimization to check for already known vehicles
for vehicle_id in vehicle_index.vehicle_ids:
Gamenot marked this conversation as resolved.
Show resolved Hide resolved
# get vehicles by pattern
if pattern.match(vehicle_id):
sensor_state.seen_interest_actors = True
return False
if actors_alive.strict or sensor_state.seen_interest_actors:
# if agent requires the actor to exist immediately
# OR if previously seen relevant actors but no actors match anymore
return True

## if never seen a relevant actor
return False

@classmethod
def _is_done_with_events(cls, sim, agent_id, vehicle, sensor_state):
interface = sim.agent_manager.agent_interface_for_agent_id(agent_id)
Expand All @@ -354,6 +386,9 @@ def _is_done_with_events(cls, sim, agent_id, vehicle, sensor_state):
agents_alive_done = cls._agents_alive_done_check(
sim.agent_manager, done_criteria.agents_alive
)
actors_alive_done = cls._actors_alive_done_check(
sim.vehicle_index, sensor_state, done_criteria.actors_alive
)

done = not sim.resetting and (
(is_off_road and done_criteria.off_road)
Expand All @@ -365,6 +400,7 @@ def _is_done_with_events(cls, sim, agent_id, vehicle, sensor_state):
or (is_off_route and done_criteria.off_route)
or (is_wrong_way and done_criteria.wrong_way)
or agents_alive_done
or actors_alive_done
)

events = Events(
Expand All @@ -377,6 +413,7 @@ def _is_done_with_events(cls, sim, agent_id, vehicle, sensor_state):
wrong_way=is_wrong_way,
not_moving=is_not_moving,
agents_alive_done=agents_alive_done,
actors_alive_done=actors_alive_done,
)

return done, events
Expand Down Expand Up @@ -519,11 +556,21 @@ def __init__(self, max_episode_steps: int, plan):
self._max_episode_steps = max_episode_steps
self._plan = plan
self._step = 0
self._seen_interest_actors = False

def step(self):
"""Update internal state."""
self._step += 1

@property
def seen_interest_actors(self) -> bool:
"""If a relevant actor has been spotted before."""
return self._seen_interest_actors

@seen_interest_actors.setter
def seen_interest_actors(self, value: bool):
self._seen_interest_actors = value

@property
def reached_max_episode_steps(self) -> bool:
"""Inbuilt sensor information that describes if episode step limit has been reached."""
Expand Down