Keresés

Új hozzászólás Aktív témák

  • schawo

    titán

    válasz tvamos #41 üzenetére

    PWM jelentése impulzusszélesség moduláció, önmagában bármilyen kapcsolófrekvenciát jelenthet. Az én értelmezésemben legalábbis.

    metro.h
    Ha jól emlékszem a hőmérővel a soros kommunikációhoz van rá szükség.

  • schawo

    titán

    válasz tvamos #38 üzenetére

    Itt egy kód. Nem a végleges, mert azt most valamiért nem találom (asszem notin fejeztem be, az meg most nincs velem), de a lényeg megvan itt is.

    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <LiquidCrystal.h>
    #include <Metro.h>
    #include <PID_v1.h>
    #include <PID_AutoTune_v0.h>


    #define ONE_WIRE_BUS_PIN 0

    #define TIME_INTERVAL 100
    #define INITIAL_INTERVAL 800
    #define REPEAT_INTERVAL 100

    Metro keyboardTimer(100); // keyboard timer intervals
    Metro cookingTimer(1000); // confirm timer
    Metro powerTimer(100);

    OneWire oneWire(ONE_WIRE_BUS_PIN);
    DallasTemperature sensors(&oneWire);

    DeviceAddress Probe01 = { 0x28, 0x2C, 0xBA, 0xE6, 0x03, 0x00, 0x00, 0x83 };
    DeviceAddress Probe02 = { 0x28, 0xEA, 0xD8, 0xE6, 0x03, 0x00, 0x00, 0x3C };
    DeviceAddress Probe03 = { 0x28, 0xE6, 0xD7, 0xE6, 0x03, 0x00, 0x00, 0x2E };
    DeviceAddress Probe04 = { 0x28, 0xEB, 0xBD, 0xE6, 0x03, 0x00, 0x00, 0xC8 };

    LiquidCrystal lcd(8, 9, 10, 11, 12, 13); // setup LCD

    #define keyboardAnalogInput 0 // keyboard analog pin
    // #define MAX_STRING_LEN = 32;
    // #define MAX_WORDS = 10;
    // lang definitions
    const char* TEXT_WELCOME_L1 = "Sous Viduino";
    const char* TEXT_WELCOME_L2 = "Udvozollek!";
    const char* TEXT_TEMP_LONG = "Homerseklet";
    const char* TEXT_TEMP = "H";
    const char* TEXT_DEG = "C";
    const char* TEXT_TIME_LONG = "Fozesi ido";
    const char* TEXT_TIME = "I";
    const char* TEXT_MINUTE = "perc";
    const char* TEXT_CURRENT_TEMP_L1 = "Pillanatnyi";
    const char* TEXT_CURRENT_TEMP_L2 = "homerseklet";
    const char* TEXT_TIME_REMAINING = "Hatralevo ido";
    const char* TEXT_ARE_YOU_SURE = "Egeszen biztos?";
    const char* TEXT_YES = "IGEN";
    const char* TEXT_NO = "NEM";
    const char* TEXT_BACK = "Vissza";
    const char* TEXT_START_COOKING = "Fozes inditasa";
    const char* TEXT_PREHEATING = "Elomelegites";
    const char* TEXT_COOKING = "Fozes";
    const char* TEXT_TURN_OFF = "Kikapcsolas";
    const char* TEXT_BYE_L1 = "Sous Viduino";
    const char* TEXT_BYE_L2 = "Viszlat!";
    const char* TEXT_ERROR = "Hijnye, baj van.";
    const char* TEXT_SENSOR_FAIL = "Homero hiba.";


    // keyboard button definitions
    #define btnRIGHT 0
    #define btnUP 1
    #define btnDOWN 2
    #define btnLEFT 3
    #define btnENTER 4
    #define confNONE 5

    #define confNO 0
    #define confYES 1

    int keyIn = 0; // keyboard analog value
    int buttonPressed; // keyboard digital value
    int i = 0;
    int prevButton = confNONE; // stores previous digital value
    int counter = 0; // for keyoard repeats
    int Temp = 50;
    int Time = 240;
    int menuItem = 1;
    int menuSize = 3;
    int confValue = confNO;
    int Confirm = 0;
    int Cooking = 0;
    int Error = 0;
    int tempError = 0;
    const char* Status = TEXT_PREHEATING;
    float temp1;
    float temp2;
    float temp3;
    float temp4;
    float tempAvg;
    unsigned int timeRemaining = 0;
    int tempSetting = 0;


    //////////////////////

    byte ATuneModeRemember = 2;
    double input = 40, output = 1000, setpoint = 30;
    double kp = 1000, ki = 0.0, kd = 0.0;

    double kpmodel = 1.5, taup = 100, theta[50];
    double outputStart = 5;
    double aTuneStep = 50, aTuneNoise = 1, aTuneStartValue = 400;
    unsigned int aTuneLookBack = 20;

    boolean tuning = false;
    unsigned long modelTime, serialTime;

    PID myPID(&input, &output, &setpoint, kp, ki, kd, DIRECT);
    PID_ATune aTune(&input, &output);

    //set to false to connect to the real world
    boolean useSimulation = false;

    ///////////////////////

    void setup()
    {
    sensors.begin();
    sensors.setResolution(Probe01, 12);
    sensors.setResolution(Probe02, 12);
    sensors.setResolution(Probe03, 12);
    sensors.setResolution(Probe04, 12);

    delay(500);

    lcd.begin(16, 2); // init LCD
    lcd.print(TEXT_WELCOME_L1);
    lcd.setCursor(0, 1);
    lcd.print(TEXT_WELCOME_L2);
    delay(3000);
    lcd.clear();
    lcd.print(TEXT_TEMP_LONG);
    lcd.setCursor(0, 1);
    lcd.print("50 C");

    ////////////////////////
    myPID.SetOutputLimits(0, 1000);
    if(useSimulation) {
    for(byte i = 0; i < 50; i++) {
    theta[i] = outputStart;
    }
    modelTime = 0;
    }
    //Setup the pid
    myPID.SetMode(AUTOMATIC);

    if(tuning) {
    tuning = false;
    changeAutoTune();
    tuning = true;
    }
    //////////////////////
    }


    void loop()
    {
    if (keyboardTimer.check() == 1 && !Error) {
    lcd.setCursor(0, 1);
    buttonPressed = readKeyboard(); // read digital value
    if (buttonPressed == confNONE) counter = 0; // if button released, reset counter
    if (prevButton == buttonPressed) { // if button kept pressed
    ++counter;
    if (counter < (INITIAL_INTERVAL / TIME_INTERVAL) || counter % (REPEAT_INTERVAL / TIME_INTERVAL)) buttonPressed = confNONE; // if repeat timer not active, drop keyboard value
    } else if (buttonPressed == confNONE) prevButton = buttonPressed;
    if (buttonPressed != confNONE) // if new key or repeat active
    {
    switch(buttonPressed) {
    int result;
    case btnUP:
    if(menuItem > 3) break; // draw only for main menu
    menuItem = (menuItem == 1) ? menuSize : menuItem - 1; // move in the main menu
    showMenu(menuItem);
    break;
    case btnDOWN:
    if(menuItem > 3) break; // draw only for main menu
    menuItem = (menuItem == menuSize) ? 1 : menuItem + 1; // move in main menu
    showMenu(menuItem);
    break;
    case btnRIGHT:
    switch(menuItem) {
    case 1:
    showValue(++Temp, TEXT_DEG); // increase temp
    break;
    case 2:
    if(Time < 999) showValue(++Time, TEXT_MINUTE); // increase time
    break;
    case 4:
    showConfirm(confValue = ((confValue == confYES) ? confNO : confYES)); // select reply
    break;
    }
    break;
    case btnLEFT:
    if (menuItem == 1 && Temp > 0) showValue(--Temp, TEXT_DEG); // decrease temp, stay above zero
    if (menuItem == 2 && Time > 0) showValue(--Time, TEXT_MINUTE); // decrease time, stay above zero
    if (menuItem == 4) showConfirm(confValue = ((confValue == confYES) ? confNO : confYES)); // select reply

    break;
    case btnENTER:
    switch(menuItem) {
    case 3: // show confirm menu
    Confirm = 1;
    confValue = confNO;
    showConfirm(confValue);
    menuItem = 4;
    break;
    case 4:
    Confirm = 0;
    if(confValue == confYES) { // start cooking
    Cooking = 1;
    menuItem = 5;
    timeRemaining = Time * 60;
    tempSetting = Temp;
    setpoint = tempSetting;
    lcd.clear();
    }
    else {
    menuItem = 1; // return to main menu
    showMenu(menuItem);
    }
    }
    break;
    }
    prevButton = buttonPressed; // store
    }
    }

    if (cookingTimer.check() == 1 && Cooking && !Error) {
    // showStatus(Status);
    if (Status == TEXT_COOKING) timeRemaining--;
    sensors.requestTemperatures();
    temp1 = sensors.getTempC(Probe01);
    temp2 = sensors.getTempC(Probe02);
    temp3 = sensors.getTempC(Probe03);
    temp4 = sensors.getTempC(Probe04);
    if (temp1 > 0 && temp1 < 110 && temp2 > 0 && temp2 < 110 && temp3 > 0 && temp3 < 110 && temp4 > 0 && temp4 < 110) {
    tempError = 0;
    tempAvg = (temp1 + temp2 + temp3 + temp4) / 4;
    /* lcd.setCursor(0, 1);
    lcd.print(TEXT_TEMP);
    lcd.print(":");
    lcd.print(tempAvg);
    lcd.print(" ");
    lcd.setCursor(8, 1);
    lcd.print(TEXT_TIME);
    lcd.print(":");
    lcd.print(timeRemaining / 60);
    lcd.print(":");
    if (timeRemaining % 60 < 10) lcd.print("0");
    lcd.print(timeRemaining % 60); */

    /////////////////////////
    if(!useSimulation) input = tempAvg;
    if(tuning) {
    byte val = (aTune.Runtime());
    if (val != 0) {
    tuning = false;
    }
    if(!tuning) { //we're done, set the tuning parameters
    kp = aTune.GetKp();
    ki = aTune.GetKi();
    kd = aTune.GetKd();
    myPID.SetTunings(kp, ki, kd);
    AutoTuneHelper(false);
    }
    }
    else myPID.Compute();

    if(useSimulation) {
    theta[30] = output;
    DoModel();
    }
    //// else analogWrite(0,output);
    //send-receive with processing if it's time
    SerialSend();

    //////////////////
    } else {
    if (++tempError > 10) {
    lcd.clear();
    lcd.print(TEXT_ERROR);
    lcd.setCursor(0, 1);
    lcd.print(TEXT_SENSOR_FAIL);
    Error = 1;
    }
    }
    }
    }

    int showStatus(const char* currStatus) {
    lcd.setCursor(0, 0);
    lcd.print(currStatus);
    }

    int readKeyboard()
    {
    keyIn = analogRead(keyboardAnalogInput);
    // read the value from the sensor
    // buttons when read are centered at these values: 0, 144, 329, 504, 741
    // add approx 70 to those values and check to see if we are close
    if (keyIn > 1000) return confNONE;
    if (keyIn < 70) return btnLEFT;
    if (keyIn < 215) return btnUP;
    if (keyIn < 400) return btnDOWN;
    if (keyIn < 575) return btnRIGHT;
    if (keyIn < 810) return btnENTER;
    return confNONE; // when all others fail, return this...
    }

    void showValue(int Value, const char* Unit) {
    lcd.setCursor(0, 1);
    lcd.print(Value);
    lcd.print(" ");
    lcd.print(Unit);
    lcd.print(" "); // to clear
    }

    void showMenu(int Menu) {
    lcd.clear();
    switch(Menu) {
    case 1:
    lcd.print(TEXT_TEMP_LONG); // temp
    showValue(Temp, TEXT_DEG);
    break;
    case 2:
    lcd.print(TEXT_TIME_LONG); // time
    showValue(Time, TEXT_MINUTE);
    break;
    case 3:
    lcd.print(TEXT_START_COOKING);
    break;
    // default:
    // lcd.print(TEXT_ERROR);
    }
    }

    void showConfirm(int Value)
    {
    if (Confirm == 1) {
    lcd.clear(); // reset screen for first use only
    lcd.print(TEXT_ARE_YOU_SURE);
    Confirm++;
    }
    lcd.setCursor(0, 1); // draw selection
    if (Value == confYES) lcd.print("#"); else lcd.print(" ");
    lcd.print(TEXT_YES);
    if (Value == confYES) lcd.print("#"); else lcd.print(" ");
    if (Value == confNO) lcd.print("#"); else lcd.print(" ");;
    lcd.print(TEXT_NO);
    if (Value == confNO) lcd.print("#"); else lcd.print(" ");;
    }

    void printTemperature(DeviceAddress deviceAddress, byte pos)
    {
    float tempC = sensors.getTempC(deviceAddress);
    switch(pos) {
    case 1:
    lcd.setCursor(0, 0);
    break;
    case 2:
    lcd.setCursor(8, 0);
    break;
    case 3:
    lcd.setCursor(0, 1);
    break;
    case 4:
    lcd.setCursor(8, 1);
    break;
    }
    if (tempC == -127.00) lcd.print("Error"); else lcd.print(tempC);
    }


    /////////////////////////////

    void changeAutoTune()
    {
    if(!tuning)
    {
    //Set the output to the desired starting frequency.
    output = aTuneStartValue;
    aTune.SetNoiseBand(aTuneNoise);
    aTune.SetOutputStep(aTuneStep);
    aTune.SetLookbackSec((int)aTuneLookBack);
    AutoTuneHelper(true);
    tuning = true;
    }
    else
    { //cancel autotune
    aTune.Cancel();
    tuning = false;
    AutoTuneHelper(false);
    }
    }

    void AutoTuneHelper(boolean start)
    {
    if(start)
    ATuneModeRemember = myPID.GetMode();
    else
    myPID.SetMode(ATuneModeRemember);
    }


    void SerialSend()
    {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("i"); lcd.print(input); lcd.print(" ");
    lcd.print("o"); lcd.print(output); // lcd.print(" ");
    lcd.setCursor(0, 1);
    // if(tuning){
    // lcd.print("tuning mode");
    // } else {
    lcd.print("p"); lcd.print(myPID.GetKp()); // lcd.print(" ");
    lcd.print("i"); lcd.print(myPID.GetKi()); // lcd.print(" ");
    lcd.print("d"); lcd.print(myPID.GetKd());
    // }
    }

    void DoModel()
    {
    //cycle the dead time
    for(byte i=0;i<49;i++)
    {
    theta[i] = theta[i+1];
    }
    //compute the input
    input = (kpmodel / taup) *(theta[0]-outputStart) + input*(1-1/taup) + ((float)random(-10,10))/100;

    }

  • schawo

    titán

    válasz tvamos #38 üzenetére

    Nyugodtan lehet 2% alá is vinni a teljesítményt, ha a PWM ciklus elég nagy :)

  • schawo

    titán

    válasz mexel #35 üzenetére

    A relé arra való, hogy a nagy teljesítményű, hálózati áramforrásról üzemelő eszközöket (itt forraló) lehessen vezérelni az elektronikával.

    Igen arra gondoltam. Persze tudom, hogy már rég feltalálták a vekkert, de akkor is :D

  • schawo

    titán

    válasz mexel #32 üzenetére

    De arra figyelj, hogy a legutóbb linkeltben nincs relé.

    Ami esetleg hiányozni fog az ilyen kütyükből, az az időzítés.

  • schawo

    titán

    válasz mexel #32 üzenetére

    K az erősítési faktor. Minden PID K-vezérléssel működik. Nem szenzornak hívjuk, de ez részletkérdés.

  • schawo

    titán

    válasz mexel #30 üzenetére

    Legyen valamilyen öntanuló elektronikája, a relé kimenő teljesítménye elegendő legyen (ezzel nem lesz gond), és az elektronika tényleg tudja, amit ráírtak (ez valószínű)

    Továbbá szüksége lesz egy vízmozgatóra is (keverő vagy szivattyú), különben nagyon egyenetlen lesz a vízhőmérséklet. Az én itteni példámból hiányzik a vízmozgató, de van 4 hőmérő és 2 forraló. Viszont ez így ebben a formában működésképtelen volt. Amikor viszont belekerült a vízmozgató, utána elég volt egy forraló és egy hőmérő (van az említett csomagban).

  • schawo

    titán

    válasz mexel #28 üzenetére

    Jónak néz ki, tud mindent amit tudni kell, önkalibrálós változat. Tetszik.

  • schawo

    titán

    válasz lapa #25 üzenetére

    Így van, inkább csak elegánsabb.

    Meg ez egy sokkal geekebb megoldás :DD

  • schawo

    titán

    válasz lapa #18 üzenetére

    Várj várj várj! Remélem a kukából azért még elő tudod halászni őket. Ha már jött a kukásautó, akkor bizony így jártál. :P

  • schawo

    titán

    válasz lapa #16 üzenetére

    A cikk maga nem is annyira a főzésről akar szólni, hanem a készülék házi elkészítéséről. De azért beteszem a cikkbe is. :)

  • schawo

    titán

    válasz sing1ep1ayer #11 üzenetére

    A kész étel fagyasztás nélkül hetekig eláll a hűtőben, tehát bármikor előre elkészítheted. Tálalás előtt csak át kell sütni egy pillanatra, hogy sültes kérge keletkezzen. Tehát az ebéd elkészítése a fogyasztás előtt csak pár percet vesz igénybe, ennél gyorsabban nem lehet ételt készíteni. A bonyolultabb ételek így készülnek a jobb éttermekben, ellenkező esetben szegény vendégnek órákat kellene várnia.

    A fűtőszállal nem lesz gond, nem megy az folyamatosan, a PWM vezérléssel kábé 5-10%-on fűt, hogy tartsa a hőmérsékletet.

  • schawo

    titán

    válasz Jim Tonic #9 üzenetére

    Figyeld a kezem, mert csalok :D

    Igen, megcsináltam a változásokat, mert ésszerű volt :K

  • schawo

    titán

    válasz hcl #4 üzenetére

    Az alapmenüt megszakításokkal fogom vezérelni, egy megszakításrutinban a delay pedig maga a halál :)

    (#3) lapa
    1. Minden húsfajtának megvan a maga receptje (hőmérséklet, idő). Ha az összes mérési ponton eléri a kívánt hőmérsékletet a víz, akkor indul a főzési idő.

    2. Igen, a főzési időre van hatással. De az állaga is más egy kuktás ételnek, mint egy nem kuktásnak. Ugyanígy különbözik állagában a 100 fokon és az 50-70 fokon készített étel. Ezen kívül az étel nem érintkezik sem vízzel, sem oxigénnel.

    3. Valóban nincs effektív vákuum. Azért kell vákuumfóliázni, mert így a zacskóban nincs jelen hőszigetelő levegőbuborék, ami miatt nem lenne garantálható a maghőmérséklet, továbbá se a főzés során, sem pedig a későbbi tárolás során nincs jelen levegő, így az étel nem oxidálódik, jobb az íz, és tovább eltartható.

    Ez első rész, a cikk következő részében lesznek képek, Arduino kód, videó.

    (#4) hcl
    Az ábrák painttel készültek :D

    (#5) sonar
    Olyan nincs, hogy valami nem sörnyitó :))

  • schawo

    titán

    válasz hcl #1 üzenetére

    Rá lehet, de nagyon nem elegáns, mert a nyomásérzékelés nem lesz jó. Az áthúzás miatt egy csomó fals lenyomást érzékel. A kondi simítja a jelet, az IC meg megszünteti a kondi miatti lassú felfutásból származó fals jeleket. Bővebben itt és itt

Új hozzászólás Aktív témák

Hirdetés