Timing a relay open with millis() for RPM

Have an LDR reading the flywheel of a pneumatic engine where the timing (a solenoid opening) is controlled by what the LDR reads off a black and white timed disk, I want to know how many times per second the LDR is outputting HIGH so that I can work out the RPM and also for what proportion of the revolution it is HIGH. I'm a bit of a noob to programming and have hit a wall. Any advice questions welcome.

#define LDRpin1 A0
#define LDRPin2 A1
int LDR1Value = 0;
int LDR2Value = 0;
int Relay1 = 10;
int Relay2 = 11;
int TriggerThreshold = 700;

int long RawRevolutions = 0;
const int BaseRPM = 0;
int CurrentRPM = (RawRevolutions * 60);

unsigned long RevOnMillis = 0;
unsigned long RevOffMillis = 0;
int RevDiffMillis = 0;


unsigned long LastCount = millis();
unsigned long CountDelay = 1000;

void setup()
{
  Serial.begin(9600);
  pinMode(Relay1, OUTPUT);
  digitalWrite(Relay1, LOW);
  pinMode(Relay2, OUTPUT);
  digitalWrite(Relay2, LOW);
}

void loop()
{
  LDR1Value = analogRead(LDRpin1);
  LDR2Value = analogRead(LDRPin2);
  //Serial.println(LDR2Value);


  if (LDR1Value > TriggerThreshold) {
    digitalWrite(Relay1, HIGH);
    RevOnMillis += 1;
    //RawRevolutions += 1;
  }
  else {
    digitalWrite(Relay1, LOW);
    RevOffMillis += 1;
  }

  if (LDR2Value > TriggerThreshold) {
    digitalWrite(Relay2, HIGH);
  }
  else {
    digitalWrite(Relay2, LOW);
  }

  unsigned long CurrentCount = millis();

  if (CurrentCount - LastCount > CountDelay) {
    LastCount = CurrentCount;

    RevDiffMillis = (5000 - (RevOffMillis-RevOnMillis));

    Serial.print("LDR Input Value: ");
    Serial.print(LDR1Value);
    Serial.print("\t Average RPM: ");
    Serial.print(CurrentRPM);
    Serial.print("\t Milliseconds Open: ");
    Serial.print(RawRevolutions);
    Serial.print("\t UpMillis ");
    Serial.println(RevDiffMillis);
    //CurrentRPM = BaseRPM;
    RawRevolutions = 0;
    RevOnMillis = 0;
    RevOffMillis = 0;
    RevDiffMillis = 0;

  }
  else {
    return;
  }
  
}


You need your code to detect the moment when the LDR value changes from being below the threshold to above it, or vice-versa. When the change happens, calculate the high time or low time, then take a snapshot of millis() to use next time the threshold is crossed.

I suspect a fundamental problem: a relay can not switch reliably multiple times per second. Please explain which input frequency range you expect, and what should consequently happen on the output side.

While the relay may struggle to keep up surely the LDR can still be used to measure the value?
Expected RPM range somewhere between 200-1500, I am fully expecting there to be a limiting factor somewhere along the line, but I'm struggling to wrap my head round how to record it.

As for relays not being fast enough, I suspect I will swap the relay for a 5v solenoid eventually rather than the current (less than ideal) setup.

Eventually the plan is to have a single "blip" input on the LDR in the revolution and use that as a start point, then have the relay open for a time inversely proportional to the RPM (i.e. less air in at high RPM for better efficiency, more at lower RPM for greater power). For now being able to just have a monitor output of the RPM would suit me fine for testing etc.

How many pulses per revolution? Why not use a light barrier?

You want to control a valve? Then use PWM and a transistor or H-bridge for the output.

How many pulses per revolution?

One, at top dead center of the piston.

Use a PWM...

With the best will in the world I am never going to have the skill to do that level of electrickery, plus the aim is to basically use the setup stated above, the whole thing is just a proof of concept really.

I can already get the engine to turn over with the valve timing provided based on white tape on the flywheel providing the signal for the inlet valve opening. but this gives fixed valve timing and not what I want to eventually end up with.

If a hall effect sensor would be a better way of detecting TDC then a change to that will be made, but really I am most interested in help coding the RPM counter as that's where the brain fart is currently, as you an probably tell by my spaghetti code (not to look a gift horse in the mouth obviously).

don't understand why there are 2 LDRs.

look this over

#define LDRPin2 A1

enum { Light, Dark };
int  ldrState;

int  ThreshLight = 700;
int  ThreshDark  = 300;

unsigned long msecPerRev;
unsigned long msecLdr;
unsigned long msecLst;

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();
    int           ldr  = analogRead (LDRPin2);

    // time each revolution using separate light/dark thresholds
    if (Dark == ldrState && ldr > ThreshLight) {
        ldrState   = Light;
        msecPerRev = msec - msecLdr;
        msecLdr    = msec;
    }
    else if (Light == ldrState && ldr < ThreshDark) {
        ldrState   = Dark;
    }

    // limit prints to 1/sec
    if (msec - msecLst >= 1000) {
        msecLst = msec;

        Serial.print ("msecPerRev ");
        Serial.println (msecPerRev);
    }
}


void setup ()
{
    Serial.begin (9600);

    pinMode      (LDRPin2, INPUT_PULLUP);   // using switch
}

Don't design with the assumption that a relay closing and a relay opening time are the same. They are not. The residual magnetism must decay before a relay will open.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.