AttendanceScanning

Problem
An engineering seminar is attended by over 70 students. The previous class exits 10 minutes before the next class enters. The room holds over 100 students. Calling out student names takes too much time. Asking students to find their name on a sheet and put a check by it works, but a line forms. Some students would rather find a seat near their friend than wait in line. They begin signing in for each other. And the slippery slope results in starting a seminar with a head count of 30, but 50 people signed in.

Conceive
Making seminar attendance part of one's grade is necessary to get community college students to attend. Otherwise, it becomes an optional club. Maybe in the future, the seminar will be so valued, that everyone will want to attend. But to get to that point, to figure out what works and doesn't work in the seminar means that students need additional motivation.

Design

 * Signin .. order of arrival .. hand writing .. much more difficult to enter into the gradebook
 * Initial by name on a sheet .. students find their name, put initials by their name .. line slows down .. but easier to enter into electronic gradebook because order of names on the sheet matches gradebook, but students begin signing in for each other.
 * Magnetic strip reader .. initial pairing of shopping vanity card strip with name and then when the card is lost would not work in real time at the start of the seminar ... end up with an exceptions process that students begin to depend on ... slippery slope again
 * RFID tags in student id, leverage something on the student ID .. costs $5/student which is too much for a community college ..
 * School library card .. school puts bar code sticker on the back of the student id .. could scan this bar code .. but not all students use the library and get the bar code ... would put strain on the library which doesn't print them in bulk and expect to match with 80 students during the first week
 * Facial recognition .. Google Picasa facial recognition software can be downloaded and run as a separate application. Lots of software can grab pictures of people and detect movement. But in all trials, lighting and head direction becomes a problem. Would have to put chin on a chin rest with fixed lighting and then the software trained to recognize. False positives would be a problem and through put .. processing hits as fast as people walk through a door ... was never tested. Gave up when chin logistics began to feel like mug shots. Expectations were set by CSI TV shows showing facial recognition software. Such software didn't exist in the open source world .. as of 2013.

Print bar code labels for students. Put these labels on the back of their engineering notebooks in the second class before the first seminar. Expect that barcodes can be scanned almost as fast as people walk.

This has the following benefit of being expanded to enabling a door to automatically unlock.

The goal is to be able to scan very quickly bar codes on the engineering notebooks. So there has to be a window that gives students feed back ... their name, date, time, event, activity in the event such as entering, leaving or asking question, successful secondary scan such as a clicker.

The other goal is to administrate this successfully. Data should be saved after a period of inactivity, but in any case there should be a save button. Administrators are going to need to print bar codes, manually enter attendance, check names and faces, switch event activities and adjudicate questions.

There are at least three ways to create the user interface: G4P was choosen because of it's integration into the IDE and prior experience. G4P feels like the code way ahead of the documentation. ControlP5 looks better documented, but was last checked with Processing 2.0b7.
 * Using Processing (see GUI in the processing examples)
 * GUI Tool built into Processing G4P
 * GUI add on to Processing ControlP5
 * Native Java GUI Swing
 * Original Abstract_Window_Toolkit Sun Java GUI AWT

The first user interface tried use one screen and became too messy. It was split into an instructor screen and student screen.

The second user interface designed is presented in this video. See the operations user manual below for the final result.

A state diagram was made describing a possible scenario for allowing both smart phones and clickers to be used for feedback during the seminar. The problem is if a student scans their ID, then the next student scans their clicker. Every other scan pair after that would be out of sink. Clickers would be assigned to students that didn't have them. Other students would have the wrong clicker assigned.

So the design goal now is to enforce alternating of ID scan and clicker scan when arriving at the seminar.

The goal is to focus on reliably accumulating attendance information, not analyzing it. It should be saved automatically, and be review-able at the end of an event. It should capture the following information:
 * event description (seminar, club, class, openlab)
 * event activity (arriving, leaving, clicker checkout and return, and grades assigned during the activity)

Implement
Purchased a TaoTronics TT-BS003 usb cabled scanner because was cheapest in Amazon at the time. Out of the box it registers as an input device as if it were a second keyboard. When aimed at any barcode, outputs text into what ever program typed characters would normally appear in. The trigger doesn't do much other than force the start of a scan. Can mount and then pass items with bar codes underneath it without touching the scanner video. Looks like this scanner cost about $50, a wireless version costs $80 and a version without the stand costs $30.

The next step was to figure out how to print unique bar codes for each student. There are lots of different formats, and lots of "free" software to print bar codes. Code 39 was settled upon because it exists as a true type font that can be downloaded. Text is then turned into a bar code by selecting the bar code font.

Testing on an inkjet printer showed it can scan fonts 10 point or larger. The bar code must begin with * and end with a * otherwise it will not scan. The font translates ! into a *.

This is the processing pde. It generates a file TestPrint.pdf in the sketch directory. If the file already exists, it fails. Delete the previous file first. Automatically printing the PDF can be done with FoxitReader which requires a DOS batch file to be written. The processing sketch silently starts this batch process which would delete the file when done. PFont font; // The font IDAutomationHC39M must be downloaded // in the operating system ... other programs must see it

import processing.pdf.*; PFont myFont;

void setup { size (320,40, PDF, "TestPrint.pdf"); myFont = createFont("IDAutomationHC39M",12); fill(0); background(255); textFont(myFont); }

void draw { text("*FirstLast0123456789*", 15, 30); exit; }

This program was built by looking through the processing.org. Started off with getting loadTable to run. Biggest problem was figuring out that the csv file had to be in the data folder. Kept getting "null pointer" error messages when it was not.

The next step was storing everything in a several string arrays. The array reference shows integer and number arrays, but not strings. But the description talks about string arrays so seemed possible. When the word string did not change color in the IDE, String was tried. Capitalizing S was the difference.

Could not figure out how to find the number of students and then set the array size, so made 120 the max number of students ... arbitrarily. If the number is fewer, the program works. If roster.csv has more students in it, then probably will get an error message when it runs. just change the size in ScanGUI16 at the top where the variables are defined.

Comparing strings was difficult. Tried == but didn't work. The .equals method is not on the reference page.

The "while" command to pad the student id with leading 0's because they were lost in canvas worked correctly the first time.

Tried saveStrings to save the drop down list, but saved the word "null" for the 120-class size students. So had to go with PrintWrite which is more verbose. Had to add path to the data file so the actual file is created in the data directory where the GUI drop down will look for it.

Table table; String[] sis = new String[120]; String[] name = new String[120]; String[] section = new String[120]; int NumStudents = 0; PrintWriter output;

void setup { int i=0; //is going to count rows in roster.csv table = loadTable("roster.csv", "header");//roster.csv is downloaded from canvas gradebook course megasite

for (TableRow row : table.rows) { int j; // is going to count rows of students, skipping header, second line and hopefully default, test students if (i>0) { if (!(row.getString("Student").equals("Student, Test"))) { j = i-1; sis[j] = row.getString("ID");//using only three columns of canvas gradebook name[j] = row.getString("Student"); String[] q = split(row.getString("Section"),'-'); section[j] = q[3];//hcc naming convention is 2013-ENES-100-501, want just the section 501 while (sis[j].length < 7) { sis[j] = "0" + sis[j];//canvas strips leading zero's off the student's sis, so putting back on       } println(j + " " + sis[j] + " " + name[j] + " " + section[j]);//debugging line }   }    i++; } NumStudents = i-2; println ("number of students is " + NumStudents); output = createWriter("data/rosterList.txt");//creating drop down student list for main application for (int k=0; k<NumStudents; k++) { output.println(name[k]+" "+section[k]+" "+sis[k]); } output.flush; output.close; }

The Seminar Attendance GUI, as designed, only uses the mouse to navigate buttons, drop down boxes, radio buttons and check boxes. It was planned that all events would originate in the gui tab.

However, another set of events evolved that just involved the scanner. The scanner looks like a keyboard to the software. There were ID scans, clicker Scans, random scans of other barcodes and random keystrokes coming through the same input interface. The good scans triggered different events depending upon whether the event activity drop down box was arriving, returning clickers, etc.

The initial code ended up looking like a knot woven with if commands. It worked, sort of. But then a tipping point was reached where nothing could be added without something else breaking. It had to be split up into smaller chunks. The graphic on the right was an attempt at this.

The solution ended breaking the code up into major chunks for a variety of reasons:
 * ScanGUI ... variables, setup, draw
 * csvProcess ... run once during setup .. snipped out of ScanGUI setup to reduce bloat
 * drawStudentWindow ... snipped out of ScanGUI draw to reduce bloat and because it was the biggest of three Student Windows .. scan information (drawStudentWindow), clicker return report and taking student's picture
 * fileOutput ... was split out because it is triggered three ways: through a timeout in ScanGUI draw, through a transaction buffer filling in fileOutput (processTransaction) and gui save button. This turned out to be the most time consuming part of the project. A Processing file append command would have saved lots of time.
 * findStudent ... is used four times in ProcessEvent .. is very similar to code in recordClicker (look at the while commands).
 * gui .. this is created by G4P and should not be touched because the Processing GUI tool manipulates it. If the GUI tool doesn't expect your changes, it will trash GUI and files in several of the program folders. Backup frequently. Can see functions defined else where scattered in the public functions starting with dropLists at the top.
 * keyOrScanner ... this is referenced only in GUI. It is triggered when the focus is on the instructors window. Remnants of the initial IF command knot can be seen in this function. Try to add processEvent written with IF commands to this code and one can intuitively feel the initial mess.
 * printBarCode ... this was done first .. to prove that a barcode font could be accessed by Processing. It was also done last .. to try and automate sending the bar codes to the printer. Turns out that processing has no ability to send data to the printer directly. So this was done with a windows batch file. It is an ugly solution.
 * processEvent is beautiful .. it pushes scanner information into different categories depending upon the event activities (the drop down list) .. it deals with "Leaving" and subcontracts the rest to processQuestion, recordAttendance and recordClicker.
 * takePicture selects the webcam to use. The real take picture code is in ScanGUI draw. The problem is that second webcam may be attached to the computer. This code will probably have to be changed when different webcam hardware is purchased. It is fragile. Sometimes the entire program bombs. This is particularly true of a webcam that is drawing near the max power from the USB port. Can hear device registration beeps as it drops and re-inserts itself.

The function keyOrScanner is called by the instructors window through the gui tab through the process textWindowKey and called by the students window through the ScanGUI tab, keyTyped function. It has three main functions:


 * 1) 1 Only one window at a time has keystrokes flowing into it. G4P takes over the keyboard if it uses the original processing window and keyTyped doesn't work. When G4P takes over the second java window, then a function can be defined that processes the keystrokes. This function was named keyOrScanner in this program. Since G4P funnels three events for every keystroke (the three events are imagined to be keydown, keyhold, keyup) then the first step of keyOrScanner is to expect three characters in a row for every character pressed. This is why keyTyped in the ScanGUI tab has to send keyOrScanner three characters for every character pressed.


 * 1) 2 The second step was to figure out if the scanner was sending keystrokes or the keyboard. The goal is to use the bar code, not type in a student id into the keyboard. So distinguishing between the two became important. After some testing, the scanner sent a barcode within 50 to 200 milliseconds. It took humans at least 1000ms to type an ID and press enter. Timing test was started on the first character and ended with carriage return (char or byte 10). The constant scanTime is designed to distinguish between the two.


 * 1) 3 The third step was to check the number of characters. The scanner will scan practically any bar code. So the length can be checked to see if it is either a student id length or barcode length. This one way of testing whether it is a valid barcode.

The goal of object oriented programming is to discover re-usable chunks of code, name them, test them, document them and add them to one's personal and the worlds tool box. Programming then becomes more like decorating a room.

The starting point for this analysis seems to be the main program, ScanGUI. Global Boolean data types seem to set up a subsystem of flags that interrupt normal operation flow. Next the gobal variables need to be examined. This is sort of like judging a mechanical assembly by counting it's moving parts, assembly steps or screws. Minimizing the numbers would seem to be the goal. Counting them would indicate the relative usefulness, health of the objects and yet at the same time a large number may indicate the birth of something new, .. something doesn't fit the world at the moment. The variables seem the most important to describe are associated with "states" within the program ... which evolved and need a work:

Initialized False in ScanGui. Looked at in ProcessEvent when activity is (arriving & clicker) to alternate between creating a student ID scanning event (is false) and clicker scanning event. The default value is "false." It is set "true" only after recording student ID in recordAttendance. Is set false recordClicker. Value can be "true" but never looked at because recordAttendance sets it "true" no matter what, yet only ProcessEvent activity (arriving & clicker) looks at it. All other activity ignores it.
 * boolean turnClicker

Initialized "checking out" in ScanGui. Set to "checked out" and "checked back in" in processEvent. Turns into a boolean type flag in recordClicker to determine current state: "already checked out", or "never checked out." Primary use is to prevent the same clicker from being checked out to two different students. Can be checked back in multiple times ... so that an entire bag of clickers can be scanned again in case one was missed.
 * string clickerReturn

Contains clicker bar code number when scanned, otherwise is empty. Turns into a state variable that has to be reconstructed from past transactions with the current date in cvsProcess. Is used to determine which student is assigned to a clicker when clickers are returned without identifying the student. Just find this clicker number in the array and then the student is known since they share the same element number in the array. Is used to make the description of the transaction that appears on the student window.
 * string array clickerScan

Set to "arriving" in ScanGui. Set to "arrived" in recordAttendance. Is just text label and has nothing to do with a state.
 * string attendStatus

Set initially to "not here" in cvsProcess .. or restored from the last mention in description column with today's date in the attendance.csv file. Used primarily to update display of student window. Used to determine "never here" when trying to mark "left" in processEvent or if scanning twice in recordAttendance.
 * string array attend

Initially set to "hasn't arrived yet" in cvsProcess, or is restored from last mention in description column with today's date in attendance.csv file. Used primarily to update display of the student window in drawStudentWindow and processEvent.
 * string array left

Initially set to a space in cvsProcess or "Left" if a leaving activity was detected for the student in the attendance.csv file for the current date. Is set to "Left" in processEvent if the event activity is leaving. Primary use is to produce the error message "never arrived" when trying to leave.
 * string array leftScan

A transaction causes a horizontal row in the output file. It is triggered by scanning something successfully, the "Manually record attendance" button on the instructor's window, or the "Grade Question" button on the instructors window. The tab "fileOutput" has four functions: The saveTransaction function creates bunch of batch files because appending files and deleting files through processing/java was not figured out
 * 1) checkAttendanceExists ... create new attendance.csv if one doesn't exist
 * 2) processTransaction ... worried about scanning too rapidly, ScanGUI crashing .. so setup mechanism to throttle scanning .. limit of maxTransactions (set in ScanGUI setup) are allowed before running saveRamTransactions
 * 3) saveRamTransactions ... dump transactions in an array to a file: data/attendance/transactions-#### file as quickly as possible, save file name so can be merged into the one attendance.csv file later
 * 4) saveTransaction .. called either by a timeout in ScanGUI draw or manually by "save" button in the instructors window. Figures out all the files to combine into one, does the combination and deletes all files in the data/attendance directory

Operate

 * Bar codes are printed with students names in 6 point font (very small). This is because the students name next to the bar code confuses the scanner.
 * When cutting the bar codes from white paper, leave 2 inches in white on either side when taping onto the brown notebook. The dark brown cover of the engineering notebook confuses the scanner.
 * Can put at least 3 layers of tape of either matte finish (writeable) or glossy finish as long at is clear

Dependent Software

The following needs to be installed in order for the program to work: Required Files
 * G4P (do not install from the gui> Tools > Add Tools > G4P Tool .. download and put the G4P folder in the user\documents\processing\libraries folder)
 * foxit (in order to print PDF automatically)
 * barcode fonts in order to print student bar codes

There are a number of *.PDE files that need to be program folder. Within the program folder must be a data folder. In the data folder will need to be a G4P folder containing data associated with the user interface. An attendance folder needs to be created, but nothing should ever accumulate in there. It is used temporarily during the attendance recording process. Initially there have to be two files in the data folder:


 * roster.csv (downloaded from Canvas with no modifications)
 * noImage.png (used as default image when none exists for a student)
 * list_846477 .. list of types of events used in a GUI drop down
 * list_388343 .. list of event activities used in a GUI drop down box

Program Generated Files

The program creates lots of files within data including:
 * list_293914 .. list of students created from roster.csv during each program start .. for GUI drop down box
 * bat files .. used to rename, append and delete files used to create attendance.csv (what makes this program work only in windows)
 * backup files .. incremental backups of attendance.csv
 * attendance.csv ... the main file where attendance data accumulates
 * png file with thumbnail of each student
 * Clickers.txt ... dummy file of clicker information derived from student id's that can be pulled into word or excel and printed using a bar code font
 * IDs.txt .. dummy file of all seminar student id's that can be pulled into word or excel and printed using a bar code font

Processing programs are called *.pde files or "sketches". They are each stored ina a folder. The folder has to have the name of the main sketch, csvTest in this case. Each sketch folder has a data folder. This is were the sketches store files needed to start and work. If these files are missing, often the error message is "Null Pointer."

The CSV file downloaded from the Canvas gradebook needs to be stored in the data folder with the name "roster.csv". It has to be there to start the program. It should not be edited in any way ... unless to remove columns that may contain student grade information.

Processing writes by default in the sketch folder, not the sketch data folder. At startup this scanning program reproduces a new list of students called rosterList.txt from roster.csv every time it is launched. This is because students drop, add or move around sections. The goal is to have the most current list of students at the beginning of the attendance taking event.

Most problems starting are associated with an external web cam not getting enough power through the USB port. Initializing causes the camera to reset and then ScanGui can hang or crash with a Java error message associated with "Null" or a blank Student Window. In these cases, terminate the program and start over again.

ScanGui is ideally started at the beginning of an event and turned off at the end of the event. If is restarted during an event, it will search through previous transactions, restore the state (arrived but not left, clicker checked out but not back in, already arrived, already checked out, ...). However it only restores this data from events with the same date. This makes a single machine very robust at recovering all information necessary to record a single event.

However there will be a problem when there are two attendance events for the same student on the same date. For example, if a student doesn't turn a clicker back in, they will not be able to check one out at the second event. (current feature) A student will not be able to leave twice because they "already left" the first time. (current failure) There are two solutions: When attendance.csv is renamed, a new one will be built. Someone manually will have to keep track of all these csv files and process them through a separate program that applies a grading rubric.
 * 1) separate computer for each event during a day
 * 2) manage attendance.csv

Pressing save is not necessary. Data is saved after 10 minutes of inactivity.

Stopping is done by either clicking on the X or stop of the student window, or clicking on the square top button in the Processing IDE.

Instructor and Student Windows The instructors Window controls everything. The top right displays a running dialogue of status information. There are three drop down boxes, seven buttons that can be pressed and pushbutton/checkboxes that can be used to grade something in the moment of the event. The current number of students scanned into the event and the total number in the drop down box are displayed in the bottom right corner.

The student's window displays the same running dialogue of status information in the bottom line. Underneath the student's name is information about attendance, whether they have left, what clicker they have/had. In the middle of the screen is information about the current event with a thumbnail picture.

Pressing the take picture button clears the student window and displays the web cam so that a thumbnail can be taken. Pressing "clicker report" clears the student window also and displays a list of student names that have not returned their clicker. The screen is live. Clicker's can be returned and the student's name should disappear.

In addition, clicking save will fire up a third window containing Excel with all attendance information; not just the current date. Don't save while in Excel or Excel will corrupt the attendance information.

Drop Down boxes There are three drop down boxes:

Arriving and clicker forces alternating between scanning ID and scanning clicker. Arriving expects student ID scans constantly. Asking Question does not create a attendance transaction; it only selects the student. It leaves time for an instructor to fill out the rubric and press "Grade Question." Leaving records a separate leaving event only if the student is marked arrived. Returning clickers expects a constant stream of clicker scans. Students can leave by just scanning their ID and throwing clickers in a bag. Later the clicker's can be scanned to see if they were all returned. Eventually their may be a Leaving and clicker but this has not been written.
 * Event Activity

This system could be used for a variety of events, not just taking attendance in the seminar. It could be used to take class attendance, club attendance, special event attendance, after hours lab usage attendance. So a drop down box was created called "type of event." This will be recorded along with the event activity (leaving arriving), date, time, name, section and id.
 * Event Description

The current student is looked up either through the drop down box or by scanning a bar code. If the current student's name is chosen by scanning, an attendance event is automatically created. If chosen through the drop down box, then the appropriate blue button needs to be pressed.
 * Selecting Student

Buttons

Select a student, then press this button if they don't have their bar code.
 * Manually Create Attendance Event

Select a student, press this button and the program will attempt to print on the default printer. It creates and deletes a pdf file. If it doesn't print, look for a file called output.pdf in the data directory. If this file exists delete it.
 * Print Current Student's BarCode

Select a student in the section to be printed. Press the button and just those students in that section will be printed. Creates and deletes the same output.pdf file in the data directory.
 * Print Section

Saves transactions (scans, graded questions) that are still in RAM to attendance.csv file in the data directory and then displays a backup copy of attendance.csv using Excel. Be careful using Excel to not save. Excel will mess up the attendance.csv file. The goal is to accumulate attendance data in one file for the entire semester.
 * Save

Clears the student window and displays a list of students that haven't returned their clickers. If there are more students than fit the window, a subset of the names will be displayed. Press any key on the keyboard to return to the student window. Returned clickers can still be scanned while this window is displayed. It is live, so the returned clicker should cause the student's name to disappear.
 * Clicker Report

Clears the student window, displays a web cam live video. Has a 200 by 250 pixel box to move around with the mouse to capture the person's face. Press the mouse button to capture the box and turn into a thumbnail. The thumbnail is attached to the current student. Changing students using the drop down, or scanning a students bar code will change the student in the middle of this process.
 * Take Picture

Connect two monitors to the attendance computer with two mice, one wireless. Put one monitor, the scanner, the web cam and a wireless mouse at the attendance station. Instructor keeps the keyboard and a second mouse. Student says .. take my picture. Instructor clicks button "Take Picture." Student moves pixel box over their face and presses the mouse button. Instructor presses key on keyboard to return to ID/Clicker scanning.

During the seminar, it may be necessary to grade individual students ...perhaps behavior, perhaps the quality of the questions asked. The goal is to capture an instructor evaluation in real time as students are scanning and talking into a microphone. One group of push buttons and three check boxes are available. This works in any Event Activity. The Event activity called "Asking questions" turns off transaction creation associated with scanning a bar code. Scanning results in only selecting a student. This gives the instructor time to evaluate the rubric before clicking the Grade Question button.
 * Grade Question

Messages appear on the student window bottom left and the instructor's window upper right. No messages should appear within the Processing IDE unless something is going wrong.
 * Ready to begin Scanning
 * ID not found, try scanning again
 * Must scan ID now, not Clicker
 * Barcode wrong length (probably scanning some random bar code)
 * can not type ID please Scan (don't try to use the keyboard)
 * Have printed xxxx's barcode
 * Have printed section's xxx barcodes
 * Press Button to Record Question Evaluation
 * Successful ID Scan .. marked left
 * Already Left (trying to rescan left at later date)
 * Never Arrived (trying to mark left when never arrived)
 * don't edit list_388343
 * Successful ID Scan .. marked arrived
 * Has already been scanned (ID has already been recorded as attending)
 * Successful clicker checkout
 * Clicker already checked out to someone
 * Did not find this clicker checked out to anyone (when returning clickers)
 * Successful clicker Return
 * Please scan clicker

The attendance.csv file is a single spreadsheet with the following columns:
 * Name, ID, Section .. enough information to upload a rubric to an LMS such as Canvas
 * Event, Activity .. the first two drop down boxes in the instructors window
 * Clicker Number .. clicker number only exists if a clicker was scanned
 * Date, Time .. the time is in minutes (60*hours + minutes) so that arriving can be subtracted from leaving to get total time present at the activity
 * description .. this a text description of the event that is displayed on the student window or the radio/check box description associated with a graded question

This information should be enough to provide attendance data for any rubric.

Demo
Presentation

video

Next Steps

 * Design state diagram for arriving, leaving and clicker status .. that meets expectations for all possible failure modes (program restarts forcing restore of state information) and multiple attendance events on the same day with the same machine. Currently same machine only works as expected through one attendance event per day. Multiple attendance events on the same day will cause previous event problems to impact current events ... such as not being able to arrive at a second event because already arrived at the first.
 * Make fileOutput generic to all OS .. right now it has become windows specific through the use of batch files
 * Add a leaving & barcode option to the event activity list and support this in processEvent and recordAttendance tabs
 * Add students picture to the instructors window
 * Figure out how to print directly to an OS printer from Processing/Java rather than use batch file and third party software
 * Add code to list all webcam modes in a drop down box so that each can be tried by an end user rather than the programmer try "by hand" and enter hardware specific information into the code.