Here is one that I can't really get my head around.
So we are controlling a two Gate motor (Stock standard) and it has two modes.
- Free Access
- Trigger
This is to control the gates for a Hydro Station to Generate Power.
To open the gate you from static you can use free access and the gate will open till 100%. Should you want to stop the gate midway you can use a trigger. After stop, if you use trigger again it will close.
So we need to have 3 controls for the gate motor:
Open
Close
Stop
By using the two modes one can "predict" each mode with the following logic.
Open = Free Access
Close = Free Access + Trigger (To Stop) + Trigger (To Close)
Stop = Free Access + Trigger
So here is the challenge that we have.
There are four Relays, two for each gate that commits Free Access and Trigger (They need to Switch On then Off for each mode with a 1-second delay). There are also other functions that run so I don't want to use delay() in the functions.
In the program, I have tried a couple of options.
The first was to use the "Virtual.timer" function but it seems to be slow. Then I went the "proper way" using millis but the Code keeps on looking wrong for a better word - it does work, however
.
Here are the attempts that I made.
First was with the Delay option and is triggered by a Command from MQTT
void RelayCommand(int command){
// Declare the Gate Options
int openGateA[] = {0,0};
int stopGateA[] = {0,0,1,1};
int closeGateA[] ={0,0,1,1,1,1};
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
digitalWrite(relayPins[thisPin], HIGH); // to make sure that all the relays is OFF
}
if (command == 1){ // Open Gate A
for (int thisPin = 0; thisPin < 2; thisPin++) {
int i = openGateA[thisPin-1];
RelaySwitching(i);
delay(1000);
}
}else if (command == 2){
for (int thisPin = 0; thisPin < 4; thisPin++) {
Serial.println(thisPin);
int i = stopGateA[thisPin];
RelaySwitching(i);
delay(1000);
}
}else if (command == 3){
for (int thisPin = 0; thisPin < 6; thisPin++) {
int i = closeGateA[thisPin-1];
RelaySwitching(i);
delay(1000);
}
}
Serial.println(F("Command Done"));
}
void RelaySwitching(int RelayPin ){
if(digitalRead(relayPins[RelayPin]) == HIGH){
digitalWrite(relayPins[RelayPin], LOW);
}else{
digitalWrite(relayPins[RelayPin], HIGH);
}
}
The Delay does work but at the cost of the program stopping for x seconds
The second attempt was to create a Timer that will run a bunch of functions. If one of them is true
it will run the command and then reset but that creates a lot of global variables.
byte counterGateAopen = 0 ;
byte counterGateAstop = 0 ;
byte counterGateAclose = 0 ;
byte gateAOpenCommand = 0;
byte gateAstopCommand = 0;
byte gateAcloseCommand = 0 ;
void manualGateTimer(){ // This runs within the loop
unsigned long currentMillis = millis();
if (currentMillis - previousMillisGate > 1000){
// -------------- Gate A -------------
gateAOpenF ();
gateAstopF ();
gateAcloseF ();
gateAcloseFull ();
previousMillisGate = currentMillis;
}
}
void gateAOpenF (){
if (gateAOpenCommand == 1){
int rPins[] = {0,0};
if (counterGateAopen == 0){
char status_0[40]="";
sprintf(status_0 ,"%s%s%s","stat/",topic,"/GATE1");
client.publish(status_0,"0");
}
if (counterGateAopen < 2){
counterGateAopen++ ;
int i = rPins[counterGateAopen-1];
if(digitalRead(relayPins[i]) == HIGH){
digitalWrite(relayPins[i], LOW);
}else{
digitalWrite(relayPins[i], HIGH);
}
}else{
gateAOpenCommand = 0;
gateAcommandActive = 1 ;
counterGateAopen = 0 ;
char status_0[40]="";
sprintf(status_0 ,"%s%s%s","stat/",topic,"/GATE1");
client.publish(status_0,"1");
}
}
}
void gateAstopF (){
if (gateAstopCommand == 1){
int rPins[] = {0,0,1,1};
if (counterGateAstop == 0){
char status_0[40]="";
sprintf(status_0 ,"%s%s%s","stat/",topic,"/GATE1");
client.publish(status_0,"0");
}
if (counterGateAstop < 4){
counterGateAstop++ ;
int i = rPins[counterGateAstop-1];
if(digitalRead(relayPins[i]) == HIGH){
digitalWrite(relayPins[i], LOW);
}else{
digitalWrite(relayPins[i], HIGH);
}
}else{
gateAstopCommand = 0;
gateAcommandActive = 1 ;
counterGateAstop = 0 ;
char status_0[40]="";
sprintf(status_0 ,"%s%s%s","stat/",topic,"/GATE1");
client.publish(status_0,"1");
}
}
}
void gateAcloseF (){
if (gateAcloseCommand == 1){
//Serial.print(F("Gate A Close"));
int rPins[] = {0,0,1,1,1,1};
if (counterGateAclose == 0){
char status_0[40]="";
sprintf(status_0 ,"%s%s%s","stat/",topic,"/GATE1");
client.publish(status_0,"0");
}
if (counterGateAclose < 6){
counterGateAclose++ ;
int i = rPins[counterGateAclose-1];
if(digitalRead(relayPins[i]) == HIGH){
digitalWrite(relayPins[i], LOW);
}else{
digitalWrite(relayPins[i], HIGH);
}
}else{
gateAcloseCommand = 0;
gateAcommandActive = 1 ;
counterGateAclose = 0 ;
char status_0[40]="";
sprintf(status_0 ,"%s%s%s","stat/",topic,"/GATE1");
client.publish(status_0,"1");
}
}
}
Is there a more efficient way by controlling these relays?
Here is the full code of the program if you need to see the whole picture..
The Full code is a bit big so here is the ZIP file if you want to have a look ..
Hydro_Controller.zip (9.3 KB)
