File size: 7,594 Bytes
9b5744e
a1a27eb
 
 
 
9b5744e
 
dc00fdd
b6f80c5
 
 
a1a27eb
 
 
 
9b5744e
 
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
 
b6f80c5
 
a1a27eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b6f80c5
 
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
 
 
 
 
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
 
 
b6f80c5
a1a27eb
 
 
 
 
b6f80c5
 
a1a27eb
 
 
 
 
 
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
 
 
 
 
 
 
 
 
b6f80c5
 
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
 
b6f80c5
a1a27eb
b6f80c5
 
a1a27eb
b6f80c5
a1a27eb
 
 
b6f80c5
 
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
 
 
 
 
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b6f80c5
 
a1a27eb
b6f80c5
a1a27eb
b6f80c5
a1a27eb
 
 
 
 
 
 
b6f80c5
a1a27eb
b6f80c5
a1a27eb
b6f80c5
 
a1a27eb
 
 
 
 
b6f80c5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
---
title: Autonomous Traffic Control Environment
emoji: 🚦
colorFrom: red
colorTo: green
sdk: docker
pinned: false
app_port: 7860
base_path: /web
tags:
  - openenv
  - reinforcement-learning
  - traffic-control
  - emergency-vehicles
  - autonomous-systems
---

# 🚦 Autonomous Traffic Control β€” OpenEnv Environment

An LLM-driven reinforcement learning environment for autonomous traffic signal control at a 4-way intersection. Built for the **Meta Γ— PyTorch Γ— SST Γ— OpenEnv Hackathon**.

- **HF Space:** [amanmurari/sst-hack](https://huggingface.co/spaces/amanmurari/sst-hack)
- **GitHub:** [amanmurari/openenv-hc2](https://github.com/amanmurari/openenv-hc2)

---

## Overview

An LLM agent controls traffic signals to maximise vehicle throughput while prioritising emergency vehicles. The environment features:

- Sinusoidal traffic wave patterns (realistic rush-hour simulation)
- Emergency vehicles with escalating urgency (urgency^1.5 penalty per waiting step)
- Yellow-light transition state machine
- Traffic surge events in hard tasks
- Multi-objective grading aligned with real traffic KPIs

---

## Tasks

| Task | Difficulty | Steps | Key Challenge |
|---|---|---|---|
| `basic_flow` | Easy | 200 | Maximise throughput (target 1.8 veh/step) |
| `emergency_priority` | Medium | 300 | Clear emergencies fast (avg delay < 3 steps) |
| `dynamic_scenarios` | Hard | 400 | Surge traffic + simultaneous emergencies, no collisions |

---

## Action & Observation Space

### Action
```python
TrafficAction(light_phase: int)
# 0 = NS_GREEN  (North-South green, East-West red)
# 1 = EW_GREEN  (East-West green, North-South red)
# 2 = ALL_RED   (All red β€” emergency clearance)
```

### Observation
```python
TrafficObservation(
    current_phase: int,          # Active phase (0-4, incl. yellow transitions)
    time_in_phase: int,          # Steps held in current phase
    queue_lengths: List[int],    # Regular vehicle queue [N, S, E, W]
    emergency_queue: List[int],  # Emergency vehicle count [N, S, E, W]
    emergency_urgency: List[int],# Max urgency 0-10 per approach
    vehicles_passed: int,        # Regular vehicles cleared this step
    emergency_passed: int,       # Emergency vehicles cleared this step
    avg_wait_time: float,        # Avg waiting time across all queued vehicles
    queue_trend: List[int],      # Queue growth since last step [N, S, E, W]
    collision: bool,             # Gridlock-induced collision flag
    done: bool,
    reward: float,
)
```

---

## Reward Function

```
+0.30  Γ— regular vehicles cleared per step
+12.0  Γ— emergency vehicles cleared per step
-0.08  Γ— total vehicles waiting (queue pressure)
-(urgency^1.5) Γ— 0.5  per waiting emergency vehicle (every step!)
-0.50 to -2.0  for unnecessary phase switch (proportional to empty-queue ratio)
+0.05  stability bonus when traffic flows without switching
-200   gridlock collision (episode-ending catastrophe)
```

---

## Grading Weights

### basic_flow
```
score = throughput_score Γ— 0.60 + efficiency_score Γ— 0.40 + stability_bonus
throughput_score = min(vehicles_per_step / 1.8, 1.0)
efficiency_score = 1 / (1 + avg_waiting Γ— 0.1)
stability_bonus  = max(0, 0.05 Γ— (1 βˆ’ min(switch_rate Γ— 4, 1.0)))
```

### emergency_priority
```
score = throughput Γ— 0.30 + em_rate Γ— 0.35 + delay Γ— 0.20 + efficiency Γ— 0.15
em_rate = min(emergency_cleared_per_step / (1/20), 1.0)
delay   = max(0, 1 βˆ’ avg_em_delay / 12)
```

### dynamic_scenarios
```
score = throughput Γ— 0.25 + em_rate Γ— 0.30 + delay Γ— 0.20
      + efficiency Γ— 0.15 + adaptability Γ— 0.10
adaptability = 1 / (1 + phase_changes_per_step Γ— 0.5)
```

---

## Agent Architecture

The inference agent uses a **hybrid heuristic + LLM** architecture:

1. **Heuristic recommender** β€” computes directional pressure using the actual reward formula (`urgency^1.5 Γ— 0.5`), applies 5 priority rules (critical emergency, moderate emergency, hysteresis, pressure-based switch, default hold).

2. **Live score projection** β€” computes current projected grading scores (throughput, emergency rate, delay, efficiency, adaptability) from `env.state()` and includes them in every LLM prompt.

3. **Chain-of-thought LLM** β€” the model reasons through scoring implications then outputs `{"light_phase": N}` on the final line.

4. **Heuristic fallback** β€” if LLM output is unparseable, silently falls back to the heuristic. No crashes, no missed steps.

---

## Quick Start

### Connect to the live HF Space

```python
from traffic_control.client import TrafficControlEnv
from traffic_control.models import TrafficAction

with TrafficControlEnv(base_url="https://amanmurari-sst-hack.hf.space").sync() as env:
    result = env.reset(task_id="basic_flow", seed=42)
    obs = result.observation

    while not result.done:
        action = TrafficAction(light_phase=0)   # replace with your agent
        result = env.step(action)
        obs = result.observation
        print(f"Cleared: {obs.vehicles_passed} regular, {obs.emergency_passed} emergency | reward={result.reward:.2f}")
```

### Run inference locally

```bash
# Set required env vars
export API_BASE_URL="https://router.huggingface.co/v1"
export HF_TOKEN="hf_..."
export MODEL_NAME="Qwen/Qwen2.5-72B-Instruct"
export SERVER_URL="http://localhost:7860"

python inference.py
```

### Build and run with Docker

```bash
docker build -t traffic-control-env .
docker run -p 7860:7860 traffic-control-env
```

---

## API Endpoints

Once the server is running at `http://localhost:7860`:

| Endpoint | Description |
|---|---|
| `GET /health` | Health check β€” returns `{"status": "ok"}` |
| `POST /reset` | Reset episode β€” body: `{"task_id": "basic_flow", "seed": 42}` |
| `POST /step` | Execute action β€” body: `{"light_phase": 0}` |
| `GET /state` | Cumulative episode state |
| `WS /ws` | WebSocket endpoint for low-latency multi-step sessions |
| `GET /web` | Interactive web dashboard |
| `GET /docs` | OpenAPI / Swagger docs |

---

## Project Structure

```
traffic_control/
β”œβ”€β”€ inference.py          # LLM agent (heuristic + chain-of-thought LLM)
β”œβ”€β”€ client.py             # TrafficControlEnv WebSocket client
β”œβ”€β”€ models.py             # TrafficAction / TrafficObservation / TrafficState
β”œβ”€β”€ environment.py        # Core simulation engine
β”œβ”€β”€ tasks.py              # Task graders (basic_flow, emergency_priority, dynamic_scenarios)
β”œβ”€β”€ dashboard.py          # Web UI dashboard
β”œβ”€β”€ analytics.py          # Episode analytics
β”œβ”€β”€ arena.py              # Multi-agent arena
β”œβ”€β”€ openenv.yaml          # OpenEnv manifest
β”œβ”€β”€ pyproject.toml        # Package metadata
β”œβ”€β”€ Dockerfile            # Container (port 7860)
└── server/
    β”œβ”€β”€ app.py            # FastAPI app (HTTP + WebSocket)
    └── traffic_control_environment.py
```

---

## Environment Variables

| Variable | Required | Description |
|---|---|---|
| `API_BASE_URL` | Yes | LLM proxy endpoint (injected by validator) |
| `API_KEY` | Yes | Proxy API key (injected by validator) |
| `HF_TOKEN` | Alt | Hugging Face token (used if `API_KEY` not set) |
| `MODEL_NAME` | No | LLM model (default: `Qwen/Qwen2.5-72B-Instruct`) |
| `SERVER_URL` | No | Env server URL (default: `http://localhost:7860`) |

---

## Stdout Format

```
[START] task=basic_flow env=traffic_control model=Qwen/Qwen2.5-72B-Instruct
[STEP] step=1 action=light_phase=0 reward=0.65 done=false error=null
[STEP] step=2 action=light_phase=0 reward=0.80 done=false error=null
...
[END] success=true steps=200 score=0.847 rewards=0.65,0.80,...
```