Pid регулятор

Товарищи, подниму тему одну с вашего позволения.
Есть прям жесточайшая необходимость реализовать регулятор температуры на 0-10в, на форуме нашел скрипт

// Виртуальное устройство для теста
defineVirtualDevice("DevTest", {
title: "Test",
cells: {
enabled: {
type: "range",
value: 27,
max: 34,
min: 26
},
log: {
type: "text",
value: false,
max: 100
},
kp1: {
type: "range",
value: 2,
min: 0,
max: 100,

},
}
});
// Начало кода PID регулятора
var Pid = function(opts) { //Конструктор объектов
opts = opts || {};
this._target = opts.target //|| 0;
this._kp = opts.kp || 0;
this._ki = opts.ki || 0;
this._kd = opts.kd || 0;
this._outputMin = opts.outputMin || 0;
this._outputMax = opts.outputMax === undefined ? 1 : opts.outputMax;
this._lastTime = null;
this._intervalId = null;
};

Pid.prototype.clip = function(x, min, max) { //Функция ограничения выходных значений регулирующего устройства
if (x < min){
return min;
} else if (x > max) {
return max;
} else {
return x;
}
};

Pid.prototype._clearErrors = function() { //Функция очистки накопленной ошибки PID регулятора
this._sumError = 0;
this._lastError = 0;
this._lastTime = null;
};

Pid.prototype.setup = function(opts) {
this._target = opts.target === undefined ? this._target : opts.target;
this._kp = opts.kp === undefined ? this._kp : opts.kp;
this._ki = opts.ki === undefined ? this._ki : opts.ki;
this._kd = opts.kd === undefined ? this._kd : opts.kd;
this._outputMin =
opts.outputMin === undefined ? this._outputMin : opts.outputMin;
this._outputMax =
opts.outputMax === undefined ? this._outputMax : opts.outputMax;
this._clearErrors();
};

Pid.prototype.tune = function(opts) {
this._kp += opts.kp || 0;
this._ki += opts.ki || 0;
this._kd += opts.kd || 0;
this._clearErrors();
};

Pid.prototype.update = function(input) { //Функция PID регулятора
var date = new Date();
var dt = date.getTime() - this._lastTime;
var error = this._target - input;
var dError = 0;
var integralNormalized = 0;
var differential = 0;

if (this._lastTime) {
dError = error - this._lastError;
this._sumError += error;
integralNormalized = this._ki * this._sumError * dt;
differential = (this._kd * dError) / dt;
integralNormalized = this.clip(
integralNormalized,
this._outputMin,
this._outputMax
);

} else {
this._clearErrors();
}

var output = this._kp * error + integralNormalized - differential;

output = this.clip(output, this._outputMin, this._outputMax);
this._lastError = error;
var date = new Date();
this._lastTime = date.getTime();
return output;
};

Pid.prototype.run = function(repeat, interval) {
if (!this._intervalID) {
this._intervalID = setInterval(repeat, interval * 1000);
this._clearErrors();
}
};

Pid.prototype.stop = function() {
if (this._intervalID) {
clearInterval(this._intervalID);
}
this._intervalID = null;
};
//Создаем объект с нужными параметрами PID регулятора

var myControl = new Pid({
target: 20, // требуемая величина выходного значения
kp: 0.5, // пропорциональная составляющая
ki: 5, // интегральная составляющая
kd: 0.1, // дифференциальная составляющая
outputMin: 0, // минимальное значение выхода
outputMax: 10 // максимальное значение выхода
});

myControl.run(function() {

var input = dev["DevTest"]["enabled"]; //Входное значение от виртуального устройства
var output = myControl.update(input); //Выходное значение
dev["DevTest"]["log"] = String(output); //Выходное значение передаем в виртуальное устройство
dev["TestAnalog"]["Channel 1"] = String(output);
myControl.kp = dev["DevTest/kp1"]; //Пример для подбора параметров PID
myControl.setup(myControl); //Пример для подбора параметров PID
}, 2); //Интервал запуска ПИД-регулятора каждые 200 мс

Но так и не понял как использовать сее чудо, данные не прилетают в dev["TestAnalog "]["Channel 1"] = String(output);
в dev["DevTest"]["log"] = String(output); данные прилетают, регулировка происходит в зависимости от входных данных, но только с виртуального устройства, а с реального датчика данные на вход не заходят…

К тому же уставка target: 20 тоже фиксирована, можно ли сюда подставить значение с виртуальной крутилки?

Но ведь в документации описано, как писать правила с примерами

В конкретно Вашем случае нужно подставить вместо var input = dev["DevTest"]["enabled"] var input = dev["ИМЯВАШЕГОДАТЧИКА"]["ИМЯКАНАЛАВАШЕГОДАТЧИКА"], например var input = dev["18-78ad21234"]["temperature"].

Target ничто не мешает присвоить любому каналу:

myControl.targer = dev["DevTest"]["setpoint"];

разумеется, его предварительно стоит объявить в devineVirtualDevice как

setpoint: {
type: "range",
value: 20, // какое-то значение по умолчанию
min: -100, // минимальное значение уставки
max: 100 // максимальное значение уставки
},

спасибо за помощь!)

Это было вписано, сюда не закинул просто, извиняюсь…
Создал виртуальное устройство, в которое для теста хочу отправить данные с выхода регулятора, но они не доходят(

defineVirtualDevice("TestAIout", {
title:"TestAIout",
cells: {
"temperature": {
type:"range",
value: 0,
min: -1,
max: 10000
},
}
});
var input = dev["wb-adc"]["Vin"]; //Входное значение от виртуального устройства
var output = myControl.update(input); //Выходное значение
myControl.target = dev["DevTest"]["setpoint"];
dev["DevTest"]["log"] = String(output * 1000); //Выходное значение передаем в виртуальное устройство
dev["TestAIout"]["range"] = String(output * 1000);
myControl.kp = dev["DevTest/kp1"]; //Пример для подбора параметров PID
myControl.setup(myControl); //Пример для подбора параметров PID
}, 2); //Интервал запуска ПИД-регулятора каждые 200 мс

я так понимаю, что из за того что выход надо из строки в число преобразовать)
Разобрался) dev["TestAIout"]["range"] = String(output * 1000); поменял на dev["TestAIout"]["range"] = Number(output * 1000);

Пытаюсь еще выходное значение округлить до целого числа var output = Math.round(output * 1000); но прилетает периодически значение в виде 8659.999999999996, что делаю не так?)

1 Like

Эта тема была автоматически закрыта через 7 дней после последнего ответа. В ней больше нельзя отвечать.