Midterm Assignment: Design a Camera Trap
CAD of Enclosure:
The Camera Trap App for android works! We recently solved the camera trap application code today. It was a long process but the initial system is up. Basically, when the PIR sensor goes gets a reading the camera takes a photo:
Video of Camera Trap Application in action
We still have a long way to go. We need to bluetooth enable our app so we can create a network across phones. We need also have the app function when the screen is off… Those are our next coding challenges.
In addition, we need to redesign the housing for our device and also develop user flowcharts for our system.
Here are a couple movies of the PIR Sensor talking to the phone through arudino:
PIR Sensor working through arudino
We have decided to break into two different teams: Mike and I are working on the coding end and Christie and Mark are focusing on the enclosure.
Here are the first steps made in the the enclosure design:
-Mark and Christie have hacked a pelican case to house our Arduino, battery supply, and sensor. They also placed the Android phone into a separate case that is water proof with a rubber material that allows you to access the screen. They are currently building a separate case around the phone and arduino case to make them one unit.
Android to Arudino (coding):
-Mike and I have got our photo application built in Java Eclipse and programmed our arduino. We are currently messing around with making Arduino and Android talk to each other. Here is the code
Android (Java Eclipse) Code:
package com.androidapp.sd;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.View;
import android.widget.ToggleButton;
import com.android.future.usb.UsbAccessory;
import com.android.future.usb.UsbManager;
public class AndroidLightActivity extends Activity {
// TAG is used to debug in Android logcat console
private static final String TAG = "ArduinoAccessory";
private static final String ACTION_USB_PERMISSION = "com.google.android.DemoKit.action.USB_PERMISSION";
private UsbManager mUsbManager;
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
private ToggleButton buttonLED;
UsbAccessory mAccessory;
ParcelFileDescriptor mFileDescriptor;
FileInputStream mInputStream;
FileOutputStream mOutputStream;
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
openAccessory(accessory);
} else {
Log.d(TAG, "permission denied for accessory "
+ accessory);
}
mPermissionRequestPending = false;
}
} else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory = UsbManager.getAccessory(intent);
if (accessory != null && accessory.equals(mAccessory)) {
closeAccessory();
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUsbManager = UsbManager.getInstance(this);
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(mUsbReceiver, filter);
if (getLastNonConfigurationInstance() != null) {
mAccessory = (UsbAccessory) getLastNonConfigurationInstance();
openAccessory(mAccessory);
}
setContentView(R.layout.main);
buttonLED = (ToggleButton) findViewById(R.id.toggleButtonLED);
}
@Override
public Object onRetainNonConfigurationInstance() {
if (mAccessory != null) {
return mAccessory;
} else {
return super.onRetainNonConfigurationInstance();
}
}
@Override
public void onResume() {
super.onResume();
if (mInputStream != null && mOutputStream != null) {
return;
}
UsbAccessory[] accessories = mUsbManager.getAccessoryList();
UsbAccessory accessory = (accessories == null ? null : accessories[0]);
if (accessory != null) {
if (mUsbManager.hasPermission(accessory)) {
openAccessory(accessory);
} else {
synchronized (mUsbReceiver) {
if (!mPermissionRequestPending) {
mUsbManager.requestPermission(accessory,mPermissionIntent);
mPermissionRequestPending = true;
}
}
}
} else {
Log.d(TAG, "mAccessory is null");
}
}
@Override
public void onPause() {
super.onPause();
closeAccessory();
}
@Override
public void onDestroy() {
unregisterReceiver(mUsbReceiver);
super.onDestroy();
}
private void openAccessory(UsbAccessory accessory) {
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
mAccessory = accessory;
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Log.d(TAG, "accessory opened");
} else {
Log.d(TAG, "accessory open fail");
}
}
private void closeAccessory() {
try {
if (mFileDescriptor != null) {
mFileDescriptor.close();
}
} catch (IOException e) {
} finally {
mFileDescriptor = null;
mAccessory = null;
}
}
public void blinkLED(View v){
byte[] buffer = new byte[1];
if(buttonLED.isChecked())
buffer[0]=(byte)0; // button says on, light is off
else
buffer[0]=(byte)1; // button says off, light is on
if (mOutputStream != null) {
try {
mOutputStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "write failed", e);
}
}
}
}
Arduino Code:
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
#define LED_PIN 13
AndroidAccessory acc("Manufacturer",
"Model",
"Description",
"1.0",
"http://yoursite.com",
"0000000012345678");
void setup()
{
// set communiation speed
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
acc.powerOn();
}
void loop()
{
byte msg[0];
if (acc.isConnected()) {
int len = acc.read(msg, sizeof(msg), 1); // read data into msg variable
if (len > 0) {
if (msg[0] == 1) // compare received data
digitalWrite(LED_PIN,HIGH); // turn on light
else
digitalWrite(LED_PIN,LOW); // turn off light
}
}
else
digitalWrite(LED_PIN , LOW); // turn off light
}
-WE tested the Arudino communication to the Android code by writing an app that had Android turn an LED on and off. We are also considering developing in Processing.
Midterm Assignment: Design a Camera Trap (Midterm)
Mark, Mike, Christie, and I are working on building a camera trap design that improves the data flow of the current system. We are creating a mobile android phone camera trap that connects to a tablet or other mobile phone via bluetooth. This allows the researcher to extract the photo data wirelessly without a network or taking apart the camera trap. It took some time to figure out the figure out what the best way to attack the problem was. There are many components from the enclosure to the data flow to the hardware to the software to battery life. We brainstormed combinations of these elements and put them into classified concepts models.Using Mark’s patented number system we rated our concept ideas. We assigned a number of 1, 3, and 7 (1 being the least important 7 the most) to each component (price, fiesiblity, battery life etc.) We then rated the concepts 1, 3, 7 depending how strong each concept was in each area. We multiplied the numbers in each category and then added them up to determine the best concept idea (refer to photos 3 and 5). Here are some photos of our brainstorming:
Here is the initial code we came up with for the engaging the camera. We are still working on getting the Arduino SDK to talk with the android app we built via its sensor.
//CameraIntent.java
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”vertical” >
<ImageView android:id=”@+id/ReturnedImageView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content” />
</LinearLayout>
———————————————————————————-
<!– AndroidManifest.xml –>
<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”com.muzzi.cameraintent”
android:versionCode=”1″
android:versionName=”1.0″ >
<uses-sdk android:minSdkVersion=”8″ />
<application
android:icon=”@drawable/ic_launcher”
android:label=”@string/app_name” >
<activity
android:name=”.CameraIntent”
android:label=”@string/app_name” >
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>
</manifest>
The next layer of the code to get the PIRSensor to work is here:
/////////////////////////////
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;
//the time when the sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int pirPin = 3; //the digital pin connected to the PIR sensor's output
int ledPin = 13;
/////////////////////////////
//SETUP
void setup(){
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(pirPin, LOW);
//give the sensor some time to calibrate
Serial.print("calibrating sensor ");
for(int i = 0; i < calibrationTime; i++){
Serial.print(".");
delay(1000);
}
Serial.println(" done");
Serial.println("SENSOR ACTIVE");
delay(50);
}
////////////////////////////
//LOOP
void loop(){
if(digitalRead(pirPin) == HIGH){
digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
if(lockLow){
//makes sure we wait for a transition to LOW before any further output is made:
lockLow = false;
Serial.println("---");
Serial.print("motion detected at ");
Serial.print(millis()/1000);
Serial.println(" sec");
delay(50);
}
takeLowTime = true;
}
if(digitalRead(pirPin) == LOW){
digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
//if the sensor is low for more than the given pause,
//we assume that no more motion is going to happen
if(!lockLow && millis() - lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
Serial.print("motion ended at "); //output
Serial.print((millis() - pause)/1000);
Serial.println(" sec");
delay(50);
}
}
}
Assignment 2: Studying flaws in GPS Systems:
I decided to test runkeepers GPS system on my friends phone during one of our runs around the city. Sunday we did a run across the 3 bridges (Brooklyn, Manhattan, and Williamsburg Bridge). We came up with some interesting results.
Here is what run keeper gave us:
- Run keeper had obvious flaws. First, it had us going over the manhattan bridge twice. It had a lot of double backing. Our total run was 13.7 miles not 24. 92 miles. The other issue was our pace. It claimed that we had a 4min. 29sec. pace. In various places it gave us pace readings of 30 sec. per mile. The only correct reading was on our duration. I am not sure about the technical issues involved with their particular system but our current tracking devices out in the field in ecuador would not require some much accuracy.
Here is the data readout of our actual run:
We went to google maps after our run to map out what we did from start to finish. We ran 13. 7 miles total at a pace of 8 min. a mile. In looking at the data read out here are the following observations:
-GPS reading was doubling back our tracks during parts of the bridge.
-Runkeepers GPS had a difficult time when we were under the bridges. It would often give us readings that we were in the water.
-As we crossed bridges it said we were running further into the city then we did. I think this had something to do with the double backing issue. Often when we would cross bridges we would go below them to huge the water front to the next bridge. This was an issue because the system could have read that we were still on the bridge not identifying the road running directly below.
— Tom will go over GPS tracking on weds. Hopefully that will provide some insights to issues coming up with run keeper.
Class Exercise:
We used the tracking systems Tony and his team used in the field in last class. Since the only environment we had to work in was the streets of NYC; we did our tracking around NYU washington square park. We broke into two groups. One took a radio receiver or a collar equipped with a GPS unit. The radio collar people were the animals being sought. The other groups were given the receivers. Their goal was to find the animal group, note the location, and give them the radio, and return to class. When we returned to class, we noted the path and location on the map.
The exercise was interesting in surveying the problems surround tracking and GPS. Our group came up with the following observations:
-Tracking tags on receiver had to be numerically be the same as the tracking tags. The numbers were difficult to change. We made an error in changing the numbers and paired the receiver with wrong radio collar.
-static (noise surrounding radio signals) effected the sound of the beep of the locator. You had to do fine tuning between the tone and the gain knob to get an accurate reading. This is a difficult area to remedy because there is always going excess noise with a receiver signal that is that sensitive.
- Each reciever had an LED bar that lit up as you were closer to the target GPS radio collar. I liked this feature of the receiver’s interface could have been better. The bars could be a single light that increased in intensity so it minimized power usage.
-The receivers design was big and bulky. It would be difficult to run through the jungle with the antenna arms being 2 feet long.
- The gps collars had a nice weight. We have specific weight requirements per monkey. It would be interesting see how small we could make the GPS unit.
Assignment 1: Surveying Designs of DATA SETS
Our first assignment in Designing for Wildlife Interaction was to survey data collection problems. We split into groups, one focusing on monkeys at the zoo and the others focusing on humans. We were assigned humans. We decided to use the current data collection process in the context of a pick up basketball game at NYU. Here are our results:
There were several design challenges that came up during data collection. Mainly, it was time consuming transcribing all the written notes we took in to excel files. The obvious solution would be a digital note take system. The issue with that is the expectation of the interaction. Most note taking systems are designed specifically for one type of animal in one type of environment. Pen and Paper are essencial to the note taking process because the system is quick and efficient in the field.
We discussed a universal note taking platform or software where wildlife trackers could wireframe or design their own note take systems. The specific challenges are: speed of notes, observational categories, how do you create ways to make a new elements that is presented during an observation?, is the electronic device you are using waterproof?, can it with stand the humid environment?, how long is your devices battery life?, what is the platform compatible with?
There were a number more issues with the interface and how the data could be presented. This is a possible final project in the course– to redesign the note taking interface. We are still in the process of surveying and testing out current technology in camera traps, the housing of the tracking devices, GPS problems and so on… I may be taking on one of those issues.












