Archive for the ‘Level 3’ Category

Video Frame Capture using the Video Experimenter Shield

Difficulty Level = 3 [What’s this?]

In addition to overlaying text and graphics onto a video signal, the Video Experimenter shield can also be used to capture image data from a video source and store it in the Arduino’s SRAM memory. The image data can be displayed to a TV screen and can be overlayed onto the original video signal.

Believe it or not, the main loop of the program is this simple:

void loop() {
  tv.capture();
  tv.resume();
  tv.delay_frame(5);
}

 
For this project, we connect a video camera to the input of the Video Experimenter shield. The output select switch is set to “overlay” and the sync select jumper is set to “video input”. The video output is connected to an ordinary TV. When performing this experiment, turn the analog threshold potentiometer to the lowest value to start, then adjust it to select different brightness thresholds when capturing images.

By moving the output select switch to “sync only”, the original video source is not included in the output, only the captured monochrome image. You will need to adjust the threshold potentiometer (the one with the long shaft) to a higher value when the output switch is in this position. Experiment!

Monochrome video frame capture in Arduino memory




In the VideoFrameCapture.pde sketch below, we capture the image in memory by calling tv.capture(). When this method returns, a monochrome image is stored in the TVout frame buffer. The contents of the frame buffer are not displayed until we call tv.resume(). The code depends on the enhanced TVout library and your Arduino sketchbook structure should look like this:

Arduino
    |
    +--VideoFrameCapture
    |         |
    |         +--VideoFrameCapture.pde
    |
    +--libraries
              |
              +--TVout
              |     |
              |     +--...many files
              |
              +--TVoutfonts
                    |
                    +--...many files

Here is the Arduino code which can also be downloaded here. If you use a television with the PAL standard (that is, you are not in North America), change tv.begin(NTSC, W, H) to tv.begin(PAL, W, H).

#include <TVout.h>
#include <fontALL.h>
#define W 128
#define H 96

TVout tv;
unsigned char x,y;
char s[32];


void setup()  {
  tv.begin(NTSC, W, H);
  initOverlay();
  initInputProcessing();

  tv.select_font(font4x6);
  tv.fill(0);
}


void initOverlay() {
  TCCR1A = 0;
  // Enable timer1.  ICES0 is set to 0 for falling edge detection on input capture pin.              
  TCCR1B = _BV(CS10);

  // Enable input capture interrupt                                                                  
  TIMSK1 |= _BV(ICIE1);

  // Enable external interrupt INT0 on pin 2 with falling edge.                                      
  EIMSK = _BV(INT0);
  EICRA = _BV(ISC01);
}

void initInputProcessing() {
  // Analog Comparator setup                                                                         
  ADCSRA &= ~_BV(ADEN); // disable ADC                                                               
  ADCSRB |= _BV(ACME); // enable ADC multiplexer                                                     
  ADMUX &= ~_BV(MUX0); // select A2 for use as AIN1 (negative voltage of comparator)                
  ADMUX |= _BV(MUX1);
  ADMUX &= ~_BV(MUX2);
  ACSR &= ~_BV(ACIE);  // disable analog comparator interrupts                                       
  ACSR &= ~_BV(ACIC);  // disable analog comparator input capture                                    
}

ISR(INT0_vect) {
  display.scanLine = 0;
}

void loop() {
  tv.capture();                                                                                 
  tv.resume();
  tv.delay_frame(5);
}

Published by Michael, on March 20th, 2011 at 2:52 pm. Filed under: Arduino,Level 3,Video. | 50 Comments |

TV Blaster

Difficulty Level = 3 [What’s this?]

The Video Experimenter shield gives you new ways to interact with your TV. How many times did you wish you could blast someone or something on your TV screen? Now you can! This project lets you control a laser sight using a Wii nunchuk controller and fire an imaginary laser at the screen by pulling the trigger. Have fun.




A Wii nunchuk can be connected to your Arduino using the I2C pins (analog pins 4 and 5). I use a little Wiichuck PCB to make it easy (these are available in the nootropic design store because we sell them for use with Hackvision). Don’t connect the Wiichuck PCB directly on the Arduino analog pins 2-5 because analog pin 2 is used by the Video Experimenter.

Connect a nunchuk to your Arduino on analog pins 4 and 5

 

Data from the nunchuk is read using the Hackvision Controllers library.

The TVBlaster code can be downloaded it from here. Here’s the structure in your sketchbook folder:

Arduino
    |
    +--TVBlaster
    |         |
    |         +--TVBlaster.pde
    |         +--...other files
    |
    +--libraries
              |
              +--TVout
              |     |
              |     +--...many files
              |
              +--TVoutfonts
                    |
                    +--...many files

Published by Michael, on March 20th, 2011 at 1:48 pm. Filed under: Arduino,Level 3,Video. | 2 Comments |

Arduino Breathalyzer: Calibrating the MQ-3 Alcohol Sensor

Difficulty Level = 3 [What’s this?]

The MQ-3 is an alcohol gas sensor that is available for about $5 from Sparkfun, Seeed Studio, and others. It’s easy to use and has sparked the imagination of anyone who has dreamed of building their own breathalyzer device for measuring the amount of alcohol in the human body. I got an MQ-3 sensor a couple of months ago and have spent a lot of time trying to figure out how to do this. After lots of “data gathering”, I found that this task is not as easy as it sounds.

MQ-3 Alcohol Sensor

First of all, don’t try to use the MQ-3 as a way to determine if you are sober enough to drive. If you’ve been drinking, just don’t drive! And if you’ve had a few drinks, don’t do any soldering either.


Read more…


Published by Michael, on September 17th, 2010 at 6:43 pm. Filed under: Arduino,Level 3,Processing. | 65 Comments |

LED Clock

Difficulty Level = 3 [What’s this?]

I harvested this LED clock display from an ancient VCR and wrote an Arduino sketch to drive the display. First I experimented with the leads to understand which leads controlled what behavior. There are 4 digits on the display and there are 4 corresponding leads for positive voltage to drive them (the Arduino pins connected with the resistors). Then there are 7 ground pins (the yellow wires) that correspond to the seven segments on each digit (well, the leftmost digit only has 2 segments). There’s also a pin for the colon but one of the LEDs is burned out.

ClockShield!

ClockShield!

This display is driven in a typical manner by multiplexing between the 7 segments of each digit. The display is driven by sinking current on each of the seven segments in sequence, and sending current into the leads for any digit that needs to display that segment. Ouch, that’s confusing, so I’ll give an example. The first display ground pin (connected to pin 2 on the Arduino) is for the horizontal middle segment. Some numbers need the horizontal middle segment turned on, right? Numbers ‘0’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘8’, and ‘9’. So, the code sets the ground pin for this segment to LOW (to sink current), and for each of the four digits that need that segment, we set the digit pin to HIGH. If the number to display is ‘1027’, then when Arduino pin 2 is LOW (for the horizontal middle segment), we set the digit pins HIGH for the two middle digits (the ‘0’ and the ‘2’). Then we repeat this process for each of the 7 segments. If we do it fast enough, then persistence of vision makes it look like the LEDs are all on at the same time.

If you are unfamiliar with this multiplexing I’ve tried to explain, then study the code for the sketch. The array ‘number’ contains the information about what segments need to be on for each number. This might seem hard to understand at first, but I can guarantee an “ah ha!” moment when you get it.

// These are indexes into the groundPins array
#define MIDDLE 0
#define UPPER_L 1
#define LOWER_L 2
#define BOTTOM 3
#define LOWER_R 4
#define UPPER_R 5
#define TOP 6

int groundPins[7] = {2, 3, 4, 5, 6, 7, 8};
int digitPins[4] = {9, 10, 11, 12}; // positive voltage supply for each of the 4 digits
int ON = HIGH;
int OFF = LOW;
int number[10][7]; // holds information about which segments are needed for each of the 10 numbers
int digit[4]; // holds values for each of the 4 display digits

int hours = 12;
int minutes = 8;
int elapsedMinutes = 0;
int seconds = 0;

void setup()
{
  initNumber();

  for(int i=0; i < 7; i++) {
    pinMode(groundPins[i], OUTPUT);
    digitalWrite(groundPins[i], HIGH);
  }
  for(int i=0; i < 4; i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], LOW);
  }
}

void loop() {
  int n = 0;
  unsigned long time = millis() - (elapsedMinutes * 60000);
  seconds = (time / 1000);
  if (seconds > 60) {
    seconds = 0;
    minutes++;
    elapsedMinutes++;
    if (minutes >= 60) {
      minutes = 0;
      hours++;
      if (hours > 12) {
        hours = 1;
      }
    }
  }

  n = (hours * 100) + minutes;
  setDigit(n);

  for(int g=0; g < 7; g++) {
    digitalWrite(groundPins[g], LOW);
    for(int i=0; i < 4; i++) {
      if (digit[i] < 0) {
        continue;
      }
      digitalWrite(digitPins[i], number[digit[i]][g]);
    }
    delay(getDelay());
    digitalWrite(groundPins[g], HIGH);
  }
}

void setDigit(int n) {
  n = n % 2000;
  digit[0] = n % 10;
  digit[1] = (n / 10) % 10;
  if ((digit[1] == 0) && (n < 10)) {
    digit[1] = -1;
  }
  digit[2] = (n / 100) % 10;
  if ((digit[2] == 0) && (n < 100)) {
    digit[2] = -1;
  }
  digit[3] = (n / 1000) % 10;
  if (digit[3] == 0) {
    digit[3] = -1;
  }
}

int getDelay() {
  if (millis() > 10000) {
    return 0;
  } else {
    return (int) (((10000 - millis()) / 10000.0) * 125);
  }
} 

void initNumber() {
  number[0][MIDDLE]  = OFF;
  number[0][UPPER_L] = ON;
  number[0][LOWER_L] = ON;
  number[0][BOTTOM]  = ON;
  number[0][LOWER_R] = ON;
  number[0][UPPER_R] = ON;
  number[0][TOP]     = ON;

  number[1][MIDDLE]  = OFF;
  number[1][UPPER_L] = OFF;
  number[1][LOWER_L] = OFF;
  number[1][BOTTOM]  = OFF;
  number[1][LOWER_R] = ON;
  number[1][UPPER_R] = ON;
  number[1][TOP]     = OFF;

  number[2][MIDDLE]  = ON;
  number[2][UPPER_L] = OFF;
  number[2][LOWER_L] = ON;
  number[2][BOTTOM]  = ON;
  number[2][LOWER_R] = OFF;
  number[2][UPPER_R] = ON;
  number[2][TOP]     = ON;

  number[3][MIDDLE]  = ON;
  number[3][UPPER_L] = OFF;
  number[3][LOWER_L] = OFF;
  number[3][BOTTOM]  = ON;
  number[3][LOWER_R] = ON;
  number[3][UPPER_R] = ON;
  number[3][TOP]     = ON;

  number[4][MIDDLE]  = ON;
  number[4][UPPER_L] = ON;
  number[4][LOWER_L] = OFF;
  number[4][BOTTOM]  = OFF;
  number[4][LOWER_R] = ON;
  number[4][UPPER_R] = ON;
  number[4][TOP]     = OFF;

  number[5][MIDDLE]  = ON;
  number[5][UPPER_L] = ON;
  number[5][LOWER_L] = OFF;
  number[5][BOTTOM]  = ON;
  number[5][LOWER_R] = ON;
  number[5][UPPER_R] = OFF;
  number[5][TOP]     = ON;

  number[6][MIDDLE]  = ON;
  number[6][UPPER_L] = ON;
  number[6][LOWER_L] = ON;
  number[6][BOTTOM]  = ON;
  number[6][LOWER_R] = ON;
  number[6][UPPER_R] = OFF;
  number[6][TOP]     = ON;

  number[7][MIDDLE]  = OFF;
  number[7][UPPER_L] = OFF;
  number[7][LOWER_L] = OFF;
  number[7][BOTTOM]  = OFF;
  number[7][LOWER_R] = ON;
  number[7][UPPER_R] = ON;
  number[7][TOP]     = ON;

  number[8][MIDDLE]  = ON;
  number[8][UPPER_L] = ON;
  number[8][LOWER_L] = ON;
  number[8][BOTTOM]  = ON;
  number[8][LOWER_R] = ON;
  number[8][UPPER_R] = ON;
  number[8][TOP]     = ON;

  number[9][MIDDLE]  = ON;
  number[9][UPPER_L] = ON;
  number[9][LOWER_L] = OFF;
  number[9][BOTTOM]  = ON;
  number[9][LOWER_R] = ON;
  number[9][UPPER_R] = ON;
  number[9][TOP]     = ON;
}

Now for the fun. The getDelay() method returns a delay based on how long the sketch has been running. First we start with a longer delay (125ms) between each segment so you can see visually how the digits are being rendered. Over the course of 10 seconds, we reduce the delay to 0. This way you can see exactly how quickly rendering the display causes you to see the digits without ficker even though each segment is being displayed separately! Cool, huh?


Published by Michael, on October 25th, 2009 at 9:53 pm. Filed under: Arduino,Level 3. | 5 Comments |