soumalya-iitj commited on
Commit
e0dc152
·
verified ·
1 Parent(s): cba7312

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +364 -310
index.html CHANGED
@@ -3,8 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>🚗 Embodied AI - Autonomous Vehicle Simulator</title>
7
-
8
  <style>
9
  * {
10
  margin: 0;
@@ -13,13 +12,12 @@
13
  }
14
 
15
  body {
16
- font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', sans-serif;
17
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
18
  min-height: 100vh;
19
  display: flex;
20
  flex-direction: column;
21
  color: white;
22
- overflow-x: hidden;
23
  }
24
 
25
  .header {
@@ -31,11 +29,16 @@
31
  }
32
 
33
  .header h1 {
34
- font-size: clamp(1.8rem, 4vw, 2.5rem);
35
  margin-bottom: 10px;
36
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
37
  }
38
 
 
 
 
 
 
39
  .main-container {
40
  display: flex;
41
  flex: 1;
@@ -62,18 +65,17 @@
62
  background: #1a1a2e;
63
  border-radius: 10px;
64
  overflow: hidden;
65
- border: 2px solid rgba(255, 255, 255, 0.1);
66
  }
67
 
68
  #simulationCanvas {
69
  width: 100%;
70
  height: 100%;
71
  display: block;
72
- cursor: crosshair;
73
  }
74
 
75
  .controls-panel {
76
- width: 320px;
77
  background: rgba(255, 255, 255, 0.1);
78
  border-radius: 15px;
79
  padding: 20px;
@@ -100,36 +102,14 @@
100
 
101
  .control-group label {
102
  display: block;
103
- margin-bottom: 8px;
104
  font-weight: 500;
105
  color: #e0e0e0;
106
- font-size: 0.9rem;
107
- }
108
-
109
- .slider-container {
110
- display: flex;
111
- align-items: center;
112
- gap: 10px;
113
- }
114
-
115
- .slider-container input[type="range"] {
116
- flex: 1;
117
- background: rgba(255, 255, 255, 0.2);
118
- border-radius: 5px;
119
  }
120
 
121
- .slider-value {
122
- background: rgba(0, 0, 0, 0.3);
123
- padding: 4px 8px;
124
- border-radius: 4px;
125
- font-size: 0.8rem;
126
- min-width: 40px;
127
- text-align: center;
128
- }
129
-
130
- select {
131
  width: 100%;
132
- padding: 10px;
133
  border: none;
134
  border-radius: 8px;
135
  background: rgba(255, 255, 255, 0.2);
@@ -137,6 +117,10 @@
137
  font-size: 14px;
138
  }
139
 
 
 
 
 
140
  .btn {
141
  width: 100%;
142
  padding: 12px;
@@ -166,13 +150,7 @@
166
 
167
  .btn:hover {
168
  transform: translateY(-2px);
169
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
170
- }
171
-
172
- .btn:disabled {
173
- opacity: 0.6;
174
- cursor: not-allowed;
175
- transform: none;
176
  }
177
 
178
  .stats {
@@ -180,7 +158,11 @@
180
  padding: 15px;
181
  border-radius: 8px;
182
  margin-top: 15px;
183
- border: 1px solid rgba(255, 255, 255, 0.1);
 
 
 
 
184
  }
185
 
186
  .stat-item {
@@ -188,13 +170,15 @@
188
  justify-content: space-between;
189
  margin-bottom: 8px;
190
  font-size: 14px;
191
- padding: 4px 0;
 
 
 
192
  }
193
 
194
  .stat-value {
195
  color: #4CAF50;
196
  font-weight: 600;
197
- font-family: monospace;
198
  }
199
 
200
  .ai-info {
@@ -203,16 +187,7 @@
203
  border-radius: 8px;
204
  margin-top: 15px;
205
  font-size: 13px;
206
- }
207
-
208
- .current-decision {
209
- background: rgba(76, 175, 80, 0.2);
210
- padding: 8px;
211
- border-radius: 4px;
212
- margin: 10px 0;
213
- font-family: monospace;
214
- font-size: 12px;
215
- border-left: 3px solid #4CAF50;
216
  }
217
 
218
  .legend {
@@ -220,9 +195,6 @@
220
  flex-wrap: wrap;
221
  gap: 15px;
222
  margin-top: 15px;
223
- padding: 10px;
224
- background: rgba(0, 0, 0, 0.2);
225
- border-radius: 8px;
226
  }
227
 
228
  .legend-item {
@@ -241,16 +213,11 @@
241
  @media (max-width: 768px) {
242
  .main-container {
243
  flex-direction: column;
244
- padding: 10px;
245
  }
246
 
247
  .controls-panel {
248
  width: 100%;
249
  }
250
-
251
- .canvas-container {
252
- height: 400px;
253
- }
254
  }
255
  </style>
256
  </head>
@@ -281,7 +248,7 @@
281
  </div>
282
  <div class="legend-item">
283
  <div class="legend-color" style="background: #FFC107;"></div>
284
- <span>LiDAR Sensors</span>
285
  </div>
286
  </div>
287
  </div>
@@ -289,74 +256,71 @@
289
  <div class="controls-panel">
290
  <div class="control-section">
291
  <h3>🎮 Simulation Controls</h3>
292
- <button class="btn btn-primary" id="startBtn">▶️ Start Simulation</button>
293
- <button class="btn btn-secondary" id="pauseBtn" disabled>⏸️ Pause</button>
294
- <button class="btn btn-danger" id="resetBtn">🔄 Reset</button>
295
  </div>
296
 
297
  <div class="control-section">
298
- <h3>⚙️ AI Parameters</h3>
299
  <div class="control-group">
300
  <label>Vehicle Speed</label>
301
- <div class="slider-container">
302
- <input type="range" id="speedSlider" min="0.5" max="5" value="2" step="0.5">
303
- <span class="slider-value" id="speedValue">2.0</span>
304
- </div>
305
  </div>
306
  <div class="control-group">
307
  <label>Sensor Range</label>
308
- <div class="slider-container">
309
- <input type="range" id="sensorRange" min="50" max="200" value="100" step="10">
310
- <span class="slider-value" id="sensorValue">100</span>
311
- </div>
312
  </div>
313
  <div class="control-group">
314
  <label>AI Behavior</label>
315
  <select id="behaviorSelect">
316
- <option value="cautious">🐌 Cautious</option>
317
- <option value="normal" selected>🚗 Normal</option>
318
- <option value="aggressive">🏎️ Aggressive</option>
319
  </select>
320
  </div>
321
  </div>
322
 
323
  <div class="control-section">
324
  <h3>🏭 Environment</h3>
325
- <button class="btn btn-secondary" id="addObstacleBtn">➕ Add Obstacle</button>
326
- <button class="btn btn-secondary" id="addTargetBtn">🎯 Add Target</button>
327
- <button class="btn btn-danger" id="clearBtn">🗑️ Clear All</button>
328
  </div>
329
 
330
  <div class="stats">
331
- <h4>📊 Performance Metrics</h4>
332
  <div class="stat-item">
333
- <span>Distance Traveled:</span>
334
  <span class="stat-value" id="distanceTraveled">0m</span>
335
  </div>
336
  <div class="stat-item">
337
- <span>Targets Reached:</span>
338
  <span class="stat-value" id="targetsReached">0</span>
339
  </div>
340
  <div class="stat-item">
341
- <span>Obstacles Avoided:</span>
342
  <span class="stat-value" id="obstaclesAvoided">0</span>
343
  </div>
344
  <div class="stat-item">
345
- <span>AI Decisions/sec:</span>
346
  <span class="stat-value" id="decisionsPerSec">0</span>
347
  </div>
348
  </div>
349
 
350
  <div class="ai-info">
351
- <h4>🧠 AI Decision Engine</h4>
352
- <div class="current-decision" id="currentDecision">Ready to start simulation</div>
353
-
354
- <p><strong>Features:</strong></p>
355
- <ul>
356
  <li>Real-time sensor processing</li>
357
  <li>Dynamic path planning</li>
358
  <li>Obstacle avoidance</li>
359
- <li>Target seeking behavior</li>
 
360
  </ul>
361
  </div>
362
  </div>
@@ -367,30 +331,22 @@
367
  const canvas = document.getElementById('simulationCanvas');
368
  const ctx = canvas.getContext('2d');
369
 
 
370
  function resizeCanvas() {
371
  const container = canvas.parentElement;
372
- const rect = container.getBoundingClientRect();
373
- canvas.width = rect.width;
374
- canvas.height = rect.height;
375
  }
376
 
377
  resizeCanvas();
378
  window.addEventListener('resize', resizeCanvas);
379
 
380
- // Simulation variables
381
  let isRunning = false;
382
  let animationId = null;
383
- let vehicle = null;
384
- let obstacles = [];
385
- let targets = [];
386
- let stats = {
387
- distanceTraveled: 0,
388
- targetsReached: 0,
389
- obstaclesAvoided: 0,
390
- decisionsPerSecond: 0
391
- };
392
  let decisionCount = 0;
393
- let lastDecisionTime = Date.now();
394
 
395
  // Vehicle class
396
  class AutonomousVehicle {
@@ -401,12 +357,17 @@
401
  this.vy = 0;
402
  this.angle = 0;
403
  this.speed = 2;
 
404
  this.size = 15;
405
  this.sensorRange = 100;
406
  this.sensors = [];
 
 
 
407
  this.lastX = x;
408
  this.lastY = y;
409
- this.wanderAngle = Math.random() * Math.PI * 2;
 
410
  }
411
 
412
  updateSensors() {
@@ -415,35 +376,27 @@
415
 
416
  for (let i = 0; i < numSensors; i++) {
417
  const angle = (i / numSensors) * 2 * Math.PI;
 
 
 
418
  let distance = this.sensorRange;
419
 
420
- // Check obstacles
421
  for (let obstacle of obstacles) {
422
  const dx = obstacle.x - this.x;
423
  const dy = obstacle.y - this.y;
424
  const distToObstacle = Math.sqrt(dx * dx + dy * dy);
425
- const angleToObstacle = Math.atan2(dy, dx);
426
 
427
- let angleDiff = Math.abs(angle - angleToObstacle);
428
- if (angleDiff > Math.PI) angleDiff = 2 * Math.PI - angleDiff;
429
-
430
- if (angleDiff < 0.5 && distToObstacle < distance) {
431
- distance = Math.max(0, distToObstacle - obstacle.size);
 
 
432
  }
433
  }
434
 
435
- // Check boundaries
436
- const cos = Math.cos(angle);
437
- const sin = Math.sin(angle);
438
-
439
- if (cos > 0) distance = Math.min(distance, (canvas.width - this.x) / cos);
440
- else if (cos < 0) distance = Math.min(distance, -this.x / cos);
441
-
442
- if (sin > 0) distance = Math.min(distance, (canvas.height - this.y) / sin);
443
- else if (sin < 0) distance = Math.min(distance, -this.y / sin);
444
-
445
- distance = Math.max(0, distance - 10);
446
-
447
  this.sensors.push({
448
  angle: angle,
449
  distance: distance,
@@ -455,119 +408,128 @@
455
 
456
  makeDecision() {
457
  decisionCount++;
458
- let decision = 'Exploring';
459
 
460
  // Find closest target
461
  let closestTarget = null;
462
- let minTargetDist = Infinity;
463
 
464
  for (let target of targets) {
465
- const dist = Math.sqrt((target.x - this.x) ** 2 + (target.y - this.y) ** 2);
466
- if (dist < minTargetDist) {
467
- minTargetDist = dist;
 
 
 
468
  closestTarget = target;
469
  }
470
  }
471
 
472
- // Calculate avoidance
473
- let avoidX = 0, avoidY = 0;
474
- let hasObstacle = false;
 
475
 
476
  for (let sensor of this.sensors) {
477
- if (sensor.distance < this.sensorRange * 0.6) {
478
- hasObstacle = true;
479
- const strength = (this.sensorRange * 0.6 - sensor.distance) / (this.sensorRange * 0.6);
480
- avoidX -= Math.cos(sensor.angle) * strength;
481
- avoidY -= Math.sin(sensor.angle) * strength;
482
  }
483
  }
484
 
485
- // Apply forces
486
- if (hasObstacle) {
487
- decision = 'Avoiding obstacle';
488
- this.vx += avoidX * 0.5;
489
- this.vy += avoidY * 0.5;
490
- stats.obstaclesAvoided++;
491
- } else if (closestTarget && minTargetDist < 300) {
492
- decision = `Pursuing target (${Math.round(minTargetDist)}px away)`;
493
- const dx = closestTarget.x - this.x;
494
- const dy = closestTarget.y - this.y;
495
- const dist = Math.sqrt(dx * dx + dy * dy);
496
-
497
- if (dist > 0) {
498
- this.vx += (dx / dist) * 0.2;
499
- this.vy += (dy / dist) * 0.2;
500
  }
501
  } else {
502
- decision = 'Wandering and exploring';
503
- this.wanderAngle += (Math.random() - 0.5) * 0.3;
504
- this.vx += Math.cos(this.wanderAngle) * 0.1;
505
- this.vy += Math.sin(this.wanderAngle) * 0.1;
506
  }
507
-
508
- document.getElementById('currentDecision').textContent = decision;
509
- return decision;
510
  }
511
 
512
- update() {
513
- this.speed = parseFloat(document.getElementById('speedSlider').value);
514
- this.sensorRange = parseInt(document.getElementById('sensorRange').value);
515
-
516
  this.updateSensors();
517
  this.makeDecision();
518
 
519
- // Limit velocity
520
- const vel = Math.sqrt(this.vx * this.vx + this.vy * this.vy);
521
- if (vel > this.speed) {
522
- this.vx = (this.vx / vel) * this.speed;
523
- this.vy = (this.vy / vel) * this.speed;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
524
  }
525
 
526
- // Update position
527
- this.lastX = this.x;
528
- this.lastY = this.y;
529
- this.x += this.vx;
530
- this.y += this.vy;
 
 
531
 
532
- // Boundary collision
533
- if (this.x < this.size) {
534
- this.x = this.size;
535
- this.vx = Math.abs(this.vx);
536
- }
537
- if (this.x > canvas.width - this.size) {
538
- this.x = canvas.width - this.size;
539
- this.vx = -Math.abs(this.vx);
540
- }
541
- if (this.y < this.size) {
542
- this.y = this.size;
543
- this.vy = Math.abs(this.vy);
544
- }
545
- if (this.y > canvas.height - this.size) {
546
- this.y = canvas.height - this.size;
547
- this.vy = -Math.abs(this.vy);
548
  }
549
 
550
- // Update stats
551
- const distance = Math.sqrt((this.x - this.lastX) ** 2 + (this.y - this.lastY) ** 2);
552
- stats.distanceTraveled += distance;
553
 
554
- // Check target collisions
555
- targets = targets.filter(target => {
556
- const dist = Math.sqrt((target.x - this.x) ** 2 + (target.y - this.y) ** 2);
557
- if (dist < this.size + target.size) {
558
- stats.targetsReached++;
559
- return false;
560
- }
561
- return true;
562
- });
563
 
564
- // Apply friction
565
- this.vx *= 0.98;
566
- this.vy *= 0.98;
 
 
 
 
 
 
 
 
 
 
 
 
567
  }
568
 
569
  draw() {
570
- // Draw sensors
571
  ctx.strokeStyle = 'rgba(255, 193, 7, 0.3)';
572
  ctx.lineWidth = 1;
573
  for (let sensor of this.sensors) {
@@ -578,18 +540,31 @@
578
  }
579
 
580
  // Draw vehicle
 
 
 
 
 
581
  ctx.fillStyle = '#4CAF50';
582
- ctx.beginPath();
583
- ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
584
- ctx.fill();
585
 
586
- // Draw direction indicator
587
- ctx.strokeStyle = '#ffffff';
588
- ctx.lineWidth = 3;
589
- ctx.beginPath();
590
- ctx.moveTo(this.x, this.y);
591
- ctx.lineTo(this.x + this.vx * 5, this.y + this.vy * 5);
592
- ctx.stroke();
 
 
 
 
 
 
 
 
 
 
593
  }
594
  }
595
 
@@ -606,131 +581,141 @@
606
  ctx.beginPath();
607
  ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
608
  ctx.fill();
 
 
 
 
 
 
 
 
 
 
609
  }
610
  }
611
 
612
  // Target class
613
  class Target {
614
- constructor(x, y, size = 15) {
615
  this.x = x;
616
  this.y = y;
617
- this.size = size;
618
- this.pulse = 0;
619
  }
620
 
621
- update() {
622
- this.pulse += 0.1;
623
  }
624
 
625
  draw() {
626
- const alpha = 0.5 + 0.3 * Math.sin(this.pulse);
627
- ctx.fillStyle = `rgba(33, 150, 243, ${alpha})`;
 
 
628
  ctx.beginPath();
629
- ctx.arc(this.x, this.y, this.size + 3 * Math.sin(this.pulse), 0, Math.PI * 2);
630
  ctx.fill();
 
 
 
 
 
 
 
 
 
 
631
  }
632
  }
633
 
634
- // Animation loop
635
- function animate() {
636
- if (!isRunning) return;
637
-
638
- ctx.clearRect(0, 0, canvas.width, canvas.height);
639
-
640
- // Update and draw vehicle
641
- if (vehicle) {
642
- vehicle.update();
643
- vehicle.draw();
644
- }
645
-
646
- // Update and draw targets
647
- targets.forEach(target => {
648
- target.update();
649
- target.draw();
650
- });
651
-
652
- // Draw obstacles
653
- obstacles.forEach(obstacle => obstacle.draw());
654
-
655
- // Update UI stats
656
- updateStats();
657
-
658
- animationId = requestAnimationFrame(animate);
659
- }
660
-
661
- function updateStats() {
662
- document.getElementById('distanceTraveled').textContent = Math.round(stats.distanceTraveled) + 'm';
663
- document.getElementById('targetsReached').textContent = stats.targetsReached;
664
- document.getElementById('obstaclesAvoided').textContent = stats.obstaclesAvoided;
665
-
666
- // Calculate decisions per second
667
- const now = Date.now();
668
- if (now - lastDecisionTime >= 1000) {
669
- stats.decisionsPerSecond = decisionCount;
670
- document.getElementById('decisionsPerSec').textContent = stats.decisionsPerSecond;
671
- decisionCount = 0;
672
- lastDecisionTime = now;
673
- }
674
- }
675
 
676
- // Initialize simulation
677
- function initSimulation() {
678
- vehicle = new AutonomousVehicle(100, 100);
 
679
 
680
- // Add some initial obstacles and targets
681
  obstacles.push(new Obstacle(300, 200, 25));
682
- obstacles.push(new Obstacle(500, 400, 30));
683
- targets.push(new Target(600, 150));
684
- targets.push(new Target(200, 400));
685
 
686
- document.getElementById('currentDecision').textContent = 'Ready - Click Start!';
 
 
 
687
  }
688
 
689
- // Control functions
690
- function startSimulation() {
691
- if (!vehicle) initSimulation();
692
  isRunning = true;
693
- document.getElementById('startBtn').disabled = true;
694
- document.getElementById('pauseBtn').disabled = false;
695
  animate();
696
- }
697
 
698
- function pauseSimulation() {
699
  isRunning = false;
700
- document.getElementById('startBtn').disabled = false;
701
- document.getElementById('pauseBtn').disabled = true;
702
  if (animationId) {
703
  cancelAnimationFrame(animationId);
704
  }
705
- }
706
 
707
- function resetSimulation() {
708
  isRunning = false;
709
  if (animationId) {
710
  cancelAnimationFrame(animationId);
711
  }
712
 
713
- obstacles = [];
714
- targets = [];
715
- stats = { distanceTraveled: 0, targetsReached: 0, obstaclesAvoided: 0, decisionsPerSecond: 0 };
 
 
 
 
 
 
 
 
716
  decisionCount = 0;
717
 
718
- document.getElementById('startBtn').disabled = false;
719
- document.getElementById('pauseBtn').disabled = true;
720
 
721
- ctx.clearRect(0, 0, canvas.width, canvas.height);
722
- initSimulation();
723
- }
 
 
 
 
 
724
 
725
- // Event listeners
726
- document.getElementById('startBtn').addEventListener('click', startSimulation);
727
- document.getElementById('pauseBtn').addEventListener('click', pauseSimulation);
728
- document.getElementById('resetBtn').addEventListener('click', resetSimulation);
 
 
 
 
729
 
730
  document.getElementById('addObstacleBtn').addEventListener('click', () => {
731
  const x = Math.random() * (canvas.width - 100) + 50;
732
  const y = Math.random() * (canvas.height - 100) + 50;
733
- obstacles.push(new Obstacle(x, y, 20 + Math.random() * 20));
 
734
  });
735
 
736
  document.getElementById('addTargetBtn').addEventListener('click', () => {
@@ -740,34 +725,103 @@
740
  });
741
 
742
  document.getElementById('clearBtn').addEventListener('click', () => {
743
- obstacles = [];
744
- targets = [];
745
  });
746
 
747
- // Canvas click events
748
  canvas.addEventListener('click', (e) => {
749
  const rect = canvas.getBoundingClientRect();
750
  const x = e.clientX - rect.left;
751
  const y = e.clientY - rect.top;
752
 
753
  if (e.shiftKey) {
754
- obstacles.push(new Obstacle(x, y));
755
  } else {
756
  targets.push(new Target(x, y));
757
  }
758
  });
759
 
760
- // Slider updates
761
- document.getElementById('speedSlider').addEventListener('input', (e) => {
762
- document.getElementById('speedValue').textContent = e.target.value;
763
- });
 
 
 
764
 
765
- document.getElementById('sensorRange').addEventListener('input', (e) => {
766
- document.getElementById('sensorValue').textContent = e.target.value;
767
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
768
 
769
- // Initialize on load
770
- initSimulation();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771
  </script>
772
  </body>
773
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Embodied AI - Autonomous Vehicle Simulator</title>
 
7
  <style>
8
  * {
9
  margin: 0;
 
12
  }
13
 
14
  body {
15
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
  min-height: 100vh;
18
  display: flex;
19
  flex-direction: column;
20
  color: white;
 
21
  }
22
 
23
  .header {
 
29
  }
30
 
31
  .header h1 {
32
+ font-size: 2.5rem;
33
  margin-bottom: 10px;
34
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
35
  }
36
 
37
+ .header p {
38
+ font-size: 1.1rem;
39
+ opacity: 0.9;
40
+ }
41
+
42
  .main-container {
43
  display: flex;
44
  flex: 1;
 
65
  background: #1a1a2e;
66
  border-radius: 10px;
67
  overflow: hidden;
68
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
69
  }
70
 
71
  #simulationCanvas {
72
  width: 100%;
73
  height: 100%;
74
  display: block;
 
75
  }
76
 
77
  .controls-panel {
78
+ width: 300px;
79
  background: rgba(255, 255, 255, 0.1);
80
  border-radius: 15px;
81
  padding: 20px;
 
102
 
103
  .control-group label {
104
  display: block;
105
+ margin-bottom: 5px;
106
  font-weight: 500;
107
  color: #e0e0e0;
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  }
109
 
110
+ .control-group input, .control-group select {
 
 
 
 
 
 
 
 
 
111
  width: 100%;
112
+ padding: 8px 12px;
113
  border: none;
114
  border-radius: 8px;
115
  background: rgba(255, 255, 255, 0.2);
 
117
  font-size: 14px;
118
  }
119
 
120
+ .control-group input::placeholder {
121
+ color: rgba(255, 255, 255, 0.6);
122
+ }
123
+
124
  .btn {
125
  width: 100%;
126
  padding: 12px;
 
150
 
151
  .btn:hover {
152
  transform: translateY(-2px);
153
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
 
 
 
 
 
 
154
  }
155
 
156
  .stats {
 
158
  padding: 15px;
159
  border-radius: 8px;
160
  margin-top: 15px;
161
+ }
162
+
163
+ .stats h4 {
164
+ margin-bottom: 10px;
165
+ color: #fff;
166
  }
167
 
168
  .stat-item {
 
170
  justify-content: space-between;
171
  margin-bottom: 8px;
172
  font-size: 14px;
173
+ }
174
+
175
+ .stat-label {
176
+ color: #ccc;
177
  }
178
 
179
  .stat-value {
180
  color: #4CAF50;
181
  font-weight: 600;
 
182
  }
183
 
184
  .ai-info {
 
187
  border-radius: 8px;
188
  margin-top: 15px;
189
  font-size: 13px;
190
+ line-height: 1.4;
 
 
 
 
 
 
 
 
 
191
  }
192
 
193
  .legend {
 
195
  flex-wrap: wrap;
196
  gap: 15px;
197
  margin-top: 15px;
 
 
 
198
  }
199
 
200
  .legend-item {
 
213
  @media (max-width: 768px) {
214
  .main-container {
215
  flex-direction: column;
 
216
  }
217
 
218
  .controls-panel {
219
  width: 100%;
220
  }
 
 
 
 
221
  }
222
  </style>
223
  </head>
 
248
  </div>
249
  <div class="legend-item">
250
  <div class="legend-color" style="background: #FFC107;"></div>
251
+ <span>Sensors (LiDAR)</span>
252
  </div>
253
  </div>
254
  </div>
 
256
  <div class="controls-panel">
257
  <div class="control-section">
258
  <h3>🎮 Simulation Controls</h3>
259
+ <button class="btn btn-primary" id="startBtn">Start Simulation</button>
260
+ <button class="btn btn-secondary" id="pauseBtn">Pause</button>
261
+ <button class="btn btn-danger" id="resetBtn">Reset</button>
262
  </div>
263
 
264
  <div class="control-section">
265
+ <h3>⚙️ Parameters</h3>
266
  <div class="control-group">
267
  <label>Vehicle Speed</label>
268
+ <input type="range" id="speedSlider" min="0" max="5" value="2" step="0.5">
269
+ <span id="speedValue">2.0</span>
 
 
270
  </div>
271
  <div class="control-group">
272
  <label>Sensor Range</label>
273
+ <input type="range" id="sensorRange" min="50" max="200" value="100" step="10">
274
+ <span id="sensorValue">100</span>
 
 
275
  </div>
276
  <div class="control-group">
277
  <label>AI Behavior</label>
278
  <select id="behaviorSelect">
279
+ <option value="cautious">Cautious</option>
280
+ <option value="normal" selected>Normal</option>
281
+ <option value="aggressive">Aggressive</option>
282
  </select>
283
  </div>
284
  </div>
285
 
286
  <div class="control-section">
287
  <h3>🏭 Environment</h3>
288
+ <button class="btn btn-secondary" id="addObstacleBtn">Add Obstacle</button>
289
+ <button class="btn btn-secondary" id="addTargetBtn">Add Target</button>
290
+ <button class="btn btn-danger" id="clearBtn">Clear All</button>
291
  </div>
292
 
293
  <div class="stats">
294
+ <h4>📊 Real-time Stats</h4>
295
  <div class="stat-item">
296
+ <span class="stat-label">Distance Traveled:</span>
297
  <span class="stat-value" id="distanceTraveled">0m</span>
298
  </div>
299
  <div class="stat-item">
300
+ <span class="stat-label">Targets Reached:</span>
301
  <span class="stat-value" id="targetsReached">0</span>
302
  </div>
303
  <div class="stat-item">
304
+ <span class="stat-label">Obstacles Avoided:</span>
305
  <span class="stat-value" id="obstaclesAvoided">0</span>
306
  </div>
307
  <div class="stat-item">
308
+ <span class="stat-label">AI Decisions/sec:</span>
309
  <span class="stat-value" id="decisionsPerSec">0</span>
310
  </div>
311
  </div>
312
 
313
  <div class="ai-info">
314
+ <h4>🧠 AI Decision Making</h4>
315
+ <p id="currentDecision">System initializing...</p>
316
+ <br>
317
+ <p><strong>Embodied AI Features:</strong></p>
318
+ <ul style="margin-left: 15px; margin-top: 5px;">
319
  <li>Real-time sensor processing</li>
320
  <li>Dynamic path planning</li>
321
  <li>Obstacle avoidance</li>
322
+ <li>Goal-oriented behavior</li>
323
+ <li>Environmental adaptation</li>
324
  </ul>
325
  </div>
326
  </div>
 
331
  const canvas = document.getElementById('simulationCanvas');
332
  const ctx = canvas.getContext('2d');
333
 
334
+ // Set canvas size
335
  function resizeCanvas() {
336
  const container = canvas.parentElement;
337
+ canvas.width = container.clientWidth;
338
+ canvas.height = container.clientHeight;
 
339
  }
340
 
341
  resizeCanvas();
342
  window.addEventListener('resize', resizeCanvas);
343
 
344
+ // Simulation state
345
  let isRunning = false;
346
  let animationId = null;
347
+ let lastTime = 0;
 
 
 
 
 
 
 
 
348
  let decisionCount = 0;
349
+ let lastDecisionTime = 0;
350
 
351
  // Vehicle class
352
  class AutonomousVehicle {
 
357
  this.vy = 0;
358
  this.angle = 0;
359
  this.speed = 2;
360
+ this.maxSpeed = 5;
361
  this.size = 15;
362
  this.sensorRange = 100;
363
  this.sensors = [];
364
+ this.path = [];
365
+ this.currentTarget = null;
366
+ this.distanceTraveled = 0;
367
  this.lastX = x;
368
  this.lastY = y;
369
+ this.behavior = 'normal';
370
+ this.avoidanceVector = { x: 0, y: 0 };
371
  }
372
 
373
  updateSensors() {
 
376
 
377
  for (let i = 0; i < numSensors; i++) {
378
  const angle = (i / numSensors) * 2 * Math.PI;
379
+ const endX = this.x + Math.cos(angle) * this.sensorRange;
380
+ const endY = this.y + Math.sin(angle) * this.sensorRange;
381
+
382
  let distance = this.sensorRange;
383
 
384
+ // Check collision with obstacles
385
  for (let obstacle of obstacles) {
386
  const dx = obstacle.x - this.x;
387
  const dy = obstacle.y - this.y;
388
  const distToObstacle = Math.sqrt(dx * dx + dy * dy);
 
389
 
390
+ if (distToObstacle < distance && distToObstacle > 0) {
391
+ const angleToObstacle = Math.atan2(dy, dx);
392
+ const angleDiff = Math.abs(angle - angleToObstacle);
393
+
394
+ if (angleDiff < 0.5 || angleDiff > 2 * Math.PI - 0.5) {
395
+ distance = Math.max(0, distToObstacle - obstacle.size);
396
+ }
397
  }
398
  }
399
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  this.sensors.push({
401
  angle: angle,
402
  distance: distance,
 
408
 
409
  makeDecision() {
410
  decisionCount++;
 
411
 
412
  // Find closest target
413
  let closestTarget = null;
414
+ let minDistance = Infinity;
415
 
416
  for (let target of targets) {
417
+ const dx = target.x - this.x;
418
+ const dy = target.y - this.y;
419
+ const distance = Math.sqrt(dx * dx + dy * dy);
420
+
421
+ if (distance < minDistance) {
422
+ minDistance = distance;
423
  closestTarget = target;
424
  }
425
  }
426
 
427
+ this.currentTarget = closestTarget;
428
+
429
+ // Calculate avoidance vector
430
+ this.avoidanceVector = { x: 0, y: 0 };
431
 
432
  for (let sensor of this.sensors) {
433
+ if (sensor.distance < this.sensorRange * 0.7) {
434
+ const avoidanceStrength = (this.sensorRange * 0.7 - sensor.distance) / (this.sensorRange * 0.7);
435
+ this.avoidanceVector.x -= Math.cos(sensor.angle) * avoidanceStrength;
436
+ this.avoidanceVector.y -= Math.sin(sensor.angle) * avoidanceStrength;
 
437
  }
438
  }
439
 
440
+ // Normalize avoidance vector
441
+ const avoidanceMag = Math.sqrt(this.avoidanceVector.x ** 2 + this.avoidanceVector.y ** 2);
442
+ if (avoidanceMag > 0) {
443
+ this.avoidanceVector.x /= avoidanceMag;
444
+ this.avoidanceVector.y /= avoidanceMag;
445
+ }
446
+
447
+ // Update decision display
448
+ const decisionElement = document.getElementById('currentDecision');
449
+ if (this.currentTarget) {
450
+ if (avoidanceMag > 0.1) {
451
+ decisionElement.textContent = `Avoiding obstacles while navigating to target (${Math.round(minDistance)}m away)`;
452
+ } else {
453
+ decisionElement.textContent = `Direct path to target (${Math.round(minDistance)}m away)`;
 
454
  }
455
  } else {
456
+ decisionElement.textContent = 'Searching for targets...';
 
 
 
457
  }
 
 
 
458
  }
459
 
460
+ update(deltaTime) {
 
 
 
461
  this.updateSensors();
462
  this.makeDecision();
463
 
464
+ // Calculate target vector
465
+ let targetVector = { x: 0, y: 0 };
466
+ if (this.currentTarget) {
467
+ const dx = this.currentTarget.x - this.x;
468
+ const dy = this.currentTarget.y - this.y;
469
+ const distance = Math.sqrt(dx * dx + dy * dy);
470
+
471
+ if (distance > 0) {
472
+ targetVector.x = dx / distance;
473
+ targetVector.y = dy / distance;
474
+ }
475
+
476
+ // Check if reached target
477
+ if (distance < 20) {
478
+ const index = targets.indexOf(this.currentTarget);
479
+ if (index > -1) {
480
+ targets.splice(index, 1);
481
+ stats.targetsReached++;
482
+ document.getElementById('targetsReached').textContent = stats.targetsReached;
483
+ }
484
+ }
485
  }
486
 
487
+ // Combine vectors based on behavior
488
+ let finalVector = { x: 0, y: 0 };
489
+ const behaviorSettings = {
490
+ cautious: { avoidance: 0.8, target: 0.2 },
491
+ normal: { avoidance: 0.6, target: 0.4 },
492
+ aggressive: { avoidance: 0.3, target: 0.7 }
493
+ };
494
 
495
+ const settings = behaviorSettings[this.behavior];
496
+ finalVector.x = targetVector.x * settings.target + this.avoidanceVector.x * settings.avoidance;
497
+ finalVector.y = targetVector.y * settings.target + this.avoidanceVector.y * settings.avoidance;
498
+
499
+ // Normalize final vector
500
+ const finalMag = Math.sqrt(finalVector.x ** 2 + finalVector.y ** 2);
501
+ if (finalMag > 0) {
502
+ finalVector.x /= finalMag;
503
+ finalVector.y /= finalMag;
 
 
 
 
 
 
 
504
  }
505
 
506
+ // Update velocity
507
+ this.vx = finalVector.x * this.speed;
508
+ this.vy = finalVector.y * this.speed;
509
 
510
+ // Update position
511
+ this.x += this.vx * deltaTime;
512
+ this.y += this.vy * deltaTime;
 
 
 
 
 
 
513
 
514
+ // Keep within bounds
515
+ this.x = Math.max(this.size, Math.min(canvas.width - this.size, this.x));
516
+ this.y = Math.max(this.size, Math.min(canvas.height - this.size, this.y));
517
+
518
+ // Update angle for rendering
519
+ if (this.vx !== 0 || this.vy !== 0) {
520
+ this.angle = Math.atan2(this.vy, this.vx);
521
+ }
522
+
523
+ // Track distance traveled
524
+ const dx = this.x - this.lastX;
525
+ const dy = this.y - this.lastY;
526
+ this.distanceTraveled += Math.sqrt(dx * dx + dy * dy);
527
+ this.lastX = this.x;
528
+ this.lastY = this.y;
529
  }
530
 
531
  draw() {
532
+ // Draw sensor lines
533
  ctx.strokeStyle = 'rgba(255, 193, 7, 0.3)';
534
  ctx.lineWidth = 1;
535
  for (let sensor of this.sensors) {
 
540
  }
541
 
542
  // Draw vehicle
543
+ ctx.save();
544
+ ctx.translate(this.x, this.y);
545
+ ctx.rotate(this.angle);
546
+
547
+ // Vehicle body
548
  ctx.fillStyle = '#4CAF50';
549
+ ctx.fillRect(-this.size, -this.size/2, this.size * 2, this.size);
 
 
550
 
551
+ // Vehicle direction indicator
552
+ ctx.fillStyle = '#fff';
553
+ ctx.fillRect(this.size/2, -this.size/4, this.size/2, this.size/2);
554
+
555
+ ctx.restore();
556
+
557
+ // Draw path
558
+ if (this.path.length > 1) {
559
+ ctx.strokeStyle = 'rgba(76, 175, 80, 0.5)';
560
+ ctx.lineWidth = 2;
561
+ ctx.beginPath();
562
+ ctx.moveTo(this.path[0].x, this.path[0].y);
563
+ for (let i = 1; i < this.path.length; i++) {
564
+ ctx.lineTo(this.path[i].x, this.path[i].y);
565
+ }
566
+ ctx.stroke();
567
+ }
568
  }
569
  }
570
 
 
581
  ctx.beginPath();
582
  ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
583
  ctx.fill();
584
+
585
+ // Add warning stripes
586
+ ctx.strokeStyle = '#fff';
587
+ ctx.lineWidth = 2;
588
+ ctx.beginPath();
589
+ ctx.moveTo(this.x - this.size/2, this.y - this.size/2);
590
+ ctx.lineTo(this.x + this.size/2, this.y + this.size/2);
591
+ ctx.moveTo(this.x + this.size/2, this.y - this.size/2);
592
+ ctx.lineTo(this.x - this.size/2, this.y + this.size/2);
593
+ ctx.stroke();
594
  }
595
  }
596
 
597
  // Target class
598
  class Target {
599
+ constructor(x, y) {
600
  this.x = x;
601
  this.y = y;
602
+ this.size = 15;
603
+ this.pulsePhase = Math.random() * Math.PI * 2;
604
  }
605
 
606
+ update(deltaTime) {
607
+ this.pulsePhase += deltaTime * 0.003;
608
  }
609
 
610
  draw() {
611
+ const pulse = Math.sin(this.pulsePhase) * 0.3 + 1;
612
+ const size = this.size * pulse;
613
+
614
+ ctx.fillStyle = '#2196F3';
615
  ctx.beginPath();
616
+ ctx.arc(this.x, this.y, size, 0, Math.PI * 2);
617
  ctx.fill();
618
+
619
+ // Target rings
620
+ ctx.strokeStyle = '#fff';
621
+ ctx.lineWidth = 2;
622
+ ctx.beginPath();
623
+ ctx.arc(this.x, this.y, size * 0.7, 0, Math.PI * 2);
624
+ ctx.stroke();
625
+ ctx.beginPath();
626
+ ctx.arc(this.x, this.y, size * 0.4, 0, Math.PI * 2);
627
+ ctx.stroke();
628
  }
629
  }
630
 
631
+ // Game objects
632
+ const vehicle = new AutonomousVehicle(100, 100);
633
+ const obstacles = [];
634
+ const targets = [];
635
+
636
+ // Stats
637
+ const stats = {
638
+ distanceTraveled: 0,
639
+ targetsReached: 0,
640
+ obstaclesAvoided: 0,
641
+ decisionsPerSec: 0
642
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
643
 
644
+ // Initialize with some default objects
645
+ function initializeEnvironment() {
646
+ obstacles.length = 0;
647
+ targets.length = 0;
648
 
649
+ // Add some initial obstacles
650
  obstacles.push(new Obstacle(300, 200, 25));
651
+ obstacles.push(new Obstacle(500, 350, 30));
652
+ obstacles.push(new Obstacle(200, 400, 20));
653
+ obstacles.push(new Obstacle(600, 150, 35));
654
 
655
+ // Add some initial targets
656
+ targets.push(new Target(400, 100));
657
+ targets.push(new Target(600, 400));
658
+ targets.push(new Target(150, 300));
659
  }
660
 
661
+ // Event handlers
662
+ document.getElementById('startBtn').addEventListener('click', () => {
 
663
  isRunning = true;
 
 
664
  animate();
665
+ });
666
 
667
+ document.getElementById('pauseBtn').addEventListener('click', () => {
668
  isRunning = false;
 
 
669
  if (animationId) {
670
  cancelAnimationFrame(animationId);
671
  }
672
+ });
673
 
674
+ document.getElementById('resetBtn').addEventListener('click', () => {
675
  isRunning = false;
676
  if (animationId) {
677
  cancelAnimationFrame(animationId);
678
  }
679
 
680
+ // Reset vehicle
681
+ vehicle.x = 100;
682
+ vehicle.y = 100;
683
+ vehicle.vx = 0;
684
+ vehicle.vy = 0;
685
+ vehicle.distanceTraveled = 0;
686
+ vehicle.path = [];
687
+
688
+ // Reset stats
689
+ stats.targetsReached = 0;
690
+ stats.obstaclesAvoided = 0;
691
  decisionCount = 0;
692
 
693
+ // Reinitialize environment
694
+ initializeEnvironment();
695
 
696
+ // Update display
697
+ updateStatsDisplay();
698
+ });
699
+
700
+ document.getElementById('speedSlider').addEventListener('input', (e) => {
701
+ vehicle.speed = parseFloat(e.target.value);
702
+ document.getElementById('speedValue').textContent = vehicle.speed.toFixed(1);
703
+ });
704
 
705
+ document.getElementById('sensorRange').addEventListener('input', (e) => {
706
+ vehicle.sensorRange = parseInt(e.target.value);
707
+ document.getElementById('sensorValue').textContent = vehicle.sensorRange;
708
+ });
709
+
710
+ document.getElementById('behaviorSelect').addEventListener('change', (e) => {
711
+ vehicle.behavior = e.target.value;
712
+ });
713
 
714
  document.getElementById('addObstacleBtn').addEventListener('click', () => {
715
  const x = Math.random() * (canvas.width - 100) + 50;
716
  const y = Math.random() * (canvas.height - 100) + 50;
717
+ const size = Math.random() * 20 + 15;
718
+ obstacles.push(new Obstacle(x, y, size));
719
  });
720
 
721
  document.getElementById('addTargetBtn').addEventListener('click', () => {
 
725
  });
726
 
727
  document.getElementById('clearBtn').addEventListener('click', () => {
728
+ obstacles.length = 0;
729
+ targets.length = 0;
730
  });
731
 
732
+ // Canvas click handler for adding objects
733
  canvas.addEventListener('click', (e) => {
734
  const rect = canvas.getBoundingClientRect();
735
  const x = e.clientX - rect.left;
736
  const y = e.clientY - rect.top;
737
 
738
  if (e.shiftKey) {
739
+ obstacles.push(new Obstacle(x, y, 20));
740
  } else {
741
  targets.push(new Target(x, y));
742
  }
743
  });
744
 
745
+ // Update stats display
746
+ function updateStatsDisplay() {
747
+ document.getElementById('distanceTraveled').textContent = Math.round(vehicle.distanceTraveled) + 'm';
748
+ document.getElementById('targetsReached').textContent = stats.targetsReached;
749
+ document.getElementById('obstaclesAvoided').textContent = stats.obstaclesAvoided;
750
+ document.getElementById('decisionsPerSec').textContent = stats.decisionsPerSec;
751
+ }
752
 
753
+ // Main animation loop
754
+ function animate(currentTime = 0) {
755
+ if (!isRunning) return;
756
+
757
+ const deltaTime = currentTime - lastTime;
758
+ lastTime = currentTime;
759
+
760
+ // Calculate decisions per second
761
+ if (currentTime - lastDecisionTime > 1000) {
762
+ stats.decisionsPerSec = Math.round((decisionCount / (currentTime - lastDecisionTime)) * 1000);
763
+ decisionCount = 0;
764
+ lastDecisionTime = currentTime;
765
+ }
766
+
767
+ // Clear canvas
768
+ ctx.fillStyle = '#1a1a2e';
769
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
770
+
771
+ // Update and draw targets
772
+ for (let target of targets) {
773
+ target.update(deltaTime);
774
+ target.draw();
775
+ }
776
+
777
+ // Draw obstacles
778
+ for (let obstacle of obstacles) {
779
+ obstacle.draw();
780
+ }
781
+
782
+ // Update and draw vehicle
783
+ vehicle.update(deltaTime);
784
+ vehicle.draw();
785
+
786
+ // Update stats display
787
+ updateStatsDisplay();
788
+
789
+ animationId = requestAnimationFrame(animate);
790
+ }
791
 
792
+ // Initialize
793
+ initializeEnvironment();
794
+ animate();
795
+
796
+ // Add instructions
797
+ const instructions = document.createElement('div');
798
+ instructions.style.cssText = `
799
+ position: fixed;
800
+ top: 20px;
801
+ right: 20px;
802
+ background: rgba(0, 0, 0, 0.8);
803
+ color: white;
804
+ padding: 15px;
805
+ border-radius: 10px;
806
+ font-size: 12px;
807
+ max-width: 200px;
808
+ z-index: 1000;
809
+ `;
810
+ instructions.innerHTML = `
811
+ <strong>Controls:</strong><br>
812
+ • Click to add targets<br>
813
+ • Shift+Click to add obstacles<br>
814
+ • Use panel controls for settings<br>
815
+ • Watch AI make real-time decisions!
816
+ `;
817
+ document.body.appendChild(instructions);
818
+
819
+ // Hide instructions after 5 seconds
820
+ setTimeout(() => {
821
+ instructions.style.opacity = '0';
822
+ instructions.style.transition = 'opacity 1s';
823
+ setTimeout(() => instructions.remove(), 1000);
824
+ }, 5000);
825
  </script>
826
  </body>
827
  </html>