Проблемы c ПИД-регулятором

Тема в разделе "Iskra JS, Espruino, Йодо", создана пользователем Trem, 22 янв 2018.

  1. Trem

    Trem Нерд

    Добрый день.
    Столкнулся с проблемой в работе клавиатуры.
    Задача сделать простенький ПИД регулятор с вводом значения с клавиатуры и запуском самого регулятора и отображением всего этого на LCD-экране.
    ПИД регулятор управляет вентилятором по средствам ШИМа (взят из библиотеки @amperka/led и функции brightness())
    И все вроде бы просто и работает отдельно по блокам: сам по себе ПИД регулятор, экран и клавиатура.
    Проблемы возникают при совместной работе и проявляются в следующем:
    После ввода уставки и нажатия запуска основного цикла функции run, в момент времени когда целевое значение ниже уставки (выходной значение ПИД регулятор - 0) все работает, но в момент когда целевое значение пересекает уставку и выходное значение ПИД регулятора начинает расти, все ломается. Сбивается частота setinterval на LCD-экране мерцают разные значения. Добавив console.log после каждого шага удалось выяснить, что в этот момент произвольным образом меняется значение value (в основном это цифры 3, 6, 9 и их комбинации 36, 69, 96 и тд) соответственно вместе с setinterval запускаются и другие функции.
    Код (Javascript):
    var lcd = require("HD44780")
    .connect(C6,C7,C8,C9,A8,A10); //  Библиотека LCD экрана
    var pid = require('@amperka/pid')
    .create({
            target: 25,           // Уставка
            kp: 30,                // пропорциональная составляющая
            ki: 1.5,              // интегральная составляющая
            kd: 0.2,              // дифференциальная составляющая
            outputMin: 0,         // минимальное значение выхода
            outputMax: 100          // максимальное значение выхода
        });
    var cl = console.log;
    var thermometer = require('@amperka/thermometer')
    .connect(A4); // Библиотека цифрового термометра
    var x = thermometer.read('C')
    .toFixed(3); // Переменная температуры
    var speed = 100; //Переменная скорости
    var pwm = 0; //Переменная значения обратного значения ШИМ
    var t=99; // Счетчик масштаба времени
    var fan = require('@amperka/led') //библиотека умеющая делать ШИМ
        .connect(P1)
        .turnOn()
        .brightness(0);
    var value = "";
       
    function clrscr(){
        lcd.clear();
        lcd.clear();
        lcd.clear();
    }

    function doPrint(x,strNum,message){
        lcd.setCursor(x,strNum);
        lcd.print(message);
    }

    clrscr();
    doPrint(5,0,"HELLO");
    doPrint(3,1,"Input temp");

    function pwmCalc (){
        x = thermometer.read('C').toFixed(3);
        speed = pid.update(x);
        pwm = 100 - speed;
        fan.brightness(pwm / 100);
    }

    function hi (){
        clrscr();
        doPrint(4,0,"Hi temp!");
        doPrint(3,1,"Try again!");
        value = "";
    }

    function low (){
        clrscr();
        doPrint(4,0,"Low temp!");
        doPrint(3,1,"Try again!");
        value = "";
    }

    function lcdPrint (){
        clrscr();
        doPrint(0,0,"Temp - "+x);  
        doPrint(11,0," ("+value+")");      
        doPrint(0,1,"Speed - "+pwm);  
        doPrint(12,1,"     ");
    }

    function run () {
        if (value < 22) {
            low ();
        }
        else {
            pid.setup({target: value});  // задаём новую уставку
            setInterval(
                function(){
                    t = t + 1;
                    cl(pwm, x, t, value);
                    if (t < 10){
                        pwmCalc();
                    }
                    else{
                        pwmCalc();
                        lcdPrint ();
                        t = 0;
                    }
                },50);
        }
    }

    function onKey(key){
        cl(key);
        var ch = "123456789*0#"[key];
        if ("0123456789".indexOf(ch)<0){
            cl("Run");
            run();
        } else {
            value += ch;
            if (Number(value) > 70) {
                hi();
            }else {
                console.log(value);
                clrscr();
                doPrint(4,0,"SetPoint");  
                doPrint(0,1,value+"\x99C");          
            }
        }
    }

    require("KeyPad").connect([P1, P2, P3], [P4, P5, P6, P7], onKey);
    Я предположил, что проблема в что переменная value может быть не совсем числом и попытался сделать ее числом.
    Код (Javascript):
    function onKey(){  
        cl("onKey=");
        var key=keypad.read();
        var ch = "123456789*0#"[key];
        cl("KEY="+ch);
        if ("0123456789".indexOf(ch)<0){      
          cl("Run");
            run();
        } else {
            value += ch;
            var valueNum=value!==""?Number(value):0;
            if (Number(value) > 70) {
                hi();
            }else {
                console.log(value);
                clrscr();
                doPrint(4,0,"SetPoint");  
                doPrint(0,1,value+"\x99C");          
            }
        }
    }
    Но это не помогло.
    Попытки не дать запускаться циклу несколько раз, так же провалились:
    Код (Javascript):
    var interval;
    function run () {
        var valueNum=value!==""?Number(value):0;
        if (valueNum < 22) {
          cl("LOW="+valueNum);
            low ();
        }
        else {
            pid.setup({target: value});  // задаём новую уставку
            if(interval)clearInterval(interval);
            interval=setInterval(
                function(){
                    t = t + 1;
                    cl(pwm, x, t, value);
                    if (t < 10){
                        pwmCalc();
                    }
                    else{
                        pwmCalc();
                        lcdPrint ();
                        t = 0;
                    }
                },500);
        }
    }
    Попытка сделать опрос клавиатуры в цикле так же провалилась:
    Код (Javascript):
    ...
    var keypad=require("KeyPad").connect([P1, P2, P3], [P4, P5, P6, P7]);
    .........
    function onKey(){  
        cl("onKey=");
        var key=keypad.read();
        if(key==-1)return;
        var ch = "123456789*0#"[key];
        cl("KEY="+ch+",value="+value);
        if ("0123456789".indexOf(ch)<0){      
          cl("Run");
            run();
        } else {
            value += ch;
            var valueNum=value!==""?Number(value):0;
            if (Number(value) > 70) {
                hi();
            }else {
                console.log(value);
                clrscr();
                doPrint(4,0,"SetPoint");  
                doPrint(0,1,value+"\x99C");          
            }
        }
    }
    Посоветуйте как правильно подружить и доделать простецкий ПИД регулятор?
     
  2. Trem

    Trem Нерд

    Победить клавиатуру так и не вышло, решил заменить ввод с клавиатуры на энкодер. Его под рукой не оказалось и временно заменил переменным резистором.
    Код (Javascript):
    var lcd = require("HD44780").connect(C6,C7,C8,C9,A8,A10); //  Библиотека LCD экрана
    var pid = require('@amperka/pid').create({
            target: 25,           // требуемая величина выходного значения
            kp: 30,                // пропорциональная составляющая
            ki: 1.5,              // интегральная составляющая
            kd: 0.2,              // дифференциальная составляющая
            outputMin: 0,         // минимальное значение выхода
            outputMax: 100          // максимальное значение выхода
        });
    var cl = console.log; //  Переменая лога в консоль
    var thermometer = require('@amperka/thermometer').connect(A4); // Библиотека цифрового термометра
    var x = thermometer.read('C').toFixed(3); // Переменная температуры
    var speed = 100; //Переменная скорости
    var pwm = 0; //Переменная значения обратного значения ШИМ
    var t=99; // Счетчик масштаба времени
    var t2=0; // счетчик
    var mint = 21;
    var maxt = 70;
    var a = mint;
    var startstop = false;

    var fan = require('@amperka/led') //библиотека умеющая делать ШИМ
        .connect(P1)
        .turnOn()
        .brightness(pwm);
    var Pot = require('@amperka/pot').connect(A0);
    var y = Pot.read().toFixed(3); //значение потенциометра

    var Button = require('@amperka/button')
      .connect(P4, {
        holdTime: 0.5
      });

    function calca(){
        y = Pot.read().toFixed(3);
        a = (y * (maxt - mint) + mint).toFixed(0);
    }


    function clrscr(){
        lcd.clear();
        lcd.clear();
        lcd.clear();
    }

    function doPrint(x,strNum,message){
        lcd.setCursor(x,strNum);
        lcd.print(message);
        cl(message);
    }

    function start(){
    var interval1 =    setInterval(function(){
        Button.on('hold', function() {
        startstop = true;
    });
            if (startstop === false){
            cl(pwm, x, t, a);
            calca();
            clrscr();
            doPrint(4,0,"SetPoint");  
            doPrint(6,1,a+"\x99C");
                                        }
            else{
            pid.setup({target: a});      // задаём новую уставку
            clearInterval (interval1);
            run();
            }
    },100);
    }
    start();


    function run() {
    var interval2 = setInterval(function(){
            calca();
            Button.on('hold', function() {
            startstop = false;});
                if (startstop === true){
                    t = t + 1;
                    cl(pwm, x, t, a);
                        if (t < 100){
                            pwmCalc();
                        }
                        else{
                            pwmCalc();
                            clrscr();
                            lcdPrint();
                            t = 0;
                            }
                }
                else{
                    clearInterval(interval2);
                    stop();
                }
    },10);
    }


    function pwmCalc (){
        x = thermometer.read('C').toFixed(3);
        speed = pid.update(x);
        cl("SPEED="+speed);
        pwm = 100 - speed;
        fan.brightness(pwm / 100);
    }

    function lcdPrint (){
        clrscr();
        doPrint(0,0,"Temp - "+x);  
        doPrint(11,0," ("+a+")");      
        doPrint(0,1,"Speed - "+pwm);  
        doPrint(12,1,"     ");
    }


    function stop (){
        clrscr();
        doPrint(6,0,"STOP");
    }
    И все вроде хорошо значение вводятся, ПИД-регулятор работает, но появилась проблема с: ERROR: Out of Memory!

    Куда теперь смотреть и в чем проблема?
     
  3. sys

    sys Злобный Буратино Модератор

    Глубоко не вникал, но... засовывать Button.on в циклы очень плохая примета. Для начала, вынесите его наружу и сделайте в нем startstop = !startstop;
    и какая у вас версия прошивки....
     
  4. Trem

    Trem Нерд

    Добрый день.
    Версия 1v91.193
    Вынос Button.on за цикл помог, посмотрел, что есть свежие прошивки при перепрошивки из под Espruino IDE плата перестала отвечать, перепрошил через DFU плата ожила прошивка 1v92.194, но перестали подгружаться библиотеки