Gruppe:
Morten Krogh Jensen (mortj18@student.sdu.dk)
Thomas Steenfeldt Laursen (tlaur18@student.sdu.dk)

Semester:
F21

Afleveringsdato:
29. april 2021

Introduktion

I dette projekt har vi valgt at gå med en alarmløsning med dørlås. Dette system består af en række sensor- og aktuator-komponenter:

  • Sensorer
    • RFID-scanner: Til scanning af tag/brik eller keycard så brugen kan låse døren op
    • KeyPad: Brugeren kan indtaste en kode som åbner og låser døren.
    • Motion Sensor: Til at registrere om nogen er i huset når døren er låst.
    • Termistor: Til simulering en brandalarm i hjemmet.
  • Aktuatorer
    • Display: Til at vise Systemets tilstand
    • Servomotor: Til at styre låsen på døren.
    • DC Motor: Til at sætte rummet i overtryk i tilfælde af brand.
    • Buzzer: Til at give lyd i tilfælde af enten tyverialarm eller brandalarm.

Samlet set er dette system bygget til at man på flere forskellige måde kan aktivere og deaktivere alarmsystemer i sit hus. Bevægelsessensoren fungerer som indbrudsalarm og termistoren som brandalarm.

Systemet er bygget op, så det altid befinder sig i én af fire forskellige tilstande. Systemet vil skifte tilstand baseret på hvad der sker omkring det. Den aktuelle tilstand for systemet er vist med forskellige billeder på displayet. Herunder er de fire tilstande beskrevet:

  • Åben: Illustreret med glad smiley. Døren er oplåst, og den eneste aktive alarm er brandalarmen.
  • Lukket: Illustreret med sur smiley. Døren er låst og bevægelsessensoren samt brandalarm er aktiv.
  • Alarm: Illustreret med et udråbstegn. Døren var i låst tilstand og der blev registreret bevægelse i rummet. Døren forbliver låst og indbrudsalarmen lyder. Brandalarm forbliver aktiv.
  • Brand: Illustreret med en flamme. Temperaturen i bygningen er for høj og brandalarmen lyder. Døren låses op for at sikre flugtveje.

Derudover er der to visninger som displayet har, men som ikke knytter sig til specifikke tilstande:

  • Korrekt kode: Såfremt at der er indtastet en korrekt kode, eller brugt en godkendt RFID-enhed. Illustreret med et flueben
  • Forkert kode: Såfremt der er indtastet forkert kode, eller brugt en ikke-godkendt RFID-enhed. Illustreret med et kryds

Videogennemgang af løsningen

Demonstration af tilstande

I nedenstående video vises det hvordan at systemet starter i tilstanden ”Åben” (glad smiley), og derefter skiftes til ”Lukket” (sur smiley). Herefter aktiveres ”alarm” tilstanden (Udråbstegn) ved at bevægelsessensoren i rummet registrerer bevægelse. Skiftet til ”alarm” tilstand sker kun såfremt at systemet i forvejen er i tilstanden ”Lukket”. Den sidste tilstand, ”Brand” aktiveres i videoen ved at placere termistoren i en kop med vand på næsten 100 grader. Det ses at selvom alarmen i forvejen er aktiv så skifter systemet stadig tilstand til brand, da denne tilstand altid prioriteres over alle de andre tilstande. Under denne tilstand ses det også at blæseren, som skaber overtryk, er aktiv, samt man kan høre at servomotoren åbner døren for at gøre det nemmere for indespærrede folk at komme ud af den brændende bygning. Sidst i videoen ses det hvordan tilstanden resettes når der bliver brugt en valid RFID-tag.

Demonstration af RFID og keypad

Denne video er en demonstration af de forskellige muligheder for at låse samt åbne døren i alarmsystemet. Læg venligst mærke til hvordan displayet viser om det er en valid RFID-enhed, og om koden er korrekt, samt at displayet viser om døren er låst eller åben.

I starten af videoen ses det hvordan døren er låst og der derefter med kode bliver låst op, for at blive låst igen med samme kode efterfølgende. Herefter vises samme princip bare med RFID i stedet for Keypad, og det vises også at det ikke er muligt at åbne låsen med en RFID-enhed som ikke er godkendt.

Opbygning af hardware

Diagrammet herunder viser den endelige sammensætning af hardwaren. I midten ses de to Arduinoer som kontrollerer hele systemet. Det var nødvendigt med to Arduinoer, da vi med alle vores komponenter hurtigt løb tør for porte. Derfor forbandt vi keypad-komponenten til Arduinoen til venstre. Det eneste formål denne Arduino har er derfor at registrere input fra keypad’en og derefter give besked til Arduinoen til højre. Arduinoen til højre foretager derfor det meste af arbejdet og kan betragtes som den primære styreenhed i systemet.
For at mindske forvirring, vil vi i dette afsnit præsentere kredsløbsdiagrammerne for hver enkelt komponent hver for sig.

Figur 1 – Breadboard-diagram

Keypad

Som sagt er keypad-komponenten forbundet til den venstre Arduino. Herunder ses et forsimplet kredsløbsdiagram med kun keypad’en og de to Arduinoer. Keypad’en består af 4×4 grid. Derfor skal den optage hele otte digitale porte på Arduinoen. Dog har vores system ikke brug for bogstav-knapperne (A, B, C, og D) i højre kolonne af keypad’en. Det er derfor muligt at undlade den ene forbindelse.

Efter den venstre Arduino registrerer input, skal den meddele det til den primære Arduino. Dette er opnået med en I2C-forbindels gennem Arduinoernes A4 og A5-porte. Her er det yderligere vigtigt at Arduinoerne deler den samme jordforbindelse.

Figur 2 – Kredsløbsdiagram over keypad-setup

RFID-scanner

Diagrammet under viser hvordan RFID-scanneren er forbundet til den primære Arduino. Denne komponent skal forsynes med 3,3V, og er derfor forbundet til Arduinoens 3,3V-port.

RFID-scanneren kommunikerer med Arduinoen igennem SPI-protokollen (Serial Peripheral Interface) (men den understøtter også I2C og UART). De pins på RFID-scanneren der relaterer sig til SPI er MISO, MOSI, SCK, og SS/SDA. MISO står for Master In Slave Out og anvendes når slaven (RFID-scanneren) skal sende data til masteren (Arduinoen). MOSI står for Master Out Slave In og bruges til kommunikation fra master til slave. SCK er den pin hvor RFID-scanneren modtager et clock-signal fra Arduinoen. Dette sikrer at deres kommunikation er synkroniseret. I SPI-mode fungerer SS/SDA-pin’en som Slave Select. Den bruges til at bestemme hvilken slave der kommunikeres med hvis man har at gøre med et system med flere slave-enheder. Den sidste anvendte pin på RFID-scanneren er RST, og bruges til at genstarte eller slukke komponenten.

Arduinoen har dedikerede porte til MISO, MOSI, og SCK. Derfor er det vigtigt at disse pins på RFID-scanneren er forbundet til netop disse porte. RST og SS/SDA kan dog forbindes til valgfri porte.

Derudover har RFID-scanneren en IRQ-pin. Dette er en interrupt-pin som kan anvende til at give Arduinoen besked når et RFID-tag bliver scannet. Denne funktionalitet har vi ikke gjort brug af i dette projekt. Senere i program-delen af beskrives det hvordan vores system håndterer scanningen af RFID-tags.

Figur 3 – Kredsløbsdiagram over RFID

Display

Herunder ses kredsløbsdiagrammet for display-komponenten. Denne er forbundet til Arduinoen gennem fem pins: VCC, GND, DIN, CLK, og CS. Ligesom RFID-scanneren kommunikerer displayet og Arduinoen ved brug af SPI-protokollen. DIN svarer til MOSI (Master Out Slave In), CLK svarer til SCK, og CS svarer til SS (Slave Select). Bemærk at komponenten ikke har en MISO-pin siden den aldrig skal sende data til Arduinoen.

Siden displayet anvender samme kommunikationsprotokol som RFID-scanneren kan man forbinde dens MOSI- og CLK-pins til de pågældende porte på Arduinoen samtidig med RFID-scanneren. Dog havde vi problemer med denne løsning, så vi gav den separate porte. En ulempe ved denne løsning er at den skulle være en smule langsommere end hvis man brugte de dedikerede porte. Det er dog ikke noget vi mærkede til overhovedet.

Figur 4 – Kredsløbsdiagram over display

Servomotor

Kendetegnende ved servomotoren er at denne kan blive placeret i forudbestemte positioner og var derfor ideel for os at bruge som låsemekanisme til dette system. Servomotoren har tre terminaler, nemlig vcc (+), ground og signal. Vcc er vores 5v input, ground(-) er vores jordforbindelse, og signal(pulse) er forbundet direkte til vores Arduino hvor den får signalet om hvilken position den skal stå i. I vores tilfælde er servomotoren forbundet til digital pin 7 som det ses i kredsløbsdiagrammet nedenfor. I koden er der importeret et bibliotek som giver os muligheden for at bruge en vinkel som input, i vores tilfælde er det sat til at åben-tilstanden er 180 grader, og lukket/låst er 80 grader.

Den typiske servo har bestemte puls værdier som afgør positionen for servoen, og det samme er gældende for vores servo. Vores servo hedder en SG90 og i databladet for denne kan det ses at position ”0”, som er midterste position kræver en puls på 1.5ms, position ”90”, som er positionen længst mod højre, kræver en puls på 2ms og position ”-90” som er positionen længst mod venstre, kræver en puls på ca 1ms.

Figur 5 – Kredsløbsdiagram over servomotor

Motion sensor

I dette projekt er der brugt en PIR motion sensor, som er en bevægelses sensor som indeholder infrarødsensorer. Denne sensor udnytter andre objekter i verden som udsender infrarød belysning, f.eks. menneskekroppen, til at registrere om der er bevægelse inden for den 110 graders vinkel den kan se i.

På sensoren sidder to potentiometre som gør det muligt for brugeren at justere følsomheden for sensorerne.  Forbindelsen til denne enhed er meget simpel, da den kun skal bruge en 5v forbundet til VDD, en jord forbundet til ground, og en signal forbundet mellem signal og Arduino. Som det er vist i diagrammet nedenfor har vi forbundet vores til den digitale pin 8 i vores system.  Signalet som bruges som input i Arduinoen er enten af værdien 1 eller 0, hvor 1 er værdien for hvis sensoren registrerer bevægelse.

Figur 6 – Kredsløbsdiagram over motion sensor

Buzzer

Som man kan se på kredsløbsdiagrammet herunder, er der lavet en meget simpel forbindelse af buzzeren. Den bliver forsynet med strøm fra en af Arduinoens digitale output porte. Mellem buzzeren og ground er der forbundet en modstand på 220Ω. Denne begrænser strømstyrken til buzzeren, så den ikke brænder af. I databladet til buzzeren er det angivet at den maksimalt kan holde til 30mA [http://www.farnell.com/datasheets/2171929.pdf]. Ved hjælp af Ohms lov kan den nødvendige modstand beregnes:

Den nærmeste modstand vi havde tilgængelig var 220Ω.

Figur 7 – Kredsløbsdiagram over buzzer

Røgventilationssystem (DC-motor)

DC-motoren er en meget strømslugende komponent og kan derfor ikke styres direkte fra Arduinoen. Derfor får den strøm direkte fra den eksterne strømkilde igennem en H-bro (se kredsløbsdiagrammet herunder). H-broens pins 8 og 16 forsyner den med strøm og er derfor forbundet til 5V. Pin 4, 5, 12, og 13 er alle til jord, men vi har nøjes med at forbinde kun én af dem. Pins 11 og 14 er output til motoren. Om strømmen løber den ene eller anden vej igennem afhænger af om man sætter 5V på pin 10 eller 15. I vores tilfælde har vi kun forbundet pin 15 til digitalt output på Arduinoen, fordi den kun har brug for at køre den ene vej. Så når motoren skal tændes, sættes Arduinoens digital pin 4 til høj. Man kan argumentere for at vi kunne have nøjes med en simpel transistor i stedet for en H-bro, men den voldte os problemer.

Figur 8 – Kredsløbsdiagram over DC-motor

Brandregistreringssystem (Termistor)

Til at registrere om der er brand i huset, har vi benyttet os af en termistor. Dette er en resistor hvis størrelse afhænger af dens temperatur. Ved stuetemperatur målte vi en modstand på 10kΩ, og nedsænket i kogende vand faldt modstanden til 0,8kΩ.
Termistoren er forbundet i et spændingsdelerkredsløb (se kredsløbsdiagram i bunden af afsnit), så Arduinoen ved hjælp af en analog port kan måle om termistoren bliver varmere. Den faste modstand i spændingsdelerkredsløbet er på 2kΩ. Spændingen i punktet mellem de to modstande kaldes V_out og ændrer sig efter følgende formel. R_1 og R_2 er størrelsen på henholdsvis den faste og den variable modstand.

Det er ikke ligegyldigt hvilken størrelse fast modstand der bruges i spændingsdeleren. Man ønsker at vælge en modstand som giver stor variation i V_out siden det giver en højere ”opløsning”, og man kan registrere finere ændringer i temperaturen. Følgende beregninger viser hvordan vi kom frem til at en fast modstand på 2kΩ ville give den største variation af V_out.
Vi definerer ΔV som værende ændringen i V_out når termistoren går fra stuetemperatur til 100 grader:

Vi ønsker at ΔV er så stor som muligt for at få den fineste opløsning på spændingsdeleren. Vi kan nu substituere formlen for V_out ind i udtrukket:

Fra vores målinger vides det at R_2(stue)=10kΩ og R_2(100)=0,8kΩ. Siden vi forsyner spændingsdeleren med 5V, er V_in=5V.

Man kan nu betragte ΔV som værende en funktion af R_1. Herunder ses grafen for denne funktion:

Figur 9 – Graf over ΔV som funktion af R_1

Maksimumspunktet ligger et sted mellem R_1=2kΩ og R_1=3kΩ. Den nærmeste modstand vi har i sættet (uden at forbinde flere sammen) er 2kΩ, så det var hvad vi gik med.

Figur 10 – Kredsløbsdiagram over termistor

Opbygning af program

I dette afsnit beskrives opbygningen af de Arduino-kode vores system kører på (kan ses i bunden af afsnittet). Her vil vi dokumentere hvad de forskellige funktioner i vores system gør og hvordan softwaredelen af projektet hænger sammen. Der bliver i starten givet en overordnet beskrivelse af systemets flow og mulige tilstande. Derefter er metoderne listet op i den rækkefølge som de står i softwaren med en beskrivelse af deres ansvarsområde.

Overordnet opførsel

Som det tidligere har været beskrevet, vil vores system være i én af fire tilstande på hvilket som helst tidspunkt (OPEN, CLOSED, ALARM, EMERGENCY). Systemet kan skifte imellem tilstandene på flere forskellige måder. Dette er illustreret gennem tilstandsdiagrammet herunder. Dette diagram viser blandt andet at systemet kan gå i EMERGENCY-tilstand hvis der registreres brand uanset hvilken anden tilstand systemet har. Man slipper kun ud af EMERGECY ved at indtaste en korrekt kode eller scanne et korrekt RFID. I tilstanden CLOSED er bevægelses-sensoren tændt og ALARM kan aktiveres. Systemet går ud af ALARM på samme måde som EMERGENCY.

Figur 11 – Tilstandsdiagram

For at få en bedre indblik i hvordan systemet prioriterer sit input, kan man kigge på flowdiagrammet herunder. Dette viser rækkefølgen af de beslutninger som den primære Arduino tager mens den kører (i loop-funktionen). De øverste beslutninger eksekveres først og har derfor højest prioritet. Den starter med at læse termistor-sensoren for at afgøre om der er brand. Hvis det er tilfældet, går den direkte til EMERGENCY-tilstand. Ellers kører den videre til næste input. Hvis der registreres bevægelse inde i huset mens systemet har tilstanden CLOSED, må der være en ubuden gæst. Derfor initialiseres ALARM.

Den tredje form for input der læses er RFID-sensoren. Hvis der registreres den korrekte RFID-brik, vil systemet låse op (OPEN) hvis den befinder sig i en af de andre tilstande. Det er også muligt at låse døren fra OPEN tilstand hvis man scanner en RFID-brik (bemærk at døren også vil låse hvis en uautoriseret person anvender scanneren).
Den sidste form for input er Keypad’en. Arduinoen sammenligner den indtastede kode med den gemte korrekte kode. I tilfældet at koden er korrekt, vil systemet gå i enten CLOSED eller OPEN tilstand afhængig af om den nuværende tilstand er OPEN eller ej.

Til helt sidst i rækkefølgen sættes buzzeren til at larme, hvis tilstanden enten er ALARM eller EMERGENCY. Ellers springes dette skridt over.

Figur 12 – Flowdiagram

Beskrivelser af funktioner hos Arduino 1

setup()

I denne metode starter vi med at aktivere Serial.begin() for at kunne bruge vores Serial monitor.
Derefter sættes Keypad, Servo, Display, RFID, Alarm og DC motor op, med de porte som er påkrævet for at de kan sende og modtage de signaler som er krævet. Til sidst i setup() giver vi systemet den state som hedder ”Closed” og dette er for at sikre at et eventuelt strømnedbrud ikke resetter systemet og lader døren stå åben.

loop()

Denne metode følger flowdiagrammet beskrevet lidt højere oppe i afsnittet. I starten, når den skal kontrollere om der er brand, læser den værdien fra termistor-spændingsdeleren ved hjælp af analogRead. Hvis denne værdi er forbi en bestemt grænse vi har bestemt (tempSensorLimit), vil EMERGENCY-tilstanden aktiveres.

Bevægelsessensoren aflæses med en digitalRead på den port dedikeret til sensoren. Den returner enten true eller false afhængig af om der er bevægelse eller ej.

Resultatet fra RFID-scanneren hentes ved at kalde metoden rfidCheck. Metoden returnerer en streng som repræsenterer den unikke kode indbygget i en RFID-brik. Hvis ingen brik scannes, vil metoden returnere en tom streng. Dette bruger loop-metoden til at bestemme om der skal skiftes tilstand. Yderligere, hvis der scannes en godkendt RFID-brik, vil metoden blinkAnimation kaldes og displayet vil blinke et flueben. Hvis der scannes en ukendt RFID-brik, vil displayet blinke et kryds.

Logikken der håndterer Keypad’ens input minder meget om RFID-scannerens. De tal man indtaster på keypad’en gemmes i variablen received_code. Hvis received­_code ender på det afsluttende tegn (nummertegn #), sammenlignes received_code med den gemte korrekte kode, og der besluttes om tilstanden skal skiftes (meget som hos RFID-scanneren).

Sidst i loop metoden kontrolleres den nuværende tilstand, og hvis den er ALARM eller EMERGENCY (Brand), vil den afspille den ene eller anden lyd igennem buzzeren.

recieveEvent()

Oppe i setup-metoden registreres denne metode til at blive kaldt hver gang Arduinoen modtager noget fra den anden Arduino som håndterer keypad’en. Inde i metoden lægges det modtagne symbol til variablen received_code.

rfidCheck()

Her kontrolleres hvorvidt der er scannes en brik på RFID-scanneren. Hvis ikke der er registreret et en RFID-brik eller at den ikke kan læse dens unikke kode, returneres en tom streng. Ellers returneres brikkens unikke kode.

initState(State state)

Denne metode sørger for at tage den state som bliver givet som parameter og bruger denne til at aktivere de rigtige animationer i displayet samt justere servomotoren, så den passer til om døren er åben eller lukket i den pågældende tilstand. F.eks Hvis tilstanden er ”EMERGENCY”, så vil døren åbne og displayet skiftet til en flamme.

blinkAnimation(byte* sprite)

Denne metode tager et array af bytes ind som argument. Dette array er den animation som skal vises i displayet. Denne metode står så for at få displayet til at skifte mellem blankt display og vores sprite således at vores display blinker. Et eksempel er hvis brugeren indtaster korrekt kode, så vil denne metode sørge for at blinke fire gange med et flueben.

Buzzer(long duration, int  freq)

Denne metode bruges til at aktivere buzzeren på den port som den er knyttet til, og dermed sende signal om hvilken lyd den skal lave på baggrund af den frekvens som der ønskes og hvor længe hver tone skal være.

Beskrivelser af funktioner hos Arduino 2

Arduino 2 er meget simpel da dens eneste opgave er at tage inputtet fra vores keypad og videresende dette til Arduino 1, som laver alle kontroller af hvorvidt koden er godkendt eller ej.

setup()

Ligesom i Arduino 1 er vores setup lave til at initialisere de første elementer som senere skal bruges i loopet. I denne setup er det eneste vi gør at starte vores Serial Monitor med Serial.begin(), så vi har mulighed for at debugge undervejs, og derefter instantieres vores Wire-bibliotek som bruges til at lave forbindelsen mellem Arduino 1 og Arduino 2.

loop()

I loop på Arduino 2 kontrolleres der hvorvidt der er indtastet noget på vores Keypad og såfremt at det er tilfældet, så vil vi åbne en transmission til vores Arduino 1 og sende den indtastede værdi, for derefter at lukke transmissionen igen. Måden hvorpå beskeden sendes via Wire-biblioteket er over en protokol som hedder I2C. Denne protokol er lavet til Seriel kommunikation, og kan sende bytes på tværs af de forbundne enheder.

Andet

Det er også værd at tage med at denne kode også indeholder et bibliotek til håndtering af keypad og at deklarere i starten af koden hvordan vores knapper på keypadden ser ud i rækker og kolonner, og derefter registrer disse rækker og kolonner i biblioteket for at den rigtige knap, også for tildelt den rigtige værdi.

Arduino 1 code

#include <Wire.h>
#include <Servo.h>
#include <SPI.h>
#include <MFRC522.h>
#include <MaxMatrix.h>
#include <avr/pgmspace.h>

// KEYPAD INIT
String correct_code = "49555157";  // 1 7 3 9
String last_int = "";
String received_code = "";
String code_end = "35";   // #

// SERVO INIT
Servo servo;
int servoPin = 7;
int angleOpen = 180;
int angleClosed = 80;

// DISPLAY INIT
const int data  = 3;     // DIN or MOSI
const int load  = 10;    // CS
const int clock = 2;     // SCK
MaxMatrix m(data, load, clock, 1);
byte angry[] = {8, 8, B00000000, B11100110, B00100110, B00100000, B00100000, B00100110, B11100110, B00000000};
byte happy[] = {8, 8, B00000000, B11100110, B10000110, B10000000, B10000000, B10000110, B11100110, B00000000};
byte alarm[] = {8, 8, B00000000, B00000000, B00000000, B11011111, B11011111, B00000000, B00000000, B00000000};
byte emerg[] = {8, 8, B00000000, B00000000, B00111000, B01111110, B01111111, B00111100, B00000000, B00000000};
byte check[] = {8, 8, B00100000, B01000000, B10000000, B01000000, B00100000, B00010000, B00001000, B00000100};
byte cross[] = {8, 8, B10000001, B01000010, B00100100, B00011000, B00011000, B00100100, B01000010, B10000001};
byte* currentAnimation;

// RFID INIT
#define SS_PIN 6
#define RST_PIN 5
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance.
String correctRFID = "3C 39 0F 18";

// ALARM INIT
#define buzzerPin 9
#define pirPin 8

// THERMISTOR INIT
#define thermistor A0
int tempSensorLimit = 300;

// DC MOTOR INIT
#define dcMotorPin 4

enum State {
  EMERGENCY,
  ALARM,
  OPEN,
  CLOSED
};
State currentState = CLOSED;


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

  // KEYPAD SETUP
  Wire.begin(9);    // Start the I2C Bus as Slave on address 9
  Wire.onReceive(receiveEvent);   // Attach a function to trigger when something is received.

  // SERVO SETUP
  servo.attach(servoPin);
  servo.write(angleClosed);

  // DISPLAY SETUP
  m.init();
  m.setIntensity(2);  // led matrix intensity: 0-15

  //RFID SETUP
  SPI.begin();      // Initiate  SPI bus
  mfrc522.PCD_Init();   // Initiate MFRC522

  // ALARM SETUP
  pinMode(buzzerPin, OUTPUT);
  pinMode(pirPin, INPUT);

  // DC MOTOR SETUP
  pinMode(dcMotorPin, OUTPUT);

  initState(CLOSED);
}


void loop() {
  // ---------- FIRE CHECK ----------
  int tempSensorValue = analogRead(thermistor);
  if (tempSensorValue < tempSensorLimit) {
    if (currentState == ALARM || currentState == CLOSED || currentState == OPEN) {
      initState(EMERGENCY);
      return;
    }
  }

  // ---------- INTRUDER CHECK ----------
  int motion_val = digitalRead(pirPin);
  if (motion_val) {
    if (currentState == CLOSED) {
      initState(ALARM);
      return;
    }
  }

  // ---------- RFID CHECK ----------
  String rfidResult = rfidCheck();
  if (rfidResult != "") {
    if (rfidResult == correctRFID) {
      if (currentState == EMERGENCY || currentState == ALARM || currentState == CLOSED) {
        blinkAnimation(check);
        initState(OPEN);
        return;
      } else if (currentState == OPEN) {
        blinkAnimation(check);
        initState(CLOSED);
        return;
      }
    } else {
      blinkAnimation(cross);
      m.writeSprite(0, 0, currentAnimation);
      if (currentState == OPEN) {
        initState(CLOSED);
        return;
      }
    }
  }

  // ---------- KEYPAD CHECK ----------
  if (last_int == code_end) {
    last_int = "";
    if (received_code == correct_code + code_end) {
      received_code = "";
      blinkAnimation(check);
      if (currentState == EMERGENCY || currentState == ALARM || currentState == CLOSED) {
        initState(OPEN);
        return;
      } else if (currentState == OPEN) {
        initState(CLOSED);
        return;
      }
    } else {
      received_code = "";
      blinkAnimation(cross);
      m.writeSprite(0, 0, currentAnimation);
    }
  }

  // ---------- BUZZ BUZZING BUZZER ----------
  if (currentState == EMERGENCY) {
    buzzer(500, 2000);
  } else if (currentState == ALARM) {
    buzzer(500, 1600);
  }

}


void receiveEvent(int bytes) {
  last_int = (String)Wire.read();    // read one character from the I2C
  Serial.println(last_int);
  received_code += last_int;
}


String rfidCheck() {
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return "";
  }
  if (!mfrc522.PICC_ReadCardSerial()) {
    return "";
  }

  String content = "";
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  content.toUpperCase();

  return content.substring(1);
}

void initState(State state) {
  int motorAngle;
  currentState = state;
  if (state == EMERGENCY) {
    Serial.println("EMERGENCY");
    digitalWrite(dcMotorPin, HIGH);
    currentAnimation = emerg;
    motorAngle = angleOpen;
  } else if (currentState == ALARM) {
    Serial.println("ALARM");
    digitalWrite(dcMotorPin, LOW);
    currentAnimation = alarm;
    motorAngle = angleClosed;
  } else if (currentState == CLOSED) {
    Serial.println("CLOSED");
    digitalWrite(dcMotorPin, LOW);
    currentAnimation = angry;
    motorAngle = angleClosed;
  } else if (currentState == OPEN) {
    Serial.println("OPEN");
    digitalWrite(dcMotorPin, LOW);
    currentAnimation = happy;
    motorAngle = angleOpen;
  }
  m.clear();
  m.writeSprite(0, 0, currentAnimation);
  servo.write(motorAngle);
}

void blinkAnimation(byte* sprite) {
  for (int i = 0; i < 4; i++) {
    m.writeSprite(0, 0, sprite);
    delay(250);
    m.clear();
    delay(250);
  }
}

void buzzer(long duration, int freq) {
  tone(buzzerPin, freq);
  delay(duration);
  noTone(buzzerPin);
}

Arduino 2 code

#include <Wire.h>
#include <Keypad.h>

const byte ROWS = 4; // number of rows
const byte COLS = 4; // number of columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6}; // row pinouts of the keypad R1 = D8, R2 = D7, R3 = D6, R4 = D5
byte colPins[COLS] = {5, 4, 3, 2};    // column pinouts of the keypad C1 = D4, C2 = D3, C3 = D2
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

void setup() {
  Serial.begin(9600);
  // Start the I2C Bus as Master
  Wire.begin();
}


void loop() {
  char key = keypad.getKey();

  if (key != NO_KEY) {
    Serial.println(key);
    Wire.beginTransmission(9); // transmit to device #9
    Wire.write(key);              // sends x
    Wire.endTransmission();    // stop transmitting
  }
}

Opbygning af den samlede fysiske prototype

Prototypen er bygget op af en papkasse med skillerum, som således skal simulere henholdsvis indersiden og ydersiden af en yderdør.

Figur 13 – Opbyggelsen fra ydersiden

Som det ses på figur 13, så vil dem som kommer på ydersiden blive mødt med en Keypad, RFID-scanner, samt et display, og dermed har de 2 forskellige muligheder for at få adgang til alarmsystemet og dørens lås.

Figur 14 – Opbyggelsen fra indersiden

På indersiden af huset er der en længere række af komponenter. Indersiden af bygningen har tre aktuatorer, nemlig en DC-motor, En servomotor, og en buzzer, hvor DC-motorens ansvar er at lave overtryk i lokalet, såfremt der er en brand, servomotorens ansvar er at fungere som lås til døren, og buzzerens ansvar er at signalere auditivt til brugen til tilfælde af Alarm eller brand.  Som sensorer inden i bygningen har vi her en bevægelsessensor som sender signal tilbage til den ene Arduino om hvis der er bevægelse i bygningen. En anden sensor er den termistor som registrerer temperaturen i rummet og som vi dermed kan læse på i softwaren, og vurdere hvornår der er brand. Både sensorer og aktuatorer i dette rum er knyttet til Arduino 1 som i softwaren håndterer deres input og output.

På billede 14 ses det også at der er 2 Arduinoer hvoraf Arduino 1 er hjernen bag det hele, og Arduino 2 kun håndtere input fra keypad og videresender den til Arduino 1, som derefter kontrollere hvor vidt at koden er godkendt.

I dette projekt er det valgt at tilknytte en strømforsyning til fumlebrættet hvor alle komponenterne henter deres strøm fra.

Konklusion

I dette projekt er det lykkedes at bygge en prototype til et alarmsystem til hjemmet.
Alarmsystemet er bygget op af 4 aktuatorer, 4 sensorer, en H-bro, 2 Arduinoer samt flere små komponenter, som tilsammen udgør et komplet alarmsystem som kan alarmere i tilfælde af brand eller indbrud. Der er igennem projektet lavet nøje overvejelser omkring hvilke komponenter systemet skulle indeholde, hvordan disse skulle prioriteres i softwaren, samt hvordan de skulle forbindes til de to Arduinoer. Specielt det sidste viste sig som en interessant opgave da mængden af porte var begrænset.

Ved siden af hardwareløsningen er der lavet et softwaresystem, som bruger input fra hardwaren til logisk at udregne og bestemme hvilke tilstande systemet skal være i på hvilke tidspunkter, samt oplyse brugeren med både visuelle og auditive effekter.

Perspektivering

Til fremtidig forbedring af produktet ville det være optimalt at lave hele systemet væsentligt mere kompakt så de fleste komponenter ville passe ind i en dørlås. Derudover ville man skulle have et backupsystem, så at man stadig har mulighed for at åbne døren, selv hvis strømmen gik.
Termistoren skulle fjernes og systemet skulle sættes til et rigtigt professionelt brandalarmeringssystem, som mere intelligent ville kunne definere hvorvidt der er brand, da den nuværende løsning gør det nemt at udnytte varme til at få adgang til bygningen.

I en fremtidig version ville det også være muligt at udvide alarmsystemet med sensorer ved vinduer og andre potentielle indgange, for at gøre det sværere for indbrudstyve at komme uden om alarmsystemet.

Leave a Reply