update
Browse files- certs/cert.pem +19 -0
- certs/key.pem +28 -0
- dummy_server.py +2 -2
- requirements.txt +3 -0
- server.py +5 -0
- static/main.js +2 -2
- static/sinus-io.js +97 -0
- static/sinus.html +60 -0
- static/sinus.js +84 -0
certs/cert.pem
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
-----BEGIN CERTIFICATE-----
|
| 2 |
+
MIIDGjCCAgKgAwIBAgIUdNm0OQEuMPg1qCqxpUdmqWEwlpIwDQYJKoZIhvcNAQEL
|
| 3 |
+
BQAwFDESMBAGA1UEAwwJMTI3LjAuMC4xMB4XDTI1MDUxMjE4NDY0MFoXDTI2MDUx
|
| 4 |
+
MjE4NDY0MFowFDESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEF
|
| 5 |
+
AAOCAQ8AMIIBCgKCAQEAtX4QVKYQOKceZLfstjNTV3FPBHkDqneaDwyVvsPbm8gm
|
| 6 |
+
slhPTY5upHFjMJFH5MBkbR6jdG0aKTLIaBOct8RcJ6LkECNtb5Wn7A4QhPogHrev
|
| 7 |
+
qOTT7/tVhCOgDTmvmJD33GA3tHfo2QLXbfYxXxiAO0WB2L2F2/oWPOOji6UCKL9B
|
| 8 |
+
+TgoivP99im2GIanJy8muVU4piKfOUskQs0WbjkCclNROohxiMUK8iBXXFvIxhpg
|
| 9 |
+
2l1MKVSo9IPbwvrlha5Ixyb3yguzkfCILjTDtJoXsUkpfdc4XYaHbcuI8LEujcoN
|
| 10 |
+
dmHwImkpWd7I/MTZDNbvcaCpd1+APqJyuIOhZCdXxwIDAQABo2QwYjAdBgNVHQ4E
|
| 11 |
+
FgQUG/GjXqossD4HAaDWRT17HMQ9190wHwYDVR0jBBgwFoAUG/GjXqossD4HAaDW
|
| 12 |
+
RT17HMQ9190wDwYDVR0TAQH/BAUwAwEB/zAPBgNVHREECDAGhwR/AAABMA0GCSqG
|
| 13 |
+
SIb3DQEBCwUAA4IBAQBnhkeoWRk/2FLlSXx4kI8nAUVyOfzdRGtNw80IZk5eIJun
|
| 14 |
+
eI030W0NvrQIxuzvfQIUB3D1sfwkfMAgR10viKSOUcAalrJYup6TKOizXIB+r3Yx
|
| 15 |
+
rhRiolw4wP3HixmnlcqfZXekVcRVM3GW9+0o0NW223EEp3vNCskMvSiJ2Ia6J+TI
|
| 16 |
+
LAoteVZ1FxZBt0b9uWuDD6btfhBXza/dzIxVTWswfaqlfBQYznqX2ZzUS9bIMC37
|
| 17 |
+
UdihzUgEpPoiqKfN3PoeXsXq3NZvqTx4E25qJWhIVSuOBUmzdfizRAy4SiKJfEmT
|
| 18 |
+
5MJvnthT47CH2Yym50YL9ZBVj6K9vBGiSYjTaLhV
|
| 19 |
+
-----END CERTIFICATE-----
|
certs/key.pem
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
-----BEGIN PRIVATE KEY-----
|
| 2 |
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1fhBUphA4px5k
|
| 3 |
+
t+y2M1NXcU8EeQOqd5oPDJW+w9ubyCayWE9Njm6kcWMwkUfkwGRtHqN0bRopMsho
|
| 4 |
+
E5y3xFwnouQQI21vlafsDhCE+iAet6+o5NPv+1WEI6ANOa+YkPfcYDe0d+jZAtdt
|
| 5 |
+
9jFfGIA7RYHYvYXb+hY846OLpQIov0H5OCiK8/32KbYYhqcnLya5VTimIp85SyRC
|
| 6 |
+
zRZuOQJyU1E6iHGIxQryIFdcW8jGGmDaXUwpVKj0g9vC+uWFrkjHJvfKC7OR8Igu
|
| 7 |
+
NMO0mhexSSl91zhdhodty4jwsS6Nyg12YfAiaSlZ3sj8xNkM1u9xoKl3X4A+onK4
|
| 8 |
+
g6FkJ1fHAgMBAAECggEACIQ3LJAZ8CnTamMarfzf+v+O3cUp9iyKygyYO3pOvbm/
|
| 9 |
+
xLWri8mhVbRMzo4hFmuUXges7Un88ZSRXktK56REtZPWUA8n7WKgULQWQI8vxURv
|
| 10 |
+
iNh4CemJPHXWTSVfh1eIi5eBdav8yeLxJf1PMsjgPfSUhvQM9uLk4T8s9C2uWY52
|
| 11 |
+
DeqW0SbVfs0LXEJ6GZT3oGm5seN5Gac1vkPEoRAHFo5kvi5zMmMJkP0UgVOdlgE6
|
| 12 |
+
mxusdYlNdQCUTebQpaBUMBAFz7geyTnx3uMJJ5G1KxW7VA6uSVAN5RUuhD467/2n
|
| 13 |
+
U40EnI9Skv7o/+pznmZu6yKtIs6OwEy+ASQGuodxDQKBgQDBiRmJHmybQXqvKXCH
|
| 14 |
+
82Th4eiNoAMz5PmK8VrMhZraXJOIV7IywPiywDMWNFfWM3LEMsJKl3VXHtUrQL5N
|
| 15 |
+
7WY7xCkRF9Qhay7Hlhi7aBBWk0DPqgN4qdJhWr9xvKuhOxZVC+pMtHZZFyBjtADW
|
| 16 |
+
NI9rnC0uosAoSzjzPwdNikXZHQKBgQDwEeaJ3mK4lev5IbqZO6SKxJ2IFdViD+h2
|
| 17 |
+
TtCjSx2XKJ0fPLDjHhYE7quPFrUQh9kzDoWKTjCdwLOu/sr+VL9nn5bhcsQT7t9l
|
| 18 |
+
TmehjxYgHaqVdtwNjV3S/E6T3gKbWRAHMpLcvqiwt9PdWELsAbjf/ugwraPM9CUr
|
| 19 |
+
xjNgCIzDMwKBgAh3afGQrimglLBi/LRF1oz3KAhCDsHPa4dDhbhaw+p3kFCvnXEQ
|
| 20 |
+
9hBDzjhTc+BAAe5JViyTMaPtCmBJBco873L/4tgHldUcbkB29YAFTmmrKXOsOVim
|
| 21 |
+
/TgbEzLzkQKNpi10RvyyDFdbZqRV9I9qXzfS7jsTDZr1p3kksboXqXSVAoGACUhH
|
| 22 |
+
57DHlGeHljxtoJsjw5HSnX5qn74JuPlXK9ktrbiOSrToCgARzeMEkyXHnnoCNe0r
|
| 23 |
+
0KsxSgg3al7Dro3MUM9k4Ba16idkT+B2NVL5AgjjnZ/Y5lU++Xdz+letNiB9dCnK
|
| 24 |
+
b+qXTy3sbTSKceGnKlIK3Eb6fGQ8Q7MILYBnIO0CgYEAn9WJHcJodXFVd1vngU1A
|
| 25 |
+
/+hGs9PMOUHqD7SuNy0HggifuCXJ9w+PWPT5gFtGlgY5EyH0DYKQ+ZrTgRdL2mTA
|
| 26 |
+
6BYUjaIi1ggWsc71xwM8loqahz+Amwo1Mqfk3KAbR2LQ8qog87+Pn3AVn3T/EWGf
|
| 27 |
+
Tbg2W8xEdzpksMzugg8Vx7E=
|
| 28 |
+
-----END PRIVATE KEY-----
|
dummy_server.py
CHANGED
|
@@ -2,7 +2,7 @@ from flask import Flask, request
|
|
| 2 |
from flask_cors import CORS
|
| 3 |
|
| 4 |
app = Flask(__name__)
|
| 5 |
-
CORS(app)
|
| 6 |
|
| 7 |
motor_states = {f"motor_{i}": 0.0 for i in range(6)}
|
| 8 |
|
|
@@ -18,4 +18,4 @@ def control_motor():
|
|
| 18 |
|
| 19 |
|
| 20 |
if __name__ == "__main__":
|
| 21 |
-
app.run(host="0.0.0.0", port=5001)
|
|
|
|
| 2 |
from flask_cors import CORS
|
| 3 |
|
| 4 |
app = Flask(__name__)
|
| 5 |
+
CORS(app)
|
| 6 |
|
| 7 |
motor_states = {f"motor_{i}": 0.0 for i in range(6)}
|
| 8 |
|
|
|
|
| 18 |
|
| 19 |
|
| 20 |
if __name__ == "__main__":
|
| 21 |
+
app.run(host="0.0.0.0", port=5001, ssl_context=("certs/cert.pem", "certs/key.pem"))
|
requirements.txt
CHANGED
|
@@ -1 +1,4 @@
|
|
|
|
|
| 1 |
flask
|
|
|
|
|
|
|
|
|
| 1 |
+
eventlet
|
| 2 |
flask
|
| 3 |
+
flask-cors
|
| 4 |
+
flask-socketio
|
server.py
CHANGED
|
@@ -8,5 +8,10 @@ def root():
|
|
| 8 |
return send_from_directory("static", "index.html")
|
| 9 |
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
if __name__ == "__main__":
|
| 12 |
app.run(host="0.0.0.0", port=7860)
|
|
|
|
| 8 |
return send_from_directory("static", "index.html")
|
| 9 |
|
| 10 |
|
| 11 |
+
@app.route("/sinus")
|
| 12 |
+
def sinus():
|
| 13 |
+
return send_from_directory("static", "sinus.html")
|
| 14 |
+
|
| 15 |
+
|
| 16 |
if __name__ == "__main__":
|
| 17 |
app.run(host="0.0.0.0", port=7860)
|
static/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
const robotIp = "
|
| 2 |
window.onload = () => {
|
| 3 |
const container = document.getElementById("sliders");
|
| 4 |
for (let i = 0; i < 6; i++) {
|
|
@@ -13,7 +13,7 @@ window.onload = () => {
|
|
| 13 |
fetch(`${robotIp}/motor_control`, {
|
| 14 |
method: "POST",
|
| 15 |
headers: { "Content-Type": "application/json" },
|
| 16 |
-
body: JSON.stringify({
|
| 17 |
}).catch(err => console.error("Send error:", err));
|
| 18 |
};
|
| 19 |
container.appendChild(label);
|
|
|
|
| 1 |
+
const robotIp = "http://127.0.0.1:5001"
|
| 2 |
window.onload = () => {
|
| 3 |
const container = document.getElementById("sliders");
|
| 4 |
for (let i = 0; i < 6; i++) {
|
|
|
|
| 13 |
fetch(`${robotIp}/motor_control`, {
|
| 14 |
method: "POST",
|
| 15 |
headers: { "Content-Type": "application/json" },
|
| 16 |
+
body: JSON.stringify({ [`motor_${i}`]: parseFloat(input.value) }),
|
| 17 |
}).catch(err => console.error("Send error:", err));
|
| 18 |
};
|
| 19 |
container.appendChild(label);
|
static/sinus-io.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
window.onload = () => {
|
| 2 |
+
const socket = io("127.0.0.1:5001");
|
| 3 |
+
let connected = false;
|
| 4 |
+
|
| 5 |
+
socket.on("connect", () => {
|
| 6 |
+
console.log("Connected to the server");
|
| 7 |
+
connected = true;
|
| 8 |
+
});
|
| 9 |
+
socket.on("disconnect", () => {
|
| 10 |
+
console.log("Disconnected from the server");
|
| 11 |
+
connected = false;
|
| 12 |
+
});
|
| 13 |
+
|
| 14 |
+
const robotIp = "http://127.0.0.1:5001"
|
| 15 |
+
|
| 16 |
+
const amplitudeSlider = document.getElementById("amplitude");
|
| 17 |
+
const amplitudeValue = document.getElementById("amplitudeValue");
|
| 18 |
+
const frequencySlider = document.getElementById("frequency");
|
| 19 |
+
const frequencyValue = document.getElementById("frequencyValue");
|
| 20 |
+
const syncSlider = document.getElementById("sync");
|
| 21 |
+
const syncValue = document.getElementById("syncValue");
|
| 22 |
+
|
| 23 |
+
const motor_0Synced = document.getElementById("motor_0_synced");
|
| 24 |
+
const motor_1Synced = document.getElementById("motor_1_synced");
|
| 25 |
+
const motor_2Synced = document.getElementById("motor_2_synced");
|
| 26 |
+
const motor_3Synced = document.getElementById("motor_3_synced");
|
| 27 |
+
const motor_4Synced = document.getElementById("motor_4_synced");
|
| 28 |
+
const motor_5Synced = document.getElementById("motor_5_synced");
|
| 29 |
+
|
| 30 |
+
const verboseCheckbox = document.getElementById("verbose");
|
| 31 |
+
|
| 32 |
+
amplitudeSlider.addEventListener("input", function () {
|
| 33 |
+
amplitudeValue.textContent = amplitudeSlider.value;
|
| 34 |
+
});
|
| 35 |
+
|
| 36 |
+
frequencySlider.addEventListener("input", function () {
|
| 37 |
+
frequencyValue.textContent = frequencySlider.value;
|
| 38 |
+
});
|
| 39 |
+
|
| 40 |
+
syncSlider.addEventListener("input", function () {
|
| 41 |
+
syncValue.textContent = syncSlider.value;
|
| 42 |
+
});
|
| 43 |
+
|
| 44 |
+
let t0 = Date.now();
|
| 45 |
+
|
| 46 |
+
const syncStep = () => {
|
| 47 |
+
let t = Date.now() - t0;
|
| 48 |
+
|
| 49 |
+
const value = computeSinValue(
|
| 50 |
+
frequencySlider.value,
|
| 51 |
+
amplitudeSlider.value,
|
| 52 |
+
t / 1000
|
| 53 |
+
);
|
| 54 |
+
|
| 55 |
+
let goals = {};
|
| 56 |
+
if (motor_0Synced.checked) {
|
| 57 |
+
goals["motor_0"] = value;
|
| 58 |
+
}
|
| 59 |
+
if (motor_1Synced.checked) {
|
| 60 |
+
goals["motor_1"] = value;
|
| 61 |
+
}
|
| 62 |
+
if (motor_2Synced.checked) {
|
| 63 |
+
goals["motor_2"] = value;
|
| 64 |
+
}
|
| 65 |
+
if (motor_3Synced.checked) {
|
| 66 |
+
goals["motor_3"] = value;
|
| 67 |
+
}
|
| 68 |
+
if (motor_4Synced.checked) {
|
| 69 |
+
goals["motor_4"] = value;
|
| 70 |
+
}
|
| 71 |
+
if (motor_5Synced.checked) {
|
| 72 |
+
goals["motor_5"] = value;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
if (verboseCheckbox.checked) {
|
| 76 |
+
console.log("Sending goals:", goals);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
if (Object.keys(goals).length !== 0 && connected) {
|
| 80 |
+
// fetch(`${robotIp}/motor_control`, {
|
| 81 |
+
// method: "POST",
|
| 82 |
+
// headers: { "Content-Type": "application/json" },
|
| 83 |
+
// body: JSON.stringify(goals),
|
| 84 |
+
// }).catch(err => console.error("Send error:", err));
|
| 85 |
+
socket.emit("motor_control", goals);
|
| 86 |
+
}
|
| 87 |
+
const syncPeriod = 1000.0 / syncSlider.value;
|
| 88 |
+
setTimeout(syncStep, syncPeriod);
|
| 89 |
+
};
|
| 90 |
+
syncStep();
|
| 91 |
+
|
| 92 |
+
// Compute the current sin value at a given frequency
|
| 93 |
+
function computeSinValue(frequency, amplitude, time) {
|
| 94 |
+
return amplitude * Math.sin(2 * Math.PI * frequency * time);
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
};
|
static/sinus.html
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8" />
|
| 6 |
+
<title>Sinus</title>
|
| 7 |
+
</head>
|
| 8 |
+
|
| 9 |
+
<body>
|
| 10 |
+
<h1>Sinus</h1>
|
| 11 |
+
<div id="sliders">
|
| 12 |
+
<label for="amplitude">Amplitude:</label>
|
| 13 |
+
<input type="range" id="amplitude" min="0" max="100" value="25" />
|
| 14 |
+
<span id="amplitudeValue">25</span>
|
| 15 |
+
<br />
|
| 16 |
+
<label for="frequency">Sinus Frequency:</label>
|
| 17 |
+
<input type="range" id="frequency" min="0" max="2" step="0.1" value="0.5" />
|
| 18 |
+
<span id="frequencyValue">0.5</span>
|
| 19 |
+
<br />
|
| 20 |
+
</div>
|
| 21 |
+
<h1>Synchronisation</h1>
|
| 22 |
+
<div id="synchronisation">
|
| 23 |
+
<label for="sync">Sync freq:</label>
|
| 24 |
+
<input type="range" id="sync" min="1" max="200" step="10" value="100" />
|
| 25 |
+
<span id="syncValue">100</span>
|
| 26 |
+
<br />
|
| 27 |
+
<label for="motor_0">Motor 0 synced:</label>
|
| 28 |
+
<input type="checkbox" id="motor_0_synced" />
|
| 29 |
+
<br />
|
| 30 |
+
<label for="motor_1">Motor 1 synced:</label>
|
| 31 |
+
<input type="checkbox" id="motor_1_synced" />
|
| 32 |
+
<br />
|
| 33 |
+
<label for="motor_2">Motor 2 synced:</label>
|
| 34 |
+
<input type="checkbox" id="motor_2_synced" checked />
|
| 35 |
+
<br />
|
| 36 |
+
<label for="motor_3">Motor 3 synced:</label>
|
| 37 |
+
<input type="checkbox" id="motor_3_synced" checked />
|
| 38 |
+
<br />
|
| 39 |
+
<label for="motor_4">Motor 4 synced:</label>
|
| 40 |
+
<input type="checkbox" id="motor_4_synced" />
|
| 41 |
+
<br />
|
| 42 |
+
<label for="motor_5">Motor 5 synced:</label>
|
| 43 |
+
<input type="checkbox" id="motor_5_synced" />
|
| 44 |
+
<br />
|
| 45 |
+
</div>
|
| 46 |
+
|
| 47 |
+
<h1>Debug</h1>
|
| 48 |
+
<div id="debug">
|
| 49 |
+
<label for="verbose">Verbose:</label>
|
| 50 |
+
<input type="checkbox" id="verbose" />
|
| 51 |
+
</div>
|
| 52 |
+
|
| 53 |
+
<!-- <script src="sinus.js"></script> -->
|
| 54 |
+
|
| 55 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
|
| 56 |
+
<script src="sinus-io.js"></script>
|
| 57 |
+
|
| 58 |
+
</body>
|
| 59 |
+
|
| 60 |
+
</html>
|
static/sinus.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
window.onload = () => {
|
| 2 |
+
const robotIp = "http://127.0.0.1:5001"
|
| 3 |
+
|
| 4 |
+
const amplitudeSlider = document.getElementById("amplitude");
|
| 5 |
+
const amplitudeValue = document.getElementById("amplitudeValue");
|
| 6 |
+
const frequencySlider = document.getElementById("frequency");
|
| 7 |
+
const frequencyValue = document.getElementById("frequencyValue");
|
| 8 |
+
const syncSlider = document.getElementById("sync");
|
| 9 |
+
const syncValue = document.getElementById("syncValue");
|
| 10 |
+
|
| 11 |
+
const motor_0Synced = document.getElementById("motor_0_synced");
|
| 12 |
+
const motor_1Synced = document.getElementById("motor_1_synced");
|
| 13 |
+
const motor_2Synced = document.getElementById("motor_2_synced");
|
| 14 |
+
const motor_3Synced = document.getElementById("motor_3_synced");
|
| 15 |
+
const motor_4Synced = document.getElementById("motor_4_synced");
|
| 16 |
+
const motor_5Synced = document.getElementById("motor_5_synced");
|
| 17 |
+
|
| 18 |
+
const verboseCheckbox = document.getElementById("verbose");
|
| 19 |
+
|
| 20 |
+
amplitudeSlider.addEventListener("input", function () {
|
| 21 |
+
amplitudeValue.textContent = amplitudeSlider.value;
|
| 22 |
+
});
|
| 23 |
+
|
| 24 |
+
frequencySlider.addEventListener("input", function () {
|
| 25 |
+
frequencyValue.textContent = frequencySlider.value;
|
| 26 |
+
});
|
| 27 |
+
|
| 28 |
+
syncSlider.addEventListener("input", function () {
|
| 29 |
+
syncValue.textContent = syncSlider.value;
|
| 30 |
+
});
|
| 31 |
+
|
| 32 |
+
let t0 = Date.now();
|
| 33 |
+
|
| 34 |
+
const syncStep = () => {
|
| 35 |
+
let t = Date.now() - t0;
|
| 36 |
+
|
| 37 |
+
const value = computeSinValue(
|
| 38 |
+
frequencySlider.value,
|
| 39 |
+
amplitudeSlider.value,
|
| 40 |
+
t / 1000
|
| 41 |
+
);
|
| 42 |
+
|
| 43 |
+
let goals = {};
|
| 44 |
+
if (motor_0Synced.checked) {
|
| 45 |
+
goals["motor_0"] = value;
|
| 46 |
+
}
|
| 47 |
+
if (motor_1Synced.checked) {
|
| 48 |
+
goals["motor_1"] = value;
|
| 49 |
+
}
|
| 50 |
+
if (motor_2Synced.checked) {
|
| 51 |
+
goals["motor_2"] = value;
|
| 52 |
+
}
|
| 53 |
+
if (motor_3Synced.checked) {
|
| 54 |
+
goals["motor_3"] = value;
|
| 55 |
+
}
|
| 56 |
+
if (motor_4Synced.checked) {
|
| 57 |
+
goals["motor_4"] = value;
|
| 58 |
+
}
|
| 59 |
+
if (motor_5Synced.checked) {
|
| 60 |
+
goals["motor_5"] = value;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
if (verboseCheckbox.checked) {
|
| 64 |
+
console.log("Sending goals:", goals);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
if (Object.keys(goals).length !== 0) {
|
| 68 |
+
fetch(`${robotIp}/motor_control`, {
|
| 69 |
+
method: "POST",
|
| 70 |
+
headers: { "Content-Type": "application/json" },
|
| 71 |
+
body: JSON.stringify(goals),
|
| 72 |
+
}).catch(err => console.error("Send error:", err));
|
| 73 |
+
}
|
| 74 |
+
const syncPeriod = 1000.0 / syncSlider.value;
|
| 75 |
+
setTimeout(syncStep, syncPeriod);
|
| 76 |
+
};
|
| 77 |
+
syncStep();
|
| 78 |
+
|
| 79 |
+
// Compute the current sin value at a given frequency
|
| 80 |
+
function computeSinValue(frequency, amplitude, time) {
|
| 81 |
+
return amplitude * Math.sin(2 * Math.PI * frequency * time);
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
};
|