First project, am I going in the right direction?

Hi,

I’m doing my first bit of programming but I don’t have access to my arduino. Would you be so kind as to scan my code for possible errors or feasibility?

BACKGROUND:
Hi have a mechanical code lock on my tool shed. It’s a sliding bolt style in the middle of the door. I want to have more locking points, without having 25keys to open the door. My intention is to install a Yale night latch style lock, top and bottom. When the mechanical code lock is opened it will open a n/c micro switch. This will cause two servo motors to open the Yale locks (keys for when it all goes wrong!). Additionally there will be a reed switch on the door. If the door is opened while the mechanical lock reads locked, it sounds a sounder for 15mins and operates a strobe until reset. This prevents simply pressing the micro switch when the door is forced open to deactivate.

Reset by closing the door and unlocking the mechanical lock.

Since I can’t run this code, am I making any obvious mistakes?

#include <Servo.h> 
 
Servo lock1;                // servo object
Servo lock2;                // servo object
const int unlockVal = 170;  // servo position to unlock
const int unlockPin = 2;    // mechanical lock pin, 10K to Gnd, +5v from switch
int unlockState = 0;        //state of unlockSwitch, LOW means unlocked

const int doorPin = 4;    // doorSwitch pin, 10K to Gnd, +5v from switch
int doorState = 0;        //state of doorSwitch

const int sounderPin = 7;    // sounder pin
int sounderState = 0;        // sounderState
long lastSounderTime = 0;  // the last time the sounder was turned on
long sounderOnTime = 900000;    // 15mins

const int strobePin = 8;    // strobe pin
int strobeState = 0;        // strobeState


void setup() 
{ 
    
  pinMode(unlockPin, INPUT); // initialize the unlockSwitch pin as an input
  pinMode(doorPin, INPUT); // initialize the doorSwitch pin as an input
  pinMode(sounderPin, OUTPUT); // initialize the sounderPin pin as an output
  digitalWrite(sounderPin, LOW); // sounder off
  pinMode(strobePin, OUTPUT); // initialize the strobePin pin as an output
  digitalWrite(strobePin, LOW); // strobe off
  lock1.attach(5);  // attaches the servo on pin 5 to the servo object
  lock2.attach(6);  // attaches the servo on pin 6 to the servo object
  lock1.write(0);  // reset to locked
  lock2.write(0);  // reset to locked
} 
 
void loop() 
{ 
  unlockState = digitalRead(unlockPin); // read the state of the unlockSwitch
  doorState = digitalRead(doorPin); // read the state of the doorSwitch
  sounderState = digitalRead(sounderPin); // read the state of the sounder
  strobeState = digitalRead(strobePin); // read the state of the strobe
  // check if the unlockSwitch is pressed.
  if (unlockState == LOW && doorState == HIGH) {    //door closed, mechanical lock unlocked 
      digitalWrite(strobePin, LOW); // strobe OFF
     digitalWrite(sounderPin, LOW); // sounder OFF
    // drive servos to unlocked    
    lock1.write(unlockVal);
    lock2.write(unlockVal);
    delay(15); // some time to get to position 
    // 
    // some kind of alert to inform ready to open
    //
  }else if(unlockState == HIGH && doorState == LOW && sounderState == LOW && strobeState == LOW){ //door opened before the lock! and sounder not already on
     digitalWrite(strobePin, HIGH); // strobe ON
     digitalWrite(sounderPin, HIGH); // sounder ON 
     lastSounderTime = millis();
  } 
  // turn sounder off if it's been on for too long
  if (sounderState == HIGH && (millis() - lastSounderTime) > sounderOnTime) {
    digitalWrite(sounderPin, LOW); // sounder OFF
  }
}

here is a quick schematic, it’s a bit messy. Trying to familiarise myself with Fritzing, but you get the idea, I hope :slight_smile:

D7 and D9 need to be protected from excessive current drain by the sounder and strobe. Make sure they don't pull over 40ma (try to keep it around 20ma).

The power used by the two servos will overwhelm the voltage regulator on the Arduino and probably cause it to reset. You'll want to power them from a separate 5V source.

R2 and R1 should be of a much higher resistance. I assume you understand that you need them so to prevent your pins from floating but with just 220 ohms you'll be passing a constant 5V / 220 = 20ma through them which is wasteful. A 10K ohm resistor is the usual choice here.

Chagrin: D7 and D9 need to be protected from excessive current drain by the sounder and strobe. Make sure they don't pull over 40ma (try to keep it around 20ma).

Turns out the strobe/sounder unit is 9-12v 200mA, So I need a separate supply that can be switched via transistors on D7 & D9. I need to check my box of bits to see if I have anything suitable. I'm quite happy to check datasheets but if you know of any common transistor that covers the current requirement it would help :D

The power used by the two servos will overwhelm the voltage regulator on the Arduino and probably cause it to reset. You'll want to power them from a separate 5V source.

Glad you pointed that out! I hadn't considered that. I will regulate 5v from the above separate supply. A 7805 should be sufficient? I'll check the data sheet as the servos are rated 450mA each, call it 1A

R2 and R1 should be of a much higher resistance. I assume you understand that you need them so to prevent your pins from floating but with just 220 ohms you'll be passing a constant 5V / 220 = 20ma through them which is wasteful. A 10K ohm resistor is the usual choice here.

I intended to have a 10K resistors, can't find how to change the value in Fritzing :~

I'm more concerned with the programming (that's not to say my electronics skill is much!), I have done website programming for years. But this is more C like and less forgiving. Is there any kind of simulators available?

Many thanks for your input. It's greatly appreciated!

Your use of sounderState and strobeState is kinda wierd in how you set them based on digitalReading the pins. Both could be eliminated just by looking at sounderOnTime where a zero value means that those states are off (and you should be resetting sounderOnTime to zero when the door lock has been unlocked). Similarly you should not set sounderOnTime to millis() if it is non-zero. It's just a bad practice to be doing so much digitalReading/Writing in those loops.

Also, the argument to delay() is in milliseconds. I don't think your servos are that fast ;)

Chagrin: Your use of sounderState and strobeState is kinda wierd in how you set them based on digitalReading the pins. Both could be eliminated just by looking at sounderOnTime where a zero value means that those states are off (and you should be resetting sounderOnTime to zero when the door lock has been unlocked). Similarly you should not set sounderOnTime to millis() if it is non-zero. It's just a bad practice to be doing so much digitalReading/Writing in those loops.

Very true, I'm playing the tired card now! Joys of doing this at 4am!

Chagrin: Also, the argument to delay() is in milliseconds. I don't think your servos are that fast ;)

Wishful thinking. They haven't arrived yet :-(

Sorry for the delay in responding. I have been researching MOSFETS, trying to pick a suitable logic level FET for the servos. I built a Solar Panel that I would like to make use of, I have a couple of SLA batteries too plus the parts to make an arduino Max Power Point Tracker. I'd like this to run off battery so RDSon needs to be as low as possible but it's proving a bit of a mine field selecting components. I was looking at the IRLZ34N that has a 0.06 rDS(on) at 4v.

If I have 2 servos at 0.45A, call it 1A for both (I need to check that's stall current) then dissipation is 0.06w I'd guess it was ok without a heat sink? But then I'm not sure how long it will take to switch given the limited current from the arduino.

I think I jumped on here before I was ready. I have way to much figure out.

Is there a good list of recommended common parts? So much choice it's overwhelming.

Well I have been getting the schematic sorted out, I think I have a solution now but as I’m not that great at electronics it would be great if someone could cast their eye over the attached schematic for any problems I over looked. I’m most concerned about the resistor values for the NPN PNP transistors that switch the Siren & Strobe. I did a test with calculated values but the output voltage was low, about 8-9v, lowered the resistance to drive them into saturation giving me 11.5v

Servos: 5v 1A - 2A stall current x2
Siren+Strobe unit: 12v 200mA

Many thnaks

Here is the code so far. Be nice to get some feedback :slight_smile:

#include <Servo.h> 
#include <EEPROM.h>

/// SERVOS
const int servoEnablePin = 4; //pin 6 D4 
Servo lock1;                // servo object
Servo lock2;                // servo object
const int unlockVal = 10;  // servo position to unlock
const int lockedVal = 170;  // servo position to lock
int servoLockState = 0;     // LOW open HIGH closed
/// SENSORS
const int unlockPin = 5;    // mechanical lock pin, 10K to Gnd, +5v from switch
int unlockState = 0;        //state of unlockSwitch, LOW = unlocked, HIGH = locked / armed
const int doorPin = 4;    // doorSwitch pin, 10K to Gnd, +5v from switch
int doorState = 0;        //state of doorSwitch
int lastDoorState = 0;        //state of doorSwitch
/// OUTPUTS
const int sirenPin = 5;    // pin 11 D5 - siren pin
long lastSirenTime = 0;    // last time the siren was turned on
  //long sirenOnTime = 900000; // 15mins
long sirenOnTime = 2000; // 2 sec tst
int sirenMute = 0;
const int strobePin = 6;     // pin 12 D6 - strobe pin
const int led1Pin = 13;      // status led
int triggerPostReset = EEPROM.read(0);


void setup() 
{ 
  Serial.begin(9600);
  Serial.println('STARTING');
  pinMode(led1Pin, OUTPUT); // initialize as an output  
  digitalWrite(led1Pin, HIGH); // led1 on
  pinMode(unlockPin, INPUT); // initialize the unlockSwitch pin as an input
  pinMode(doorPin, INPUT); // initialize the doorSwitch pin as an input
  pinMode(sirenPin, OUTPUT); // initialize the sounderPin pin as an output
  digitalWrite(sirenPin, LOW); // sounder off
  pinMode(strobePin, OUTPUT); // initialize the strobePin pin as an output
  digitalWrite(strobePin, LOW); // strobe off
  pinMode(servoEnablePin, OUTPUT); // servos on
    digitalWrite(servoEnablePin, HIGH); // servos on
    delay(250);
  lock1.attach(3);  // attaches the servo on pin 5 D3
  lock1.write(lockedVal);  // reset to locked
  lock2.attach(2);  // attaches the servo on pin 4 D2
  lock2.write(lockedVal);  // reset to locked
   delay(1500); //wait for position
   digitalWrite(servoEnablePin, LOW); // servos off
  digitalWrite(led1Pin, LOW); // led1 off

} 
 
void loop() 
{ 
 
  checkSensors();
  if(doorState != lastDoorState){
    lastDoorState =  doorState;
    if(doorState == 1){
    Serial.println("DOOR OPENED");
    }else{
    Serial.println("DOOR CLOSED");
    }
} 
   // check if the unlockSwitch is pressed.
  if (unlockState == LOW && doorState == LOW && servoLockState == 1) {    //door closed, mechanical lock unlocked 
   Serial.println("DISARMED - UNLOCKED + DOOR CLOSED");
      digitalWrite(strobePin, LOW);  // strobe OFF
      digitalWrite(sirenPin, LOW); // sounder OFF
      sirenMute = 0;
      lastSirenTime = 0;           // reset sounder ON time
      //if(servoLockState == 1){// drive servos to unlocked if locked
       Serial.println("SERVOS TO UNLOCKED");
       servoLockState = 0;
       digitalWrite(servoEnablePin, HIGH); // servos on
      lock1.write(unlockVal);
      flashDelay(led1Pin, 150, 10); // some time to get to position
     digitalWrite(servoEnablePin, LOW); // servos off 
      //}
  }else if(doorState == LOW && unlockState == HIGH && servoLockState == 0){ // door closed and lock locked
   Serial.println("SERVOS TO LOCKED");
      digitalWrite(servoEnablePin, HIGH); // servos on
      lock1.write(lockedVal);
      servoLockState = 1;
      flashDelay(led1Pin, 100, 15); // some time to get to position
      digitalWrite(servoEnablePin, LOW); // servos off
  }else if((unlockState == HIGH && doorState == HIGH && lastSirenTime == 0) || triggerPostReset == 1){ //door opened before the lock! and sounder is off
      Serial.println("ALERT DOOR OPENED OR LOCK TAMPER"); Serial.println(" SIREN + STROBE ON");
      EEPROM.write(0,1); // save triggerPostReset
      digitalWrite(strobePin, HIGH); // strobe ON
      digitalWrite(sirenPin, HIGH); // sounder ON 
      lastSirenTime = millis();
  } 
  // turn sounder off if it's been on for too long
  int sirenOnFor = millis() - lastSirenTime;
  if (lastSirenTime != 0 && sirenOnFor > sirenOnTime && sirenMute != 1) { // siren not OFF & siren ON in excess of sirenOnTime
      sirenMute = 1;
      Serial.println(" SIREN OFF");
      digitalWrite(sirenPin, LOW); // sounder OFF
  }
}

int flashDelay(int outputPin, int rTime, int rAmount){
  for (int thisPin = 0; thisPin < rAmount; thisPin++) {
    // turn the pin on:
    digitalWrite(outputPin, HIGH);  
    delay(rTime);                  
    // turn the pin off:
    digitalWrite(outputPin, LOW); 
 delay(rTime);    
  }
}

void checkSensors() {
 flashDelay(led1Pin, 30, 5);
 checkSensor(&doorPin, &doorState); 
 checkSensor(&unlockPin, &unlockState);
}


void checkSensor(const int *sensorPin, int *sensorState){
 
  int reading = analogRead(*sensorPin);  
  // converting that reading to voltage, for 3.3v arduino use 3.3
  float voltage = reading * 5.0;
  voltage /= 1024.0;
  if(voltage <= 0.5){  // 0v short - alarm
    *sensorState = 1;
  }else if(voltage > 2 && voltage < 2.5){  // 2.5v normal
    *sensorState = 0;
  }else if(voltage > 2.8 && voltage < 3.8){  //3.3v  sensor trip
    *sensorState = 1;
  }else{ // 5v wire cut or tamper trip
    *sensorState = 1;
  }
  // print out
  //Serial.print(voltage); Serial.print("v CH Pin"); Serial.print(*sensorPin);  Serial.print("CH State");Serial.println(*sensorState); 
}

I think I’m getting the hang of this now. I had problems with the servos resetting or hanging the uC. Changing the order in which I signaled possition and enabled servo power seems to have resolved the problem. I’m just not sure why it mattered? Revised code with some eeprom fix

#include <Servo.h> 
#include <EEPROM.h>

/// SERVOS
const int servoEnablePin = 4; //pin 6 D4 
Servo lock1;                // servo object
Servo lock2;                // servo object
const int lock1Pin = 3; // lock1 pin 5 D3
const int lock2Pin = 2; // lock1 pin 4 D4
const int unlockVal = 800;  // servo position to unlock
const int lockedVal = 2200;  // servo position to lock
int servoLockState = 0;     // LOW open HIGH closed
/// SENSORS
const int unlockPin = 5;    // mechanical lock pin, 10K to Gnd, +5v from switch
int unlockState = 0;        //state of unlockSwitch, LOW = unlocked, HIGH = locked / armed
const int doorPin = 4;    // doorSwitch pin, 10K to Gnd, +5v from switch
int doorState = 0;        //state of doorSwitch
int lastDoorState = 0;        //state of doorSwitch
/// OUTPUTS
const int sirenPin = 5;    // pin 11 D5 - siren pin
long lastSirenTime = 0;    // last time the siren was turned on
  //long sirenOnTime = 900000; // 15mins
long sirenOnTime = 1000; // 2 sec tst
int sirenMute = 0;
const int strobePin = 6;     // pin 12 D6 - strobe pin
const int led1Pin = 13;      // status led
int triggerPostReset = EEPROM.read(0);
int protectEEPROM = 1;



void setup() 
{ 
  Serial.begin(9600);
  if(triggerPostReset == 0){
     protectEEPROM = 0;
   }else{
     protectEEPROM = 1;
   }
  Serial.print("STARTING - POST RESET ALERT = "); Serial.print(triggerPostReset); Serial.println(protectEEPROM);
  pinMode(led1Pin, OUTPUT); // initialize as an output  
  digitalWrite(led1Pin, HIGH); // led1 on
  pinMode(unlockPin, INPUT); // initialize the unlockSwitch pin as an input
  pinMode(doorPin, INPUT); // initialize the doorSwitch pin as an input
  pinMode(sirenPin, OUTPUT); // initialize the sounderPin pin as an output
  digitalWrite(sirenPin, LOW); // sounder off
  pinMode(strobePin, OUTPUT); // initialize the strobePin pin as an output
  digitalWrite(strobePin, LOW); // strobe off
  pinMode(servoEnablePin, OUTPUT); // servos on
  pinMode(lock1Pin, OUTPUT); // initialize the servo pin as an output
  pinMode(lock2Pin, OUTPUT); // initialize the servo pin as an output  
  lock1.attach(lock1Pin);  // attaches the servo on pin 5 D3
  lock1.writeMicroseconds(lockedVal);
  lock2.attach(lock2Pin);  // attaches the servo on pin 4 D2
  lock2.writeMicroseconds(lockedVal);
  digitalWrite(servoEnablePin, HIGH); // servos on
  delay(1500); //wait for position
  lock1.detach();
  lock2.detach();
  digitalWrite(servoEnablePin, LOW); // servos off
  
  digitalWrite(led1Pin, LOW); // led1 off

} 
 
void loop() 
{ 
 
  checkSensors();
  if(doorState != lastDoorState){
    lastDoorState =  doorState;
    if(doorState == 1){
    Serial.println("DOOR OPENED");
    }else{
    Serial.println("DOOR CLOSED");
    }
} 
   // check if the unlockSwitch is pressed.
  if (unlockState == LOW && doorState == LOW && servoLockState == 1) {    //door closed, mechanical lock unlocked 
   Serial.println("DISARMED - UNLOCKED + DOOR CLOSED");
       
      if(protectEEPROM == 1){
         Serial.println("POST RESET ALERT DISABLED");
         EEPROM.write(0,0); // save triggerPostReset
         protectEEPROM = 0;
      }
      digitalWrite(strobePin, LOW);  // strobe OFF
      digitalWrite(sirenPin, LOW); // sounder OFF
      sirenMute = 0;
      lastSirenTime = 0;           // reset sounder ON time
      
       Serial.println("SERVOS TO UNLOCKED");
       servoLockState = 0;
       lock1.attach(lock1Pin);
       lock1.writeMicroseconds(unlockVal); 
       lock2.attach(lock2Pin);  // attaches the servo on pin 4 D2
       lock2.writeMicroseconds(unlockVal);
       digitalWrite(servoEnablePin, HIGH); // servos on
      // delay(1500);
      flashDelay(led1Pin, 150, 10); // some time to get to position
       lock1.detach();
       lock2.detach();
       digitalWrite(servoEnablePin, LOW); // servos off 
      
  }else if((unlockState == HIGH && doorState == HIGH && lastSirenTime == 0) || triggerPostReset == 1){ //door opened before the lock! and sounder is off
      Serial.println("ALERT DOOR OPENED OR LOCK TAMPER"); Serial.println(" SIREN + STROBE ON");
      
      if(protectEEPROM == 0){
        protectEEPROM = 1;
        Serial.println("POST RESET ALERT ENABLED");  
        EEPROM.write(0,1); // save triggerPostReset
      }else{  
        triggerPostReset = 0;
      }
      digitalWrite(strobePin, HIGH); // strobe ON
      digitalWrite(sirenPin, HIGH); // sounder ON 
      lastSirenTime = millis();
  }else if(doorState == LOW && unlockState == HIGH && servoLockState == 0){ // door closed and lock locked
   Serial.println("SERVOS TO LOCKED");
      lock1.attach(3); 
      lock1.writeMicroseconds(lockedVal);
      lock2.attach(lock2Pin);  // attaches the servo on pin 4 D2
      lock2.writeMicroseconds(lockedVal);
      digitalWrite(servoEnablePin, HIGH); // servos on
      servoLockState = 1;
      //delay(1500);
      flashDelay(led1Pin, 100, 15); // some time to get to position
      lock1.detach();
      lock2.detach();
      digitalWrite(servoEnablePin, LOW); // servos off
  } 
  // turn sounder off if it's been on for too long
  int sirenOnFor = millis() - lastSirenTime;
  if (lastSirenTime != 0 && sirenOnFor > sirenOnTime && sirenMute != 1) { // siren not OFF & siren ON in excess of sirenOnTime
      sirenMute = 1;
      Serial.println(" SIREN OFF");
      digitalWrite(sirenPin, LOW); // sounder OFF
  }
}

int flashDelay(int outputPin, int rTime, int rAmount){
  for (int thisPin = 0; thisPin < rAmount; thisPin++) {
    // turn the pin on:
    digitalWrite(outputPin, HIGH);  
    delay(rTime);                  
    // turn the pin off:
    digitalWrite(outputPin, LOW); 
 delay(rTime);    
  }
}

void checkSensors() {
 flashDelay(led1Pin, 30, 5);
 checkSensor(&doorPin, &doorState); 
 checkSensor(&unlockPin, &unlockState);
}


void checkSensor(const int *sensorPin, int *sensorState){
 
  int reading = analogRead(*sensorPin);  
  // converting that reading to voltage, for 3.3v arduino use 3.3
  float voltage = reading * 5.0;
  voltage /= 1024.0;
  if(voltage <= 0.5){  // 0v short - alarm
    *sensorState = 1;
  }else if(voltage > 2 && voltage < 2.5){  // 2.5v normal
    *sensorState = 0;
  }else if(voltage > 2.8 && voltage < 3.8){  //3.3v  sensor trip
    *sensorState = 1;
  }else{ // 5v wire cut or tamper trip
    *sensorState = 1;
  }
  // print out
  //Serial.print(voltage); Serial.print("v CH Pin"); Serial.print(*sensorPin);  Serial.print("CH State");Serial.println(*sensorState); 
}

Changing the order in which I signaled possition and enabled servo power seems to have resolved the problem. I'm just not sure why it mattered?

Wasn't programming. It turned out the servos were pulling the voltage down and the uC resets. Dropped a 100u cap on the servo power lines which fixed it.

Having said that I get the feeling I'm talking to myself here so beginning to wonder whether updating this thread is pointless :(

Well I for one am assuming that you still dont have access to your arduino. If you have, then I,ve missed it. If not, then until you try your idea's out for real then there is a lot of guesswork. And you'll not get a lot of help for that. Keep posting ;-)

Texy

Texy:
Well I for one am assuming that you still dont have access to your arduino. If you have, then I,ve missed it. If not, then until you try your idea’s out for real then there is a lot of guesswork. And you’ll not get a lot of help for that.
Keep posting :wink:

Texy

Oh I have prototyped an arduino & supporting components as per the schematic above on strip brd minus the regulator as i’m using regulated power and intend to do the solar with mains backup stuff. I will handle that on a seperate brd eventually. That’s how I found the arduino resetting and debouncing issues.

I invested in a new soldering iron and dusted off my oscilloscope (which i’m not quite sure how to use if i’m honest, last years impulse purchase! although found the servo volt drop with it :smiley: )
I have since prepared a yale lock for servo and it’s working now i reduced the lock spring tension. (turning the servo power off to preserve bat power caused them to drift otherwise)

Programming wise I’ve worked on removing my use of Delay() learning its referencing/dereferencing and arrays delayed me somewhat. Is this C or is it just C like?

Here is the most recent code. I will see if I can get some pics too

shedLocks.txt (8.76 KB)