Blog 14 – Finishing up the Arduino

Version 2.1

As mentioned in Blog 6 – Pause to plan in version 2.1 I wanted to move the timestamp aspect from the website to the Arduino. In version 2.0 the timestamp was the time that the web server submitted the record to the database. This meant that it wasn’t the exact time that student swiped their student ID card.
I went and found a time library and downloaded it. This library is a software library, this means that it uses the onboard processor to keep time. It also had the function to contact the public time libraries to keep it up to date. I started to implement the library into my original arduino code.  I was reading a couple forum about how to implement the time library and came across some problems with the library.

The first being that the as the time library is software based it uses the oscillator/crystal and the tick rate of the processor to keep time. Theses are both not perfectly accurate, as outlined in this forum post. The oscillator/crystal used to help keep time is affected by environmental conditions around the Arduino. The oscillator/crystal vibration rate of 16Mhz changes slightly when the temperature changes. This in turn affects the time. Also the software works based on the processor tick rate of 1ms but is actually 1.024ms. Therefore this leads to the time slowly becoming inaccurate. Also if the command Delay is used in a program, like it is in mine, It can also greatly affect the time. This is due the delay command actually stops the processor for the time specified. It uses the oscillator/crystal as the timer. When the processor stops, so does the timekeeping function.  There are ways to combat this issue, like updating the time from the internet time servers periodically, but this leads into my second problem.

The international time servers that you can use to get the time are publicly run and keeping them online costs money. Having the Arduino unit call the time server once a week to get the time would be fine. But this would lead to huge inaccuracies in the time that the students ID card was scanned. Therefore the unit would need to call the time server once or twice a day. Each time the unit calls the time server it cost them money and adds extra load to the server, so time servers should only be call occasionally. If one IP address is calling the time server once or twice a day then it may be added to the blocked list, but it is unlikely. However if there where one or two of the Arduino units in each classroom at NMIT, let’s say a total of 100 units, calling the time server 200 times a day, then the IP address will certainly be blocked. The above problem is discussed in this forum post.

Considering the above problems mentioned I have decided to skip version 2.1. The problems it causes are to great to give me a reason to change from version 2.0. I have decided to make sure time is kept accurate in the records in the database I will use to error reporting feature to make sure that the timestamp is inserted into the database at the time that the card is swiped. If there is a connection failure it will be shown by the arduino unit to the student, using features implemented in version 2.2. This time is takes to perform the insert is at max 2 seconds. So the difference from when the card was swiped to the time in the database is marginal enough that it doesn’t matter for this application. This means sticking with using the web server to provide the time. This works as the time is taken from the web server’s operating system, which has a very accurate time keeping system.

Version 2.2

I needed to add some sort of visual interaction with the user. I decided to use an RGB LED to indicate the Arduino system is working. I also decided to add a buzzer for when the students UID was successfully added to the database records. I decided the buzzer needed as most students would just touch their ID cards to the unit and walk off without checking that it sent. The buzz would help confirm if it is sent. If the buzzer doesn’t sound then it has failed.
Below are the different stages and actions;

2016-10-28 (1).png

This is the new code;

/*
 Ethernet shield attached to pins 10, 11, 12, 13
*/

#include <SPI.h>
#include <Ethernet.h>
#include <MFRC522.h>

#define RST_PIN 5 // Configurable
#define SS_PIN 53 // Configurable

// pins for the LEDs:
const int redPin = 11;
const int greenPin = 12;
const int bluePin = 13;

const int buzzer = 9; //buzzer to arduino pin 9

MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.

int sendTime = 60000;
int bstate = 0;
String read_rfid;
String rfid_uid;
int Unit_No = 1;

// common-cathode LED, setting color "constrain(color, 0, 255);"
int red = 100 - constrain(red, 0, 255);
int green = 50 - constrain(green, 0, 255);
int blue = 100 - constrain(blue, 0, 255);
int off = 0 - constrain(red, 0, 0);

//Mac and ip address of php server
byte mac[] = { 0x00, 0xAB, 0xBA, 0xBC, 0xDD, 0x02 };
char server[] = "ec2-52-65-157-177.ap-southeast-2.compute.amazonaws.com";

EthernetClient client;


void setup() {

Serial.begin(9600); // Initialize serial communications with the PC
 while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
 SPI.begin(); // Init SPI bus
 mfrc522.PCD_Init(); // Init MFRC522 card
 mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
 Serial.println(F("Scan PICC to send UID"));
 rfid_uid = "";

pinMode(redPin, OUTPUT); // make the pins outputs for RGB
 pinMode(greenPin, OUTPUT); // make the pins outputs for RGB
 pinMode(bluePin, OUTPUT); // make the pins outputs for RGB

pinMode(buzzer, OUTPUT); // Set buzzer - pin 9 as an output

Ethernet.begin(mac);
 delay(1000);
 startEthernet();
 analogWrite(greenPin, green);
}

//------------------------------------------------------

/*
 Helper routine to dump a byte array as hex values to Serial.
*/
void dump_byte_array(byte *buffer, byte bufferSize) {
 read_rfid = "";
 for (byte i = 0; i < bufferSize; i++) {
 read_rfid = read_rfid + String(buffer[i], HEX);
 }
}

//------------------------------------------------------

void loop() {
 //Let Reader start
 delay(200);

// Look for new cards
 if ( ! mfrc522.PICC_IsNewCardPresent())
 return;

// Select one of the cards
 if ( ! mfrc522.PICC_ReadCardSerial())
 return;

dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);

if ( read_rfid != rfid_uid) {
 if (read_rfid != rfid_uid) {
 analogWrite(greenPin, off);
 analogWrite(bluePin, blue);
 Serial.println(read_rfid);
 rfid_uid = read_rfid;
 DataToMySQL();
 }
 }
 else {
 analogWrite(greenPin, off);
 analogWrite(redPin, red);
 delay(500);
 analogWrite(redPin, off);
 analogWrite(greenPin, green); 
 }
}

//------------------------------------------------------

void DataToMySQL() {

bstate++;

EthernetClient client;

if (client.connect(server, 80))
 {
 // print to serial monitor
 Serial.println("connected...");
 Serial.println("ARDUINO: forming HTTP request message");

// send data the server through GET request
 client.print("GET /add_UID_v2.php?UnitNo=");
 client.print(Unit_No);
 client.print("&UID=");
 client.print(read_rfid);
 client.println(" HTTP/1.1");
 client.print("HOST: ");
 client.println(server);
 client.println();
 Serial.println("ARDUINO: HTTP message sent");

// give server some time to receive and store data
 // before asking for response from it
 delay(500);

// get the response from the page and print it to serial port
 // to ascertain that data was received properly
 if (client.available())
 {
 Serial.println("ARDUINO: HTTP message received");
 Serial.println("ARDUINO: printing received headers and script response...\n");
 tone(buzzer, 500);
 delay(400); // ...for .4 sec
 noTone(buzzer); 
 analogWrite(bluePin, off);
 analogWrite(greenPin, green);

while (client.available())
 {
 char c = client.read();
 Serial.print(c);
 }
 }
 else
 {
 Serial.println("ARDUINO: no response received / no response received in time");
 analogWrite(bluePin, off);
 analogWrite(redPin, red);
 delay(1500);
 analogWrite(redPin, off);
 analogWrite(greenPin, green);
 
 }

client.stop();
 }
}

//----------------------------------------------------
void startEthernet()
{
 client.stop();

Serial.println("Connecting Arduino to network...");

delay (1000);

//connect to network and obtain an IP address using DHCP
 if (Ethernet.begin(mac) == 0)
 {
 Serial.println("DHCP failed, reset Arduino to try again");
 Serial.println();
 analogWrite(redPin, red);
 }
 else
 {
 Serial.println("Arduino connected to network using DHCP.");
 Serial.print("IP address is ");
 Serial.println(Ethernet.localIP());
 Serial.println();
 }

delay(1000);
}

Although this is almost the final version of the code it is the largest it will be. I wanted to test it the code will run on a smaller and cheaper Arduino device, such as the nano, a $5 USD chip. I change the IDE compiler options so that it thought it was compiling it for a Nano. The results came in that it could. With plenty of room to spare. This means that this system, using the cheapest parts could be put together for about $20 USD per unit, much cheaper than the $35-$50 USD my unit costs. Below are the test results;

28-10 Will run on nano.PNG

Version 2.3

This is not any changes to the code but a mounting example solution. I wanted a way to securely hold all the Arduino components. The best solution I could find, that was cheap, was a tupperware container from Kmart. It was $1, and the right size to fit the Arduino Mega I am using. The container was also thin enough that the RFID tag could be read through the container lid meaning that all the components could be mounted inside it.

This slideshow requires JavaScript.

I started off by arranging the components in the container and then drilling the holes required to fit them. Those components I then attached using what I had lying around.
To hold the Arduino in the container I found some tiny screw and screwed them through the mounting holes on the Arduino. You can see they aren’t screwed all the way in, this because they will come out the base of the container and be a hazard.
To secure the RFID reader in the container I used two zip ties. They worked well to hold the reader tight against the lid.
To secure the buzzer and LED I used a hot glue gun.
The big red button on the side is a hard reset button. I added this so that the unit can be reset without the need to open the case or disconnect the power to the device.

Version 3.0

3.0 although not implement yet will have just remove the command that starts the serial port. This means that if the USB port was connected to a computer and the serial reader started, there would still be nothing displayed. This is a simple change, and when done will complete the Arduino unit.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s