Skip to content

Commit aeba458

Browse files
authored
Merge pull request #463 from Emerge-Lab/ev/goal-terminate-mode
goal_on_lane knob — scatter goals within waypoint-spacing range
2 parents e22e96c + d83e60d commit aeba458

5 files changed

Lines changed: 152 additions & 4 deletions

File tree

pufferlib/config/ocean/drive.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ compute_eval_metrics = False
7676
; --- Goal / Target ---
7777
; Target representation - options: "static", "dynamic"
7878
target_type = "static"
79+
; True: place goals along the agent's route (existing behavior, on-lane and
80+
; in front of the agent). False: scatter each goal at a uniformly random
81+
; drivable point anywhere on the map.
82+
goal_on_lane = True
7983
; Meters around goal to be considered "reached"
8084
goal_radius = 2.0
8185
; Maximum speed at final waypoint to count goal reward

pufferlib/ocean/drive/binding.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,6 +1953,7 @@ static int my_init(Env *env, PyObject *args, PyObject *kwargs) {
19531953
env->num_target_waypoints = MAX_TARGET_WAYPOINTS;
19541954
}
19551955
env->target_type = (int) unpack(kwargs, "target_type");
1956+
env->goal_on_lane = (int) unpack(kwargs, "goal_on_lane");
19561957
env->obs_slots_boundary_n = (int) unpack(kwargs, "obs_slots_boundary_n");
19571958
env->obs_slots_lane_n = (int) unpack(kwargs, "obs_slots_lane_n");
19581959
env->obs_slots_partners_n = (int) unpack(kwargs, "obs_slots_partners_n");

pufferlib/ocean/drive/drive.h

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
// => For each entity type in gridmap, diagonal poly-lines -> sqrt(2), include diagonal ends -> 2
113113
#define MAX_ENTITIES_PER_CELL 30
114114

115-
// TARGET_TYPE modes (controls what target info is in observations)
115+
// TARGET_TYPE modes (controls what target info is in observations).
116116
#define TARGET_STATIC 0
117117
#define TARGET_DYNAMIC 1
118118

@@ -396,6 +396,7 @@ struct Drive {
396396
int num_target_waypoints;
397397
int logs_capacity;
398398
int target_type;
399+
int goal_on_lane;
399400
char *ini_file;
400401
int collision_behavior; // 0 = none, 1=stop, 2 = remove
401402
int offroad_behavior; // 0 = none, 1=stop, 2 = remove
@@ -1927,8 +1928,142 @@ static int compute_new_route(Drive *env, int agent_idx, int current_lane_idx) {
19271928
return 1; // Success
19281929
}
19291930

1931+
// Pick a random drivable point on the map whose Euclidean distance from
1932+
// (ref_x, ref_y) lies in [min_dist, max_dist]. Returns 1 on success.
1933+
static int pick_random_drivable_position(
1934+
Drive *env,
1935+
float ref_x,
1936+
float ref_y,
1937+
float min_dist,
1938+
float max_dist,
1939+
float *out_x,
1940+
float *out_y,
1941+
float *out_z) {
1942+
GridMap *gm = env->grid_map;
1943+
float cell = GRID_CELL_SIZE;
1944+
float half_diag = 0.5f * cell * (float) M_SQRT2;
1945+
float min_d2 = min_dist * min_dist;
1946+
float max_d2 = max_dist * max_dist;
1947+
float cell_filter = max_dist + half_diag;
1948+
float cell_filter2 = cell_filter * cell_filter;
1949+
1950+
int ref_cx = (int) ((ref_x - gm->top_left_x) / cell);
1951+
int ref_cy = (int) ((ref_y - gm->bottom_right_y) / cell);
1952+
int half_extent = (int) ceilf(cell_filter / cell);
1953+
1954+
int x_lo = ref_cx - half_extent;
1955+
int y_lo = ref_cy - half_extent;
1956+
int x_hi = ref_cx + half_extent;
1957+
int y_hi = ref_cy + half_extent;
1958+
if (x_lo < 0) {
1959+
x_lo = 0;
1960+
}
1961+
if (y_lo < 0) {
1962+
y_lo = 0;
1963+
}
1964+
if (x_hi >= gm->grid_cols) {
1965+
x_hi = gm->grid_cols - 1;
1966+
}
1967+
if (y_hi >= gm->grid_rows) {
1968+
y_hi = gm->grid_rows - 1;
1969+
}
1970+
1971+
int n_cand = 0;
1972+
float pick_x = 0.0f, pick_y = 0.0f, pick_z = 0.0f;
1973+
for (int gy = y_lo; gy <= y_hi; gy++) {
1974+
float cy = gm->bottom_right_y + (gy + 0.5f) * cell;
1975+
for (int gx = x_lo; gx <= x_hi; gx++) {
1976+
float cx = gm->top_left_x + (gx + 0.5f) * cell;
1977+
float dcx = cx - ref_x;
1978+
float dcy = cy - ref_y;
1979+
if (dcx * dcx + dcy * dcy > cell_filter2) {
1980+
continue;
1981+
}
1982+
int gi = gy * gm->grid_cols + gx;
1983+
for (int i = 0; i < gm->cell_entities_count[gi]; i++) {
1984+
GridMapEntity e = gm->cells[gi][i];
1985+
RoadMapElement *lane = &env->road_elements[e.entity_idx];
1986+
if (!is_drivable_road_lane(lane->type)) {
1987+
continue;
1988+
}
1989+
// The grid stores polyline SEGMENTS (start vertex = geometry_idx).
1990+
// Sample a uniform point along the segment so candidate positions
1991+
// are continuous along the road rather than quantized to vertices.
1992+
int k = e.geometry_idx;
1993+
if (k + 1 >= lane->segment_length) {
1994+
continue;
1995+
}
1996+
float t = (float) rand() / (float) RAND_MAX;
1997+
float ex = lane->x[k] + t * (lane->x[k + 1] - lane->x[k]);
1998+
float ey = lane->y[k] + t * (lane->y[k + 1] - lane->y[k]);
1999+
float ez = lane->z[k] + t * (lane->z[k + 1] - lane->z[k]);
2000+
float edx = ex - ref_x;
2001+
float edy = ey - ref_y;
2002+
float ed2 = edx * edx + edy * edy;
2003+
if (ed2 < min_d2 || ed2 > max_d2) {
2004+
continue;
2005+
}
2006+
n_cand++;
2007+
if (rand() % n_cand == 0) {
2008+
pick_x = ex;
2009+
pick_y = ey;
2010+
pick_z = ez;
2011+
}
2012+
}
2013+
}
2014+
}
2015+
2016+
if (n_cand == 0) {
2017+
return 0;
2018+
}
2019+
*out_x = pick_x;
2020+
*out_y = pick_y;
2021+
*out_z = pick_z;
2022+
return 1;
2023+
}
2024+
19302025
static void compute_goals(Drive *env, int agent_idx) {
19312026
Agent *agent = &env->agents[agent_idx];
2027+
2028+
// goal_on_lane=False: place each goal at a random drivable point whose
2029+
// Euclidean distance from the previous anchor (agent for goal 0, previous
2030+
// goal for subsequent ones) lies in [min_waypoint_spacing,
2031+
// max_waypoint_spacing].
2032+
if (!env->goal_on_lane) {
2033+
int num_target_waypoints = env->num_target_waypoints;
2034+
if (num_target_waypoints <= 0 || num_target_waypoints > MAX_TARGET_WAYPOINTS) {
2035+
num_target_waypoints = MAX_TARGET_WAYPOINTS;
2036+
}
2037+
float ref_x = agent->sim_x;
2038+
float ref_y = agent->sim_y;
2039+
for (int i = 0; i < num_target_waypoints; i++) {
2040+
float gx, gy, gz;
2041+
if (!pick_random_drivable_position(
2042+
env,
2043+
ref_x,
2044+
ref_y,
2045+
env->min_waypoint_spacing,
2046+
env->max_waypoint_spacing,
2047+
&gx,
2048+
&gy,
2049+
&gz)) {
2050+
printf("[GIGAFLOW WARNING] -> pick_random_drivable_position failed for agent %d\n", agent_idx);
2051+
agent->removed = 1;
2052+
return;
2053+
}
2054+
agent->goal_positions_x[i] = gx;
2055+
agent->goal_positions_y[i] = gy;
2056+
agent->goal_positions_z[i] = gz;
2057+
ref_x = gx;
2058+
ref_y = gy;
2059+
}
2060+
agent->current_goal_idx = 0;
2061+
agent->goal_position_x = agent->goal_positions_x[0];
2062+
agent->goal_position_y = agent->goal_positions_y[0];
2063+
agent->goal_position_z = agent->goal_positions_z[0];
2064+
return;
2065+
}
2066+
19322067
struct Path *path = agent->path;
19332068

19342069
// Validate path exists

pufferlib/ocean/drive/drive.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ def __init__(
7878
control_mode="control_vehicles",
7979
map_dir=None,
8080
target_type="static",
81+
goal_on_lane=True,
8182
reward_conditioning=False,
8283
reward_randomization=False,
8384
compute_eval_metrics=True,
@@ -144,6 +145,7 @@ def __init__(
144145
self.target_type = binding.TARGET_DYNAMIC
145146
else:
146147
raise ValueError(f"target_type must be 'static' or 'dynamic'. Got: {target_type}")
148+
self.goal_on_lane = int(bool(goal_on_lane))
147149
self.collision_behavior = collision_behavior
148150
self.offroad_behavior = offroad_behavior
149151
self.traffic_light_behavior = traffic_light_behavior
@@ -393,6 +395,7 @@ def _env_init_kwargs(self, map_file, max_agents):
393395
"max_waypoint_spacing": self.max_waypoint_spacing,
394396
"num_target_waypoints": self.num_target_waypoints,
395397
"target_type": self.target_type,
398+
"goal_on_lane": self.goal_on_lane,
396399
"obs_slots_lane_n": self.obs_slots_lane_n,
397400
"obs_slots_boundary_n": self.obs_slots_boundary_n,
398401
"obs_slots_partners_n": self.obs_slots_partners_n,

scripts/cluster_configs/single_agent_speed_run.yaml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ env.max_agents_per_env: 1
2424
env.num_agents: 1024
2525
env.use_map_cache: 1
2626

27-
# Single goal waypoint ahead of the agent (route mode uses the default
28-
# min/max waypoint spacing of 20m/60m to place it).
27+
# Single goal placed at a random drivable point on the map whose Euclidean
28+
# distance from the agent lies in [min_waypoint_spacing, max_waypoint_spacing].
29+
# 6m floor avoids spawning the goal on top of the agent; 500m saturates at the
30+
# Town10HD map diameter (~260m) so goals can land anywhere on the network.
2931
env.num_target_waypoints: 1
32+
env.goal_on_lane: False
33+
env.min_waypoint_spacing: 6.0
34+
env.max_waypoint_spacing: 500.0
3035

3136
# Traffic lights fully off: not observed, not scored, no reward penalty.
3237
env.traffic_light_behavior: 0
@@ -63,5 +68,5 @@ eval.behaviors_unprotected_right.enabled: 0
6368
# W&B. Group has no space: submit_cluster.py joins the inner command into a
6469
# bash -c string without quoting arg values, so a space would split the arg.
6570
wandb: True
66-
wandb_project: puffer_drive
71+
wandb_project: single_agent_nightly_test
6772
wandb_group: Nightly_Test

0 commit comments

Comments
 (0)