So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By schufti
#87033
so I will avoid long loops? It makes sense, but loses the elegance.

quite contrary as it shows your understanding for state machines.
For µC's a program that gets cought in a empty loop is allways a threat for "dead loops".
The concept of constantly looping and reacting on (change of) signals (state machine) is the way to go as it allows for constant monitoring of a healthy state.
It can get so atomic that on one step in the loop you check the opto and just set a "signal", in another step where you e.g. advance a stepper one step cw/ccw you do this depending on this "signal".
User avatar
By MeMagic
#87131
schufti wrote:
so I will avoid long loops? It makes sense, but loses the elegance.

quite contrary as it shows your understanding for state machines.
For µC's a program that gets cought in a empty loop is allways a threat for "dead loops".
The concept of constantly looping and reacting on (change of) signals (state machine) is the way to go as it allows for constant monitoring of a healthy state.
It can get so atomic that on one step in the loop you check the opto and just set a "signal", in another step where you e.g. advance a stepper one step cw/ccw you do this depending on this "signal".

ucp.php
OK, so I have removed all my delays and skip everything until the "moment is right" instead.
Still, can't make it work as I'm exepcting. Please, somebody take a look at the code and tell me what I'm doing wrong this time.
Code: Select allbyte FwdPin = 12;
byte BkwPin = 13;
byte OpcPin = 14;
int TargetTimer = 0;

byte System_NonCalibrated = 0;
byte System_CalibrationStarted = 1;
byte System_InitExtremeFound = 2;
byte System_FindFwdExtreme = 3;
byte System_ForwExtremeFound = 4;
byte System_FindBkwExtreme = 5;
byte System_BckwExtremeFound = 6;
byte System_AvgCcleTimeFound = 7;
byte System_Calibrated = 8;
byte System_State = 0;
byte System_PrevState = -1;
byte System_StartFwdMtn = -1;
byte System_EndFwdMtn = -1;
byte System_StartBkwMtn = -1;
byte System_EndBkwMtn = -1;

byte Motor_State = 0;
byte Motor_StopSignal = LOW;
byte Motor_RunSignal = HIGH;
byte Motor_RunForwd = 2;
byte Motor_RunBackw = 3;
int Motor_AvgCcleTime = 0;

byte OC_State = 0;
byte OC_Prev = -1;
byte OC_Covered = LOW;
byte OC_NonCovered = HIGH;
byte OC_CoverCount = 0;


void setup() {
  pinMode(OpcPin, INPUT);
  pinMode(FwdPin, OUTPUT);
  pinMode(BkwPin, OUTPUT);
  Serial.begin(115200);
  Serial.println();
  Serial.println("   Let's ROCK!");
  Serial.println();
  Serial.println();
}

void Motor_Stop()
{
  digitalWrite(FwdPin, Motor_StopSignal);
  digitalWrite(BkwPin, Motor_StopSignal); 
  Motor_State = Motor_StopSignal;
}

void Motor_StartForward()
{
  Motor_Stop();
  digitalWrite(FwdPin, Motor_RunSignal);
  Motor_State = Motor_RunForwd;
}

void Motor_StartBackward()
{
  Motor_Stop();
  digitalWrite(BkwPin, Motor_RunSignal);
  Motor_State = Motor_RunBackw;
}

void System_Calibration()
{
  switch (System_State) {
    case 0:
      Motor_StartBackward();
      System_State = System_CalibrationStarted;
      System_StartFwdMtn = 0;
      System_StartBkwMtn = 0;
      System_EndFwdMtn = 0;
      System_EndBkwMtn = 0;
      break;
    case 1:
      if (OC_State == OC_Covered) {
        Motor_Stop();
        System_State = System_InitExtremeFound;
        TargetTimer = millis() + 2000;
      }
      break;
    case 2:
      Motor_StartForward();
      System_StartFwdMtn = millis();
      System_State = System_FindFwdExtreme;
      break;
    case 3:
      if (OC_State == OC_Covered) {
        System_EndFwdMtn = millis();
        Motor_Stop();
        System_State = System_ForwExtremeFound;
        TargetTimer = millis() + 2000;
      }
      break;
    case 4:
      Motor_StartBackward();
      System_StartBkwMtn = millis();
      System_State = System_FindBkwExtreme;
      break;
    case 5:
      if (OC_State == OC_Covered) {
        System_EndBkwMtn = millis();
        Motor_Stop();
        System_State = System_BckwExtremeFound;
      }
      Break;
    case 6:
      Motor_AvgCcleTime = (System_EndFwdMtn - System_StartFwdMtn + System_EndBkwMtn - System_StartBkwMtn) / 2;
      TargetTimer = millis() + int(Motor_AvgCcleTime / 4);
      Motor_StartForward();  //   turn it to 45 degrees.
      System_State = System_AvgCcleTimeFound;
      break;
    case 7:
      System_State = System_Calibrated;
      break;
  }
}


void loop() {
  OC_State = digitalRead(OpcPin);
 
  if (System_State < 0 or System_State > 8) System_State = System_NonCalibrated;

  if (OC_Prev != OC_State) {
    if (OC_State == OC_Covered) {
      Serial.println("Opto interrupter covered.");
      if (System_State == System_Calibrated) OC_CoverCount++;
      if (OC_CoverCount > 5) {
//   send it to start over if I cover the OI for five times while it is calibrated. Just for testing
        OC_CoverCount = 0;
        if (System_State == System_Calibrated) System_State = System_NonCalibrated;
      }
    }
    else {
      Serial.println("Opto interrupter not covered");
    }
    OC_Prev = OC_State;
  }
  if (TargetTimer < millis()) if (System_State != System_Calibrated) {
    System_Calibration();
  }
  if (System_State == System_Calibrated and Motor_AvgCcleTime <= 0) {
    System_State = System_NonCalibrated;
  }

  yield();   //   almost sure, it has nothing to do with my code now.
}

In output I have this:
Code: Select allCurrent system state -
Opto interrupter not covered.
System not calibrated. Starting initial rotation backward.
Current system state - 1
Opto interrupter covered.
Initial extreme found. What next?
Current system state - 2
Started measurement rotation forward. Start forward time = 110
Current system state - 3
Opto interrupter not covered.
Opto interrupter covered.
Measurement rotation forward stopped. End forward time = 179
Current system state - 4
Opto interrupter not covered.
Started measurement rotation backward. Start backward time = 132
Current system state - 5
Opto interrupter covered.
Measurement rotation backward stopped. End backward time = 74
Current system state - 6
Average circle time calculated - 5 millisecs.
Current system state - 7
System calibrated?
Current system state - 8

What's going on? Why a later millis() returns a smaller value that an earlier one?
User avatar
By MeMagic
#87134
MeMagic wrote:OK, so I have removed all my delays and skip everything until the "moment is right" instead.
Still, can't make it work as I'm exepcting. Please, somebody take a look at the code and tell me what I'm doing wrong this time.

So, I've found an error in my previous code - I used byte values for storing millis() output. After correction time vars are showing ascendant values.
Here is the new code, this time I have left the code for debug output, so it is clear what is output and when:
Code: Select allbyte FwdPin = 12;
byte BkwPin = 13;
byte OpcPin = 14;
unsigned long TargetTimer = 0;

byte System_NonCalibrated = 0;
byte System_CalibrationStarted = 1;
byte System_InitExtremeFound = 2;
byte System_FindFwdExtreme = 3;
byte System_ForwExtremeFound = 4;
byte System_FindBkwExtreme = 5;
byte System_BckwExtremeFound = 6;
byte System_AvgCcleTimeFound = 7;
byte System_Calibrated = 8;

byte System_State = 0;
byte System_PrevState = -1;
byte OC_State = 0;
byte OC_Prev = -1;
byte Motor_State = 0;
unsigned long System_StartFwdMtn = -1;
unsigned long System_EndFwdMtn = -1;
unsigned long System_StartBkwMtn = -1;
unsigned long System_EndBkwMtn = -1;

byte Motor_StopSignal = LOW;
byte Motor_RunSignal = HIGH;
byte Motor_RunForwd = 2;
byte Motor_RunBackw = 3;

byte OC_Covered = LOW;
byte OC_NonCovered = HIGH;
byte OC_CoverCount = 0;

unsigned long Motor_AvgCcleTime = 0;

bool debug = true;

void setup() {
  // put your setup code here, to run once:
  pinMode(OpcPin, INPUT);
  pinMode(FwdPin, OUTPUT);
  pinMode(BkwPin, OUTPUT);
  Serial.begin(115200);
  Serial.println();
  Serial.println("   Let's ROCK!");
  Serial.println();
  Serial.println();
}

void debug_print(char str1[], unsigned long str2, char str3[]) {
  if (!debug) return;
  if (str1 != "") Serial.print(str1);
  if (str2 != 0) Serial.print(str2);
  if (str3 != "") Serial.print(str3);
  Serial.println();
}

void Motor_Stop()
{
  digitalWrite(FwdPin, Motor_StopSignal);
  digitalWrite(BkwPin, Motor_StopSignal); 
  Motor_State = Motor_StopSignal;
}

void Motor_StartForward()
{
  Motor_Stop();
  digitalWrite(FwdPin, Motor_RunSignal);
  Motor_State = Motor_RunForwd;
}

void Motor_StartBackward()
{
  Motor_Stop();
  digitalWrite(BkwPin, Motor_RunSignal);
  Motor_State = Motor_RunBackw;
}

void System_Calibration()
{
  switch (System_State) {
    case 0:
      debug_print("System not calibrated. Starting initial rotation backward.", 0, "");
      Motor_StartBackward();
      System_State = System_CalibrationStarted;
      System_StartFwdMtn = 0;
      System_StartBkwMtn = 0;
      System_EndFwdMtn = 0;
      System_EndBkwMtn = 0;
      break;
    case 1:
      if (OC_State == OC_Covered) {
        Motor_Stop();
        System_State = System_InitExtremeFound;
        TargetTimer = millis() + 2000;
        debug_print("Initial extreme found. What next?", 0, "");
      }
      break;
    case 2:
      TargetTimer = millis() + 400;
      Motor_StartForward();
      System_StartFwdMtn = millis();
      System_State = System_FindFwdExtreme;
      debug_print("Started measurement rotation forward. Start forward time = ", System_StartFwdMtn, "");
      break;
    case 3:
      if (OC_State == OC_Covered) {
        System_EndFwdMtn = millis();
        Motor_Stop();
        System_State = System_ForwExtremeFound;
        TargetTimer = millis() + 2000;
        debug_print("Measurement rotation forward stopped. End forward time = ", System_EndFwdMtn, "");
      }
      break;
    case 4:
      TargetTimer = millis() + 400;
      Motor_StartBackward();
      System_StartBkwMtn = millis();
      System_State = System_FindBkwExtreme;
      debug_print("Started measurement rotation backward. Start backward time = ", System_StartBkwMtn, "");
      break;
    case 5:
      if (OC_State == OC_Covered) {
        System_EndBkwMtn = millis();
        Motor_Stop();
        System_State = System_BckwExtremeFound;
        debug_print("Measurement rotation backward stopped. End backward time = ", System_EndBkwMtn, "");
      }
      break;
    case 6:
      Motor_AvgCcleTime = (System_EndFwdMtn - System_StartFwdMtn + System_EndBkwMtn - System_StartBkwMtn) / 2;
      TargetTimer = millis() + int(Motor_AvgCcleTime / 4);
      Motor_StartForward();
      System_State = System_AvgCcleTimeFound;
      debug_print("Average circle time calculated - ", Motor_AvgCcleTime, " millisecs.");
      break;
    case 7:
      System_State = System_Calibrated;
      debug_print("System calibrated?", 0, "");
      break;
  }
}

void loop() {
  OC_State = digitalRead(OpcPin);
 
  if (System_State < 0 or System_State > 8) System_State = System_NonCalibrated;
  if (System_State != System_PrevState) {
      debug_print("Current system state - ", System_State, "");
      System_PrevState = System_State;
  }
  if (OC_Prev != OC_State) {
    if (OC_State == OC_Covered) {
      debug_print("Opto interrupter covered. Time: ", millis(), "");
      if (System_State == System_Calibrated) OC_CoverCount++;
      if (OC_CoverCount > 5) {
        OC_CoverCount = 0;
        if (System_State == System_Calibrated) System_State = System_NonCalibrated;
      }
    }
    else {
      debug_print("Opto interrupter not covered. Time: ", millis(), "");
    }
    OC_Prev = OC_State;
  }
  if (TargetTimer < millis()) if (System_State < System_Calibrated) {
    System_Calibration();
  }
  if (System_State == System_Calibrated and Motor_AvgCcleTime <= 0) {
    System_State = System_NonCalibrated;
    debug_print("Average circle time corrupted, going to run calibration. Average circle: ", Motor_AvgCcleTime, ".");
  }

  yield();
}


And here is the output:
Code: Select all   Let's ROCK!


Current system state -
Opto interrupter not covered. Time: 61
System not calibrated. Starting initial rotation backward.
Current system state - 1
Opto interrupter covered. Time: 4927
Initial extreme found. What next?
Current system state - 2
Opto interrupter not covered. Time: 4927
Opto interrupter covered. Time: 4928
Started measurement rotation forward. Start forward time = 6928
Current system state - 3
Measurement rotation forward stopped. End forward time = 7329
Current system state - 4
Opto interrupter not covered. Time: 7678
Started measurement rotation backward. Start backward time = 9330
Current system state - 5
Opto interrupter covered. Time: 11689
Measurement rotation backward stopped. End backward time = 11689
Current system state - 6
Average circle time calculated - 1380 millisecs.
Current system state - 7
System calibrated?
Current system state - 8
Opto interrupter not covered. Time: 17653
Opto interrupter covered. Time: 20302
Opto interrupter not covered. Time: 20302
Opto interrupter covered. Time: 20302
Opto interrupter not covered. Time: 22919


As one can see from the output, there are a couple of same values for time - it happened when I was removing the handmade flag from the Opto Interrupter (Opto Isolator?). I don't know why it reacts so sharp when placing and removing the flag in/from the Opto Interrupter's opening. Is the ESP-12 defective?