Spaces:
Sleeping
Sleeping
| """ | |
| Rule-based baseline agent for the Autonomous Traffic Control environment. | |
| Uses the openenv-core EnvClient (via TrafficControlEnv) for HTTP interaction. | |
| Demonstrates the correct sync API pattern. | |
| Run: | |
| # 1. Start the server (in another terminal): | |
| uvicorn traffic_control_env.server.app:app --port 8000 | |
| # 2. Run this agent: | |
| python -m traffic_control_env.baseline_agent | |
| python -m traffic_control_env.baseline_agent --task emergency_priority | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import time | |
| from typing import Optional | |
| from client import TrafficControlEnv | |
| from models import TrafficAction, TrafficObservation | |
| from models import ( | |
| PHASE_NS_GREEN, PHASE_EW_GREEN, PHASE_ALL_RED, | |
| PHASE_NS_YELLOW, PHASE_EW_YELLOW, | |
| ) | |
| # --------------------------------------------------------------------------- | |
| # Rule-based policy | |
| # --------------------------------------------------------------------------- | |
| class RuleBasedAgent: | |
| """ | |
| Simple heuristic agent: | |
| 1. If any emergency vehicle is waiting, switch to their direction. | |
| 2. Otherwise, switch to the direction with more queued vehicles. | |
| 3. Enforce a minimum green time to avoid flicker. | |
| """ | |
| MIN_GREEN_STEPS = 4 | |
| def __init__(self) -> None: | |
| self._steps_in_green = 0 | |
| self._last_phase = PHASE_NS_GREEN | |
| def act(self, obs: TrafficObservation) -> TrafficAction: | |
| current = obs.current_phase | |
| # During yellow/transition, keep the current phase request | |
| if current in (PHASE_NS_YELLOW, PHASE_EW_YELLOW): | |
| return TrafficAction(light_phase=self._last_phase) | |
| self._steps_in_green += 1 | |
| # 1. Emergency override | |
| em_q = obs.emergency_queue | |
| em_urg = obs.emergency_urgency | |
| ns_em = em_q[0] + em_q[1] # North + South | |
| ew_em = em_q[2] + em_q[3] # East + West | |
| ns_urg = max(em_urg[0], em_urg[1]) if ns_em else 0 | |
| ew_urg = max(em_urg[2], em_urg[3]) if ew_em else 0 | |
| if ns_em > 0 or ew_em > 0: | |
| if ns_urg >= ew_urg and current != PHASE_NS_GREEN: | |
| self._last_phase = PHASE_NS_GREEN | |
| self._steps_in_green = 0 | |
| return TrafficAction(light_phase=PHASE_NS_GREEN) | |
| elif ew_urg > ns_urg and current != PHASE_EW_GREEN: | |
| self._last_phase = PHASE_EW_GREEN | |
| self._steps_in_green = 0 | |
| return TrafficAction(light_phase=PHASE_EW_GREEN) | |
| # Enforce minimum green time | |
| if self._steps_in_green < self.MIN_GREEN_STEPS: | |
| return TrafficAction(light_phase=self._last_phase) | |
| # 2. Queue-length balancing | |
| q = obs.queue_lengths | |
| ns_q = q[0] + q[1] | |
| ew_q = q[2] + q[3] | |
| want_phase = PHASE_NS_GREEN if ns_q >= ew_q else PHASE_EW_GREEN | |
| if want_phase != current: | |
| self._last_phase = want_phase | |
| self._steps_in_green = 0 | |
| return TrafficAction(light_phase=want_phase) | |
| # --------------------------------------------------------------------------- | |
| # Run loop | |
| # --------------------------------------------------------------------------- | |
| def run(task_id: str = "basic_flow", seed: Optional[int] = 42, url: str = "http://localhost:8000"): | |
| agent = RuleBasedAgent() | |
| # Use the sync wrapper provided by openenv-core's EnvClient | |
| with TrafficControlEnv(base_url=url).sync() as env: | |
| print(f"\n=== Traffic Control Baseline Agent ===") | |
| print(f"Task: {task_id} | Seed: {seed} | Server: {url}") | |
| step_result = env.reset(task_id=task_id, seed=seed) | |
| step = 0 | |
| while not step_result.done: | |
| obs = step_result.observation | |
| action = agent.act(obs) | |
| step_result = env.step(action) | |
| obs = step_result.observation | |
| step += 1 | |
| if step % 20 == 0: | |
| q = obs.queue_lengths | |
| em_q = obs.emergency_queue | |
| print( | |
| f" Step {step:3d} | Phase {obs.current_phase} | " | |
| f"Q [N{q[0]},S{q[1]},E{q[2]},W{q[3]}] | " | |
| f"EmQ [N{em_q[0]},S{em_q[1]},E{em_q[2]},W{em_q[3]}] | " | |
| f"Reward {step_result.reward:+.2f}" | |
| ) | |
| state = env.state() | |
| print(f"\n=== Episode Ended (step {step}) ===") | |
| print(f" Total vehicles: {state.total_vehicles_passed}") | |
| print(f" Emergency passed: {state.total_emergency_passed}") | |
| print(f" Total waiting: {state.total_waiting_time:.1f}") | |
| print(f" Collisions: {state.total_collisions}") | |
| print(f" Phase changes: {state.total_phase_changes}") | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser(description="Rule-based baseline agent") | |
| parser.add_argument("--task", default="basic_flow", | |
| choices=["basic_flow", "emergency_priority", "dynamic_scenarios"]) | |
| parser.add_argument("--seed", type=int, default=42) | |
| parser.add_argument("--url", default="http://localhost:8000") | |
| args = parser.parse_args() | |
| run(task_id=args.task, seed=args.seed, url=args.url) | |