Keyboard input added
This commit is contained in:
		
							
								
								
									
										59
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								index.html
									
									
									
									
									
								
							@ -199,24 +199,57 @@ if scale < 1:
 | 
			
		||||
                <legend>Translation & 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>
 | 
			
		||||
                    <button id="control-mode-toggle" type="button">Switch to Keyboard Controls (WASD + QE)</button>
 | 
			
		||||
                </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 id="slider-controls">
 | 
			
		||||
                    <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>
 | 
			
		||||
                </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>
 | 
			
		||||
                <div id="keyboard-controls" style="display: none;">
 | 
			
		||||
                    <div class="control-group">
 | 
			
		||||
                        <label for="keyboard-max-speed">Max Speed (pixels/s)</label>
 | 
			
		||||
                        <input type="range" id="keyboard-max-speed" min="50" max="300" step="10" value="150">
 | 
			
		||||
                        <output id="keyboard-max-speed-value">150</output>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                <button id="reset-btn" type="button">Reset Controls</button>
 | 
			
		||||
                    <div class="control-group">
 | 
			
		||||
                        <label for="keyboard-max-rotation">Max Rotation (rad/s)</label>
 | 
			
		||||
                        <input type="range" id="keyboard-max-rotation" min="0.5" max="3" step="0.1" value="1.5">
 | 
			
		||||
                        <output id="keyboard-max-rotation-value">1.5</output>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="keyboard-instructions">
 | 
			
		||||
                        <h4>Keyboard Controls:</h4>
 | 
			
		||||
                        <ul>
 | 
			
		||||
                            <li><strong>W:</strong> Move Forward</li>
 | 
			
		||||
                            <li><strong>A:</strong> Strafe Left</li>
 | 
			
		||||
                            <li><strong>S:</strong> Move Backward</li>
 | 
			
		||||
                            <li><strong>D:</strong> Strafe Right</li>
 | 
			
		||||
                            <li><strong>Q:</strong> Rotate Counter-Clockwise</li>
 | 
			
		||||
                            <li><strong>E:</strong> Rotate Clockwise</li>
 | 
			
		||||
                        </ul>
 | 
			
		||||
                        <p><em>Click on the canvas area to focus for keyboard input</em></p>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </fieldset>
 | 
			
		||||
 | 
			
		||||
            <fieldset>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										147
									
								
								script.js
									
									
									
									
									
								
							
							
						
						
									
										147
									
								
								script.js
									
									
									
									
									
								
							@ -288,6 +288,15 @@ const generateInputsBtn = document.getElementById('generate-inputs-btn');
 | 
			
		||||
const clearInputsBtn = document.getElementById('delete-inputs-btn');
 | 
			
		||||
const applyCustomBtn = document.getElementById('apply-custom-btn');
 | 
			
		||||
 | 
			
		||||
// Get control mode elements
 | 
			
		||||
const controlModeToggle = document.getElementById('control-mode-toggle');
 | 
			
		||||
const sliderControls = document.getElementById('slider-controls');
 | 
			
		||||
const keyboardControls = document.getElementById('keyboard-controls');
 | 
			
		||||
const keyboardMaxSpeed = document.getElementById('keyboard-max-speed');
 | 
			
		||||
const keyboardMaxSpeedOutput = document.getElementById('keyboard-max-speed-value');
 | 
			
		||||
const keyboardMaxRotation = document.getElementById('keyboard-max-rotation');
 | 
			
		||||
const keyboardMaxRotationOutput = document.getElementById('keyboard-max-rotation-value');
 | 
			
		||||
 | 
			
		||||
// Preset buttons
 | 
			
		||||
const preset2WheelBtn = document.getElementById('preset-2wheel');
 | 
			
		||||
const preset3WheelBtn = document.getElementById('preset-3wheel');
 | 
			
		||||
@ -301,6 +310,29 @@ const preset16OctBtn = document.getElementById('preset-16oct');
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* END DOM VARIABLES
 | 
			
		||||
* BEGIN CONTROL MODE AND INPUT DEVICE VARIABLES
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Control mode state
 | 
			
		||||
let isManualInputMode = false; // true = keyboard/gamepad mode, false = slider mode
 | 
			
		||||
 | 
			
		||||
// Keyboard state tracking
 | 
			
		||||
const keyState = {
 | 
			
		||||
    w: false,  // Forward
 | 
			
		||||
    a: false,  // Left
 | 
			
		||||
    s: false,  // Backward
 | 
			
		||||
    d: false,  // Right
 | 
			
		||||
    q: false,  // Counter-clockwise
 | 
			
		||||
    e: false   // Clockwise
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Current manual input velocities (from keyboard or gamepad)
 | 
			
		||||
let manualInputVelX = 0;
 | 
			
		||||
let manualInputVelY = 0;
 | 
			
		||||
let manualInputOmega = 0;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* END CONTROL MODE AND INPUT DEVICE VARIABLES
 | 
			
		||||
* BEGIN LISTENER CODE
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -319,6 +351,93 @@ resetBtn.addEventListener('click', (e) => {
 | 
			
		||||
    omegaOutput.textContent = parseFloat(omegaSlider.value);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Keyboard control sliders
 | 
			
		||||
keyboardMaxSpeed.addEventListener('input', (e) => {
 | 
			
		||||
    keyboardMaxSpeedOutput.textContent = parseFloat(e.target.value);
 | 
			
		||||
});
 | 
			
		||||
keyboardMaxSpeedOutput.textContent = parseFloat(keyboardMaxSpeed.value);
 | 
			
		||||
 | 
			
		||||
keyboardMaxRotation.addEventListener('input', (e) => {
 | 
			
		||||
    keyboardMaxRotationOutput.textContent = parseFloat(e.target.value);
 | 
			
		||||
});
 | 
			
		||||
keyboardMaxRotationOutput.textContent = parseFloat(keyboardMaxRotation.value);
 | 
			
		||||
 | 
			
		||||
// Control mode toggle
 | 
			
		||||
controlModeToggle.addEventListener('click', () => {
 | 
			
		||||
    isManualInputMode = !isManualInputMode;
 | 
			
		||||
 | 
			
		||||
    if (isManualInputMode) {
 | 
			
		||||
        // Switch to manual input mode (keyboard/gamepad)
 | 
			
		||||
        sliderControls.style.display = 'none';
 | 
			
		||||
        keyboardControls.style.display = 'block';
 | 
			
		||||
        controlModeToggle.textContent = 'Switch to Slider Controls';
 | 
			
		||||
 | 
			
		||||
        // Reset slider values when switching to manual input
 | 
			
		||||
        vxSlider.value = 0;
 | 
			
		||||
        vySlider.value = 0;
 | 
			
		||||
        omegaSlider.value = 0;
 | 
			
		||||
        vxOutput.textContent = '0';
 | 
			
		||||
        vyOutput.textContent = '0';
 | 
			
		||||
        omegaOutput.textContent = '0';
 | 
			
		||||
    } else {
 | 
			
		||||
        // Switch to slider mode
 | 
			
		||||
        sliderControls.style.display = 'block';
 | 
			
		||||
        keyboardControls.style.display = 'none';
 | 
			
		||||
        controlModeToggle.textContent = 'Switch to Keyboard Controls (WASD + QE)';
 | 
			
		||||
 | 
			
		||||
        // Reset manual input state
 | 
			
		||||
        Object.keys(keyState).forEach(key => keyState[key] = false);
 | 
			
		||||
        manualInputVelX = 0;
 | 
			
		||||
        manualInputVelY = 0;
 | 
			
		||||
        manualInputOmega = 0;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Keyboard event listeners
 | 
			
		||||
document.addEventListener('keydown', (e) => {
 | 
			
		||||
    if (!isManualInputMode) return;
 | 
			
		||||
 | 
			
		||||
    const key = e.key.toLowerCase();
 | 
			
		||||
    if (key in keyState) {
 | 
			
		||||
        keyState[key] = true;
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        updateManualInputVelocities();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
document.addEventListener('keyup', (e) => {
 | 
			
		||||
    if (!isManualInputMode) return;
 | 
			
		||||
 | 
			
		||||
    const key = e.key.toLowerCase();
 | 
			
		||||
    if (key in keyState) {
 | 
			
		||||
        keyState[key] = false;
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        updateManualInputVelocities();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// Function to update velocities based on manual input devices (keyboard/gamepad)
 | 
			
		||||
function updateManualInputVelocities() {
 | 
			
		||||
    const maxSpeed = parseFloat(keyboardMaxSpeed.value);
 | 
			
		||||
    const maxRotation = parseFloat(keyboardMaxRotation.value);
 | 
			
		||||
 | 
			
		||||
    // Calculate translation velocities from keyboard input
 | 
			
		||||
    manualInputVelX = 0;
 | 
			
		||||
    manualInputVelY = 0;
 | 
			
		||||
 | 
			
		||||
    if (keyState.d) manualInputVelX += maxSpeed;  // Right
 | 
			
		||||
    if (keyState.a) manualInputVelX -= maxSpeed;  // Left
 | 
			
		||||
    if (keyState.w) manualInputVelY += maxSpeed;  // Forward  
 | 
			
		||||
    if (keyState.s) manualInputVelY -= maxSpeed;  // Backward
 | 
			
		||||
 | 
			
		||||
    // Calculate rotation velocity from keyboard input
 | 
			
		||||
    manualInputOmega = 0;
 | 
			
		||||
    if (keyState.e) manualInputOmega += maxRotation;  // Clockwise
 | 
			
		||||
    if (keyState.q) manualInputOmega -= maxRotation;  // Counter-clockwise
 | 
			
		||||
 | 
			
		||||
    // TODO: Add gamepad input processing here
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Preset button event listeners
 | 
			
		||||
preset2WheelBtn.addEventListener('click', () => {
 | 
			
		||||
    const positions = PresetConfigs.twoWheel(robotSize);
 | 
			
		||||
@ -652,10 +771,16 @@ function animate() {
 | 
			
		||||
    ctx.save();
 | 
			
		||||
    ctx.translate(canvas.width / 2, canvas.height / 2);
 | 
			
		||||
 | 
			
		||||
    // Update speeds based on sliders
 | 
			
		||||
    xSpeed = parseFloat(vxSlider.value);
 | 
			
		||||
    ySpeed = -parseFloat(vySlider.value);
 | 
			
		||||
    turnSpeed = parseFloat(omegaSlider.value);
 | 
			
		||||
    // Update speeds based on control mode
 | 
			
		||||
    if (isManualInputMode) {
 | 
			
		||||
        xSpeed = manualInputVelX;
 | 
			
		||||
        ySpeed = -manualInputVelY; // Negative because canvas Y axis is inverted
 | 
			
		||||
        turnSpeed = manualInputOmega;
 | 
			
		||||
    } else {
 | 
			
		||||
        xSpeed = parseFloat(vxSlider.value);
 | 
			
		||||
        ySpeed = -parseFloat(vySlider.value);
 | 
			
		||||
        turnSpeed = parseFloat(omegaSlider.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update module states before drawing the robot
 | 
			
		||||
    // The drive() method will update the gyroHeading internally
 | 
			
		||||
@ -665,11 +790,17 @@ function animate() {
 | 
			
		||||
    // Get the actual robot velocity (after scaling to max module speed) for grid animation
 | 
			
		||||
    const actualVelocity = robot.getActualVelocity();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Update control outputs with actual speeds
 | 
			
		||||
    vxOutput.textContent = `Requested: ${vxSlider.value} | Actual: ${actualVelocity.x.toFixed(2)}`;
 | 
			
		||||
    vyOutput.textContent = `Requested: ${vySlider.value} | Actual: ${-actualVelocity.y.toFixed(2)}`;
 | 
			
		||||
    omegaOutput.textContent = `Requested: ${omegaSlider.value} | Actual: ${robot.actualTurnSpeed.toFixed(2)}`;
 | 
			
		||||
    if (isManualInputMode) {
 | 
			
		||||
        // In manual input mode (keyboard/gamepad), show the current values
 | 
			
		||||
        keyboardMaxSpeedOutput.textContent = `Max: ${keyboardMaxSpeed.value} | Current: ${Math.max(Math.abs(actualVelocity.x), Math.abs(actualVelocity.y)).toFixed(1)}`;
 | 
			
		||||
        keyboardMaxRotationOutput.textContent = `Max: ${keyboardMaxRotation.value} | Current: ${Math.abs(robot.actualTurnSpeed || 0).toFixed(2)}`;
 | 
			
		||||
    } else {
 | 
			
		||||
        // In slider mode, show requested vs actual
 | 
			
		||||
        vxOutput.textContent = `Requested: ${vxSlider.value} | Actual: ${actualVelocity.x.toFixed(2)}`;
 | 
			
		||||
        vyOutput.textContent = `Requested: ${vySlider.value} | Actual: ${-actualVelocity.y.toFixed(2)}`;
 | 
			
		||||
        omegaOutput.textContent = `Requested: ${omegaSlider.value} | Actual: ${(robot.actualTurnSpeed || 0).toFixed(2)}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Animate the grid
 | 
			
		||||
    let offsetSpeedDivisor = (100 - gridSquareSize <= 0 ? 1 : 100 - gridSquareSize);
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user