Sunday, January 31, 2010

The Simple Alarm

A simple alarm system is pretty easy.  Most alarm systems are just checking to see if the current going through a wire stops or changes in some way to say that the sensor has been tripped. 

You might ask why we would want the current to continually be going through the sensor instead of just kicking it high when the sensor is tripped.  That would certainly use less power and might be less work for the circuits.  This might be a good thing if your alarm is powered by a battery.  The problem with this is that to disable a sensor all you would need to do is clip a wire running to the sensor and it would never be tripped.  However if you are checking for the current to go low from your sensor then clipping a wire would trigger it off. 

Ok, if you knew that the system was looking for the low current, then instead of clipping the wire you could just bridge the wires.  Then if the sensor is tripped the current would still be going through the bridge and the monitor wouldn't know it was tripped.  There is a way to deal with this problem also.  Instead of just looking for a wire to go low we could look for the current going through the wire to change.

One way to do this is to have three wires and a couple of different sized resistors at the sensor. Two of the wires are the positive and ground, the last wire would be attached between the two resistors where you would measure. When the sensor is tripped the positive or ground is disconnected from the circuit and the value at the third wire changes to either very high or very low.  Your monitor would measure a difference and decide that the sensor has tripped.  If some one tries to cut or bridge the wires then the resistance in the circuit will still change and the monitor would signal a tripped sensor.  Of course there are still ways you could defeat a sensor like this but it would take time measuring current in all of the wires and building something that would measure exactly the same.  You would also have to be careful to not do anything that would cause a change in the wires while you were measuing or the monitor would think that it was tripped.  Part of what you are measuring is the difference in the resistors.  The resistors in the sensor wouldn't have to be different but for the different sensors you would probably want to switch them up just to make things more difficult to defeat.    

There is an issues that you need to deal with in a circuit like this.  It is that resistance in a circuit can change over time.  If a connection becomes oxidized or the sensor wears then the value that is measured at the third wire could change.  If you have hard coded the value you are going to start seeing false alarms.  In our system the values will be measured at start up or when the alarm is set.  Since you have different resistance in each of the different sensors you also have to deal with storing more than one value.

Below is the circuit that I have built to test my basic alarm system along with a parts list.  Instead of using 2 resistors I used a potentiometer.  You could probably also use one of these in your actual sensor too.  The pot is basically the circuit from above only the resistance can be varied very easily which was nice for testing the initialization stuff.  There are two of these sensors with the pots set at different resistance.  I haven't actually tested the sensors in my current alarm system to see if they work this way but I am pretty sure that the motion sensor does and if not I will deal with it when I get there.  The button is to turn the alarm off on the hardware side.  And of course every alarm has to be loud and obnoxious so I added a peizo buzzer and a routine in the sketch that will make noise.  I will replace this with a system to kick off the siren that is now a part of my current alarm. 


Fritzing Bill of Materials:

J1 Piezo Speaker
R1 10kΩ Resistor
R3 Basic Potentiometer
R4 Basic Potentiometer
S1 Pushbutton

This is what the system might look like if you want to build it with your ardurino and a small bread board.


Then what it looks like on the proto shield on top of my Arduino.
 

By the way, the program that I used to generate the schematic and the component view is an open-source app called fritzing and its available at http://www.fritzing.org/.  It is very cool and very useful.

By the way also, the proto shield came with my Arduino projects pack but the url on the board that tells how to assemble it is http://www.ladyada.net/make/pshield.  It came unassembled and I had to solder it together.  I love soldering ( is that weird or what ).  The shield is also very cool and very useful.

The biggest thing this time is the sketch code. 

/*
 * arduino alarm controler code
 *
 * author: Stacy Brothers
 * http://stacysarduino.blogspot.com
 */

const int MAX_CMD_LEN = 128;
char cmd[MAX_CMD_LEN];

int buttonState = 0;
int alarmPin = 9;
int sensorVal = 0;

const int ALARM_OFF = 0;
const int ALARM_ON = 1;
int alarmState = ALARM_ON;
boolean alarmTriggered = false;
int allowedError = 5;

int zonePins[] = {0,2};
int zoneVal[] = {0,0};
boolean zoneTripped[] = {false,false};
const int ZONE_OFF = 0;
const int ZONE_ON = 1;
int zoneStatus[] = {ZONE_ON, ZONE_ON};
int zoneCount = 2;

boolean connected = false;

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

  // triggers on doors etc.
  for ( int i = 0; i < zoneCount; i++ ) { 
    pinMode(zonePins[i], INPUT);
  }

  pinMode(13, OUTPUT);  // alarm flasher
  pinMode(alarmPin, OUTPUT); // alarm sounder
  
  pinMode(7, INPUT);  // reset alarm
  
  setupSensors();

}

long pingWait = 0; // this is the counter to send the ping
const long pingSend = 500000L; // when to send the ping

void loop() {
  if ( Serial.available() != 0 ) { 
      readln(cmd);
  }

  if (strcmp(cmd,"") == 0 && pingWait == pingSend) { 
    Serial.println("ping");
    pingWait = 0;
  } else if (strcmp(cmd, "pong") == 0) { 
    connected = true;
    pingWait = 0;
  } else if (strcmp(cmd, "ping") == 0) {
    Serial.println("pong");
    connected = true;
    pingWait = 0;
  } else if (strcmp(cmd, "reset alarm") == 0) { 
    Serial.println("alarm reset");
    alarmTriggered = false;
    digitalWrite( 13, LOW );
  } else if (strcmp(cmd, "alarm off") == 0) { 
    alarmState = ALARM_OFF;
    Serial.println("alarm turned off");
  } else if (strcmp(cmd, "alarm on") == 0) { 
    alarmState = ALARM_ON;
    Serial.println("alarm turned on");
  }
  cmd[0]= NULL;  // what ever the command was reset it
  pingWait++;
  
  // loop through the zones and make sure they are not triggered
  for ( int i = 0; i < zoneCount; i++ ) {
    if ( !zoneTripped[i] && zoneStatus[i] == ZONE_ON && alarmState == ALARM_ON ) { 
      sensorVal = analogRead(zonePins[i]);
      if ( sensorVal > zoneVal[i] + allowedError || sensorVal < zoneVal[i] - allowedError ) { 
        Serial.print("tripped zone: ");
        Serial.println(i);
        alarmTriggered = true;
        zoneTripped[i] = true;
      }
    }
  }
  
  // reset the alarm
  buttonState = digitalRead(7);
  if ( buttonState == LOW && alarmTriggered == true ) { 
    //if ( connected ) Serial.println("alarm reset");
    Serial.println("alarm reset");
    alarmTriggered = false;
    digitalWrite( 13, LOW );
    for ( int i = 0; i < zoneCount; i++ ) zoneTripped[i] = false;
  }
  
  if ( alarmTriggered && alarmState == ALARM_ON ) { 
    soundAlarm();
  }
  
}

// setup the base values for the sensors
void setupSensors() { 
  for ( int i = 0; i < zoneCount; i++ ) {
    int test1 = analogRead(zonePins[i]);
    delay(500);
    int test2 = analogRead(zonePins[i]);
    delay(500);
    int test3 = analogRead(zonePins[i]);
    delay(500);
    zoneVal[i] = ( test1 + test2 + test3 ) / 3; 
  }
}

int tone = 1915;  // c note...
boolean flasher = false;

void soundAlarm() {
  for (long i = 0; i < 200000L; i += tone * 2) {
    digitalWrite(alarmPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(alarmPin, LOW);
    delayMicroseconds(tone);
  }
  
  if ( tone == 1915 ) tone = 1700;   // d note...
  else tone = 1915;
  
  if ( flasher ) { 
    digitalWrite( 13, LOW );
    flasher = false;
  } else { 
    digitalWrite( 13, HIGH );
    flasher = true;
  } 
  // pause between notes
  delay(150); 
}

void readln( char buffer[] ) {
  char c;  
  int i = 0;  
  int quiet = 0;
  while( true ) {
    if ( Serial.available() ) {
      quiet = 0;
      c = Serial.read();
      if ( c == 13 ) {  // carriage return
        Serial.read();  // line feed
        break;
      }
      buffer[i++] = c;    
      if ( i == (MAX_CMD_LEN-1) ) break;
    } else {
      if ( quiet > 10000 ) break;
      quiet ++;
    }
    delay(10); // short delay         
  } 
  buffer[i] = NULL;     
}

So this might look like a lot but really it isn't.  The setup method contains a call to the function setupSensors.  This is what I was talking about before.  This function takes a couple of readings on the pots and averages them.  It loops through all of the pots and stores a check value for each.  I had to do the average thing because I found that sometimes the pots are at a point where they will bounce by one.  So far it has only been by one but when I read the sensors in the loop I give or take 5.  I can change this later if I find that I don't need 5 or if I need more. So far it looks like I need only one or two.

There is the bit for making the noise on the piezo.  It will all go when I figure out how to hook up the real siren.  The problem with the real siren is that the thing is built to use 12V and 500 mA.  That is a way more than the arduino will push so I am going to use the rechargeable 12V on my current alarm to drive it and a big ole transistor to switch it on with input from the arduino. It might also be nice if I could figure out how to step the 12V down to use it for the arduino power. 

There is a bit of code in there that I will be using to turn zones on and off and to only deal with sensors that are in specific states so that I don't have to deal with events multiple times.

I had to play with the communication between the arduino and the java application quite a bit.  I want the arduino to be able to continue even if the java app isn't there so I have a flag to tell the arduino to deal with is if it is not.  Both applications need to deal with timeouts in their readln routines.  I have made these timeouts pretty short because we don't want to miss a sensor being tripped and if the program misses a command it will be back again soon enough to check again anyway.  I made it so that the sketch would notify the java app that there was an sensor tripped when the alarm was on.  The java app can reset the alarm and turn off the alarm all together.  That is it. 

Here is the code for the java app.

package com.stacybro.arduino;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

/**
 * @author Stacy Brothers
 * http://stacysarduino.blogspot.com
 *
 */
public class ArduinoAlarmCtrl {
 
 static String CRLN = "" + (char)13 + (char)10;

 public static void main(String[] args) {
  InputStream input;
     OutputStream output;  
  CommPortIdentifier portId = null;
  SerialPort port = null;
  
  try {
   portId = CommPortIdentifier.getPortIdentifier("COM3");
   port = (SerialPort)portId.open("arduino", 4000);
         input = port.getInputStream();
         output = port.getOutputStream();
         port.setSerialPortParams(9600,
                 SerialPort.DATABITS_8,
                 SerialPort.STOPBITS_1,
                 SerialPort.PARITY_NONE);
         while ( true ) { 
          String inStr = readln(input);
          String outStr;
          System.out.println("From Arduino:|" + inStr + "|");
          if ( inStr.equals("ping" ) ) { 
           outStr = "pong" + CRLN;
           System.out.println("Sending:"+ outStr); output.write(outStr.getBytes());
          } else if ( inStr.startsWith("zone triggered:" ) ) {
           String zone = inStr.replace("zone triggered:", "");
           System.out.println("Alarm Triggered!  zone: " + zone + " (" + inStr + ")");
           // wait a while and then reset the alarm
           inStr = readln(input);System.out.println("From Arduino:|" + inStr + "|");
           if ( inStr.equals("alarm reset")) continue;
           outStr = "reset alarm" + CRLN;
           System.out.println("Sending:"+ outStr); output.write(outStr.getBytes());
          } 
         }
         
  } catch (Exception e) {
   e.printStackTrace();
  } finally { 
   port.close();
  }
 }
 
 static String readln(InputStream input) throws IOException { 
        String inStr = "";
        int quiet = 0;
        while ( true ) {
         if (input.available() > 0) {
          int inChar = input.read();
          if ( inChar == 13 ) { // carriage return 
           input.read();  // line feed
           break;
          }
          quiet = 0;
          inStr += (char)inChar;
         } else {
          if ( quiet > 5000 ) break;
          quiet ++;
            }
         try {
    Thread.sleep(10);
   } catch (InterruptedException e) {
    System.out.println("Interrupted");
   }
        }
  return inStr;
 }
}

The only really important thing is the readln routine in the java app.

The next things that I need to deal with is the real user interface on both the hardware side and the software side.

Saturday, January 9, 2010

Communication

Please note that I am making some assumptions. 

The first is that you have already made yourself familiar with your arduino by going through the getting started tutorials at http://arduino.cc/en/Guide/HomePage.  This would mean that you have already installed the arduino tools and have tested the USB communication between the arduino and your PC using the arduino tool.  BTW I am using version 17.

The next is that you are familiar with java.  If not then buy a book.  Or you could pay a university a crazy amount of money to teach you and then buy a book to teach yourself.  That is pretty much what I did.  Whatever.  I don't feel resentful about that at all.  Anyway...

I am using eclipse for the java side of the development and the arduino tool for the sketch code. Since you are familiar with java and you understand the arduino tool then that shouldn't be a problem.  I am also running everything under windows.

First thing that you need to do to start is install a communication library for your Java environment.  You can use the Sun libraries or you can use the rxtx communication libraries.  The Sun stuff is better documented and probably better supported but the arduino tool uses the rxtx and it seems to work well.  The arduino tool also comes with all of the required rxtx libraries and it turns out it is pretty easy to install so I went with the rxtx.  To use them I just copied the rxtxSerial.dll from the arduino directory into the bin directory of the jre that I am using (ex: c:/program files/java/jre6/bin).  I also included the RXTXcomm.jar file from the ardurino tools lib directory in my class path.  If everything is set up right, the first time that you run your java application you will see a message like the following:

     Stable Library
     =========================================
     Native lib Version = RXTX-2.1-7
     Java lib Version = RXTX-2.1-7

If you don't see that then you will probably see an error about the serial libraries not being found which may mean that you do not have your dll in the correct place.  Make sure that you are using the jre that you think you are ( in eclipse you would look under Window->Preferences->Java->Installed JREs and see which one is checked ).  If not then look at the rxtx link above or try using the sun api instead. 

So here is some code.  First is the sketch code the arduino will run.  Basically communicating via serial is built into the arduino.  It is how you program the thing.  This program starts the conversation.  It just sits there saying hello until somethng responds.  Then it responds based on what it receives.

const int MAX_CMD_LEN = 128;

char cmd[MAX_CMD_LEN];
int quiet = 0;

void setup() {
     Serial.begin(9600);
     // start conversation
     while (Serial.available() <= 0) {
          Serial.println("hello");
          delay(300);
     }
}

void loop() {
     readln(cmd);
     if (strcmp(cmd,"") == 0) {
          Serial.println("ping");
          delay(1000);
          readln(cmd);
          if ( strcmp(cmd,"pong") != 0 ) {
               // there was a problem so do something like flash a red led
               Serial.println("error!");
          }
     } else if (strcmp(cmd, "hello") == 0) {
          Serial.println("How are you?");
     } else if (strcmp(cmd, "How are you?") == 0) {
          Serial.println("I am working...");
          delay(3000);
          Serial.println("good bye.");
     } else if (strcmp(cmd, "ping") == 0) {
          Serial.println("pong");
     }
}

void readln( char buffer[] ) {
     char c;
     int i = 0;
     while( true ) {
          if ( Serial.available() ) {
               quiet = 0;
               c = Serial.read();
               if ( c == 13 ) { // carriage return
                    Serial.read(); // line feed
                    break;
               }
               buffer[i++] = c;
               if ( i == (MAX_CMD_LEN-1) ) break;
          } else {
               if ( quiet > 10000 ) break;
               quiet ++;
          }
          delay(10);
     }
     buffer[i] = NULL;
}

Some things to note about the sketch code. I have set the max length of a string to be received at 128 characters. Should be enough but if it isn't then we will change it. All communication is ended by sending a CR/LF. The arduino does this automatically with println().  In the Java code below we do it by appending the (char)13 + (char)10 on to all of the strings that are going to be sent.  The readln has a timeout of sorts.  If things are quiet for a while it will ping the java app.  It should get a pong back and if it doesn't then something might have gone wrong.  The quiet on the line could be a normal situation. 


The Java class does almost exactly the same thing as the arduino sketch.  Super simple.  Listen on the port specified and respond.  Note the com port that my machine decided to use was COM3.  Yours might be different.  Look in your control panel device manager under USB controllers.
 
package com.stacybro.arduino;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier;

public class Communicate {
     static String CRLN = "" + (char)13 + (char)10;

     public static void main(String[] args) {
          InputStream input;
          OutputStream output;
          CommPortIdentifier portId = null;
          SerialPort port = null;

          try {
               portId = CommPortIdentifier.getPortIdentifier("COM3");
               port = (SerialPort)portId.open("testing", 4000);
               input = port.getInputStream();
               output = port.getOutputStream();
               port.setSerialPortParams(9600,
                         SerialPort.DATABITS_8,
                         SerialPort.STOPBITS_1,
                         SerialPort.PARITY_NONE);
               while ( true ) {
                    String inStr = readln(input);
                    String outStr;
                    System.out.println("From Arduino:" + inStr );
                    if ( inStr.equals("hello")) {
                         outStr = "hello" + CRLN;
                         System.out.println("Sending:"+ outStr);
                         output.write(outStr.getBytes());
                    } else if ( inStr.equals("How are you?" ) ) {
                         outStr = "I am functional." + CRLN;
                         System.out.println("Sending:"+ outStr);
                         output.write(outStr.getBytes());
                         Thread.sleep(5000);
                         outStr = "How are you?" + CRLN;
                         System.out.println("Sending:"+ outStr);
                         output.write(outStr.getBytes());
                    } else if ( inStr.equals("ping" ) ) {
                         outStr = "pong" + CRLN;
                         System.out.println("Sending:"+ outStr);
                         output.write(outStr.getBytes());
                    } else {
                         outStr = "I am testing" + CRLN;
                         System.out.println("Sending:"+ outStr);
                         output.write(outStr.getBytes());
                    }
               }
          } catch (Exception e) {
               e.printStackTrace();
          } finally {
               port.close();
          }
     }

     static String readln(InputStream input) throws IOException {
          String inStr = "";
          while ( true ) {
               // should probably do something here to do a timeout
               if (input.available() > 0) {
                    int inChar = input.read();
                    if ( inChar == 13 ) { // carriage return
                         input.read(); // line feed
                         break;
                    }
                    inStr += (char)inChar;
               }
          }
          return inStr;
     }
}

Thanks to Silveira at http://silveiraneto.net/2009/03/01/arduino-and-java/.  It is what got me started.

Friday, January 8, 2010

The Project

One of my favorite magazines is a DIY magazine called Make.  Pretty much every issue since the magazine started has had a project including an Arduino.

The Arduino is "an open-source physical computing platform based on a simple microcontroller board".  The Arduino has been used as a component in about a bazillion projects.  Everything from robots to "scent dispensers", musical instruments to moisture sensors.  I read (not sure where) that a recent NASA satellite launch had 3 Arduino based sensor projects.

I wanted one.  But I had to have some justification to spend the cash.  It isn't that they are expensive, you can get one for as little as 35 bucks, 20 if you want to practice your soldering skills.  I am just one of those types of people that can't buy themselves a "toy" without feeling guilty.  I had to have some really useful project in order to feel good about spending the time and money.

The Project: Home Security System.  OK, we already have a security system, but it sucks.  I can't control it from my phone or the web and the keypad is ugly.  Was that enough justification?  Too late... already bought the arduino!

The Ardurino Projects Pack.  I decided to go all out, because I might need the extra components (yuk yuk), and went with the Arduino Projects Pack from the Maker Shed.  99 bucks.  Only 2 digits and not too much guilt, after all my wife can spend that on hair cuts for her and our daughter.  It seems to have lots of fun stuff in it like thermistors, tilt sensors, a couple dinky motors, photoresistors, and an NPN Transistor.  Well, the thermistors added an item to my feature list but I will have to think a bit in order to figure out how to use the rest.  Is a RC robot a necessary part of a security system?  Most important part is the Arduino Duemilanove.  Only 14 digital inputs ( 6 analog ) so I am going to have to use one of the protoboards for a couple of multiplexers to give me more inputs.  The ATmega328 microprocesser, 32K of flash memory to hold controller code.  Hopefully that will be enough to give me good control.  This model has a USB link built on which is probably the most important part.  Since I am a software developer "in my real life", there is also going to be a lot I want to do on the server that it is connected to. 

Planned Features:
  • Enough sensors for all of the windows and doors.
  • Motion sensor.
  • Connect to our Fire / CO2 alarm system.
  • Key pad & lcd, maybe touch screen interface. 
  • House temperature sensor ( got a thermistor, gotta use it! )
  • Web based interface.
  • Commands and notifications via text message/email.
I think that my first task will be to figure out how to do communication between Arduino and Java app.


A quick google for "arduino security system" tells me that I am not alone in thinking that this is a good project.  There should be lots of resources anyway.

Some links:
http://arduino.cc/en
http://blog.makezine.com/archive/arduino
http://hacknmod.com/hack/top-40-arduino-projects-of-the-web
http://www.arduinoprojects.com/
http://www.practicalarduino.com/projects