// UserFiniteStateMachine.h
//*========================================================================================
//* Application code
//*
//* Name: UserFSM()
//* Version:
//* Date:
//* Author:
//*
//* Short description:
//*
//*
//*========================================================================================
//*========================================================================================
//*============ START USER APPLICATION ======= START USER APPLICATION =====================
//*========================================================================================
//*========================================================================================
//
// State machine
//
// Each phase exists of 2 parts, e.g. the phase actions and transition conditions.
// In the phase actions, all activated tags are mentioned. Deactivation is not needed, deactivation is
// done at the end of the main loop. In the conditions section, all conditions for the transitions to another
// phase are mentioned. When all condition are true, the new phase can be set. It is possible to programm
// more then 1 transition. In such a case it is necassery to keep the priority in mind.
//
//*========================================================================================
void UserFSM()
{
// START
//
// Doe de initialisatie voor het programma.
// Breng de spindel naar rechts tot het eindcontact, zodat het programma
// weet waar de beker houder is. Ga start daarna de status INIT, NORMAL enn CIP.
//
if (MachineState == FiniteState("START"))
{
// Move the cup transport to the left to find the zero position...
// Now we know where we are in the machine
Spindle.setSpeed(-200);
Spindle.runSpeed();
CupPressent = false;
NewCup = true;
PrepareDrink = false;
//UpdateServo("HATCH", 90);
//UseHMISerial = false;
if (DigLow("ZERO"))
{
Spindle.stop();
Spindle.disableOutputs();
Spindle.setCurrentPosition(0);
TransitionToState("INIT");
TransitionToState("NORMAL");
TransitionToState("CIP");
}
};
// NORMAL
//
// Door de toetsen combinatie F1 en F2, 5 seconden in te houden en onder
// voorwaarde dat we géén drankjes maken; start dan nu de service mode.
//
if (MachineState == FiniteState("NORMAL"))
{
Service = 0;
//if (DigLow("F1") && DigLow("F2") && DigLow("F3") && !Service) if (Timer(5000, timService)) TransitionToState("SERVICE");
if (DigLow("F1") && DigLow("F2") && !PrepareDrink)
{
if (Timer(5000, timService)) TransitionToState("SERVICE");
}
else CancelTimer(timService);
}
// SERVICE
//
// Laat de LEDS in een looplicht oplichten. Het is nu mogelijk de betreffende
// pompjes en de water klep te bedienen buiten de besturing om.
// Leid het water naar een riool punt!
// Wanneer 3 seconden op F1 en F2 wordt gedrukt, wordt de service mode
// weer verlaten.
//
if (MachineState == FiniteState("SERVICE"))
{
Service = 1;
if (Timer(50, timServiceMode)) ServiceLED = ServiceLED + 1;
if (ServiceLED == 6) ServiceLED = 1;
switch (ServiceLED)
{
case 1:
Activate("ACKD1");
break;
case 2:
Activate("ACKD2");
break;
case 3:
Activate("ACKD3");
break;
case 4:
Activate("ACKSTART");
break;
case 5:
Activate("READY");
break;
}
if (DigLow("F1") && DigHigh("F2") && DigHigh("F3") && DigHigh("START")) { Activate("&D1"); Activate("ACKD1"); }
if (DigHigh("F1") && DigLow("F2") && DigHigh("F3") && DigHigh("START")) { Activate("&D2"); Activate("ACKD2"); }
if (DigHigh("F1") && DigHigh("F2") && DigLow("F3") && DigHigh("START")) { Activate("&D3"); Activate("ACKD3"); }
if (DigHigh("F1") && DigHigh("F2") && DigHigh("F3") && DigLow("START")) { Activate("&DW"); Activate("ACKSTART"); }
//if (DigLow("F1") && DigLow("F2") && DigLow("F3")) if (Timer(3000, timService)) TransitionToState("NORMAL");
if (DigLow("F1") && DigLow("F2"))
{
if (Timer(3000, timService)) TransitionToState("NORMAL");
}
else CancelTimer(timService);
};
// INIT
//
// Na het initialiseren van het programma, brengt de besturing de beker houder op de
// laad/los positie van de machine.
// Start nu de state CHOICE (keuze maken) en CUPPRESSENT (check op "beker aanwezig").
//
if (MachineState == FiniteState("INIT"))
{
// Move to the load/unload position
if (Timer(2000, timStartup))
{
Spindle.setSpeed(350);
Spindle.runToNewPosition(200);
Spindle.setCurrentPosition(0);
Spindle.disableOutputs();
TransitionToState("CHOICE");
TransitionToState("CUPPRESSENT");
}
};
// CHOICE
//
// Wacht op de keuze van de gebruiker voor één van de drie smaken.
// Wanneer er een keuze is gemaakt EN er is een beker aanwezig EN
// de machine zit niet in de servide mode; Start dan status MIX.
//
if (MachineState == FiniteState("CHOICE"))
{
if (CupPressent && !Service) if (Timer(400, timAanUit)) AanUit = !AanUit; else if (AanUit)
{
Activate("ACKD1");
Activate("ACKD2");
Activate("ACKD3");
}
if (DigRising("F1"))
{
LiquirNo = 1;
TimeLiquir = 2200;
PositionLiquir = 6750;
}
if (DigRising("F2"))
{
LiquirNo = 2;
TimeLiquir = 2400;
PositionLiquir = 4850;
}
if (DigRising("F3"))
{
LiquirNo = 3;
TimeLiquir = 2200;
PositionLiquir = 2850;
}
if ((DigRising("F1") || DigRising("F2") || DigRising("F3")) && CupPressent && !Service) TransitionToState("MIX");
if (!CupPressent) if (Timer(150, timAanUit)) AanUit = !AanUit; else if (AanUit) Activate("READY");
};
// MIX
//
// Wacht op de bevestiging van de keuze (knop "START") OF op het drukken op een
// keuze knop. Wanneer er weer op een keuze knop wordt gedrukt, gaat de status
// terug naar CHOICE. Bij een bevestiging, sluit het toegangshekje en start de
// besturing de status GOTO-LIQUIR, ondervoorwaarde dat er een nieuwe beker
// staat EN deze op de laad/los plaats staat.
//
if (MachineState == FiniteState("MIX"))
{
Activate("ACKD" + String(LiquirNo));
if (Timer(400, timAanUit)) AanUit = !AanUit; else if (AanUit) Activate("ACKSTART");
if (!CupPressent) if (Timer(150, timAanUit)) AanUit = !AanUit; else if (AanUit) Activate("READY");
if ((DigRising("START")) && CupPressent && NewCup)
{
//UpdateServo("HATCH", 1);
GoMix = true;
PrepareDrink = true;
Activate("ACKSTART");
CupPressent = false;
//UseHMISerial = true;
UpdateText("MUZIEK", "---" );
//UseHMISerial = false;
TransitionToState("GOTO-LIQUIR");
}
if (DigRising("F1") || DigRising("F2") || DigRising("F3")) TransitionToState("CHOICE");
};
// GOTO-LIQUIR
//
// Stop bij de juiste positie voor één van de drie
// limonade vulpunten. Bij aankomst start de status LIQUIR.
//
if (MachineState == FiniteState("GOTO-LIQUIR"))
{
Activate("ACKD" + String(LiquirNo));
Activate("ACKSTART");
UpdateText("MUZIEK", "F" + String(LiquirNo));
if (Timer(200, timWait))
{
Spindle.setSpeed(350);
Spindle.runToNewPosition(PositionLiquir);
Spindle.disableOutputs();
TransitionToState("LIQUIR");
}
};
// LIQUIR
//
// Sart de pomp voor het limonade smaak voor bepaalde tijd.
// Ga daarna naar status GOTO-WATER.
//
if (MachineState == FiniteState("LIQUIR"))
{
Activate("ACKD" + String(LiquirNo));
Activate("ACKSTART");
Activate("&D" + String(LiquirNo));
if (Timer(TimeLiquir,timLimo)) TransitionToState("GOTO-WATER");
};
// GOTO-WATER
//
// Wacht eerst 4 seconden, om de limonade te laten uitdruppen en
// ga dan terug naar de laad/los positie. Bij aankomst start
// de water dosering in status WATER.
//
if (MachineState == FiniteState("GOTO-WATER"))
{
Activate("ACKD" + String(LiquirNo));
Activate("ACKSTART");
if (Timer(4000, timWait))
{
Spindle.setSpeed(350);
Spindle.runToNewPosition(0);
Spindle.disableOutputs();
TransitionToState("WATER");
}
};
// WATER
//
// Start de water dosering voor bepaalde tijd door openen van de afsluiter.
// Daarna starten de states READY en NEWCUP.
//
if (MachineState == FiniteState("WATER"))
{
Activate("ACKSTART");
Activate("ACKD" + String(LiquirNo));
Activate("&DW");
if (Timer(1500, timWater))
{
NewCup = false;
TransitionToState("READY");
TransitionToState("NEWCUP");
}
};
// READY
//
// Hekje open sturen. Start status CHOICE en CUPPRESENT.
//
if (MachineState == FiniteState("READY"))
{
PrepareDrink = false;
//UpdateServo("HATCH", 90);
if (Timer(150, timAanUit)) AanUit = !AanUit; else if (AanUit && !Service) Activate("READY");
if ((Timer(5000, timGameOver)) && NewCup)
{
GoMix = false;
TransitionToState("CHOICE");
TransitionToState("CUPPRESSENT");
}
};
// NEWCUP
//
// Controle of de beker is wegehaald van de laad/los plaats.
// Dit is een voorwaarde (NewCup) voor het opnieuw starten van een cyclus.
// Hiermee wordt voorkomen dat een gevulde beker weer de machine
// in gaat.. en ja daar wordt alles niet skjinner van!
//
if (MachineState == FiniteState("NEWCUP"))
{
PollUltra = true;
if (DistanceLonger("PRESENT", 8))
{
PollUltra = false;
NewCup = true;
TransitionToState("END");
}
};
// CUPPRESSENT
//
// In deze status wordt gecontroleerd of er een beker op de laad/los plek
// aanwezig is (CupPressent). Check d.m.v. een ultrasone meting.
//
if (MachineState == FiniteState("CUPPRESSENT"))
{
PollUltra = true;
if (Distance("PRESENT") != 0) if (DistanceBetween("PRESENT", 4, 7)) CupPressent = true; else CupPressent = false;
if (GoMix)
{
PollUltra = false;
TransitionToState("END");
}
};
// CIP
//
// Elke 2 minuten, wanneer er geen drankjes worden gemaakt, zal
// een afsluiter worden open gestuurd door CIPCYCLE om de aanvoerslang
// te verversen.
//
if (MachineState == FiniteState("CIP"))
{
if (Timer(120000, timWaitCIP))
{
if (!PrepareDrink)
{
TransitionToState("CIPCYCLE");
TransitionToState("CIP");
}
else CancelTimer(timWaitCIP);
}
};
// CIPCYCLE
//
// Afsluiter voor de CIP gaat open voor 10 seconden. Daarna wordt
// de status gestopt. Het kan zijn dat iemand ondertussen weer
// een drankje wil maken; de CIP afsluiter wordt nu ook dichtgestuurd.
//
if (MachineState == FiniteState("CIPCYCLE"))
{
Activate("&CIP");
if (Timer(10000, timCIP)) TransitionToState("END");
if (PrepareDrink)
{
TransitionToState("END");
CancelTimer(timCIP);
}
};
//*========================================================================================
//*========================================================================================
//*============ END USER APPLICATION ========= END USER APPLICATION =====================
//*========================================================================================
//*========================================================================================
}
Comments