4 aspect railway signalling in NZ

Heres my cloud sketch for you to look at.

Credit to Sven - GitHub - SvenRosvall/SignalControl: Arduino library for controlling signals on a model railway.. I have asked him some queries to how to get it to work, but unfortunately he's to busy with other projects. Rightly so. Hes been helpfull as much as he can.

Ive managed to create a flashing yellow which wasn't in his original code. Its works as expected.

Issue Im having is with the Signal4aspect.h, I cannot get a solid yellow to light. If its last .update() then yes it will light but none will flash yellow. Its one or the other, I'd like both. Yes they share the same output pin.

Currently the block input must be held low to hold a signal. This is normal where you can use the track to create the link. In my case I want to use proximity sensors for detection because the track is fully welded and cant be used for a link.

The other thing i'd like it to do is latch it low on proximity sensor detection input and release it with the next proximity sensor detection input.

The three position with advanced caution is what im trying to get working. Ignore the little red light. Assume all signals are 3 lens signals.

Still learning.
Thanks

Is that in the code that you have on Arduino Cloud? If so, where? In that code, I don't seem to be able to find the actual flashing, only a pin number that refers to it.

        case 1: // Signal is yellow (DOESNT WORK)
          yellowLight.set(true); // Doesnt work, stays dark
          flashyellowLight.set(false);
...
...

      yellowLight.update();
      flashyellowLight.update();

Those last two lines apply what you configured in the first part. So you will always have a conflict where (in this case) flashyellowLight will win because it's the last one and your light will be off.

I think that you actually need to write a flash() method in FastLight.h and use that instead of update() when flashing is needed.

A remark
You should not configure hardware in the constructors; the ones that I found are below where you use pinMode (which configures the hardware).

  FastLight(int lightPin, bool lightOn = false)
    : lightPin(lightPin)
    , lightOn(lightOn)
  {
    pinMode(lightPin, OUTPUT);
  }

and in

  PinInput(int inputPin)
    : inputPin(inputPin)
  {
    pinMode(inputPin, INPUT_PULLUP);
  }

The usual approach is to initialise with the constructor and next use a begin() method to configure the pin.

You have a serious piece of code for somebody who is still learning :smiley:

Cheers for the reply.

The cloud code is what I have in the Arduino IDE software,


[quote="sterretje, post:2, topic:1173058"]
Is that in the code that you have on Arduino Cloud? If so, where? In that code, I don't seem to be able to find the actual flashing, only a pin number that refers to it.
[/quote]

So my thinking with this was have a bool object called ledState. It toggles every 1000ms back and forth in the background .

    case 2: // Signal is flashing yellow (WORKS)
      flashyellowLight.set(ledState); // FY works only if its the last .update();

As the code runs several times a second, I reference the call to the state of the object at that time. ie. is ledstate is true, then set the flashyellowLight.set(true), if its false, flashyellowLight.set(false).

The pin is refernced in the .ino

FastLight flashyellowLight1(24);

and

FastLight flashyellowLight2(30);

and so on.

      yellowLight.update();
      flashyellowLight.update();

Depending on which one executes first, is the one that works in the outputs. or so I thought,

   yellowLight.update();
   flashyellowLight.update();
   greenLight.update();
   redLight.update();

With both yellows above red and green, flashing yellow still working but yellowlight doesnt.

What I was trying to achieve was that is flashingyellow is set, don't set the yellow. Run one of the other. I haven't figured the code for this yet.

What I can see when wondering out how fast the code loop cycles was... initially I speed up the baud rate and am at 115200 at the moment. when removing all the serial.print lines and only had Serial.print("Loops last second:"); Serial.println(loops);
I was getting about 8000 loops per second. I observed the yellowled that I thought wasn't being set, actually being lit very slightly, so I'm thinking that its being set and them immediately unset.

How would you write it?

Credit to Sven for 95% if the code.
Thanks for your insight.

Just to demonstrate for the Signal4Aspect class; it compiles (for a Mega) but is not tested.

(1)
Add a virtual begin() method to the Light class

class Light
{
public:
  virtual void set(bool lightOn) = 0;
  virtual void update() = 0;
  // sterretje
  virtual void begin();
};

(2)
Implement a begin() method in the FastLight class and remove the pinMode from the constructor

class FastLight : public Light
{
  int lightPin;
  bool lightOn;

public:
  FastLight(int lightPin, bool lightOn = false)
    : lightPin(lightPin)
    , lightOn(lightOn)
  {
    // sterretje: removed pinMode
  }

  // sterretje
  void begin()
  {
    pinMode(lightPin, OUTPUT);
  }

  void set(bool lightOn)
  {
    this->lightOn = lightOn;
  }

  void update()
  {
    digitalWrite(lightPin, lightOn ? HIGH : LOW);
  }
  
};

(3)
Implement a begin method in the Signal4Aspect class; this will call the begin() methods for the lights.

class Signal4Aspect
{
    const BlockDistanceInput & distanceInput;
    Light & greenLight;
    Light & redLight;
    Light & yellowLight;
    Light & flashyellowLight;

  public:
    Signal4Aspect(const BlockDistanceInput & distanceInput,
                  Light & greenLight,
                  Light & redLight,
                  Light & yellowLight,
                  Light & flashyellowLight)
      : distanceInput(distanceInput)
      , greenLight(greenLight)
      , redLight(redLight)
      , yellowLight(yellowLight)
      , flashyellowLight(flashyellowLight)
    {
    }

    // sterretje
    void begin()
    {
      greenLight.begin();
      redLight.begin();
      yellowLight.begin();
      // no need to do flashyellowLight
    }

    void update()
    {
...
...

(4)
In setup, call the begin() methods for each signal

void setup()
{
  Serial.begin(9600);  // Start the serial monitor.
  
  // sterretje
  signal1.begin();
  signal2.begin();
  signal3.begin();
  signal4.begin();
}

You can give this a try for now and check if it still works as expected.

You will have to implement this for your other SignalXAspect classes and also for your PinInput / DigitalInput classes. Next you can add calls to the begin() methods in the begin() method of the SignalXAspect classes.

Thanks for that explanation; I did see the part in loop() but missed it in the Signal4Aspect class.

I will see if I can figure something out regarding the flashing.

Regarding the flashing yellow.

You only have one yellow LED so I would get rid of all FastLight flashyellowLight1(x); variables in the ino file as shown below; this include a change to the instantiation of signalX

FastLight redLight1(22, true);
FastLight yellowLight1(24);
// sterretje
//FastLight flashyellowLight1(24);
FastLight greenLight1(26);
// sterretje
//Signal4Aspect signal1(distanceInput1, greenLight1, redLight1, yellowLight1, flashyellowLight1);
Signal4Aspect signal1(distanceInput1, greenLight1, redLight1, yellowLight1);

Remove Light & flashyellowLight; as shown below

class Signal4Aspect
{
  const BlockDistanceInput& distanceInput;
  Light& greenLight;
  Light& redLight;
  Light& yellowLight;
  // sterretje
  //Light & flashyellowLight;

The constructor in Signal4Aspect.h now becomes

  Signal4Aspect(const BlockDistanceInput& distanceInput,
                Light& greenLight,
                Light& redLight,
                Light& yellowLight
                // sterretje
                //Light& flashyellowLight
                )
    : distanceInput(distanceInput), greenLight(greenLight), redLight(redLight), yellowLight(yellowLight)
  {
  }

The update() method can now be changed; all control of the yellow LED is now a single statement (not one for yellow and another one for flashing yellow).

  void update()
  {
    switch (distanceInput.freeBlocks())
    {

      case 0:  // Signal is red (WORKS)
        redLight.set(true);
        greenLight.set(false);
        yellowLight.set(false);
        // sterretje
        //flashyellowLight.set(false);  // Must exist, else when flashing will lock a yellow on if yellow output is on when changing to red
        break;

      case 1:                   // Signal is yellow (DOESNT WORK)
        yellowLight.set(true);  // Doesnt work, stays dark
        // sterretje
        //flashyellowLight.set(false);
        greenLight.set(false);
        redLight.set(false);
        break;

      case 2:                            // Signal is flashing yellow (WORKS)
        // sterretje
        //flashyellowLight.set(ledState);  // FY works only if its the last .update();
        //yellowLight.set(false);
        yellowLight.set(ledState);
        greenLight.set(false);
        redLight.set(false);
        break;

      case 3:  // Signal is green (WORKS)
        yellowLight.set(false);
        // sterretje
        //flashyellowLight.set(false);
        greenLight.set(true);
        redLight.set(false);
        break;

      default:  // Signal is unknown
        greenLight.set(true);
        redLight.set(false);
        yellowLight.set(false);
        // sterretje
        //flashyellowLight.set(false);
        break;
    }
    greenLight.update();
    redLight.update();
    yellowLight.update();
    // sterretje
    ///flashyellowLight.update();

    // whichever yellow .update is last gives the correct output. solid or flashing, the other remains digital output=0.
    // If a signal is flashing yellow, then signal goes to red, if flashing yellow output is on, it locks on,kind of traps is in its current state. FIXED by enable yellow(false) in case 0
    // How it is currently running, a solid yellow does not light. The idea is that the same physical pin for both solid yellow and flashing yellow as its the same light fixture.
    // check http://www.valleysignals.org.nz/masterton/twoposition.html - three position light for example. Ignore the tiny red light.
  }

It compiles, not tested. Note that there no longer is a flashyellowLight anywhere.

but shouldn't there be separate cases for each aspect, not LED

in code i've written, each aspect is a separate case

            // turn all LEDs off
            SigPin *p = & sigPin [s->idx - 1];

            for (unsigned i = 0; i < P_Size; i++)  {
                if (0xFF != p->LedPins [i])
                    i2cWriteBit  (p->LedPins [i], ! s->On);
            }

            // turn LEDs on
            switch (s->state) {
            case Stop:
                i2cWriteBit  (p->LedPins [P_Rd], s->On);
                break;
            case Approach:
                i2cWriteBit  (p->LedPins [P_Am], s->On);
                break;
            case Clear:
                i2cWriteBit  (p->LedPins [P_Gn], s->On);
                i2cWriteBit  (p->LedPins [P_Wh], s->On);
                break;
            }

i'm curious what is the condition for flashing yellow, is it the the next-next block is occupied where APPROACH is when the next block is occupied?

There are separate cases based on distanceInput.freeBlocks(). And in each case three LED objects are configured. And after the switch/case, they are updated.

Cheers for the input. appreciate it.

[Use in NZ] (Account Suspended)
The indication will be an "Advance Caution Normal Speed" meaning:-

  1. Two sections ahead are clear.
  2. The next signal is at Caution Normal Speed.
  3. The second signal ahead is at Stop.

[Advanced caution] (Account Suspended)
The indication is to warn that the spacing between signals are such that usual stopping distance is not provided OR To provide additional warning in adverse weather conditions
ie, next signal displaying "Caution Normal Speed" second signal at "Stop".

Insufficient Stopping Distance - The first use of Advance Caution is to warn that the spacing between signals are such that usual stopping distance is not provided.

example image of 3 aspect and 4 aspect signals.

Cheers sterretje

Where does this go?

If i put it in the .imo where the current serial.begin is, I get

C:\Users\tgagu\OneDrive\Documents\Arduino\New Signals\ASignal4AspectWithBlockDistanceInput_Flashingyellow\ASignal4AspectWithBlockDistanceInput_Flashingyellow.ino: In function 'void setup()':
C:\Users\tgagu\OneDrive\Documents\Arduino\New Signals\ASignal4AspectWithBlockDistanceInput_Flashingyellow\ASignal4AspectWithBlockDistanceInput_Flashingyellow.ino:12:3: error: 'signal1' was not declared in this scope
signal1.begin();
^~~~~~~

for all 4 signal begin code.

.....
FastLight redLight4(43, true);
FastLight yellowLight4(45);
// FastLight flashyellowLight4(45);  
FastLight greenLight4(47);
// Signal4Aspect signal4(distanceInput4, greenLight4, redLight4, yellowLight4, flashyellowLight4);
Signal4Aspect signal4(distanceInput4, greenLight4, redLight4, yellowLight4);

void setup()
{
  Serial.begin(9600);  // Start the serial monitor.
  
  // sterretje
  signal1.begin();
  signal2.begin();
  signal3.begin();
  signal4.begin();
}

void loop()
{
  unsigned long currentMillis = millis();
  loops++;
  // Make a flip flop timer for flashing led.
....

thanks for your input.

Cloud code is updated with your changes. Let me know if something else isn't right.

Found the issue, I has accidentally commented out a Signal4Aspect at signal1. that did it. its working as expected now. Thank you so much.

Now what I want to do is occupy a block with a momentary input. and un-occupy with the next input. Then signals should display with respect to occupied blocks, not digital inputs.

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