LDR detection in model railway setup

Hello, I've currently got a small system within my lego railway where I reset some signals using LDRs in the track. The system consists of a PCA9685 Servo driver hooked up the the LEDs, an IR receiver to control a secondary signal and 3 LDRs (1 per signal). Independently the code seems to work but the LDR detection within the main program doesn't seem to be picking up on any values. It's not a hardware fault as the LDRs work on a different program that just detects the resistance based on the light level so I'm guessing it's a coding error I've missed. Anyone any ideas?
Rather annoyingly TinkerCad does not have the PCA board as a component, but that is operating fine.

#include "Wire.h"
#include "Adafruit_PWMServoDriver.h"
#include "IRremote.h"
Adafruit_PWMServoDriver PCA = Adafruit_PWMServoDriver(0x40, Wire);
String remoteInput = "0";
String SignalList[3];
int IRpin = 9;
IRrecv IR(IRpin);
decode_results cmd;
int bayStatus = 0;
//For PCA: A4 --> SCL, A5 --> SDA

class Signal{
  public:
    int RedPin;
    int Yellow1Pin;
    int GreenPin;
    int Yellow2Pin;
    int readPin;
    int Status = 0;
    int stepCount = 0;
    int a = 1;
    int stepUpVal = 100;
    bool setReset = true;
    int ambientValue;
    int currentValue;
    
    Signal(int Red, int Yellow1, int Green, int Yellow2, int readPin) {
      RedPin = Red;
      Yellow1Pin = Yellow1;
      GreenPin = Green;
      Yellow2Pin = Yellow2;
      readPin = readPin;
    }
    int lightSet(){
      int i = 0;
      ambientValue = 0;
      for (i; i < 40; i = i + 1){
        //currentValue = analogRead(readPin);
        ambientValue = ambientValue + currentValue;
        delay(10);
      }
      ambientValue = ambientValue / i;
      if (ambientValue < 0){
        ambientValue = 800;
      }
      //Serial.println(ambientValue);
      Serial.println("");
    }
    void lightDetect(){
      stepCount = stepCount + a;
      
      currentValue = analogRead(readPin);
      Serial.println(currentValue);
      if (currentValue < ambientValue *0.55){
        Status = 1;
        stepCount = 0;
        setReset = true;
      }
      if (stepCount == stepUpVal){
        stepUp();
        stepCount = 0;
      }
    }

    void stepUp(){
      Status = Status + 1;

      if (Status == 5){
        Status = 4;
        stepCount = 0;
      } 
    
      if (Status == 1){
        PCA.setPWM(RedPin, 0, 4095);
        PCA.setPWM(Yellow1Pin, 0, 0);
        PCA.setPWM(GreenPin, 0, 0);
        PCA.setPWM(Yellow2Pin, 0, 0);
      }
      if (Status == 2){
        PCA.setPWM(RedPin, 0, 0);
        PCA.setPWM(Yellow1Pin, 0, 4095);
        PCA.setPWM(GreenPin, 0, 0);
        PCA.setPWM(Yellow2Pin, 0, 0);
      }
      if (Status == 3){
        PCA.setPWM(RedPin, 0, 0);
        PCA.setPWM(Yellow1Pin, 0, 4095);
        PCA.setPWM(GreenPin, 0, 0);
        PCA.setPWM(Yellow2Pin, 0, 4095);
      }
      if (Status == 4){
        PCA.setPWM(RedPin, 0, 0);
        PCA.setPWM(Yellow1Pin, 0, 0);
        PCA.setPWM(GreenPin, 0, 4095);
        PCA.setPWM(Yellow2Pin, 0, 0);
      }

    }
};

Signal Ed1(0, 1, 2, 3, A3);
Signal Ed2(4, 5, 6, 7, A1);
Signal Ed4(8, 9, 10, 11, A2);

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
Wire.begin(0);
PCA.begin();
PCA.setPWMFreq(1600);
IR.enableIRIn();
Ed1.lightSet();
Ed2.lightSet();
Ed4.lightSet();
Ed1.stepUp();
Ed2.stepUp();
Ed4.stepUp();
}

void loop() {
  // put your main code here, to run repeatedly:
while (IR.decode(&cmd)==0) {
  Ed1.lightDetect();
  Ed2.lightDetect();
  Ed4.lightDetect();

  if (cmd.value == 0x6BC6597B) {
    //Train into bay, remote 1
    bayStatus = 1;
    Ed1.setReset = false;
  }
  if (cmd.value == 0x735B797E) {
    //Train out of bay, remote 2
    bayStatus = 2;
  }
  if (bayStatus == 0){
    Ed4.stepCount = 0;
    Ed4.Status = 1;
  }
  if (bayStatus == 1){
    Ed4.stepCount = 0;
    Ed4.Status = 1;
    if (Ed1.Status == 2){
      Ed1.stepCount = 0;
      Ed1.setReset = false;
      bayStatus =  3;
    }
  }

  if (bayStatus == 3){
    Ed1.stepCount = 0;
    if (Ed1.setReset == true){
      bayStatus = 0;
    }

  }
  if (bayStatus == 2){
    if (Ed1.Status != 1 || Ed2.Status != 1){
      Ed4.stepCount = 0;
      Ed4.Status = 1;
    }
    if (Ed1.Status == 1){
      Ed1.stepCount = 0;
    }
    if (Ed2.Status == 1){
      Ed2.stepCount = 0;
    }
    if (Ed1.Status == 1 && Ed2.Status == 1){
      delay(10000);
      Ed4.stepUp();
      Ed4.setReset = false;
      bayStatus = 4;
    }
  }
  if (bayStatus == 4){
    if(Ed1.setReset == true){
      bayStatus = 0;
    }
  }
  delay(100);
  Serial.println(Ed1.currentValue);
}
IR.resume();
}

  • Please show us your schematic.

  • Always add meaningful comments to your code.

  • BTW, you should really get into the habit of setting i to an initial value.
    for (i; i < 40; i = i + 1){

can you explain how you expect your code to work?

  • not sure why your main code within loop() is only executed when IR.decode() returns zero. In code i've written i check for a non-zero value and always execute a resume() when a code is received
  • don't understand why you calls to lightdetect() are within the loop checking IR.decode()
  • don't understand the logic inside lightDetect() it seems to repeatedly increment stepCount, reset it if the level is < theshold and only invoke steup() after 100 iterations
  • in steup() don't see how Status ever gets beyond 1 since stepup() is only invoked once after Status and stepCount are reset when the lightLevel < the ambient threshold
  • I'm not sure either but that does seem to be working fine, I copied that from an arduino tutorial. If something with the remote functions goes wrong that'll be my next point of call, thanks for the heads up.
  • That is a good question but it didn't seem to be running when outside the loop, I suspect that potentially the IR bit could be redone entirely
  • stepcount is basically a timer, it's using the delay in the code (times 100 in this case) to make the signal change colour every ~10 seconds. If a train is above the LDR, the signal needs to reset to red (Status 1). If the stepCount reaches the stepUp value, the signal changes to it's next colour then restarts the counter.

Hope that helps! I'm not the most experienced with this stuff.

-Would a Tinkercad screenshot be okay? It's the only thing I have to hand :confused:
-Yeah bad habit on my part
-I'll try and remember next time!

  • You can also use paper and pencil and show us a good image of it.

what is it suppose to do?

So I have two signals that, until a button on an IR remote are pressed, are changing some LEDs connected to a PCA9685 board. Each set of LEDs has an LDR adjacent to it on the railway, so that when something passes over the LDR, it gets dark and the LDR detects it, which then should reset the signals back to the first set in the sequence. If I've not pressed anything, two of the light sets should change from red to yellow to two yellows to green (like a 4 aspect railway signal) then the LDR resets it to red, and it starts changing again. If I press one button on the remote, it should hold one of the light sets at yellow until the train has passed it (It's entering a bay platform, hence baystatus). If i press a different button, it should wait until the first two light sets are both red, keep them at red and then change the third light set until the train has passed. Afterwards it should resume changing the first two sets of lights. Hope that helps explain it.

Added a TinkerCad screenshot to the post. It didn't have the PCA board. I'd rather avoid drawing it as it'd become a mild mess of lines! Also I've no idea what the component symbols and conventions are :confused:

i think the primary problem is that both the argument and private variable have the same name and didn't set the private variable correctly.

if i understand your intention correctly, i think Status should be initialized to 4

also separated the calls to lightDetect() outside of the code for the IR detector and presumably fix some of the issues with it

but look this over

// LDR Signal controller

# include "Wire.h"
# include "Adafruit_PWMServoDriver.h"
# include "IRremote.h"

Adafruit_PWMServoDriver PCA = Adafruit_PWMServoDriver (0x40, Wire);

String remoteInput = "0";
String SignalList[3];
int IRpin = 9;
IRrecv IR (IRpin);
decode_results cmd;
int bayStatus = 0;
//For PCA: A4 --> SCL, A5 --> SDA

char s [90];

// -----------------------------------------------------------------------------
class Signal{
  public:
    int RedPin;
    int Yellow1Pin;
    int GreenPin;
    int Yellow2Pin;
    int readPin;
    int Status = 0;
    int stepCount = 0;
    int a = 1;
    int stepUpVal = 100;
    bool setReset = true;
    int ambientValue;
    int currentValue;

    // -------------------------------------
    Signal (int Red, int Yellow1, int Green, int Yellow2, int _readPin) {
        RedPin      = Red;
        Yellow1Pin  = Yellow1;
        GreenPin    = Green;
        Yellow2Pin  = Yellow2;
        readPin     = _readPin;
        pinMode (readPin, INPUT_PULLUP);
    }

    // -------------------------------------
    void lightSet ()
    {
        int i;

        ambientValue = 0;
        for (i = 0; i < 40; i++)  {
            currentValue = analogRead (readPin);
            ambientValue = ambientValue + currentValue;
            delay (10);
        }

        ambientValue = ambientValue / i;
        if (ambientValue < 0)  {
            ambientValue = 800;
        }

        Status = 4;

        sprintf (s, "lightSet: ambientValue %d", ambientValue);
        Serial.println (s);
    }

    // -------------------------------------
    void lightDetect ()
    {
        stepCount = stepCount + a;

        currentValue = analogRead (readPin);

        if (currentValue < ambientValue *0.55)  {
            Status = 1;
            stepCount = 0;

            sprintf (s, " lightDetect: %2d currentValue %4d",
                            readPin, currentValue);
            Serial.println (s);
            setReset = true;
        }
        if (stepCount == stepUpVal)  {
            stepUp ();
            stepCount = 0;
        }
    }

    // -------------------------------------
    void stepUp ()  {
        sprintf (s, "  stepUp: %2d Status %d, cnt %4d",
                                readPin, Status, stepCount);
        Serial.println (s);

        Status = Status + 1;

        if (Status == 5)  {
            Status = 4;
            stepCount = 0;
        }

        if (Status == 1)  {
            PCA.setPWM (RedPin, 0, 4095);
            PCA.setPWM (Yellow1Pin, 0, 0);
            PCA.setPWM (GreenPin, 0, 0);
            PCA.setPWM (Yellow2Pin, 0, 0);
        }
        if (Status == 2)  {
            PCA.setPWM (RedPin, 0, 0);
            PCA.setPWM (Yellow1Pin, 0, 4095);
            PCA.setPWM (GreenPin, 0, 0);
            PCA.setPWM (Yellow2Pin, 0, 0);
        }
        if (Status == 3)  {
            PCA.setPWM (RedPin, 0, 0);
            PCA.setPWM (Yellow1Pin, 0, 4095);
            PCA.setPWM (GreenPin, 0, 0);
            PCA.setPWM (Yellow2Pin, 0, 4095);
        }
        if (Status == 4)  {
            PCA.setPWM (RedPin, 0, 0);
            PCA.setPWM (Yellow1Pin, 0, 0);
            PCA.setPWM (GreenPin, 0, 4095);
            PCA.setPWM (Yellow2Pin, 0, 0);
        }

    }
};


Signal Ed1 (0, 1, 2, 3, A3);
Signal Ed2 (4, 5, 6, 7, A1);
Signal Ed4 (8, 9, 10, 11, A2);

// -----------------------------------------------------------------------------
void setup () {
    // put your setup code here, to run once:
    Serial.begin (9600);
    Wire.begin (0);
    PCA.begin ();
    PCA.setPWMFreq (1600);
    IR.enableIRIn ();
    Ed1.lightSet ();
    Ed2.lightSet ();
    Ed4.lightSet ();
    Ed1.stepUp ();
    Ed2.stepUp ();
    Ed4.stepUp ();
}


// -----------------------------------------------------------------------------
void loop ()
{
    Ed1.lightDetect ();
    Ed2.lightDetect ();
    Ed4.lightDetect ();

    if (IR.decode(&cmd)) {
        if (cmd.value == 0x6BC6597B) {
            //Train into bay, remote 1
            bayStatus = 1;
            Ed1.setReset = false;
        }

        if (cmd.value == 0x735B797E) {
            //Train out of bay, remote 2
            bayStatus = 2;
        }

        if (bayStatus == 0)  {
            Ed4.stepCount = 0;
            Ed4.Status = 1;
        }
        if (bayStatus == 1)  {
            Ed4.stepCount = 0;
            Ed4.Status = 1;
            if (Ed1.Status == 2)  {
                Ed1.stepCount = 0;
                Ed1.setReset = false;
                bayStatus =  3;
            }
        }

        if (bayStatus == 3)  {
            Ed1.stepCount = 0;
            if (Ed1.setReset == true)  {
                bayStatus = 0;
            }

        }
        if (bayStatus == 2)  {
            if (Ed1.Status != 1 || Ed2.Status != 1)  {
                Ed4.stepCount = 0;
                Ed4.Status = 1;
            }
            if (Ed1.Status == 1)  {
                Ed1.stepCount = 0;
            }
            if (Ed2.Status == 1)  {
                Ed2.stepCount = 0;
            }
            if (Ed1.Status == 1 && Ed2.Status == 1)  {
                delay (10000);
                Ed4.stepUp ();
                Ed4.setReset = false;
                bayStatus = 4;
            }
        }
        if (bayStatus == 4)  {
            if (Ed1.setReset == true)  {
                bayStatus = 0;
            }
        }
        IR.resume ();
    }

    delay (20);
}

Please add new information to new posts, don't add it to old posts as it confuses the flow of the thread.

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

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