As computing becomes more ubiquitous in our objects, designers need to be more aware of how to design meaningful interactions into electronically enhanced objects. At the University of Washington, a class of junior Interaction Design majors is exploring this question. These pages chronicle their efforts.

Tuesday, June 11, 2013

Sensor + Actuator Combo [Maddie and Candice]

Maddie and I kept trying to figure out why our code wasn't working. We kept getting the error "avrdude: stk500_getsync(): not in sync: resp=0x00".

We realized after asking Matt from Metrix Create Space that the reason we were getting this error was because we had the TXD and RXD pins plugged in as we were trying to upload the code into Arduino, and we had to disconnect it before uploading and connect it back after the upload was complete.

After fixing this problem, we were able to get the camera board to take a picture and the system to write a file on the SD Card. This happened a total of at least 5 times. However, they were only flukes because about 2/5 times, the picture was blurry, and the rest of the time, the file written was an empty JPEG (Zero bytes). We looked into the Serial Monitor, and it was displaying unreadable gibberish text. We continued to ask Matt for help, but eventually we deduced that the code from RadioShack might not be configured properly.

It was at this point that we had to leave Metrix because it was time for them to close. However, Matt said that Richard would be on duty the following morning, and that Richard was a smart guy who would be able to help us with our Arduino problem.

We spent most of the next day at Metrix. Richard worked with us on troubleshooting the code. As hours trickled by, we slowly isolated the problem, and with additional help from other random strangers from Metrix (oh, my gosh, Metrix is amazing!!), Maddie and I (and Richard, and Dan, and Aaron) concluded that there was simply something wrong with the code.

The system first kept getting stuck at the capture_photo function, and seemed like it was randomizing writing the file when the picture was supposedly taken. As we narrowed down where the problem code was, it soon became clear that the code provided by RadioShack for both the camera board and SD card shield, which we customized, was broken. It wouldn't even take a write the picture file anymore. As neither Maddie nor I knew enough about going into the code libraries for camera shield and SD card shield to fix the code, and upon confirming that it wouldn't be an easy task for our generous helpers either, we finally accepted that Maddie and I could not fit this square peg of our vision into the round hole of the equipment and code we got from RadioShack.

Fearing the very real possibility that our code ultimately would not work the day before, and that the solution to our design situation might not become a reality, Maddie and I had brainstormed other alternatives. One of the ideas that stuck because we thought it was silly, and would be fun to do, was this thought of a motion-triggered water gun/cannon to ward off intruders/lurkers/pee-happy dogs. However, upon further thought, we found that we didn't like the negative connotations of guns or cannons, and that we wanted to do something more approachable. We still wanted to have motion be the thing that was being sensed, and re-devised a situation.

Perhaps in a "life imitates art" sort of way, one of the situations we discussed kept getting revisited: stress relief.

We asked ourselves, how could Arduino solve the problem of stress? Perhaps it was inspired from our water gun/cannon idea, but we came up with something pretty smile-inducing: bubbles.

There's no way you could say "bubbles" angry.

So, with this Plan B at the back of our mind, we simultaneously tried to build a working motion-triggered bubble machine while trying to fix the code for the camera. And we succeeded!




Below are some codes (in final stages) we used to try to isolate and fix the problem.



CUSTOMIZED CODE FROM http://stratigrafia.org/blog/entries/2012-09-01.html

(There are redundancies on this code, but it shouldn't affect the outcome. Our new friend Dan, who seemed pretty knowledgeable on Arduino, looked over this code and found nothing that stood out to him as wrong.)


// Based on http://luckylarry.co.uk/arduino-projects/arduino-motion-triggered-camera/
// The sequence of pulses needed appears to have been reverse engineered at http://www.bigmike.it/ircontrol/
// This is another useful site on the subject: http://www.bemasher.net/archives/114




//BEGIN CAMERA STUFF


/******************** (C) COPYRIGHT 2012 RadioSHack ********************
 * File Name          : camsd.pde
 * Author             : TRS
 * Version            : V1.0
 * Date               : 28/05/2012
 * Description        : Main program body
 ********************************************************************************
 * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
 * AS A RESULT, RS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
 * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
 * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
 * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
 *******************************************************************************/

#include <avr/pgmspace.h>
#include "Arduino.h"


/*
 * The following code includes all necessary routines to control Camera Shield
 *
 * In addition, we have prepared a example for making surveillance camera by putting Camera shield (RS SKU 2760248) and SD Card shield (RS SKU 2760243) together.
 * 1) Install SD Card shield properly and download all necessary FAT drivers from shield providers
 * 2) Install Camera shield properly
 * 3) Enable "#define sdCamera 1" to enable the demo code
 * 4) With the built-in motion detection function, camera shield will capture image and store to SD card automatically .
 *
 */

#define sdCamera 1 // ***** Enable it for Surveillance Camera demonstration *****

#ifdef sdCamera
#include <Sd2Card.h> // ***** SD card driver from http://www.seeedstudio.com/wiki/SD_Card_Shield or SD card shield supplier *****
#include <SdFat.h> // ***** FAT file system from http://www.seeedstudio.com/wiki/SD_Card_Shield or SD card shield supplier *****
#endif



/*
 * SD chip select pin.  Common values are:
 *
 * Arduino Ethernet shield, pin 4.
 * SparkFun SD shield, pin 8.
 * Adafruit SD shields and modules, pin 10.
 * Default SD chip select is the SPI SS pin.
 */

#ifdef sdCamera
const uint8_t SdChipSelect = SS;
SdFat sd;
Sd2Card card;
SdFile myFile;
#endif

#define NORMAL_USE 1

#define VC0706_PROTOCOL_SIGN  0x56
#define VC0706_SERIAL_NUMBER  0x00

#define VC0706_COMMAND_RESET 0x26
#define VC0706_COMMAND_GEN_VERSION 0x11
#define VC0706_COMMAND_TV_OUT_CTRL 0x44
#define VC0706_COMMAND_OSD_ADD_CHAR 0x45
#define VC0706_COMMAND_DOWNSIZE_SIZE 0x53
#define VC0706_COMMAND_READ_FBUF 0x32
#define FBUF_CURRENT_FRAME 0
#define FBUF_NEXT_FRAME 0

#define VC0706_COMMAND_FBUF_CTRL 0x36
#define VC0706_COMMAND_COMM_MOTION_CTRL 0x37
#define VC0706_COMMAND_COMM_MOTION_DETECTED 0x39
#define VC0706_COMMAND_POWER_SAVE_CTRL 0x3E
#define VC0706_COMMAND_COLOR_CTRL 0x3C
#define VC0706_COMMAND_MOTION_CTRL 0x42


#define VC0706_COMMAND_WRITE_DATA 0x31
#define VC0706_COMMAND_GET_FBUF_LEN 0x34

#define READ_DATA_BLOCK_NO 56




unsigned char  tx_counter;
unsigned char  tx_vcbuffer[20];
bool tx_ready;

bool rx_ready;
unsigned char  rx_counter;
unsigned char  VC0706_rx_buffer[80];

uint32_t  frame_length=0;

uint32_t  vc_frame_address =0;

uint32_t  last_data_length=0;


// END CAMERA STUFF




int pirPin = 4; // digital pin 4 for PIR; put a 10k Ohm resistor between pin 4 and OUT on PIR
int ledPin = 7; // digital pin 13 for LED; put a 220 Ohm resistor between pin 13 and the LED
int IRPin = 2; // assign the Infrared emitter/ diode to pin 2; connect other lead of IR diode into ground
int noMotion = 1;
int TIP120pin = 9; //for this project, I pick Arduino's PMW pin 11

// pulse the infrared emitter for a specified duration (in microseconds)
void pulseON(int pulseDuration) {
  unsigned long endPulse = micros() + pulseDuration; // calculate time when pulse should stop
  int halfCycle = 13; // half a clock cycle for a 38 Khz (26.32 microseconds period) wave
  while(micros() < endPulse) {
    digitalWrite(IRPin, HIGH); // emit IR for half a cycle
    delayMicroseconds(halfCycle);
    digitalWrite(IRPin, LOW); // stop emitting for half a cycle
    delayMicroseconds(halfCycle);
  }
}

// stop pulsing the infrared emitter for a specified duration (in microseconds)
void pulseOFF(unsigned long delayDuration) {
  unsigned long endDelay = micros() + delayDuration; // calculate time when delay is over
  while(micros() < endDelay);
}

// sequence of pulses for taking a picture on a Nikon D80 camera
void takePicture() {
  for (int i=0; i<2; i++) {
    pulseON(2000); // pulse for 2000 microseconds,
    pulseOFF(27850); // then off for 27850 microseconds,
    pulseON(390); // on for 390 microseconds, and so on
    pulseOFF(1580);
    pulseON(410);
    pulseOFF(3580);
    pulseON(400);
    pulseOFF(63200);
  } // loop the signal twice.
}

void setup() {

  Serial.begin(115200);
  Serial.println("Hello, world");

  pinMode(pirPin, INPUT); // set PIR pin as input
  pinMode(ledPin, OUTPUT); // set LED pin as output
  pinMode(IRPin, OUTPUT); // set pin as output
  pinMode(TIP120pin, OUTPUT); // Set pin for output to control TIP120 Base pin
  //attachInterrupt(0, capture_photo, CHANGE); // When pin 0 changes, camera takes a picture.
}



void loop() {
  int movementSensor=digitalRead(pirPin);

  if(movementSensor == HIGH) {
  // motion detected
    if (noMotion == 0) {
  // take picture only if coming from a state of no motion
      digitalWrite(TIP120pin, HIGH);
      digitalWrite(ledPin, HIGH);
      //takePicture();
      capture_photo();
      noMotion=1;
  //    delay(5000); // wait 5 seconds between pictures
    }
  } else {
    // No motion
    digitalWrite(TIP120pin, LOW);
    digitalWrite(ledPin, LOW);
    noMotion=0;
  }
}


// BEGIN BUFFER SEND

/*******************************************************************************
 * Function Name  : buffer_send
 * Description    : Transmit buffer to VC0706
 *              
 * Input          : tx_vcbuffer
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void buffer_send()
{
int i=0;

for (i=0;i<tx_counter;i++)
Serial.write(tx_vcbuffer[i]);

tx_ready=true;
}

// END BUFFER SEND


// BEGIN FRAME_CONTROL

/*******************************************************************************
 * Function Name  : VC0706_frame_control
 * Description    : control frame buffer register
 *              
 * Input          : frame_control=control flag(1byte)
 * 0 = stop current frame ; 1= stop next frame;2=step frame;3 =resume frame;
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_frame_control(byte frame_control)
{
if(frame_control>3)frame_control=3;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_FBUF_CTRL;
tx_vcbuffer[3]=0x01;
tx_vcbuffer[4]=frame_control;
tx_counter=5;

buffer_send();
}


// END FRAME_CONTROL



// BEGIN PASTE STUFF 1


/*******************************************************************************
 * Function Name  : VC0706_compression_ratio
 * Description   : stop current frame for reading
 *
 * Input   : ration >13(minimum)
 * <63(max)
 *
 * Output   : None
 * Return   : None
 *******************************************************************************/
void VC0706_compression_ratio(int ratio)
{
if(ratio>63)ratio=63;
if(ratio<13)ratio=13;
int vc_comp_ratio=(ratio-13)*4+53;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_WRITE_DATA;
tx_vcbuffer[3]=0x05;
tx_vcbuffer[4]=01; //chip register
tx_vcbuffer[5]=0x01; //data num ready to write
tx_vcbuffer[6]=0x12; //register address
tx_vcbuffer[7]=0x04;
tx_vcbuffer[8]=vc_comp_ratio; //data

tx_counter=9;

buffer_send();
}

// END PASTE STUFF 1


// BEGIN GET FRAMEBUFFER LENGTH


/*******************************************************************************
 * Function Name  : VC0706_get_framebuffer_length
 * Description    : get byte-lengths in FBUF
 *              
 * Input          : fbuf_type =current or next frame
 *             0   =  current frame
 *      1   =  next frame
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_get_framebuffer_length(byte fbuf_type)
{
if(fbuf_type>1)fbuf_type=1;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_GET_FBUF_LEN;
tx_vcbuffer[3]=0x01;
tx_vcbuffer[4]=fbuf_type;
tx_counter=5;

buffer_send();
}


// END GET FRAMEBUFFER LENGTH

// BEGIN BUFFER READ

/*******************************************************************************
 * Function Name  : buffer_read
 * Description    : Receive buffer from VC0706
 *              
 * Input          : None
 *              
 * Output         : rx_buffer, rx_ready
 * Return         : None
 *******************************************************************************/
void buffer_read()
{
bool validity=true;

if (rx_ready) // if something unread in buffer, just quit
return;

rx_counter=0;
VC0706_rx_buffer[0]=0;
while (Serial.available() > 0)
{
VC0706_rx_buffer[rx_counter++]= Serial.read();
//delay(1);
}

if (VC0706_rx_buffer[0]!=0x76)
validity=false;
if (VC0706_rx_buffer[1]!=VC0706_SERIAL_NUMBER)
validity=false;

if (validity) rx_ready=true;


}

// END BUFFER READ


// BEGIN READ FRAME BUFFER

/*******************************************************************************
 * Function Name  : VC0706_read_frame_buffer
 * Description    : read image data from FBUF
 *              
 * Input          : buffer_address(4 bytes); buffer_length(4 bytes)
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_read_frame_buffer(unsigned long buffer_address, unsigned long buffer_length)
{

tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_READ_FBUF;
tx_vcbuffer[3]=0x0c;
tx_vcbuffer[4]=FBUF_CURRENT_FRAME;
tx_vcbuffer[5]=0x0a; // 0x0a=data transfer by MCU mode; 0x0f=data transfer by SPI interface
tx_vcbuffer[6]=buffer_address>>24; //starting address
tx_vcbuffer[7]=buffer_address>>16;
tx_vcbuffer[8]=buffer_address>>8;
tx_vcbuffer[9]=buffer_address&0x0ff;

tx_vcbuffer[10]=buffer_length>>24; // data length
tx_vcbuffer[11]=buffer_length>>16;
tx_vcbuffer[12]=buffer_length>>8;
tx_vcbuffer[13]=buffer_length&0x0ff;
tx_vcbuffer[14]=0x00; // delay time
tx_vcbuffer[15]=0x0a;


tx_counter=16;

buffer_send();
}


// END READ FRAME BUFFER


#ifdef sdCamera

/*******************************************************************************
 * Function Name  : capture_photo
 * Description   : capture a photo and store the file named temp.jpg into SD
 *
 * Input   : None
 *
 * Output   : None
 * Return   : None
 *******************************************************************************/
void capture_photo(){

// Check to see if the file exists:
// if exists,delete the file:
if(sd.exists("temp.jpg")) sd.remove("temp.jpg");

  Serial.println("A");
// open a new empty file for write at end like the Native SD library
 if (!myFile.open("temp.jpg", O_RDWR | O_CREAT | O_AT_END)) {
   sd.errorHalt("opening temp.jpg for write failed");
 }

  Serial.println("b");
// close the file:
 myFile.close();

VC0706_compression_ratio(63);
delay(100);
  Serial.println("c");

VC0706_frame_control(3);
delay(10);
  Serial.println("d");

VC0706_frame_control(0);
delay(10);
rx_ready=false;
rx_counter=0;
  Serial.println("e");

//Serial.end(); // clear all rx buffer
//delay(5);

//Serial.begin(115200);

//get frame buffer length
VC0706_get_framebuffer_length(0);
delay(10);
buffer_read();

//while(1){};

// store frame buffer length for coming reading
frame_length=(VC0706_rx_buffer[5]<<8)+VC0706_rx_buffer[6];
frame_length=frame_length<<16;
frame_length=frame_length+(0x0ff00&(VC0706_rx_buffer[7]<<8))+VC0706_rx_buffer[8];

vc_frame_address =READ_DATA_BLOCK_NO;

myFile.open("temp.jpg", O_RDWR);
while(vc_frame_address<frame_length){
VC0706_read_frame_buffer(vc_frame_address-READ_DATA_BLOCK_NO, READ_DATA_BLOCK_NO);
delay(9);

//get the data with length=READ_DATA_BLOCK_NObytes
rx_ready=false;
rx_counter=0;
buffer_read();

// write data to temp.jpg
myFile.write(VC0706_rx_buffer+5,READ_DATA_BLOCK_NO);

//read next READ_DATA_BLOCK_NO bytes from frame buffer
vc_frame_address=vc_frame_address+READ_DATA_BLOCK_NO;

}

// get the last data
vc_frame_address=vc_frame_address-READ_DATA_BLOCK_NO;

last_data_length=frame_length-vc_frame_address;


VC0706_read_frame_buffer(vc_frame_address,last_data_length);
delay(9);
//get the data
rx_ready=false;
rx_counter=0;
buffer_read();

myFile.write(VC0706_rx_buffer+5,last_data_length);

myFile.close();

}

#endif








BASIC SD CARD WRITE

void setup()
{
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);
  //Serial.begin(115200);
  if (!myFile.open("temp.jpg", O_RDWR | O_CREAT | O_AT_END)) {
     sd.errorHalt("opening temp.jpg for write failed");
   }
  //Serial.println("success");
  digitalWrite(13,LOW);
}

void loop()
{


}

No comments:

Post a Comment