При установке значения в требуемый угол, маятник должен постепенно посредством колебаний остановиться на нем, но он просто колеблется
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body
{
text-align: center;
max-width: 50em;
margin: 0 auto;
padding: 8px;
}
h2
{
text-align: center;
}
#canvas
{
display: block;
margin: 0 auto;
padding: 0;
background: #f1f5f5;
pointer-events: none;
}
.quantity-block
{
display: grid;
grid-template-columns: 100px 250px;
justify-content: center;
align-items: flex-start;
gap: 1em;
padding: 10px ;
}
.quantity-block label
{
text-align:start;
}
.button
{
background-color: white;
color: black;
border: 2px solid #555555;
padding: 15px 20px;
text-align: center;
cursor: pointer;
border-radius: 8px;
}
input, select, button
{
font: inherit;
}
</style>
</head>
<body>
<canvas id="canvas" width="350" height="350"></canvas>
<div class="quantity-block">
<label>Начальный угол маятника</label>
<input name="α" type="range" value="1" min="-1.57" max="1.57" step="any">
<label> Масса шарика</label>
<input name="m" type="number" value="1" step="any">
<label>Длина маятника</label>
<input name="l" type="number" value="0.5" step="any">
<label>Коэффициент сопротивления окружающей среды</label>
<input name="kf" type="number" value="2" step="any">
<label>П-контролер:</label>
<input name="p" type="number" step="1" value="1000" id="kp" />
<label>И-контролер:</label>
<input name="i" type="number" step="1" value="100" id="ki" />
<label>Д-контролер:</label>
<input name="d" type="number" step="1" value="30" id="kd" />
<label>Требуемый угол:</label>
<input name="linelenght" type="number" step="5" value="60" id="target">
</div>
<button class="button" onclick="toggleSimulation();">Моделировать</button>
<script>
var canvas = $("#canvas");
var context = canvas.getContext("2d");
context.lineWidth = 3;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var α = 0;
var ω = 0;
var m = 0.1;
var g = 9.8;
var l = 0.5;
var kf = 1;
var M = 0;
var linelenght = 0;
var kp = 0;
var ki = 0;
var kd = 0;
var P = 0,
I = 0,
D = 0;
var error = 0,
prevError = 0,
dError = 0;
var isSimulationOn = false;
var lastT = performance.now();
function $(selector, context) {
return (context || document).querySelector(selector);
}
function $$(selector, context) {
return Array.from((context || document).querySelectorAll(selector));
}
function draw(t) {
requestAnimationFrame(draw);
var dt = Math.min(1 / 24, (t - lastT) / 1000);
if (isSimulationOn) {
error = linelenght - α + Math.PI / 2;
dError = error - prevError;
P = error;
I += error * Math.min(1 / 24, (t - lastT) / 1000);
D = dError / Math.min(1 / 24, (t - lastT) / 1000);
prevError = error;
M = (kp * P) + (ki * I) + (kd * D);
α += dt * ω;
ω += dt * (-g / l * Math.sin(α) - kf * l / m * ω * ω * Math.sign(ω) + M / m / l / l);
angle += α * dt;
}
var angle = α + Math.PI / 2;
var size = Math.min(WIDTH, HEIGHT);
var ox = WIDTH / 2;
var rPend = size * 0.45 * Math.tanh(0.5 * l);
var rBall = size * 0.05 * Math.tanh(0.5 * m);
var x = ox - rPend * Math.cos(angle);
var y = rPend * Math.sin(angle) + 2;
lastT = t;
context.clearRect(0, 0, WIDTH, HEIGHT);
context.beginPath();
context.arc(x, y, rBall, 0, Math.PI * 2);
context.fill();
context.moveTo(0, 2);
context.lineTo(WIDTH, 2);
context.moveTo(ox, 0);
context.lineTo(x, y);
context.stroke();
}
function updateVariables()
{
$$(".quantity-block input[name]").forEach(function (input)
{
assignVariable(input.name, input.value);
});
}
function assignVariable(name, value)
{
if (name in window)
{
window[name] = Number(value);
if (name === "α") ω = 0;
if (name === "l" || name === "m") window[name] = Math.max(0.01, window[name]);
}
}
function toggleSimulation()
{
isSimulationOn = !isSimulationOn;
$(".button").textContent = isSimulationOn ? "Остановить" : "Моделировать"
updateVariables();
}
$(".quantity-block").addEventListener("input", function (event)
{
var input = event.target;
if (input.matches("input[name]"))
{
assignVariable(input.name, input.value);
}
});
requestAnimationFrame(draw);
toggleSimulation();
</script>
</body>
</html>