Here is a brief break down of the things to do:
- Review array code from last week and discuss in depth what arrays are and how they are to be used.
- Map a potentiometer to multiple LEDs.
- Use your body as a sensor to control a group of LEDs.
- Use a potentiometer attached to the Arduino to adjust the speed of a movie playing in Processing.
- Control a drawing program with values sent from Arduino.
Arrays and For Loops:
Arrays are a way of declaring multiple of the same type of variable in a row in memory. Usually they are used with the idea that the values are multiples of the same type of object. What I mean is while the value of the photocell is an integer it doesn't make sense to include it in an array of integers that represent the digital pins used to power LEDs. Arrays are declared a little differently then other variables. Here are a few ways to declare an array:
int myInts[6];// this creates an array that has 6 places but does not define what the values are
int myPins[] = {2, 4, 8, 3, 6};// this creates an array of 5 places and defines the values
int mySensVals[6] = {2, 4, -8, 3, 2};// this creates an array of 6 places but only defines the first 5 values
This is how you access the values that are store in the arrays above:
myPins[0], where the value would equal 2.
The number inside of the square brackets [ ] indicates which element to access. Arrays are 0 based, meaning the first element is considered the 0 place not the 1st place.
Here is how you change the value of an element of an array:
myPins[1] = 9;// now the values for myPins look like this: {2, 9, 8, 3, 6}
The real power of arrays is unleashed when combined with for loops. The structure of a for loop is a little confusing at first, but once you understand how to use them they are essential. Basically a for loop is a way of repeating a command a determined number of times. You can use an array to count from any number by any number to any number. This makes it perfect for working with arrays because instead of manually putting 0-4 inside of the [ ] to access the values of myPins array, you can use a variable.
Here is a for loop that prints the values of myPins array to the serial monitor:
for(int i = 0; i < 5; i++){
Serial.print(myPins[i]);
Serial.print(", ");
}
Serial.println();
This snippet of code will display the values with a comma and space between each value and then a line break after the last element has been printed. I recommend that you take a look at the for loop link above. The guys at Arduino have a wonderful description of how the mechanics work.
Lets make the circuit below and use the map function to control a group of LEDs with a potentiometer.
Lets make this circuit to use our bodies to control LEDs.
So far we have been adjusting the values of the min and max for calibrating using the serial window to manually monitor for the lowest and highest values. This time we are going to use an example sketch to have the Arduino do the calibration for us. Open the calibration sketch, it can be found inside of /Examples/Analog/Calibration. ( or copy and paste the code below )
/*CalibrationDemonstrates one technique for calibrating sensor input. Thesensor readings during the first five seconds of the sketchexecution define the minimum and maximum of expected valuesattached to the sensor pin.The sensor minimum and maximum initial values may seem backwards.Initially, you set the minimum high and listen for anythinglower, saving it as the new minimum. Likewise, you set themaximum low and listen for anything higher as the new maximum.The circuit:* Analog sensor (potentiometer will do) attached to analog input 0* LED attached from digital pin 9 to groundcreated 29 Oct 2008By David A MellisModified 4 Sep 2010By Tom Igoehttp://arduino.cc/en/Tutorial/CalibrationThis example code is in the public domain.*/// These constants won't change:const int sensorPin = A0; // pin that the sensor is attached toconst int ledPin = 9; // pin that the LED is attached to// variables:int sensorValue = 0; // the sensor valueint sensorMin = 1023; // minimum sensor valueint sensorMax = 0; // maximum sensor valuevoid setup() {// turn on LED to signal the start of the calibration period:pinMode(13, OUTPUT);digitalWrite(13, HIGH);// calibrate during the first five secondswhile (millis() < 5000) {sensorValue = analogRead(sensorPin);// record the maximum sensor valueif (sensorValue > sensorMax) {sensorMax = sensorValue;}// record the minimum sensor valueif (sensorValue < sensorMin) {sensorMin = sensorValue;}}// signal the end of the calibration perioddigitalWrite(13, LOW);}void loop() {// read the sensor:sensorValue = analogRead(sensorPin);// apply the calibration to the sensor readingsensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);// in case the sensor value is outside the range seen during calibrationsensorValue = constrain(sensorValue, 0, 255);// fade the LED using the calibrated value:analogWrite(ledPin, sensorValue);}
When you upload the code you will notice that only the LED attached to pin 9 seems to light up. To make all of the LEDs work similar to last weeks photo resistor circuit copy and paste the following code.
/*Using an array of digital pins and a for loop to easily contol LEDswith a mapped value from a photocellAs you can see, using arrays and for loops makes your code a lot smallerand easy to change.Matt Richardhttp://idblab.blogspot.com*/int sensorPin = A0; // select the input pin for the potentiometerint ledPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};int sensorValue = 0; // variable to store the value coming from the sensorint minThresh = 1023;int maxThresh = 0;void setup() {Serial.begin(9600);for(int i = 0; i < 10; i++){pinMode(ledPins[i], OUTPUT);}// turn on LED to signal the start of the calibration period:pinMode(13, OUTPUT);digitalWrite(13, HIGH);// calibrate during the first five secondswhile (millis() < 5000) {sensorValue = analogRead(sensorPin);// record the maximum sensor valueif (sensorValue > maxThresh) {maxThresh = sensorValue;}// record the minimum sensor valueif (sensorValue < minThresh) {minThresh = sensorValue;}}// signal the end of the calibration perioddigitalWrite(13, LOW);}void loop() {// read the value from the sensor:sensorValue = analogRead(sensorPin);Serial.println(sensorValue);controlLEDs();}void controlLEDs(){int numLEDsOn = map(sensorValue, minThresh, maxThresh, 0, 10);for(int i = 0; i < numLEDsOn; i++){digitalWrite(ledPins[i], HIGH);}for(int j = numLEDsOn; j < 10; j++){digitalWrite(ledPins[j], LOW);}}
Using Arduino and Processing together:
First off, what is Processing? From the processing website:
Processing is a programming language, development environment, and online community that since 2001 has promoted software literacy within the visual arts. Initially created to serve as a software sketchbook and to teach fundamentals of computer programming within a visual context, Processing quickly developed into a tool for creating finished professional work as well.
There are a few ways to work with Arduino and Processing, but I am going to demonstrate only one way today. If you are interested you can check out the Arduino library available in Processing. The library allows you to make Arduino calls directly from Processing.
Today we are going to send a byte through serial to Processing and use that value to adjust the speed of a looping movie. Let's start off by making a simple circuit with the Arduino using a potentiometer and 2 different colored LEDs. The potentiometer will give us a value and the LEDs will give us an idea of what that value is before it gets to Processing. Go ahead and make the circuit in the following image. In your ladyada kit you have 3 clear LEDs, one red, one green, and pen blue. The diagram shows 2 clear LEDs wired to different PWM pins, any 2 of the clear will do because we know they will different. This is to help differentiate between when the video will be playing forwards and backwards.
Now lets throw the following code into Arduino and upload it to your board.
/*** Send a byte through Serial to be used by Processing* I am pretty sure the original code was written by Tom Igoe*/int analogPin = 0;int analogValue = 0;int forwardLedPin = 3;int backwardLedPin = 11;int pwmValue = 0;void setup(){// start serial port at 9600 bps:Serial.begin(9600);}void loop(){// read analog input, divide by 4 to make the range 0-255:analogValue = analogRead(analogPin);analogValue = analogValue / 4;Serial.print(analogValue, BYTE);// figure out which LED should be on// if the values are between 0-127, then the backwardLed should be litif(analogValue <= 127){pwmValue = map(analogValue, 127, 0, 0, 255);analogWrite(backwardLedPin, pwmValue);analogWrite(forwardLedPin, 0);// this will make sure the other LED is off}// if the values are between 128-255, then the forwardLed should be lit// pwm an led to show that the pot is workingif(analogValue >= 128){pwmValue = map(analogValue, 128, 255, 0, 255);analogWrite(forwardLedPin, pwmValue);analogWrite(backwardLedPin, 0);// this will make sure the other LED is off}// pause for 10 milliseconds:delay(10);}
The code maps the value of your potentiometer to light up one LED with one half of the values and light tup the other with the other half of values. The center position of the potentiometer will render both LEDs off. These results mimic how the Processing will react to the values of the potentiometer.
Lets open up Processing and load the loop example for the video library. You can find the sketch by looking in the following folders /Examples/Library/Video(movie)/Loop. Now press the play button in the upper left of the Processing IDE. You will see a transparent video playing and leaving trails where ever your mouse is. This is neat but not what we are after. Go ahead and paste the code I have below into Processing replacing all of the code for the Loop sketch.
/*** Loop Video with values sent from Arduino.** Using an Arduino and Potentiometer, contro the playback speed of a video* Recieve values using Serial I/O library*/import processing.video.*;// import video libraryimport processing.serial.*;// import serial libraryMovie myMovie; // The movie objectfloat timeJump = 0.0; // amount of time that is displaced when scrubbing the movie in reversefloat timePrevious = 0.0; // the last position of the playheadfloat timeFuture = 0.0; // the future position of the playheadfloat videoSpeed = 0.0; // the speed at which the video playsfloat maxSpeed = 5.0;float minSpeed = -5.0;Serial myPort; // The serial portvoid setup() {size(640, 480, P2D);background(0);// Load and play the video in a loopmyMovie = new Movie(this, "station.mov");myMovie.loop();println(Serial.list());myPort = new Serial(this, Serial.list()[0], 9600);}void movieEvent(Movie myMovie) {myMovie.read();}void draw() {// tint(255, 30);if(videoSpeed < 0) {timeJump = myMovie.time() - timePrevious;timeFuture = myMovie.time() + timeJump;if(timeFuture <= 0) {// we only need to ajust the playhead if the playhead goes past// the beginning of the movie in reversefloat newBackwardsTime = myMovie.duration() + timeFuture;myMovie.jump(newBackwardsTime);}}myMovie.speed(videoSpeed);image(myMovie, 0, 0, width, height);timePrevious = myMovie.time();}/*** serialEvent** This function access the values coming in from the serial port* It assigns the values to the play speed of the video, called videoSpeed* The videoSpeed has a range of -5x to +5x normal playing speed* These values are determined by the minSpeed and maxSpeed variables* If you alter them you can change the range of speed the video will play* For this to work, an Arduino must be sending one byte through the serial port*/void serialEvent (Serial myPort) {// get the byte:int inByte = myPort.read();videoSpeed = map(inByte, 0, 255, minSpeed, maxSpeed);// print it:println(inByte);}// This can be tested with using the keys if you are unable to access and Arduino and potentiometer// The UP key increases the speed and the DOWN key decreases the speedvoid keyPressed() {if(keyCode == UP) {videoSpeed += 0.1;videoSpeed = constrain(videoSpeed, minSpeed, maxSpeed);}if(keyCode == DOWN) {videoSpeed -= 0.1;videoSpeed = constrain(videoSpeed, minSpeed, maxSpeed);}println("adjusted videoSpeed with keys to: " + videoSpeed);}
/**
* Loop Video with values sent from Arduino.
*
* Using an Arduino and Potentiometer, contro the playback speed of a video
* Recieve values using Serial I/O library
*/
import processing.serial.*;// import serial library
float diameter = 0.0; // the speed at which the video plays
float maxSpeed = 200.0;
float minSpeed = 1.0;
Serial myPort; // The serial port
void setup() {
size(600, 600);
background(0);
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
}
void draw() {
ellipse(mouseX, mouseY, diameter, diameter);
}
/**
* serialEvent
*
* This function access the values coming in from the serial port
* It assigns the values to the play speed of the video, called videoSpeed
* The videoSpeed has a range of -5x to +5x normal playing speed
* These values are determined by the minSpeed and maxSpeed variables
* If you alter them you can change the range of speed the video will play
* For this to work, an Arduino must be sending one byte through the serial port
*/
void serialEvent (Serial myPort) {
// get the byte:
int inByte = myPort.read();
diameter = map(inByte, 0, 255, minSpeed, maxSpeed);
// print it:
println(inByte);
}
// This can be tested with using the keys if you are unable to access and Arduino and potentiometer
// The UP key increases the speed and the DOWN key decreases the speed
void keyPressed() {
if(keyCode == UP) {
diameter += 0.1;
diameter = constrain(diameter, minSpeed, maxSpeed);
}
if(keyCode == DOWN) {
diameter -= 0.1;
diameter = constrain(diameter, minSpeed, maxSpeed);
}
println("adjusted diameter with keys to: " + diameter);
}
Here we are able to adjust a sketch created by Dan Shiffman to allow interaction with a webcam and the arduino. We are also saving out a .mov file when you press spacebar.
/*** Mirror* by Daniel Shiffman.** Each pixel from the video source is drawn as a rectangle with rotation based on brightness.*/import processing.video.*;import processing.serial.*;// import serial libraryfloat diameter = 0.0; // the speed at which the video playsfloat maxSpeed = 200.0;float minSpeed = 1.0;MovieMaker mm; // Declare MovieMaker objectSerial myPort; // The serial port// Size of each cell in the gridint cellSize = 20;// Number of columns and rows in our systemint cols, rows;// Variable for capture deviceCapture video;void setup() {size(640, 480, P2D);frameRate(30);cols = width / cellSize;rows = height / cellSize;colorMode(RGB, 255, 255, 255, 100);// Uses the default video input, see the reference if this causes an errorvideo = new Capture(this, width, height, 12);println(Serial.list());myPort = new Serial(this, Serial.list()[0], 9600);mm = new MovieMaker(this, width, height, "drawing.mov",30, MovieMaker.ANIMATION, MovieMaker.MEDIUM);background(0);}void draw() {if (video.available()) {video.read();video.loadPixels();// Not bothering to clear background// background(0);// Begin loop for columnsfor (int i = 0; i < cols; i++) {// Begin loop for rowsfor (int j = 0; j < rows; j++) {// Where are we, pixel-wise?int x = i*cellSize;int y = j*cellSize;int loc = (video.width - x - 1) + y*video.width; // Reversing x to mirror the imagefloat r = red(video.pixels[loc]);float g = green(video.pixels[loc]);float b = blue(video.pixels[loc]);// Make a new color with an alpha componentcolor c = color(r, g, b, 75);// Code for drawing a single rect// Using translate in order for rotation to work properlypushMatrix();translate(x+cellSize/2, y+cellSize/2);// Rotation formula based on brightnessrotate((2 * PI * brightness(c) / 255.0));rectMode(CENTER);fill(c);noStroke();// Rects are larger than the cell for some overlaprect(0, 0, diameter, diameter);popMatrix();}}// want to record video into movie filemm.addFrame(); // Add window's pixels to movie}}/*** serialEvent** This function access the values coming in from the serial port* It assigns the values to the play speed of the video, called videoSpeed* The videoSpeed has a range of -5x to +5x normal playing speed* These values are determined by the minSpeed and maxSpeed variables* If you alter them you can change the range of speed the video will play* For this to work, an Arduino must be sending one byte through the serial port*/void serialEvent (Serial myPort) {// get the byte:int inByte = myPort.read();diameter = map(inByte, 0, 255, minSpeed, maxSpeed);// print it:println(inByte);}void keyPressed() {if (key == ' ') {mm.finish(); // Finish the movie if space bar is pressed!exit();}}



0 comments:
Post a Comment