2024-06-25 11:21:25 +02:00
|
|
|
<!DOCTYPE html>
|
2024-06-25 11:19:53 +02:00
|
|
|
<html lang="fr">
|
2024-06-25 11:21:25 +02:00
|
|
|
<head>
|
|
|
|
<meta charset="utf-8" />
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
|
|
<title>Contrôle du robot</title>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1>Contrôle du robot sans fils</h1>
|
|
|
|
<p>
|
|
|
|
Cette page permet de contrôler le robot depuis un PC portable
|
|
|
|
connecté au WiFi du robot. Elle est destinée aux personnes n'ayant
|
|
|
|
pas de smartphone.
|
|
|
|
</p>
|
|
|
|
<h2>Paramètres de contrôle</h2>
|
|
|
|
<p>
|
|
|
|
Ici vous pourrez paramétrer les contrôles du robot, rentrer son
|
|
|
|
adresse IP ainsi que lui indiquer la distance à parcourir ou l'angle
|
|
|
|
de rotation désiré.
|
|
|
|
</p>
|
2024-06-25 12:46:11 +02:00
|
|
|
<form class="settings" id="settings">
|
2024-06-25 11:43:34 +02:00
|
|
|
<label>
|
|
|
|
<span>Adresse IP du robot</span>
|
|
|
|
<input
|
|
|
|
type="text"
|
2024-06-25 12:46:11 +02:00
|
|
|
name="ip-address"
|
2024-06-25 11:43:34 +02:00
|
|
|
title="Adresse IP du robot (ex: 192.168.0.1)"
|
|
|
|
pattern="\d+\.\d+\.\d+\.\d+"
|
|
|
|
placeholder="192.168.0.0"
|
|
|
|
required
|
|
|
|
/>
|
|
|
|
</label>
|
|
|
|
<button>Se connecter</button>
|
2024-06-25 11:21:25 +02:00
|
|
|
</form>
|
2024-06-25 11:43:34 +02:00
|
|
|
<div class="controls">
|
|
|
|
<label>
|
|
|
|
<span>Rotation en degrés</span>
|
|
|
|
<input
|
2024-06-25 13:15:04 +02:00
|
|
|
id="rotate-input"
|
2024-06-25 11:43:34 +02:00
|
|
|
type="number"
|
2024-06-25 13:15:04 +02:00
|
|
|
title="Rotation en degrés (-360° à 360°)"
|
|
|
|
min="-360"
|
2024-06-25 11:43:34 +02:00
|
|
|
max="360"
|
|
|
|
step="1"
|
|
|
|
placeholder="90"
|
|
|
|
/>
|
|
|
|
</label>
|
2024-06-25 11:50:45 +02:00
|
|
|
<label>
|
2024-06-25 13:16:17 +02:00
|
|
|
<span>Distance en cm</span>
|
2024-06-25 11:43:34 +02:00
|
|
|
<input
|
2024-06-25 13:15:04 +02:00
|
|
|
id="move-input"
|
2024-06-25 11:43:34 +02:00
|
|
|
type="number"
|
2024-06-25 13:16:17 +02:00
|
|
|
title="Distance en cm (-2^31 à 2^31)"
|
2024-06-25 11:43:34 +02:00
|
|
|
min="-2147483647"
|
|
|
|
step="1"
|
|
|
|
max="2147483647"
|
|
|
|
placeholder="10"
|
|
|
|
/>
|
|
|
|
</label>
|
|
|
|
</div>
|
2024-06-25 11:21:25 +02:00
|
|
|
<h2>Contrôle</h2>
|
|
|
|
<p>
|
|
|
|
Amusez vous ! Pour contrôler le robot, utilisez les flèches
|
|
|
|
directionnelles pour le diriger et la barre espace pour le stopper.
|
|
|
|
</p>
|
|
|
|
</body>
|
2024-06-25 12:27:16 +02:00
|
|
|
<script type="module">
|
2024-06-25 13:19:07 +02:00
|
|
|
// Input handlers
|
|
|
|
document
|
2024-06-25 13:26:35 +02:00
|
|
|
.querySelector('#move-input')
|
2024-06-25 13:19:07 +02:00
|
|
|
.addEventListener('change', (event) =>
|
|
|
|
assignCommands('backward', 'forward', event)
|
|
|
|
)
|
|
|
|
document
|
2024-06-25 13:26:35 +02:00
|
|
|
.querySelector('#rotate-input')
|
2024-06-25 13:19:07 +02:00
|
|
|
.addEventListener('change', (event) =>
|
|
|
|
assignCommands('left', 'right', event)
|
|
|
|
)
|
|
|
|
|
|
|
|
// Keyboard handler
|
2024-06-25 13:31:27 +02:00
|
|
|
document.addEventListener('keydown', ({ code }) => {
|
|
|
|
if (code === 'ArrowUp') {
|
2024-06-25 13:41:17 +02:00
|
|
|
return sendCommand('forward', 2)
|
2024-06-25 13:31:27 +02:00
|
|
|
}
|
|
|
|
if (code === 'ArrowDown') {
|
2024-06-25 13:41:17 +02:00
|
|
|
return sendCommand('backward', 2)
|
2024-06-25 13:31:27 +02:00
|
|
|
}
|
|
|
|
if (code === 'ArrowLeft') {
|
2024-06-25 13:41:17 +02:00
|
|
|
return sendCommand('left', 5)
|
2024-06-25 13:31:27 +02:00
|
|
|
}
|
|
|
|
if (code === 'ArrowRight') {
|
2024-06-25 13:41:17 +02:00
|
|
|
return sendCommand('right', 5)
|
2024-06-25 13:31:27 +02:00
|
|
|
}
|
|
|
|
if (code === 'Space') {
|
2024-06-25 13:41:17 +02:00
|
|
|
return sendCommand('stop', 0)
|
2024-06-25 13:31:27 +02:00
|
|
|
}
|
2024-06-25 13:19:07 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
// Settings handler
|
|
|
|
document
|
|
|
|
.querySelector('#settings')
|
|
|
|
.addEventListener('submit', async (event) => {
|
|
|
|
// Don't interrupt event if not form submitting
|
|
|
|
if (!(event instanceof SubmitEvent)) return true
|
|
|
|
if (event.target === null) return true
|
|
|
|
// Disable form sending
|
|
|
|
event.preventDefault()
|
|
|
|
|
|
|
|
const form = new FormData(event.target)
|
|
|
|
const ipAddress = form.get('ip-address')
|
|
|
|
|
|
|
|
if (ipAddress === null) return
|
|
|
|
|
|
|
|
const endpoint = `http://${ipAddress}`
|
|
|
|
await testEndpoint(endpoint)
|
|
|
|
setEndpoint(endpoint)
|
|
|
|
})
|
|
|
|
|
2024-06-25 12:27:16 +02:00
|
|
|
/**
|
|
|
|
* A command string.
|
|
|
|
* @typedef {('forward' | 'backward' | 'left' | 'right' | 'stop')} Command
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send command to the robot.
|
|
|
|
*
|
|
|
|
* @param {Command} command Command to send.
|
|
|
|
* @param {number} value Value of the command if needed.
|
2024-06-25 12:49:21 +02:00
|
|
|
*
|
|
|
|
* @returns {Promise<void>}
|
2024-06-25 12:27:16 +02:00
|
|
|
*/
|
2024-06-25 13:41:17 +02:00
|
|
|
async function sendCommand(command, value) {
|
|
|
|
const endpoint = getEndpoint()
|
2024-06-25 12:49:21 +02:00
|
|
|
const url = new URL(
|
|
|
|
`/get?command=${command}&value=${value}`,
|
|
|
|
endpoint
|
2024-06-25 12:27:16 +02:00
|
|
|
)
|
2024-06-25 12:49:21 +02:00
|
|
|
const response = await fetch(url)
|
2024-06-25 12:27:16 +02:00
|
|
|
const text = await response.text()
|
|
|
|
console.log(text)
|
|
|
|
}
|
|
|
|
|
2024-06-25 12:46:11 +02:00
|
|
|
/**
|
|
|
|
* Get robot endpoint address.
|
|
|
|
*
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function getEndpoint() {
|
|
|
|
const endpoint = sessionStorage.getItem('robot-endpoint')
|
|
|
|
if (endpoint === null) {
|
|
|
|
alert("Aucune adresse IP n'a été renseignée !")
|
|
|
|
throw new Error('no given ip address')
|
|
|
|
}
|
|
|
|
return endpoint
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set robot endpoint address.
|
|
|
|
*
|
|
|
|
* @param {string} ip Robot ip.
|
|
|
|
*
|
|
|
|
* @returns void
|
|
|
|
*/
|
|
|
|
function setEndpoint(ip) {
|
2024-06-25 14:01:37 +02:00
|
|
|
sessionStorage.setItem('robot-endpoint', ip)
|
2024-06-25 12:46:11 +02:00
|
|
|
}
|
|
|
|
|
2024-06-25 12:58:11 +02:00
|
|
|
/**
|
|
|
|
* Test connection to endpoint.
|
2024-06-25 13:15:04 +02:00
|
|
|
*
|
2024-06-25 12:58:11 +02:00
|
|
|
* @param {string} endpoint Endpoint to test for.
|
2024-06-25 13:15:04 +02:00
|
|
|
*
|
2024-06-25 12:58:11 +02:00
|
|
|
* @returns {void}
|
|
|
|
* @throws {Error} Endpoint unreachable.
|
|
|
|
*/
|
|
|
|
async function testEndpoint(endpoint) {
|
|
|
|
try {
|
|
|
|
const response = await fetch(endpoint)
|
|
|
|
if (response.ok) return
|
|
|
|
} catch (cause) {
|
|
|
|
alert(`Impossible de joindre l'adresse "${endpoint}"`)
|
|
|
|
throw new Error(`unable to connect to robot at ${endpoint}`, {
|
|
|
|
cause,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-25 13:15:04 +02:00
|
|
|
/**
|
|
|
|
* Assign a command to an input.
|
|
|
|
* Do negative command if value < 0 else do positive command.
|
|
|
|
*
|
|
|
|
* @param {Command} negativeCommand Command if value < 0.
|
|
|
|
* @param {Command} positiveCommand Command if value >= 0.
|
|
|
|
* @param {event} event Event of the input.
|
|
|
|
*
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
|
|
|
function assignCommands(negativeCommand, positiveCommand, event) {
|
|
|
|
if (event.target === null) return
|
|
|
|
|
|
|
|
/** @type {HTMLInputElement} */
|
|
|
|
const target = event.target
|
|
|
|
const value = target.valueAsNumber
|
|
|
|
|
|
|
|
if (value < 0) {
|
2024-06-25 13:41:17 +02:00
|
|
|
return sendCommand(negativeCommand, Math.abs(value))
|
2024-06-25 13:15:04 +02:00
|
|
|
}
|
2024-06-25 13:41:17 +02:00
|
|
|
return sendCommand(positiveCommand, value)
|
2024-06-25 13:15:04 +02:00
|
|
|
}
|
2024-06-25 11:21:25 +02:00
|
|
|
</script>
|
2024-06-25 11:19:53 +02:00
|
|
|
</html>
|