Mag Lock System - Startup Check

Hello everyone,

This will be my first time posting within the forums so I apologize if I muck it up! Please bear with me on this one, it may be much easier than I'm making it out to be. I certainly do not offer this as an excuse but to explain any of my failings, all of my knowledge with arduino, the code, and the electrics is self taught, so I may make a mountain out of a mole hill :confused:

That being said, on to the meat of it with a brief summary of what I am attempting to create:

GREATLY, thank to many authors and skilled coders from GitHub, I have been working on an arduino controlled access system at my home. My better half and I live in a very large apartment above the business my family and I own. The tedium arrived with our stairwell. We have two locking doors which keep unwanted guests out. In a stroke of laziness I found myself looking at solutions for a tag in/tag out system for the doors so we would not constantly have to use keys.

I have, again thanks to much of the information I've found here/GitHub, managed to code up most of the system and performed a few initial tests and so far... success! So I am now working toward a more polished code as well as trying to clean up said code so that I can post it up for others to use in the event that it can in some way be helpful. While unlikely in my mind, I'd like it to be clean and easy to read/breakdown if needed. I digress...

I am currently trying to write a sequence which the micro controller will use to startup and check the components (check for faults and failures) and my question comes in here.

Here's the basic layout:

  • 1 - Arduino Uno R3
  • 1 - SeeedStudio 4 Bay Relay Shield
  • 1 - SainSmart 4 Bay Relay Board
  • 1 - Sunfounder RFID Reader
  • 1 - DIY "Push to Exit" Control Terminal
  • 2 - 12VDC Power Source

The "Push to Exit" Control Terminal Houses:

  • 3 - Basic Small 12v LED
  • 2 - Basic Large 12v LED
  • 1 - Push Button 2 Position

I'll include photos if anyone is interested.

Here's what I'd like some guidance with (or perhaps a good slap to let me know it's not possible!)

Goal:

I'd like the startup sequence to allow the power sources a moment to power up (approx. 10 seconds) and then run a system check on each component. Cycling each unit (total of 9 checked) which has power regularly and checking for failures. What I'm not certain of is if A) What I have now is accomplishing that in small way and B) If there is a working and/or better way.

I've attached my 'WorkBench' copy of the code for the full gambit, but the rub is here:

Serial.println("System warm up");       //Opening block to let the system startup.

  for(int i = 0; i < startupTime; i++){
  Serial.print(".");
  delay(2000); }

  digitalWrite(agRelayPin, HIGH);          // COMMENT 1: This sets all of the components to off (or relays on)
  digitalWrite(ayRelayPin, HIGH);          //            as the components are currently wired as NO.
  digitalWrite(arRelayPin, HIGH);
  digitalWrite(arRelayPin, HIGH);        
  digitalWrite(ldMagRelay, HIGH);
  digitalWrite(udMagRelay, HIGH);
  digitalWrite(ldStkRelay, HIGH);
  digitalWrite(udStkRelay, HIGH);
  delay(1500);
  
  
  if((agRelayPin == HIGH) && (ayRelayPin == HIGH) && (arRelayPin == HIGH) && (abRelayPin == HIGH) &&        // COMMENT 2: This is a basic dummy check, probing the units just in case one doesn't respond?
  (ldMagRelay == HIGH) && (udMagRelay == HIGH) && (ldStkRelay == HIGH) && (udStkRelay == HIGH)) {
  
  delay(500);
  Serial.println("Running system diagnostics.");
  delay(500); 
  }

    Serial.println("Access LED (G)...");        // COMMENT 3: Here the checks would begin, each one changes the state twice and then runs the purposed check.
    digitalWrite(agRelayPin, LOW);
    delay(100);
    digitalWrite(agRelayPin, HIGH);
    delay(100);
    digitalWrite(agRelayPin, LOW);
   agStat = digitalRead(agRelayPin);
   if(agStat == LOW) {
      Serial.println("Access LED (G) OK.");
      delay(2000);}
      else {
        Serial.println("Access LED (G) FAULT.");
        int faultcode = 1;                        // COMMENT 4: In the event that, for instance, the Green LED fails, faultcode is changed to 1 and moves down to the label: 'faulted'
        faulted();
        }

MS_WorkBench2.ino (7.53 KB)

I'll pick on this bit:-

  if((agRelayPin == HIGH) && (ayRelayPin == HIGH) && (arRelayPin == HIGH) && (abRelayPin == HIGH) &&        // COMMENT 2: This is a basic dummy check, probing the units just in case one doesn't respond?
  (ldMagRelay == HIGH) && (udMagRelay == HIGH) && (ldStkRelay == HIGH) && (udStkRelay == HIGH))

You can't test these this way.
'agRelayPin' won't hold 'HIGH' or 'LOW', it will hold the pin number that you set.

Since the immediately previous code set all of those pins 'HIGH', they would of course be 'HIGH' anyway.
And if you did want to check them, you'd need to use 'digitalRead()' for each.
e.g. :-

if(digitalRead(agRelayPin)==HIGH)

But there's no point. It will always be true since you just set it 'HIGH'.

The rest of the posted code is more of the same. You're only checking the state of the pins, not the attached devices, so the checks are meaningless.

Edit: I don't download attached *.ino files, so haven't checked further than the code you posted.

I was afraid that might be the case given that thinking about it logically, you're only testing information coming from the controller. I was unsure if a change or even state could be achieved if say, a powered relay failed and thus was not receiving power nor signal. Clearly my original line of thinking is incomplete. I'll back up and start looking it over again.

I appreciate the reply.

Vespen:
I was afraid that might be the case given that thinking about it logically, you're only testing information coming from the controller. I was unsure if a change or even state could be achieved if say, a powered relay failed and thus was not receiving power nor signal. Clearly my original line of thinking is incomplete. I'll back up and start looking it over again.

I appreciate the reply.

No problem.
And it's an easy trap to fall into, but to check if devices are actually working, you need some sort of feedback from the devices themselves.

It is common with electronic equipment for it to light all the LEDs briefly at startup so you can see that they all work.

You probably need a similar process for your other devices. If you want to check that relays actually switch the circuit they are intended to switch you will probably need extra stuff so the Arduino can detect the voltage being switched - with protection so that the higher voltages don't damage the Arduino.

As far as organising the code is concerned may I suggest the Thread Planning and Implementing a Program

...R

Thank you Robin, I've found several things in the thread thus far that have been a big help.

I'm curious considering what I've learned so far... It is my understanding that arduino can only "read voltage" with the analog pins, correct? If I were to change boards and move up to the Mega, perhaps I could use some of the analog pins (I'm currently reading up to make sure I understand this correctly) to tap into say, any one of the relays given that the system runs on native 12v. The 'test wire' would as Robin pointed out, then need to pass through a voltage regulator but from there would it be feasibly possible to simply use an if voltage > 0 then 'OK' else 'borked'?

Vespen:
Thank you Robin, I've found several things in the thread thus far that have been a big help.

I'm curious considering what I've learned so far... It is my understanding that arduino can only "read voltage" with the analog pins, correct? If I were to change boards and move up to the Mega, perhaps I could use some of the analog pins (I'm currently reading up to make sure I understand this correctly) to tap into say, any one of the relays given that the system runs on native 12v. The 'test wire' would as Robin pointed out, then need to pass through a voltage regulator but from there would it be feasibly possible to simply use an if voltage > 0 then 'OK' else 'borked'?

If you're only checking for the presence of 12V, you don't really even need to use an analogue input. And if set up well, no regulators would be necessary.
You could use a voltage divider from the relay-switched 12V to drop the voltage to just below 5V, or a resistor and Zener diode, then check for it's presence with a digital input using 'digitalRead()'. Anything above 0.6 x Vcc, (3V), on a 5V system will be interpreted as 'HIGH' by 'digitalRead()'.

Keep in mind, though, that although this checks that the relay is operating properly, it doesn't verify that whatever the relay is powering is functioning as expected.

Indeed, that does seem much less painful than what I've been playing with. After reading the earlier posts and reviewing I scratched out a little test sequence on the back of your initial post and did in fact get the analogRead theory to work.

 Serial.println("Warm up complete. Running diagnostics.");
    delay(2000);
      Serial.println("Relay 1...");
      digitalWrite(relayPin0, HIGH);
      relayCode0 = analogRead(A0);
      float r0Voltage = relayCode0 * (5.0/1023.0);
      Serial.println(r0Voltage);
      if(r0Voltage > 0){
        Serial.println("Relay 1 PASSED.");
        delay(1000);
        digitalWrite(relayPin0, LOW);
        
        }
        else {
          Serial.println("Relay 1 FAULT.");
          delay(1000);
          fault();

This was broken down between the two relay's that I tested. I found that the initial read would produce around 2.3-2.5v so I hand set the tolerance in the second voltage...

if(r0Voltage > 0)

Here...

and found that the 'fault' loop worked without issue.

void fault() {
  int stpcode = 0;
  Serial.println("System failed startup check.");
  delay(2000);
  do{
    if(stpcode == 0){
      Serial.println("System Fault Code");
      delay(5000);
        }
      }
    while (stpcode == 0);
  }

void passed() {
  int passcode = 0;
  Serial.println("System passed, System is armed.");
  delay(2000);
  do{
    if (passcode = 0) {
      Serial.println("System armed.");
      delay(5000);
    }
  }
    while (passcode == 0);
  }

This being the final two voids. Granted I accomplished this using my digital supply and not the typical 12v. However, I also took a breadboard and tested the output from my supply, through a 5v regulator supplied with 13.1. This produced 5.044 which concerned me since I know at least that the wide tolerance is only acceptable at the DC pin and not on incoming power (I assume there is incoming power when using AnalogRead) on a pin, which I believe is a max of 5v absolute. Maybe a little nooby but I'm pretty excited!

I really appreciate the all the help thus far!

Vespen:
It is my understanding that arduino can only "read voltage" with the analog pins, correct?

I suspect there is no need to measure the voltage (for which the analogue pins would be required) and that it would be sufficient to detect whether or not there is a voltage - and the digital pins can be used for that. They will give a HIGH reading for any voltage over (about) 3v and (of course) not exceeding 5v. If you need to check the existence of a voltage higher than 5v then you will need a voltage divider that brings the voltage below 5v. Another option may be an opto-coupler which keeps the high voltage quite separate from the Arduino.

...R

Robin: I see, I didn't realize that was the case. You'll have to forgive me, I'm relatively new to these micro electronics and C so not all of it is 100% clear to me. But with all that said that would make it vastly less frustrating, checking only for the existence of voltage over measuring the voltage. Thank you again, I was somewhat losing my hope for this thing for a while there before I posted here. Certainly you can buy magnetic access systems, and much more polished in function, but it is rewarding to see this actually working :slight_smile:

Robin2:
it would be sufficient to detect whether or not there is a voltage - and the digital pins can be used for that

Vespen:
Robin: I see, I didn't realize that was the case

I did tell you that back in reply #6.

Steve: Yes, yes you did. My apologies. I wasn't trying to offend, would have been better if I had offered credit for the advice in #7.

Vespen:
Steve: Yes, yes you did. My apologies. I wasn't trying to offend, would have been better if I had offered credit for the advice in #7.

No need for credit. :slight_smile:

I just couldn't figure why you were still using the 'analogRead()' method. 'digitalRead()' is much more efficient, and you don't need to use one of the (limited) analogue pins.
Simple is always best. :slight_smile:

This produced 5.044 which concerned me since I know at least that the wide tolerance is only acceptable at the DC pin and not on incoming power (I assume there is incoming power when using AnalogRead) on a pin, which I believe is a max of 5v absolute.

Actually, you can get away with an absolute maximum of 5.5V on the input pins of a chip supplied with 5V. (That's not to say you should do it.)

Just wanted to be clear, I do not like to appear ungrateful ha. My grasp of C/C++ is limited, so I've been relying on advice from other such as yourself and Robin to learn and advance my little project. It is greatly appreciated. I come from a medical background which doesn't lend a vast amount of aide to code/electrics. However..

Simple is always best. :slight_smile:

is 100% right. I need to try and apply "Occum's Razor" like attitude toward this!

The digRead method is so much easier! DANG. I'm still tinkering with the wiring. I had several small voltage regulators from a RadioShack that closed out nearby and purged off inventory so I've been using one of those.

Actually, you can get away with an absolute maximum of 5.5V on the input pins of a chip supplied with 5V. (That's not to say you should do it.)

This is very good to know. I've actually been concerned about that since I've seen conflicting information on it, not to say all of it was clearly credible. To my knowledge, the MFG doesn't explicitly list it on the Uno or Mega's primary product page, so having a red line I can avoid gives me peace of mind.

I'm sorting through a rebuild of the test code now (which is already much easier to deal with :slight_smile: ) and it has me curious... (Promise I'm not trying to be a pest!)

I'd like to get your thoughts on this. On the given assumption of using a digitalRead to check the relays, would it be possible/helpful to wire this in such a way that the 'test' lines are directed back to a shared pin? Essentially to have that pin be energized if the relay in question is working, it wouldn't matter if the relay and respective read pin are mutually exclusive to one another. This may have been the original concept you were trying to explain lol

Vespen:
would it be possible/helpful to wire this in such a way that the 'test' lines are directed back to a shared pin?

I just looked at a couple of potential ways of doing this. I thought I could do it with only resistors and diodes, but when I tried there was a possiblity of the Arduino 5V unintentionally powering the 12V devices, so I settled on a method using opto-couplers for isolation between 12V and 5V. One opto-coupler per relay would be needed:-

Relay fault circuit.JPG

I'm still not sure that it's worth going to all of this trouble just to check if the relays are OK. They're only a very small part of the picture, and if anything else fails, everything could fall apart anyway. Relays are pretty reliable.

To check everything for faults would require a considerably more complex system.

Edit: Actually, on reflection, a minimum 15K pullup resistor on the digital pin would be better than the 10K, to ensure the Arduino registered a 'LOW' if a relay failed to operate.

Thank you! Seeing it laid out as such cleared up a few misunderstandings I had.

I'm still not sure that it's worth going to all of this trouble just to check if the relays are OK. They're only a very small part of the picture, and if anything else fails, everything could fall apart anyway. Relays are pretty reliable.

Aye, I have seen that as the understood constant regarding relays and how often they fail. I'm not sure myself, as to if it is worth it, but my original justification for this is how the finished system will be installed. The actual 'components' are mounted in places that allow some, albeit limited, access or are visible. Given that, if one of them happen to fail, it isn't a huge undertaking to check them. However, the relays will be mounted in nearby isolated space behind the drywall in the stairwell. This makes them much harder to by comparison. This was my solution, resetting the power would at least tell me if one fails as the end product of this would be to have the PASS/FAIL or perhaps just FAIL to maybe flash a code or blink the yellow/red access LED's a given number of times as to show a code for what went wrong.

Perhaps another case of over complication?

Vespen:
Perhaps another case of over complication?

Maybe, but it is your system after all, not mine.

Steve, Robin: Just a quick update, Steve I'm still working out the wiring to get that board made for the diagram you sent me so that I can put it in line and make sure I have everything settled. I believe there is a board made specifically for posting project idea whereas this is more for assistance. Just wanted to thank you two for bearing with me and helping out!

Vespen:
Steve I'm still working out the wiring to get that board made for the diagram you sent me so that I can put it in line and make sure I have everything settled.

It's best to assemble it on a plug-in breadboard first, before committing to a permanent board, just to make sure it works OK, and as expected.
At that stage, it's easy to change values if needed. I didn't specify values for the optocoupler LEDs series resistors. They should be chosen according to the particular optocoupler's recommendation for current and the LED Vf, (probably ~20mA and 1.8V, in which case they'd be about 180 ohms).

Yes sir, absolutely. I have a couple of half non-solder BB's I'm situating it on to check it before I solder it to a blank circuit board.

The Vf listed for the optocouplers I have (4N35 317Q) is 10mA if I'm reading it correctly. I'm reading through the datasheet now, I think I'll look for some tutorials on these. This is my first time using them and I have to say its super neat.

I actually wanted to confirm something in the photo, I attached a copy.

diodeconf.jpg

I've circled and marked out a spot that I wanted to ensure I was reading right, at the "?" this is a wire jump correct, not a junction. I am 99% sure that's it but needed to check.

diodeconf.jpg