Final: Arduino & Xbee Powered Airship!

For our final, Morgen and I took the airship we had modified for our midterm, and decided to create a fully-functional airship powered by Arduinos and Xbee radios.

In our midterm, we had created a new form of hand controller for the airship, using an accelerometer-powered glove to control movement. To do this, we had hacked the original controller to receive input from our arduino (which was linked to the glove), but still used it to transmit signals to the airship’s gondola, and we still used the receiver and power internal to the airship to power it.

For the next stage, we decided to cut all the micro-controllers that came with the airship, and to build our own controller. We kept the existing airship gondola, including the three fans & fan motors.

The first step was to create our own system to power the fan motors in the gondola. To do this, we used an Xbee modem, which we attached to a breadboard. To direction in which the fans spun was determined by the direction of electricity flow, so we decided to use a H-bridges to fire the motors, so we could control the spin direction based on which digital pin we were firing. We hooked the starboard motor up to one side of an H-bridge and the port motor up to the other side of the H-bridge. We then hooked four digital pins from the Xbee into the H-bridge, so that each pin controlled one motor going one direction (pin 0, for example, could turn the starboard motor on going forward). We added a second H-Bridge to control the up & down fan, and wired up two additional pins to that H-bridge.

We powered the Xbee & the motors themselves using a 9V battery routed through a 3.3v regulator, as both the motors and the Xbees prefer 3.3V. The H-Bridges we had, however, require a minimum of 4.5V power to turn on, so we powered them directly from the 9V battery.

Once we had the H-bridges firing properly (we tested using alligator clips), the next stage was to get the two Xbees up and running.

Xbee one was hooked up to our H-bridges and was designed to take orders from the Xbee that we’d hook up to our Arduino, so we had another small breadboard, with an Xbee and an Arduino. The digital pins on the Xbee were turned into digital inputs (using the AT commands below). The Arduino’s digital pins were used as outputs, so turning a digital pin HIGH on the arduino sent that HIGH value to the Xbee attached to it via wires. That Xbee then broadcast the HIGH value over the air (using the Xbee’s “digital wire” I/O) to the Xbee installed in the airship gondola. When all went well, the Xbee in the gondola would then fire the proper fan, pushing the airship in whatever direction we wanted it to go!

To test everything initially, we used LEDs hooked up to the H-Bridges to ensure they were firing properly (and as expected). Once we had them working, we then hooked the fans up to the h-bridges and started testing them. Once we had that all working, we upgraded our code to include the code we’d used at the midterm (so that our blimp was controlled by our hand controller) and let it loose!

We ran into a number of problems getting it to work as intended. Part of it was wiring the circuit up in actual gondola; at one point, we had things wired incorrectly and fried out an Xbee radio. We also managed to fry an H-bridge, although how we did that we’re still not sure.

We also ran into a number of more logistical problems. First, fitting the xbee and breadboard into the gondola proved troublesome, as it was too big to fit and we had to make some modifications to get it in properly. The xbee/breadboard also weighed down the blimp significantly (to the point that we had to purchase a second balloon to get it buoyant again).

From the coding perspective, while the AT commands were relatively straightfoward, we’d initially tried to enabled duplex virtual wire I/O communication, with the intention of hooking up sensors on the blimp and having them transmit back to the arduino. (The idea was that the blimp could be self-correcting, and move itself up or down depending on the distance it was from the ceiling or floor). We were unable to get this working and could only get it to send values in one direction or the other. This will be for the ‘next generation’. The arduino coding was very straightforward, however, and most of the hard work came in the actual physical portion.

Ultimately, we did make a few significant improvements over the initial product. The initial microcontroller was unable to fire the up/down AND starboard or port fans at the same time; our new design allowed it to fire both fans at once. We also laid the foundation for a significant improvement in control, where we could use the arduino to fire the jets for specific periods of time rather than simply an “on/off” control, as the existing microcontroller had been. Plus, we got to play with Xbees, which was quite a lot of fun.

Our presentation, which covers a lot of the reasons and long-term goals for the project, is viewable here:

http://docs.google.com/Presentation?id=dcbvg7gb_10ghwdb5dz

Morgen will have videos of the airship in action and some photos on his site.

The code for the Airship itself is here:

/* Airship Controller Application
for Physical Computing, Summer 2009
by Aaron Glazer and Morgen Fleisig
Version 0.2
*/

// set values that flag our direction

int directionForward = 1;
int directionReverse = 2;
int directionClockwise = 3;
int directionCounterclockwise = 4;
int directionUp = 5;
int directionDown = 6;

unsigned long lastTime;

// digital pins on the breadboard to trigger the switch
// can be replaced with reed relays if we need to
int pinStarboardForward = 4;
int pinStarboardReverse = 3;
int pinUp = 6;
int pinDown = 5;
int pinPortForward = 8;
int pinPortReverse = 7;

int pinEnableHBridge = 2;

// analog input pins
int pinaccX = 0;
int pinaccY = 1;
int pinaccZ = 2;

// accelerometer values
int X;
int Y;
int Z;

// range values
int minstableX = 475;
int maxstableX = 575;
int minstableY = 490;
int maxstableY = 545;
int minstableZ = 300;
int maxstableZ = 565;

int holdZ;

int triggeredUp = 0;
int triggeredDown = 0;

// integers to hold the direction
int vertical_direct = 0;
int direct = 0;

// setup loop
// opens our serial communication and setups our pins
void setup()
{
Serial.begin(9600);
pinMode(pinEnableHBridge,OUTPUT);

pinMode(pinStarboardForward,OUTPUT);
pinMode(pinStarboardReverse,OUTPUT);
pinMode(pinUp,OUTPUT);
pinMode(pinDown,OUTPUT);
pinMode(pinPortForward,OUTPUT);
pinMode(pinPortReverse,OUTPUT);
Serial.println(“Airship Engaged!”);
digitalWrite(pinEnableHBridge,HIGH);
}

void loop()
{

// trigger values used to catch the Z value trigger
triggeredUp = 0;
triggeredDown = 0;

while(millis()-lastTime maxstableZ)
{
triggeredUp = 1;
triggeredDown = 0;
holdZ = Z;
}
else if (Z maxstableX)
{
direct = directionClockwise;
}
// if X is below the value, we want to move clockwise
else if (X maxstableY)
{
direct = directionForward;
}
// if Y triggered below max value, move backward
else if (Y < minstableY)
{
direct = directionReverse;
}
}

Serial.print(“\t”);
Serial.print(triggeredUp);
Serial.print(triggeredDown);

Serial.print(“\t”);
Serial.print(direct);
//Serial.print(“\t”);
//Serial.print(vertical_direct);

if (direct == 0)
{
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinStarboardForward,LOW);
Serial.println(“\t None”);
}
else if (direct == directionForward)
{
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinStarboardForward,HIGH);
digitalWrite(pinPortForward,HIGH);
Serial.println(“\t Forward”);
}
else if (direct == directionReverse)
{
digitalWrite(pinStarboardForward,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinStarboardReverse,HIGH);
digitalWrite(pinPortReverse,HIGH);
Serial.println(“\t Reverse”);
}
else if (direct == directionClockwise)
{
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinStarboardForward,LOW);
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinPortForward,HIGH);
digitalWrite(pinStarboardReverse,HIGH);
Serial.println(“\t Clockwise”);
}
else if (direct == directionCounterclockwise)
{
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,HIGH);
digitalWrite(pinStarboardForward,HIGH);
Serial.println(“\t Counterclockwise”);
}
else if (direct == directionUp)
{
// make sure the down pin is off
digitalWrite(pinDown,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinStarboardForward,LOW);

// then turn the up pin on
digitalWrite(pinUp,HIGH);
Serial.println(“\t Up”);
delay(3000);
}
else if (direct == directionDown)
{
// make sure ‘up’ is off
digitalWrite(pinUp,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinStarboardForward,LOW);

// then turn down on
digitalWrite(pinDown,HIGH);
Serial.println(“\t Down”);
}

//delay(1500);
}

void turnFansOff()
{
digitalWrite(pinStarboardForward,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinDown,LOW);
}

To setup the Xbees, we used two sets of AT commands.

The first controlled the Xbee connected to our arduino, which was designed to push out commands from the arduino directly to the receiving Xbee in the Gondola.

The AT commands (with comments) for the sending Xbee are:

ATID1234 // set network ID to 1234
ATMY1 // set xbee ID to 1
ATDL2 // set xbee to send to xbee id #2
ATD03 // turn digital pin 0-6 (BELOW) to receive
ATD13
ATD23
ATD33
ATD43
ATD53
ATD63
ATIR14 // set sample timing
ATIT1 // determing # of samples to take
ATWR // write to memory

The second xbee is our receiving xbee, which takes the digital output state (LOW or HIGH) from the sending xbee, and controls the state of the motors in the gondola. This is the AT command codes that setup that XBEE:

ATID1234 //network ID
ATMY2 // xbee ID
ATDL1 // send to xbeeID
ATD04 // set digital pins 0-6 on receive with an initial state of LOW
ATD14
ATD24
ATD34
ATD44
ATD54
ATD64
ATIU1 //enables I/O
ATIA1 //binds digital outputs to xbee ID #1
ATWR //writes to memory

June 25, 2009 at 6:07 pm Leave a comment

Assignment 6: Serial Duplex using an Arduino

For the serial duplex lab, I setup a simple circuit with a force resistance sensor, a photocell, and a switch. The sensors are on analog pins 4 & 5 and the switch is on digital pin 2. I used 10k pull-down resistors. The board looks like this:

To start with, I adapted the lab’s Arduino code to just read the value from my force resistance sensor, as follows:


int forceValue;

void setup()
{
Serial.begin(9600);
}

void loop()
{
forceValue = analogRead(5);
Serial.println(forceValue,DEC);
delay(500);
}


When run, it produced standard decimal (ASCII) numerical readings from the sensor, as seen the serial monitor below:

serial_duplex_single_sensor_decimal

I then updated the Serial print line and the analogRead lines as follows:

forceValue = analogRead(5)/4;
Serial.println(forceValue,BYTE);

The forceValue line reduces the the readings to less than 255, so it fits in one byte.

This time, it produced values that were funky characers, because they were converting the BYTE values back into ASCII.

serial_duplex_single_sensor_byte

For the next stage, I updated the code to output all the various type of outputs. The new code is:

int forceValue;

void setup()
{
Serial.begin(9600);
}

void loop()
{
forceValue = analogRead(5)/4;
// print in many formats:
Serial.print(forceValue, BYTE); // Print the raw binary value analogValue
Serial.print('\t'); // print a tab
Serial.print(forceValue, BIN); // print the ASCII encoded binary analogValue
Serial.print('\t'); // print a tab
Serial.print(forceValue, DEC); // print the ASCII encoded decimal analogValue
Serial.print('\t'); // print a tab
Serial.print(forceValue, HEX); // print the ASCII encoded hexadecimal analogValue
Serial.print('\t'); // print a tab
Serial.print(forceValue, OCT); // print the ASCII encoded octal analogValue
Serial.println(); // print a linefeed and carriage return
delay(500);
}

Which produces outputs like this:

serial_duplex_single_sensor_all_types

Now, I have several sensors hooked up, so I’m going to start sending all my sensor values back, using the punctuation method. This code adds a comma between each value and sends a line feed at the end of a complete line of readings:


int switchState;
int forceValue;
int lightValue;

void setup()
{
Serial.begin(9600);
pinMode(2,INPUT);
}

void loop()
{
forceValue = analogRead(5) / 4;
lightValue = analogRead(4) / 4;
switchState = digitalRead(2);

Serial.print(forceValue,DEC);
Serial.print(",");
Serial.print(lightValue,DEC);
Serial.print(",");
Serial.println(switchState,DEC);
delay(500);
}

This produces a serial output as follows:

serial_duplex_multisensor_punctuation

I then created a Processing application (based on the lab code) to read in this serial output. I made several changes to the Processing code to make it work correctly. My code is:

/*
Serial String Reader
Language: Processing

Reads in a string of characters from a serial port until
it gets a linefeed (ASCII 10). Then splits the string into
sections separated by commas. Then converts the sections to ints,
and prints them out.

created 2 Jun 2005
modified 6 Aug 2008
by Tom Igoe
*/

import processing.serial.*; // import the Processing serial library
Serial myPort; // The serial port

color bgcolor; // Background color
color fgcolor; // Fill color
float xpos, ypos; // Starting position of the ball

void setup() {
size(640,480);

// List all the available serial ports
//println(Serial.list());

myPort = new Serial(this, Serial.list()[9], 9600);

// read bytes into a buffer until you get a linefeed (ASCII 10):
myPort.bufferUntil('\n');
bgcolor = color(255);
}

void draw() {
background(bgcolor);
fill(fgcolor);
ellipse(xpos, ypos, 20, 20);
}

// serialEvent method is run automatically by the Processing applet
// whenever the buffer reaches the byte value set in the bufferUntil()
// method in the setup():

void serialEvent(Serial myPort) {
// read the serial buffer:
String myString = myPort.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null) {

myString = trim(myString);

// split the string at the commas
// and convert the sections into integers:
int sensors[] = int(split(myString, ','));

// print out the values you got:
for (int sensorNum = 0; sensorNum 1) {
xpos = map(sensors[0], 0, 255, 0, width);
ypos = map(sensors[1], 0, 255, 0, height);
println("X: " + xpos + " Y:" + ypos);
fgcolor = sensors[2] * 255;
}
}
}

The screen it produced is:
processing_three_sensors

Next, I updated the code to do a call-and-response. The updated arduino code, which now only sends a reading once it receives something via the serial port, is:

int switchState;
int forceValue;
int lightValue;

void setup()
{
Serial.begin(9600);
pinMode(2,INPUT);
establishContact();
}

void loop()
{
if (Serial.available() > 0) {
// read the incoming byte:
int inByte = Serial.read();

forceValue = analogRead(5) / 4;
lightValue = analogRead(4) / 4;
switchState = digitalRead(2);

Serial.print(forceValue,DEC);
Serial.print(",");
Serial.print(lightValue,DEC);
Serial.print(",");
Serial.println(switchState,DEC);
}
}

void establishContact() {
while (Serial.available() <= 0) {
Serial.println("hello"); // send a starting message
delay(300);
}
}

And then updated the processing code to write out a string to the serial port to trigger a response. The new code is the following:

/*
Serial String Reader
Language: Processing

Reads in a string of characters from a serial port until
it gets a linefeed (ASCII 10). Then splits the string into
sections separated by commas. Then converts the sections to ints,
and prints them out.

created 2 Jun 2005
modified 6 Aug 2008
by Tom Igoe
*/

import processing.serial.*; // import the Processing serial library
Serial myPort; // The serial port
boolean firstContact = false;

color bgcolor; // Background color
color fgcolor; // Fill color
float xpos, ypos; // Starting position of the ball

void setup() {
size(640,480);

// List all the available serial ports
//println(Serial.list());

// I know that the first port in the serial list on my mac
// is always my Arduino module, so I open Serial.list()[0].
// Change the 0 to the appropriate number of the serial port
// that your microcontroller is attached to.
myPort = new Serial(this, Serial.list()[9], 9600);

// read bytes into a buffer until you get a linefeed (ASCII 10):
myPort.bufferUntil('\n');
bgcolor = color(15,33,55);
}

void draw() {
background(bgcolor);
fill(fgcolor);
ellipse(xpos, ypos, 20, 20);
}

// serialEvent method is run automatically by the Processing applet
// whenever the buffer reaches the byte value set in the bufferUntil()
// method in the setup():

void serialEvent(Serial myPort) {
// read the serial buffer:
String myString = myPort.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null) {

myString = trim(myString);

// if you haven't heard from the microncontroller yet, listen:
if (firstContact == false) {
if (myString.equals("hello")) {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
}
}
// if you have heard from the microcontroller, proceed:
else {
// split the string at the commas
// and convert the sections into integers:
int sensors[] = int(split(myString, ','));

// print out the values you got:
for (int sensorNum = 0; sensorNum 1) {
xpos = map(sensors[0], 0, 255 ,0,width);
ypos = map(sensors[1], 0, 255, 0,height);
println("X: " + xpos + " Y:" + ypos);
fgcolor = sensors[2] * 255;
}
}
// when you've parsed the data you have, ask for more:
myPort.write("A");
}
}

The picture looked the same, but the code was only receiving a value back when it sent one.

June 22, 2009 at 3:30 am Leave a comment

Assignment 5: Serial Out using an Arduino

For this assignment, I’ve hooked up a potentiometer into the analog input of the Arduino and will be outputting the sensor readings back to the computer using Serial output. As my breadboard is currently being used for another project, I’ve hooked the potentiometer up directly to my arduino, and uploaded the following code (from the lab) to the Arduino:

int analogPin = 0;
int analogValue = 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);
// pause for 10 milliseconds:
delay(10);
}

I then turned on the serial monitor in Arduino to make sure it was outputting properly. Since it’s outputting BYTEs, it’s all gibberish, but the image is below:

serial_input

Next, I loaded a new processing sketch and pulled in the processing code from the lab, as follows:

/*
Sensor Graphing Sketch

This sketch takes raw bytes from the serial port at 9600 baud and graphs them.

Created 20 April 2005
Updated 5 August 2008
by Tom Igoe
*/

import processing.serial.*;

Serial myPort; // The serial port
int graphXPos = 1; // the horizontal position of the graph:

void setup () {
size(600, 600); // window size

// List all the available serial ports
println(Serial.list());
// I know that the fisrt port in the serial list on my mac
// is usually my Arduino module, so I open Serial.list()[0].
// Open whatever port is the one you're using.
myPort = new Serial(this, Serial.list()[8], 9600);

// set inital background:
background(22,22,22);
}
void draw () {
// nothing happens in draw. It all happens in SerialEvent()
}

void serialEvent (Serial myPort) {
// get the byte:
int inByte = myPort.read();
// print it:
println(inByte);
// set the drawing color. Pick a pretty color:
stroke(255,0,255);
// draw the line:
line(graphXPos, height, graphXPos, height - inByte);

// at the edge of the screen, go back to the beginning:
if (graphXPos >= width) {
graphXPos = 0;
// clear the screen:
background(33,44,55);
}
else {
// increment the horizontal position for the next reading:
graphXPos++;
}
}

I made minor modifications to the code to adjust the colors and size and then to select my serial port. I then ran the processing sketch and played with the potentiometer. The processing output adjusted up and down depending on the value from the potentiometer. I took a screen shot of the final output screen, which is below:

processing_input

June 21, 2009 at 6:08 am Leave a comment

Midterm: Airship Code & Videos

For our midterm, Morgen and I hacked an existing indoor flying blimp. Specifically, we hacked the remote controller so that we could trigger the controls via an arduino, and then we hooked up an accelerometer to a glove and ran the glove into the arduino, and the arduino to the controller. That way, we were able to fly the blimp using the glove.

Below are two videos of the airship working with our glove controller!

Morgen has additional information and pictures on the Airship.

Here’s the code that’s running the ship:


/* Airship Controller Application
for Physical Computing, Summer 2009
by Aaron Glazer and Morgen Fleisig
Version 0.1
*/

// set values that flag our direction

int directionForward = 1;
int directionReverse = 2;
int directionClockwise = 3;
int directionCounterclockwise = 4;
int directionUp = 5;
int directionDown = 6;

unsigned long lastTime;

// digital pins on the breadboard to trigger the switch
// can be replaced with reed relays if we need to
int pinStarboardForward = 4;
int pinStarboardReverse = 3;
int pinUp = 6;
int pinDown = 5;
int pinPortForward = 8;
int pinPortReverse = 7;

// analog input pins
int pinaccX = 0;
int pinaccY = 1;
int pinaccZ = 2;

// accelerometer values
int X;
int Y;
int Z;

// range values
int minstableX = 475;
int maxstableX = 575;
int minstableY = 490;
int maxstableY = 545;
int minstableZ = 300;
int maxstableZ = 565;

int holdZ;

int triggeredUp = 0;
int triggeredDown = 0;

// integers to hold the direction
int vertical_direct = 0;
int direct = 0;

// setup loop
// opens our serial communication and setups our pins
void setup()
{
Serial.begin(9600);
pinMode(pinStarboardForward,OUTPUT);
pinMode(pinStarboardReverse,OUTPUT);
pinMode(pinUp,OUTPUT);
pinMode(pinDown,OUTPUT);
pinMode(pinPortForward,OUTPUT);
pinMode(pinPortReverse,OUTPUT);
Serial.println("Airship Engaged!");
}

void loop()
{

// trigger values used to catch the Z value trigger
triggeredUp = 0;
triggeredDown = 0;

while(millis()-lastTime maxstableZ)
{
triggeredUp = 1;
triggeredDown = 0;
holdZ = Z;
}
else if (Z maxstableX)
{
direct = directionClockwise;
}
// if X is below the value, we want to move clockwise
else if (X maxstableY)
{
direct = directionForward;
}
// if Y triggered below max value, move backward
else if (Y < minstableY)
{
direct = directionReverse;
}
}

Serial.print("\t");
Serial.print(triggeredUp);
Serial.print(triggeredDown);

Serial.print("\t");
Serial.print(direct);

if (direct == 0)
{
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinStarboardForward,LOW);
Serial.println("\t None");
}
else if (direct == directionForward)
{
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinStarboardForward,HIGH);
digitalWrite(pinPortForward,HIGH);
Serial.println("\t Forward");
}
else if (direct == directionReverse)
{
digitalWrite(pinStarboardForward,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinStarboardReverse,HIGH);
digitalWrite(pinPortReverse,HIGH);
Serial.println("\t Reverse");
}
else if (direct == directionClockwise)
{
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinStarboardForward,LOW);
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinPortForward,HIGH);
digitalWrite(pinStarboardReverse,HIGH);
Serial.println("\t Clockwise");
}
else if (direct == directionCounterclockwise)
{
digitalWrite(pinDown,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,HIGH);
digitalWrite(pinStarboardForward,HIGH);
Serial.println("\t Counterclockwise");
}
else if (direct == directionUp)
{
// make sure the down pin is off
digitalWrite(pinDown,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinStarboardForward,LOW);

// then turn the up pin on
digitalWrite(pinUp,HIGH);
Serial.println("\t Up");
// for up only, run it for 3000 ms
delay(3000);
}
else if (direct == directionDown)
{
// make sure 'up' is off
digitalWrite(pinUp,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinStarboardForward,LOW);

// then turn down on
digitalWrite(pinDown,HIGH);
Serial.println("\t Down");
}

}

void turnFansOff()
{
digitalWrite(pinStarboardForward,LOW);
digitalWrite(pinPortForward,LOW);
digitalWrite(pinStarboardReverse,LOW);
digitalWrite(pinPortReverse,LOW);
digitalWrite(pinUp,LOW);
digitalWrite(pinDown,LOW);
}

June 9, 2009 at 6:27 pm Leave a comment

Assignment 4: Serve Motor Control with an Arduino

After preparing my breadboard, I hooked up a flex sensor and servo to my board (as established in section 3).  I didn’t have a soldering station, so I plugged by flex sensor directly into my breadboard, and I also added an LED to establish that power was going to the breadboard.

Using the code below, I determined the base range for my flex sensor.int minValue = 0;
int maxValue = 0;
int value = 0;

void setup()
{
Serial.begin(9600);
minValue = analogRead(0);
maxValue = analogRead(0);

// flash warning on you to start testing your sensor
pinMode(13,OUTPUT);
digitalWrite(13,HIGH);

while (millis() < 10000) { // loop through value = analogRead(0); if (value > maxValue)
maxValue = value;
if (value < minValue)
minValue = value;
}
digitalWrite(13,LOW);

Serial.println(maxValue);
Serial.println(minValue);
}

void loop()
{
}

I figured out how to press the “serial monitor” button this time, so I actually could see my serial results, and determined that my range was approximately 200-600, as shown in the image below.

maxmininput

Once I had that, I adjusted the code from 4.1 to my code below, and then uploaded it to my arduino…

/*
Servo control from an analog input

The minimum (minPulse) and maxiumum (maxPulse) values
will be different depending on your specific servo motor.
Ideally, it should be between 1 and 2 milliseconds, but in practice,
0.5 - 2.5 milliseconds works well for me.
Try different values to see what numbers are best for you.

This program uses the millis() function to keep track of when the servo was
last pulsed. millis() produces an overflow error (i.e. generates a number
that's too big to fit in a long variable) after about 5 days. if you're
making a program that has to run for more than 5 days, you may need to
account for this.

by Tom Igoe
additions by Carlyn Maw & Rob Faludi
Created 28 Jan. 2006
Updated 10 Jun. 2008
*/

int servoPin = 2; // Control pin for servo motor
int minPulse = 500; // Minimum servo position
int maxPulse = 2500; // Maximum servo position
int pulse = 0; // Amount to pulse the servo

long lastPulse = 0; // the time in milliseconds of the last pulse
int refreshTime = 20; // the time needed in between pulses

int analogValue = 0; // the value returned from the analog sensor
int analogPin = 0; // the analog pin that the sensor's on

void setup() {
pinMode(servoPin, OUTPUT); // Set servo pin as an output pin
pulse = minPulse; // Set the motor position value to the minimum
Serial.begin(9600);
}

void loop() {
analogValue = analogRead(analogPin); // read the analog input
pulse = map(analogValue,200,600,minPulse,maxPulse); // convert the analog value
// to a range between minPulse
// and maxPulse.

// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastPulse >= refreshTime) {
digitalWrite(servoPin, HIGH); // Turn the motor on
delayMicroseconds(pulse); // Length of the pulse sets the motor position
digitalWrite(servoPin, LOW); // Turn the motor off
lastPulse = millis(); // save the time of the last pulse
}
}


…and it worked! (As is my embedding this time, apparently). Apologies on the low quality of video – I only had my cell phone.

Next, I changed the servo motor to PWM pin 9 and uploaded Rory’s code that uses the direct servo motor control:

/*
Servo control from an analog input using the Arduino Servo library

This example code uses the Arduino Servo library which comes packaged with the Arduino software.

In order to make this work, you must include the Servo.h library file, create an instance of the Servo object,
attach a digital PWM pin to the Servo object, and then write an analog value to the Servo object to set its
position.

The difference between using the Servo library and the older method of pulsing a digital pin is that the library
handles a lot of the work for you. You no longer need to figure out the translation between pulse length and position.
You now can simply specify the angle you'd like your servo to be at and it will turn to that position.

Please note, unlike the older pulsing method you MUST use a digital PWM pin or it will not work.

by Rory Nugent
Created 20 Jan. 2009
*/

#include // include the servo library

Servo servoMotor; // creates an instance of the servo object to control a servo

int analogPin = 0; // the analog pin that the sensor is on
int analogValue = 0; // the value returned from the analog sensor

int servoPin = 9; // Control pin for servo motor, may only be pin 9 or 10

void setup() {
servoMotor.attach(servoPin); // attaches the servo on pin 2 to the servo object
}

void loop()
{
analogValue = analogRead(analogPin); // read the analog input (value between 200 and 600)
analogValue = map(analogValue, 200, 600, 0, 179); // map the analog value (200 - 600) to the angle of the servo (0 - 179)
servoMotor.write(analogValue); // write the new mapped analog value to set the position of the servo
delay(15); // waits for the servo to get there
}

Again, I adjusted my mapping values to 200-600, and re-uploaded the code to the arduino, and it worked again!

I did notice while doing all this that my servo motor was only making about a 150 degree turn, which I’m attributing to my actual ranges being a bit off. All in all, though, a successful lab!

June 2, 2009 at 2:09 am Leave a comment

Assignment 3: Analog Output (Updated)

Below is the image from part 1 on the analog input lab. This shows the potentiometer hooked up to the arduino analog input:

For some reason, however, the serial communication wasn’t sending the values back to my computer. I’ll have to work on that. Updated: I had forgotten to turn on the serial monitor. It works fine.

For the second part of my lab, I created a reverse love-o-meter using the arduino and a geophone, which measures ground movement. While normally used to measure mild seismic activity, I figured it would be a good way to measure an upset relationship – if someone was slamming doors or stomping around the house, it will report on the movement.

The green light on the love-o-meter means that all is well. The yellow lights means a single instance of seismic activity (say, a door slamming) has been picked up, while a red
means at least two successive readings have been found, and you should be warned.

I hooked the geophone up to the analog inputs in the arduino. If the geophone picks up vibration on any of the channels, then it will trigger an increase in level. If the previous state is green, then it will update the warning to yellow. If it’s already yellow, then it will update to red – a severe warning. It also trends back down to green if no movement is detected.

This is a video of the operation at work:

And this is a picture of the geophone setup on my window.

And this is my arduino code to run it:


// analog reading placeholders
int ana0;
int an1;
int ana2;
int ana3;
int lastpinON;
int triggered = 0;

void setup()
{
//Setup serial
Serial.begin(9600);

//Turn on pins
pinMode(11,OUTPUT);
pinMode(10,OUTPUT);
pinMode(9,OUTPUT);

// set our original pin state
lastpinON = 9;

// write our green pin to high
digitalWrite(9,HIGH);
}

void loop()
{

delay(1500);

//
// x direction
an1 = analogRead(1);

//z direction
ana2 = analogRead(2);

//y direction?
ana3 = analogRead(3);

//output readings
Serial.print(an1);
Serial.print("\t");
Serial.print(ana2);
Serial.print("\t");
Serial.print(ana3);
Serial.print("\t");

//set trigger to zero
triggered = 0;

//check if we're triggering
if ( ((ana3 525)) || ((an1 > 525) || (an1 525) || (ana2 < 375)) )
{
triggered = 1;
}

//output trigger
Serial.println(triggered);

//if triggered, move our pin up or down
if (triggered == 1)
{
if (lastpinON == 9)
{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(11,LOW);
lastpinON = 10;
}
else if (lastpinON == 10)
{
digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(11,HIGH);
lastpinON = 11;
}
}
else if (triggered == 0)
{
if (lastpinON == 11)
{
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(11,LOW);
lastpinON = 10;
}
else if (lastpinON == 10)
{
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(11,LOW);
lastpinON = 9;
}
}
}

May 28, 2009 at 3:28 pm Leave a comment

Assignment 2: Digital Input and Output with an Arduino and Arduino Combo Lock

The first part of the lab was setting up my arduino with digital inputs and outputs, wiring a physical switch, and then installing some basic code.  A picture of the arduino and breadboard (as wired) is below.

arduino_basic_switch

The switch turned digital switch on and off, which flipped which light was actually turned on.

After completing the basic lesson for the Arduino, I made a placemat lock.  I wired up three pieces of aluminum foil where a standard fork, knife and spoon would go on a placement, and then I wired up the cutlery.  The arduino chip checks to see if all three pieces of cutlery are in place (or, at least, the circuit is complete).  If they are, it turns on the yellow light.  If they aren’t, it continually blinks the red light as a warning.

cutlery_on

cutlery_off

cutlery_off_v2

The arduino code is below.

// declare variables:
int yellowLedPin = 4; // digital output pin for an LED
int redLedPin = 3; // digital output pin for an LED
int knifePin = 8;
int spoonPin = 2;
int forkPin = 9;
int switchStateSpoon = 0; // the state of the switch
int switchStateFork = 0;
int switchStateKnife = 0;

void setup() {
pinMode(spoonPin, INPUT); // set the switch pin to be an input
pinMode(forkPin, INPUT); // set the switch pin to be an input
pinMode(knifePin, INPUT); // set the switch pin to be an input
pinMode(yellowLedPin, OUTPUT); // set the yellow LED pin to be an output
pinMode(redLedPin, OUTPUT); // set the red LED pin to be an output
}

void loop() {
// read the switch input:
switchStateSpoon = digitalRead(spoonPin);
switchStateFork = digitalRead(forkPin);
switchStateKnife = digitalRead(knifePin);

if (switchStateFork == 1 && switchStateKnife == 1 && switchStateSpoon == 1) {
// if the switch is closed:
digitalWrite(yellowLedPin, HIGH); // turn on the yellow LED
digitalWrite(redLedPin, LOW); // turn off the red LED
}
else {
// if the switch is open:
digitalWrite(yellowLedPin, LOW); // turn off the yellow LED
blinkRed(); // turn on the red LED
}
}

void blinkRed() {
digitalWrite(redLedPin, HIGH); // turn on the red LED
delay (250);
digitalWrite(redLedPin, LOW); // turn on the red LED
delay (250);
}

Then, I decided that a combination lock should at least have some sense of order, so I changed the order so that you had to first put the spoon on and then add the fork. (The knife was used as a ruse to confuse potential cutlery combination lock thieves).

The new code is as follows:

// declare variables:
int yellowLedPin = 4; // digital output pin for an LED
int redLedPin = 3; // digital output pin for an LED
int knifePin = 8;
int spoonPin = 2;
int forkPin = 9;
int switchStateSpoon = 0; // the state of the switch
int switchStateFork = 0;
int switchStateKnife = 0;
int firstPinTriggered = 0;
int secondPinTriggered = 0;
int thirdPinTriggered = 0;

void setup() {
pinMode(spoonPin, INPUT); // set the switch pin to be an input
pinMode(forkPin, INPUT); // set the switch pin to be an input
pinMode(knifePin, INPUT); // set the switch pin to be an input
pinMode(yellowLedPin, OUTPUT); // set the yellow LED pin to be an output
pinMode(redLedPin, OUTPUT); // set the red LED pin to be an output
}

void loop() {
// read the switch input:
switchStateSpoon = digitalRead(spoonPin);
switchStateFork = digitalRead(forkPin);
switchStateKnife = digitalRead(knifePin);

// if the knife is triggered, someone is trying to break in
if (switchStateKnife == 1)
{
firstPinTriggered == 0;
secondPinTriggered == 0;
}
else
{
if (switchStateSpoon == 1 && switchStateFork == 0) {
// first put our spoon in place
firstPinTriggered = 1;
}
else if (firstPinTriggered == 1) {
if (switchStateFork == 1) {
secondPinTriggered = 1;
}
else {
secondPinTriggered = 0;
}
}
else
{
firstPinTriggered = 0;
secondPinTriggered = 0;
}

if (secondPinTriggered == 1) {
// if the switch is closed:
digitalWrite(yellowLedPin, HIGH); // turn on the yellow LED
digitalWrite(redLedPin, LOW); // turn off the red LED
}
else {
// if the switch is open:
digitalWrite(yellowLedPin, LOW); // turn off the yellow LED
blinkRed(); // turn on the red LED
}
}

}

void blinkRed() {
digitalWrite(redLedPin, HIGH); // turn on the red LED
delay (250);
digitalWrite(redLedPin, LOW); // turn on the red LED
delay (250);
}

I think there are still a few bugs to work out on that code, but it now only unlocks if you put the spoon down first and then the fork!

May 26, 2009 at 4:28 pm Leave a comment

Older Posts


Categories

  • Blogroll

  • Feeds


    Follow

    Get every new post delivered to your Inbox.