Files
swerve-visualizer/index.html

285 lines
15 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Swerve Drive Visualizer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<h1>Swerve Drive Movement Visualizer</h1>
<p>Interactive simulation of a swerve drive robot with configurable size, speeds, and number of wheels</p>
</header>
<main>
<section class="documentation">
<h2>About This Project</h2>
<details>
<summary>How To Use</summary>
<div class="documentation-content">
<h3>Getting Started</h3>
<p>This interactive visualizer demonstrates how a swerve drive robot moves based on commanded
velocities. Use the controls to experiment with different configurations and movement patterns.
</p>
<h3>Drive Controls</h3>
<ul>
<li><strong>Strafe Left/Right:</strong> Controls the robot's velocity in the X direction
(field-relative). Positive values move right, negative values move left.</li>
<li><strong>Move Forward/Backward:</strong> Controls the robot's velocity in the Y direction
(field-relative). Positive values move forward, negative values move backward.</li>
<li><strong>Rotation:</strong> Controls the robot's angular velocity (turn rate) in radians per
second. Positive values rotate counter-clockwise.</li>
<li><strong>Max Module Speed:</strong> Sets the maximum speed limit for any individual swerve
module. If calculated speeds exceed this, all modules are scaled proportionally.</li>
<li><strong>Reset Controls:</strong> Returns all velocity sliders to zero.</li>
</ul>
<h3>Preset Configurations</h3>
<p>Choose from 9 pre-built robot configurations ranging from 2 to 16 wheels. Each preset
demonstrates different module arrangements:</p>
<ul>
<li><strong>2-Wheel:</strong> Differential drive arrangement</li>
<li><strong>3-Wheel Triangle:</strong> Three modules in an equilateral triangle</li>
<li><strong>4-Wheel Square:</strong> Classic square configuration</li>
<li><strong>4-Wheel Rectangle:</strong> Rectangular configuration for longer robots</li>
<li><strong>6-Wheel Hexagon:</strong> Hexagonal arrangement</li>
<li><strong>8-Wheel Octagon:</strong> Octagonal arrangement</li>
<li><strong>8-Wheel Square:</strong> Double-layered square with inner and outer modules</li>
<li><strong>12-Wheel Hexagon:</strong> Double-layered hexagonal arrangement</li>
<li><strong>16-Wheel Octagon:</strong> Double-layered octagonal arrangement</li>
</ul>
<h3>Custom Configurations</h3>
<p>Create your own robot configuration:</p>
<ol>
<li>Enter the desired number of modules (Minimum of 2)</li>
<li>Click <strong>Generate Position Inputs</strong> to create input fields</li>
<li>For each module, specify:
<ul>
<li><strong>Module Name:</strong> A label for the module</li>
<li><strong>X Position:</strong> Distance from robot center (pixels, positive = right)
</li>
<li><strong>Y Position:</strong> Distance from robot center (pixels, positive = up)</li>
</ul>
</li>
<li>Click <strong>Apply Custom Configuration</strong> to see your design</li>
<li>Use <strong>Remove Position Inputs</strong> to clear the custom fields. This does not reset
the robot, only clears the input box</li>
</ol>
<h3>Understanding the Visualization</h3>
<ul>
<li><strong>Robot Frame:</strong> The filled polygon connecting the outer-most module positions
</li>
<li><strong>Modules:</strong> Circular markers at each wheel position</li>
<li><strong>Velocity Arrows:</strong> Red arrows showing the direction and magnitude of each
module's velocity</li>
<li><strong>Grid:</strong> Moves relative to the robot to show field-relative motion</li>
<li><strong>Gyro Heading:</strong> The current rotation angle of the robot in degrees</li>
</ul>
<h3>Module States Panel</h3>
<p>Displays real-time information for each module:</p>
<ul>
<li><strong>Angle:</strong> The direction the module is pointing (in degrees)</li>
<li><strong>Speed:</strong> The velocity of the module (in pixels/second)</li>
</ul>
</div>
</details>
<details>
<summary>Explanation of Swerve Kinematics</summary>
<div class="documentation-content">
<h3>What is Swerve Drive?</h3>
<p>Swerve drive (also called holonomic drive) is a drivetrain design where each wheel module can
independently rotate and drive in any direction. This allows the robot to move in any direction
while simultaneously rotating, providing exceptional maneuverability.</p>
<h3>Kinematic Equations</h3>
<p>The simulator calculates each module's state using inverse kinematics. Given a desired robot
velocity (v<sub>x</sub>, v<sub>y</sub>) and rotation rate (ω), we calculate each module's
required velocity.</p>
<h4>Field-Relative vs Robot-Relative</h4>
<p>This simulator uses <strong>field-relative control</strong>, meaning the velocity commands are
relative to the field, not the robot's current orientation. The inputs are transformed to
robot-relative coordinates using the current gyro heading:</p>
<pre>
v<sub>robot_x</sub> = v<sub>field_x</sub> × cos(-θ) - v<sub>field_y</sub> × sin(-θ)
v<sub>robot_y</sub> = v<sub>field_x</sub> × sin(-θ) + v<sub>field_y</sub> × cos(-θ)
</pre>
<p>Where θ is the robot's heading angle (gyro reading).</p>
<h4>Module Velocity Calculation</h4>
<p>For each module at position (x<sub>i</sub>, y<sub>i</sub>) relative to the robot's center of
rotation:</p>
<ol>
<li><strong>Translation component:</strong> The robot's linear velocity (v<sub>robot_x</sub>,
v<sub>robot_y</sub>)</li>
<li><strong>Rotation component:</strong> Perpendicular to the position vector, with magnitude
proportional to distance from center:
<pre>
v<sub>rot_x</sub> = -y<sub>i</sub> × ω
v<sub>rot_y</sub> = x<sub>i</sub> × ω
</pre>
</li>
<li><strong>Combined velocity:</strong> Vector sum of translation and rotation:
<pre>
v<sub>module_x</sub> = v<sub>robot_x</sub> + v<sub>rot_x</sub>
v<sub>module_y</sub> = v<sub>robot_y</sub> + v<sub>rot_y</sub>
</pre>
</li>
</ol>
<h4>Module Angle and Speed</h4>
<p>From the module's velocity vector, we calculate:</p>
<ul>
<li><strong>Speed:</strong> The magnitude of the velocity vector: √(v<sub>x</sub>² +
v<sub>y</sub>²)</li>
<li><strong>Angle:</strong> The direction of the velocity vector: arctan2(v<sub>y</sub>,
v<sub>x</sub>)</li>
</ul>
<h4>Speed Normalization</h4>
<p>If any module's calculated speed exceeds the maximum allowed speed, all module velocities are
scaled proportionally. This preserves the movement direction while respecting hardware limits:
</p>
<pre>
scale = max_speed / max(calculated_speeds)
if scale &lt; 1:
all_module_speeds × scale
</pre>
<h3>Gyro Integration</h3>
<p>The robot's heading (gyro angle) is continuously updated by integrating the rotation rate:</p>
<pre>
θ<sub>new</sub> = θ<sub>old</sub> + ω × Δt
</pre>
<p>Where Δt is the time step. The heading is normalized to stay within the range [-π, π].</p>
<h3>Real-World Applications</h3>
<p>Swerve drive systems are commonly used in:</p>
<ul>
<li><strong>FRC (FIRST Robotics Competition):</strong> For competitive robots requiring precise
positioning</li>
<li><strong>Industrial AGVs:</strong> Automated guided vehicles in warehouses</li>
<li><strong>Research Platforms:</strong> Mobile robots requiring omnidirectional movement</li>
</ul>
<h3>Key Advantages</h3>
<ul>
<li>True holonomic motion (can move in any direction without rotating)</li>
<li>Can translate and rotate simultaneously</li>
<li>Excellent maneuverability in constrained spaces</li>
<li>No "drift" or unwanted rotation during translation</li>
</ul>
<h3>Implementation Considerations</h3>
<ul>
<li><strong>Mechanical Complexity:</strong> Each module requires two motors (drive and steering)
</li>
<li><strong>Control Complexity:</strong> Requires coordinated control of all modules</li>
<li><strong>Sensor Requirements:</strong> Absolute encoders recommended for module angles</li>
<li><strong>Cost:</strong> More expensive than traditional drivetrains</li>
</ul>
</div>
</details>
</section>
<section class="visualization-canvas">
<h2>Robot Visualization</h2>
<canvas id="swerve-canvas" width="800" height="800"></canvas>
</section>
<section class="control-panel">
<h2>Drive Controls</h2>
<fieldset>
<legend>Translation &amp; Rotation</legend>
<div class="control-group">
<label for="vy-slider">Move Forward/Backward (pixels/s)</label>
<input type="range" id="vy-slider" min="-300" max="300" step="10" value="0">
<output id="vy-value">0</output>
</div>
<div class="control-group">
<label for="vx-slider">Strafe Left/Right (pixels/s)</label>
<input type="range" id="vx-slider" min="-300" max="300" step="10" value="0">
<output id="vx-value">0</output>
</div>
<div class="control-group">
<label for="omega-slider">Rotation (rad/s)</label>
<input type="range" id="omega-slider" min="-3" max="3" step="0.1" value="0">
<output id="omega-value">0</output>
</div>
<button id="reset-btn" type="button">Reset Controls</button>
</fieldset>
<fieldset>
<legend>Performance Limits</legend>
<div class="control-group">
<label for="max-speed-slider">Max Module Speed (pixels/s)</label>
<input type="range" id="max-speed-slider" min="200" max="1000" step="10" value="400">
<output id="max-speed-value">0</output>
</div>
</fieldset>
</section>
<section class="config-panel">
<h2>Robot Configuration</h2>
<fieldset>
<legend>Quick Presets</legend>
<div class="preset-buttons">
<button id="preset-2wheel" type="button">2-Wheel</button>
<button id="preset-3wheel" type="button">3-Wheel Triangle</button>
<button id="preset-4wheel" type="button">4-Wheel Square</button>
<button id="preset-4rect" type="button">4-Wheel Rectangle</button>
<button id="preset-6wheel" type="button">6-Wheel Hexagon</button>
<button id="preset-8wheel" type="button">8-Wheel Octagon</button>
<button id="preset-8square" type="button">8-Wheel Square</button>
<button id="preset-12hex" type="button">12-Wheel Hexagon</button>
<button id="preset-16oct" type="button">16-Wheel Octogon</button>
</div>
</fieldset>
<fieldset>
<legend>Custom Configuration</legend>
<div class="control-group">
<label for="module-count">Number of Modules</label>
<input type="number" id="module-count" min="2" max="12" value="4" step="1">
</div>
<button id="generate-inputs-btn" type="button">Generate Position Inputs</button>
<button id="delete-inputs-btn" type="button">Remove Position Inputs</button>
<div id="module-position-inputs" class="position-inputs">
<!-- Dynamically generated position inputs will appear here -->
</div>
<button id="apply-custom-btn" type="button" style="display: none;">Apply Custom Configuration</button>
</fieldset>
</section>
<section class="module-states">
<h2>Module States</h2>
<div id="current-config-info" class="config-info">
Current Configuration: <strong id="config-name">4-Wheel Rectangle</strong>
(<span id="module-count-display">4</span> modules)
<br>
Gyro Heading: <strong id="gyro-heading-display">0.0°</strong>
</div>
<div class="module-grid" id="module-grid">
<!-- Dynamically generated module data will appear here -->
</div>
</section>
</main>
<script type="module" src="vendor/lucio/graham-scan.mjs"></script>
<script type="module" src="script.js"></script>
</body>
</html>