Robot is Happy creating our robot overlords one day at a time

16Jun/100

Processing Wiki Launches by Christopher Hazlett

Check it out: Processing Wiki

Tagged as: No Comments
15Jun/100

Arduino and Android together at last by Christopher Hazlett

Bonifaz Kaufmann has released an Android to Arduino library. Check it out.

20May/100

Balancing Cube by Christopher Hazlett

Saw this at Hack a Day. I dare you not to smile at the awesomeness.

3May/100

We’ve been away…our apologies by Christopher Hazlett

Both Alex and I have been unable to undertake any new robot projects as of late, which has necessarily precluded us from posting any new project how-tos and other detritus on Robot is Happy. So, unfortunately, this is your typical apology for not posting post, but fear not, my friends. Both of us are digging out from our respective real estate deals and, I, for one, will have a completely new robot constructing lair in my new spacious basement (I've already begun buying new robot building tools).

I've got some exciting projects already planned in my head, and once I've moved in to my new house for good (and I'm not painting anymore), I'll be putting them into action and writing about them.

Filed under: News No Comments
24Jan/100

iPhone inspired kitchen computer by Christopher Hazlett

A great project by Ryan in New Zealand. He has a great write-up and he's even open-sourced his interface.

iPhone inspired Kitchen

- Chris

1Jan/100

Beacon locating robot – Visualizing sensor readings with Processing by Christopher Hazlett

I've been boning up on my Processing skills, and have been fascinated by the library for it's "easy" integration with my Arduino projects.  My beacon locating robot with the Arduino brain seemed like an excellent opportunity to wire up my robot to a Processing sketch and see what happens.  There's not a lot to the application, but it proved very helpful in understanding the robot and how it was functioning.

There weren't too many gotchas with this application, but I'll point a couple of interesting tidbits:

1) I have the baud rate set at 38400, which is rather high, but I'm doing a number of different actions at the same time on the robot itself. A lower baud rate makes the robot stutter when it's sweeping the servo back and forth.

2) You do need to use the noLoop() method in the setup of the application. If you don't, the serial event and draw action will compete...or so it seems. I forgot to use the method once and the application locked up my computer. Just a warning.

3) If you're visualizing sensor data, the only way to get the nice rendered arc like you see in the video below, is to load an array every time you read in data. Then loop through that array and render all the previous readings as well as the most recently updated one. You also may have noticed that I'm not storing the servo angle in the angles[] array, just the readings. I can do this because the count of elements in the array matches the count of servo positions the robot iterates through as it sweeps. Given that, it's very easy to extrapolate what angle the readings are at by multiplying the position of the element in the array by the servo increment.

4) You'll also notice in the video below that when the sensor detects something, the drawn arc gets red and much longer. I could have normalized and reversed the readings so when it detected something, the bar got shorter so it more accurately represented an object. I tried that, and seen that done before, but I really liked how object detections jumped out instead of disappeared.

Obviously, a little more thought went into it, but that's about the only esoteric ideas/decisions you need to know if you want to do something similar.

The Code in Action

The Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  // Serial Variables
 import processing.serial.*;
 Serial myPort;    // The serial port: 
 int baudRate = 38400; //make sure this matches the baud rate in the arduino program.
 int lf = 10;
 
// Font Settings
 PFont font;
 float radianMultiplier;
 int[] angles; 
 
 // Sensor Variables
 String direction = "N";
 int sensorReading;
 int angle;
 int degreeIncrement = 6;
 int startAngle = 0;
 int endAngle = 180;
 int totalReadings = 0;
 
 void setup(){
   smooth();
   size(600, 400);
 
   //270 is Helvetica-Neue (my current favorite) to get a list use println(PFont.list());
   font = createFont(PFont.list()[270], 24); 
   textFont(font); 
   radianMultiplier = PI / 180;
 
   totalReadings = (endAngle - startAngle)/degreeIncrement;
   angles = new int[totalReadings];
   for (int i = 0; i < totalReadings; i++){
     angles[i] = 0;
   }
 
   myPort = new Serial(this, Serial.list()[0], baudRate);
   myPort.bufferUntil(lf);
 
   noLoop();
 }
 
void draw()
{
  background(#266014);
  renderClear();
  renderScan();
  renderDirection();
 
}
 
void serialEvent(Serial p) {
  String inString;
  int pipeIndex = -1;
  int semicolonIndex = -1; 
 
  String angleString;
  String sensorString;
  String dirString;
 
  String newString;
  String stepString;
 
  try {
    // the string is shaped like so: [angle]|[sensorReading];[direction] -- 6|450;N
    inString = (myPort.readString());
    pipeIndex = inString.indexOf('|');               //find the pipe
    semicolonIndex = inString.indexOf(';');               //find the semicolon
 
    if (pipeIndex != -1) {                           //if we found the pipe
      angleString = inString.substring(0, pipeIndex);  //parse angle reading
      sensorString = inString.substring(pipeIndex+1, semicolonIndex); 
      dirString = inString.substring(semicolonIndex + 1, inString.length()-2); //length()-2 <- strips off the linefeed
      angle = int(angleString);
      sensorReading = int(sensorString);
      direction = dirString;
      angles[(angle/degreeIncrement) - 1] = sensorReading;     
    }
  }
  catch(Exception e) {
    println(e);
  }
  redraw();
}
 
 
// Render Functions
void renderReadings(int angle, int sensor){
  noStroke();
 
  mediumFont();
  text("Angle: " + angle, 139, 50);
  text("Sensor: " + sensor, 123, 90);
}
 
void renderScan(){
  noStroke();
  fill(#424242);
  rect(0,0,400,600);
 
  stroke(#000000);
  for (int x=0; x<totalReadings; x++) {
    boolean objectDetected = angles[x] >= 450;
    if(objectDetected == true){
      fill(#980f0f, 400);
    }else{
      fill(#ffffff, 100);
    }
 
    int angle = (x * degreeIncrement) - 180;
    noStroke();
    arc(200, 325, angles[x], angles[x], radians(angle), radians(angle + 6));
    if(objectDetected == true){renderAlert();}
    //renderReadings(x, angles[x]);
  }
 
  fill(#ffffff);
  rect(175,325,50,65);
}
 
void renderDirection(){
  fill(#e38a20);
  rect(400,0,200,200);
  smallFont();
  noStroke();
  renderNorth(direction.equals("N"));
  renderSouth(direction.equals("S"));
  renderWest(direction.equals("W"));
  renderEast(direction.equals("E")); 
}
 
void renderNorth(boolean isCurrent){
  if(isCurrent == true){
    fill(#2b2b2b);
    arc(500, 100, 175, 175, radians(225), radians(315)); 
  }else{
    fill(#696969, 475);
    arc(500, 100, 150, 150, radians(225), radians(315));
  } 
  fill(#ffffff);
  text("N", 492, 50);
}
 
void renderSouth(boolean isCurrent){
  if(isCurrent==true){
    fill(#2b2b2b);
    arc(500, 100, 175, 175, radians(45), radians(135));
  }else{
    fill(#696969, 475);
    arc(500, 100, 150, 150, radians(45), radians(135));
  }  
  fill(#ffffff);
  text("S", 492, 165);
}
 
void renderWest(boolean isCurrent){
  if(isCurrent==true){
    fill(#2b2b2b);
    arc(500, 100, 175, 175, radians(135), radians(225));
  }else{
    fill(#464646, 475);
    arc(500, 100, 150, 150, radians(135), radians(225));
  }  
  fill(#ffffff);
  text("W", 435, 110);
}
 
void renderEast(boolean isCurrent){
  // the 405 angle here is weird, you'd think that because you're starting at 315
  // it would be 45 (the beginning of the South arc), but
  // you have to continue around the circle adding angles
  // in when you pass the 360/0 degrees mark
  if(isCurrent==true){
    fill(#2b2b2b);
    arc(500, 100, 175, 175, radians(315), radians(405));
  }else{
    fill(#464646, 475);
    arc(500, 100, 150, 150, radians(315), radians(405));
  }  
  fill(#ffffff);
  text("E", 553, 110);
}
 
void renderAlert(){
  largeFont();
  fill(#980f0f);
  rect(400,200,200,200);
  fill(#ffffff);
  text("ALERT", 440, 305);
}
 
void renderClear(){
  mediumFont();
  fill(#ffffff);
  text("CLEAR", 450, 305);
}
 
void smallFont(){  textFont(font, 24); }
void mediumFont(){ textFont(font, 30); }
void largeFont(){  textFont(font, 40); }

Let me know if you have any questions, thoughts, or improvements.

- Chris

25Dec/090

International Robot Expo 2009 (part 2: pick and place robots) by Alex Kane

Here's part 2 of my videos from the Tokyo International Robot Expo 2009. Part 1 of the series included a few different kinds of robots, whereas this post will be dedicated to one specific breed of 'bot: the pick and place.

Pick and place robots are industrial robots. They're useful for picking things up and putting them back down in a specific place. Some of these guys are really fast and can sort tubes of toothpaste or small chocolates coming down a conveyor belt at high speeds. Other models are used to place components on circuit boards, like this one over at Adafruit.

Now on to the videos!

In this first video we see pieces move down the conveyor belt and these two Epson 'bots pick them up and place them on a second belt. They're pretty quick but even so, the first one sometimes can't grab all the pieces and the second one is there to catch any that the first one misses.

This robot shows us how it can be used to sort small chocolates on a conveyor belt, very quickly.

A fast pick and place robot that takes tubes of toothpaste from one belt and places them on the other, changing the orientation of the tube in-flight so that they line up nicely once placed.

23Dec/090

Arduino LED Shield by Jimmy P. Rodgers by Christopher Hazlett

Jimmy P. Rodgers over at jimmieprodgers.com (appropriately enough) spent some hard earned brain power developing a 126 LED shield for an Arduino. Nice work sir, nice work.

LED Shield

Take a look at it over at jimmieprodgers.com.

- Chris

Tagged as: , No Comments
13Dec/093

Beacon Locating Robot – Powered by Arduino and IR Transceiver by Christopher Hazlett

After I built my first Arduino-based robot, I wanted to graduate to a little more advanced behavior, and I had it my mind to make a robot that would find a home base via an IR Beacon. Plus I saw that Pololu had the perfect parts for the job, the IR Beacon Transceiver pair. My wife was gracious enough to get me some IR distance sensors, a servo and the transceivers for my birthday in August. If she keeps supporting my hobbies like this, she'll have more robots than she can handle. As always, I'll start with the parts.

The Parts

I, of course, re-used parts from my last robot, but I'll include the links here as well. My robots are nothing if not a source of parts for the next robot.

I also used various crimped and un-crimped wires lying around that I use regularly, but that's a separate post.

The Robot

Beacon Locating Robot

Beacon Locating Robot

It's a pretty simple concept, place a home base somewhere and then have the robot find said home base from it's current location and make it's way there. When I first started thinking about how to execute this project, I thought it was going to be much more complicated to institute the seeking behavior I was looking for. The IR transceivers from Pololu.com were much better than I thought they'd be and had a lot of power. As you can see in the video below, the beacons are powerful enough to work around corners, so I never ended up putting a seeking algorithm in place. The beacon took care of that for me. All I had to do was make sure it avoided walls on its way to the home base. To accomplish that, I put the servo and Sharp distance sensor on the front and performed a sweep with the sensor and read the values from analog input 0. That's the bare bones of the robot.

The Home Base

Home-Base

For the home base, I took one of the transceivers and raised it to the height of the robot's head. This ended up being unnecessary. The robot would find the beacon if it was at any level. The home base didn't have to do anything, so I just powered it up and let it run.

The Code

There are a couple of gotchas when writing the code. Because the IR transceivers are always reading, I had to do a comparison of each reading to determine which of the directional sensors was the highest. You can't just read the input as an on or off. The second and harder portion of the code (and actually the most fun) was determining which direction to make the robot move. At first, I just let the robot move after determining which direction was currently being read from the beacon. In practice, this seems completely fine, but you'll see in the videos that the beacon itself changes directions quite frequently. This made the robot indecisive. To combat this problem, I figure out the Mode of the readings. Essentially, I took the last ten readings and counted what the most prevalent direction was. This smoothed out the robot's behavior and it behaved as expected.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include <Servo.h>
#include <AFMotor.h>
#define TOPSPEED 200
 
// SERVO SCANNING VARIABLES //
Servo myservo;  // create servo object to control a servo
int servoPosition = 0;    // variable to store the servo position
const int SERVO_PIN = 10;
int floorState = 0;
long frontReading = 0;
boolean scanIncrement = true;  //increase position?
byte servoIncrementValue = 6;
byte servoDecrementValue = 6;
 
// MOTOR VARIABLES //
AF_DCMotor rightMotor(4, MOTOR12_8KHZ);
AF_DCMotor leftMotor(3, MOTOR12_8KHZ); 
 
// TRANSCEIVER VARIABLES //
int notFoundSensitivity = 500;
int west = 0;
int south = 0;
int east = 0;
int north = 0;
int dir = 0;
boolean detected = false;
 
// TRANSCEIVER DIRECTION MODE VARIABLES //
const int NUM_READINGS = 10;
int directionReadings[NUM_READINGS];
int modeOfDirections = 1;
int index = 0;
 
void setup()
{
  Serial.begin(38400);
  myservo.attach(SERVO_PIN);  // attaches the servo on pin 9 to the servo object
  myservo.write(0);
  rightMotor.setSpeed(200);
  leftMotor.setSpeed(200);
  delay(1500);
} 
 
void loop()
{
  scan();
  move();
} 
 
void move()
{
    if(servoPosition >= 0 && servoPosition <= 84 && frontReading > 550){ //Object on the left
      turnLeft();
    }else if((servoPosition >= 85 && servoPosition <= 105) && frontReading > 600){ // Object in Front
      turnAround();
    }else if((servoPosition >= 106 && servoPosition <= 180) && frontReading > 550){ // Object on the Right
      turnRight();
    }else{
      moveTowardBeacon();
    }
}
 
void moveTowardBeacon()
{
  readTransceiverandSetDirection();
  if(modeOfDirections == 3 || modeOfDirections == 4){ //South or West
    turnRight();
  } else if(modeOfDirections == 2) { // East
    turnLeft();
  } else if(modeOfDirections == 1){ //North
    moveForward();
  }
}
 
void scan()
{
   scanIncrement ? servoPosition+=servoIncrementValue : servoPosition-=servoDecrementValue; //increment or decrement current position
   if (servoPosition >= 180){
     scanIncrement = false;
     servoPosition = 180;
   } else if (servoPosition &lt;= 1){
     scanIncrement = true;
     servoPosition = 1;
   }
   frontReading = measureFront();
   //Serial.print(servoPosition);
   //Serial.print("|");
   //Serial.print(frontReading);
   //Serial.print(";");
   myservo.write(servoPosition);
   delay(15);
}
 
long measureFront()
{
  return analogRead(0);
}
 
void moveForward(){
  Serial.println("Move Forward");
  rightMotor.run(FORWARD);
  leftMotor.run(FORWARD);
}
 
void speedUp(){
  for (int i=0; i==TOPSPEED; i++) {
    rightMotor.setSpeed(i);
    leftMotor.setSpeed(i);
  }
}
 
void slowToStop(){
  for (int i=TOPSPEED; i==0; i--) {
    rightMotor.setSpeed(i);
    leftMotor.setSpeed(i);
  }
  rightMotor.run(RELEASE);
  leftMotor.run(RELEASE);
}
 
void turnLeft(){
  Serial.println("Turn Left");
  rightMotor.run(BACKWARD);
  leftMotor.run(FORWARD);
}
 
void turnRight(){
  Serial.println("Turn Right");
  rightMotor.run(FORWARD);
  leftMotor.run(BACKWARD);
}
 
void stop(){
  Serial.println("Stop");
  rightMotor.run(RELEASE);
  leftMotor.run(RELEASE);
  delay(500);
}
 
void turnAround(){
   stop();
   delay(500);
   moveBackward();
   delay(300);
   turnLeft();
   delay(300);
   stop();
   //runAway = true;
}
 
void moveBackward(){
  Serial.println("Move Backward");
  rightMotor.run(RELEASE);
  leftMotor.run(RELEASE);
  rightMotor.run(BACKWARD);
  leftMotor.run(BACKWARD);
}
 
//  BEACON LOGIC  //
void readTransceiverandSetDirection(){
  west = analogRead(2);
  south = analogRead(3);
  east = analogRead(4);
  north = analogRead(5);
  getDirection();
  setModeOfDirections();
}
 
boolean foundBeacon(){
  if(west < notFoundSensitivity and east < notFoundSensitivity and south < notFoundSensitivity and north < notFoundSensitivity){     return false;   }else{     return true;   } } void getDirection(){   int minValue = 1200;   if(minValue > west){
    minValue = west;
    dir = 4;
  }
 
  if(minValue > south){
    minValue = south;
    dir = 3;
  }
 
  if(minValue > east){
    minValue = east;
    dir = 2;
  }
 
  if(minValue > north){
    minValue = north;
    dir = 1;
  }
 
  addDirectionToReadings();
 
  //Serial.print("W:");
  //Serial.print(west);
  //Serial.print(" | S:");
  //Serial.print(south);
  //Serial.print(" | E:");
  //Serial.print(east);
  //Serial.print(" | N:");
  //Serial.println(north);
  //Serial.println("=================================");
  //if(dir == 1){
  //  Serial.println("North");
  //}else if(dir == 2){
  //  Serial.println("East");
  //}else if(dir == 3){
  //  Serial.println("South");
  //}else if(dir == 4){
  //  Serial.println("West");
  //}
}
 
void addDirectionToReadings(){
  directionReadings[index] = dir;
 
  index = (index + 1);
  if (index &gt;= NUM_READINGS)             // if we're at the end of the array...
    index = 0;
}
 
// =========================================
// In order to smooth out the directions readings from the
// IR transceiver, You have to take the mode (most prevalent number in a collection)
// of the directionReadings Array.  This allows the program to determine which
// direction is being read the most from the device.
// Otherwise, the readings make the robot squirrelly.
// ========================================
void setModeOfDirections(){
  int currentValue = directionReadings[0];
  int counter = 1;
  int maxCounter = 1;
  int modeValue = modeOfDirections;
  int directionCounts[4] = {0,0,0,0}; //{North(1), East(2), South(3), West(4)}
 
  for (int i = 1; i < NUM_READINGS; ++i){
    Serial.print(directionReadings[i]);
    Serial.print("|");
     ++directionCounts[directionReadings[i]-1];
  }
 
  //Determine mode of directions from count array
  Serial.println("");
  int modeCount[2] = {1,directionCounts[0]}; //This array holds the current maximum count and the direction it points to.
  for(int i = 0; i < 4; ++i){
    //Serial.print(directionCounts[i]);
    //Serial.print("|");
    if(modeCount[1] >= directionCounts[i]){
      modeCount[0] = i + 1; // set direction
      modeCount[1] = directionCounts[i]; //set count
    }
  }
 
  modeOfDirections = modeCount[0];
  Serial.println("");
  Serial.print("Direction Mode: ");
  Serial.println(modeOfDirections);
}

There you have it. Let me know if you have any questions about the code or construction.

- Chris

9Dec/090

Monitoring message queues with Arduino by Alex Kane

Finished product
This is a gadget I made to tell me at a glance the size of the various message queues that I manage at TuneCore.  It sits on my desk next to my monitor and tells me right away what's going on with our delivery system.  A steady light means the queue is not very long; a rapidly blinking light means that the number of items in the queue is very large and it needs attention.

I built it over a weekend using an Arduino microcontroller with an Ethernet shield. It requests the queue sizes from a web server once a minute.

Parsing an HTTP Response

Here's an example of an HTTP response that I have to parse in order to get the values I'm looking for:

Buffer: HTTP/1.1 200 OK
Buffer: Date: Tue, 08 Dec 2009 14:15:34 GMT
Buffer: Server: Apache/2.2.3 (CentOS)
Buffer: Last-Modified: Tue, 08 Dec 2009 14:15:02 GMT
Buffer: ETag: "fc117-28-332a2580"
Buffer: Accept-Ranges: bytes
Buffer: Content-Length: 40
Buffer: Connection: close
Buffer: Content-Type: text/plain; charset=UTF-8
Buffer:
Buffer: queue_sizes
Buffer: 0
Buffer: 0
Buffer: 0
Buffer: 0
Buffer: 0
Buffer: 0
Buffer: 0
Buffer: 1
Buffer: 0
Buffer: 0
Buffer: 0
Buffer: 0
Buffer: 0
Buffer: 0

It turns out that there's a lot of libraries for setting the Arduino Ethernet shield up as a server but I couldn't find any that make it easy to parse a response.

There were two major hurdles in the design of the program. One was how to parse the HTTP response. It took some thought (and Googling) but what you have to do is build string buffers as you read the the response one character at a time. Then process the buffer to determine if your looking at the HTTP header or the actual data that you've served.

The other programming problem was getting the lights to blink independently of one another. It was a difficult because the Arduino only does one thing at a time. I was able to accomplish this using the Metronome library, although there is still some blocking going on when the lights blink. I believe the solution will be to remove the delay() statements in the blink code.

This is the first time I've felt that a project is worthy of mounting in a project box. I got all the LEDs, mounts and box from Radio Shack, and bought a Dremel and label maker at Target. The next few hours were spent cursing and carving the plastic and soldering everything together.

More pictures

Internet-enabled blinkenlights

Internet-enabled blinkenlights

Installed

The code

Here's the code that make this thing tick:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
#include <Metro.h>
#include <WString.h>
#include <Ethernet.h>
 
#define MAX_STRING_LEN  20
#define BLINK_DELAY 100
#define LED_INTERVAL 60000
 
#define AMAZON_LED 2 // Define the led's pin
#define AMAZONOD_LED 3
#define NOKIA_LED 4
#define ITUNES_LED 5
#define LIMEWIRE_LED 6
#define RHAPSODY_LED 7
#define NAPSTER_LED 8
#define LALA_LED 9
 
int amazon_q;
int amazonod_q;
int amiestreet_q;
int emusic_q;
int groupietunes_q;
int itunes_q;
int lala_q;
int limewire_q;
int napster_q;
int nokia_q;
int rhapsody_q;
int shockhound_q;
int streaming_q;
 
Metro queueCheckMetro = Metro(10000);
 
Metro amazonMetro = Metro(1000);
Metro amazonodMetro = Metro(1000);
Metro nokiaMetro = Metro(1000);
Metro itunesMetro = Metro(1000);
Metro limewireMetro = Metro(1000);
Metro rhapsodyMetro = Metro(1000);
Metro napsterMetro = Metro(1000);
Metro lalaMetro = Metro(1000);
 
int state = HIGH;
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 2, 2 };
byte gateway[] = { 192, 168, 2, 1 };
byte subnet[] = { 255, 255, 255, 0 };
byte server[] = { 0,0,0,0 }; // Put the server's IP address here
Client client(server, 80);
int data_index = 0;
boolean header = true;
String buffer = String(100);
int response_writeindex = 0;
 
void setup()
{
 
  pinMode(AMAZON_LED,OUTPUT);
  digitalWrite(AMAZON_LED,state);
  pinMode(AMAZONOD_LED,OUTPUT);
  digitalWrite(AMAZONOD_LED,state);
  pinMode(NOKIA_LED,OUTPUT);
  digitalWrite(NOKIA_LED,state);
  pinMode(ITUNES_LED,OUTPUT);
  digitalWrite(ITUNES_LED,state);
  pinMode(LIMEWIRE_LED,OUTPUT);
  digitalWrite(LIMEWIRE_LED,state);
  pinMode(RHAPSODY_LED,OUTPUT);
  digitalWrite(RHAPSODY_LED,state);
  pinMode(NAPSTER_LED,OUTPUT);
  digitalWrite(NAPSTER_LED,state);
  pinMode(LALA_LED,OUTPUT);
  digitalWrite(LALA_LED,state);
 
  Ethernet.begin(mac, ip, gateway, subnet);
  Serial.begin(9600);
 
  delay(1000);
 
  Serial.println("connecting...");
 
  if (client.connect()) {
    Serial.println("connected");
    client.println("GET /queue_size.txt HTTP/1.0");
    client.println();
  } else {
    Serial.println("connection failed");
  }
}
 
void loop()
{ 
 
  if(queueCheckMetro.check() == 1){
   checkQueues();
 }
 
  blinkLEDS();
}
 
void checkQueues(){
  queueCheckMetro.interval(60000); // check the queues once a minute
 while (client.available()) {
    serialEvent();
  }
 
  calculateBlinkRates();
 
  if (!client.connected()) {
    Serial.println();
    Serial.println("Disconnected");
    client.stop();
 
     if (client.connect()) {
      client.println("GET /queue_size.txt HTTP/1.0");
      client.println();
      delay(2000);
    } else {
      Serial.println("Reconnect failed");
    }
  }
}
 
void serialEvent(){
  char inChar = client.read();
 
  if(inChar != '\n'){
   buffer.append(inChar);
  } else {
    Serial.print("Buffer: ");
    Serial.println(buffer);
    if(buffer.contains("queue_sizes")){
      // Finished reading HTTP header
      header = false;
    }
 
    if(header == false){
      parse_data_buffer();
      data_index = data_index++;
    }
    buffer = "";
  }
 
}
 
void parse_data_buffer(){
  // Parse the line
  switch (data_index){
          case 3:
            amazon_q = atoi(buffer);
            break;
          case 4:
            amazonod_q = atoi(buffer);
            break;
          case 5:
            amiestreet_q = atoi(buffer);
            break;
          case 6:
            emusic_q = atoi(buffer);
            break;
          case 7:
            groupietunes_q = atoi(buffer);
            break;
          case 8:
            itunes_q = atoi(buffer);
            break;
          case 9:
            lala_q = atoi(buffer);
            break;
          case 10:
            limewire_q = atoi(buffer);
            break;
          case 11:
            napster_q = atoi(buffer);
            break;
          case 12:
            nokia_q = atoi(buffer);
            break;
          case 13:
            rhapsody_q = atoi(buffer);
            break;
          case 14:
            shockhound_q = atoi(buffer);
            break;
          case 15:
            streaming_q = atoi(buffer);
            break;
        }
        return;
  }
 
void calculateBlinkRates(){
  if(amazon_q == 0){
    amazon_q=1;
  }
  if(amazonod_q == 0){
    amazonod_q=1;
  }
  if(nokia_q == 0){
    nokia_q=1;
  }
  if(itunes_q == 0){
    itunes_q=1;
  }
  if(limewire_q == 0){
    limewire_q=1;
  }
  if(rhapsody_q == 0){
    rhapsody_q=1;
  }
  if(napster_q == 0){
    napster_q=1;
  }
  if(lala_q == 0){
    lala_q=1;
  }
  int amazon_on_for = LED_INTERVAL / amazon_q;
  int amazonod_on_for = LED_INTERVAL / amazon_q;
  int nokia_on_for = LED_INTERVAL / nokia_q;
  int itunes_on_for = LED_INTERVAL / itunes_q;
  int limewire_on_for = LED_INTERVAL / limewire_q;
  int rhapsody_on_for = LED_INTERVAL / rhapsody_q;
  int napster_on_for = LED_INTERVAL / napster_q;
  int lala_on_for = LED_INTERVAL / lala_q;
  amazonMetro.interval(amazon_on_for);
  amazonodMetro.interval(amazon_on_for);
  nokiaMetro.interval(nokia_on_for);
  itunesMetro.interval(itunes_on_for);
  limewireMetro.interval(limewire_on_for);
  rhapsodyMetro.interval(rhapsody_on_for);
  napsterMetro.interval(napster_on_for);
  lalaMetro.interval(lala_on_for);
}
 
void blinkLEDS(){
 if (amazonMetro.check() == 1) { // check if the metro has passed it's interval .
    blinkLED(AMAZON_LED);
  }
 if (amazonodMetro.check() == 1) { // check if the metro has passed it's interval .
    blinkLED(AMAZONOD_LED);
  }
 if (nokiaMetro.check() == 1) { // check if the metro has passed it's interval .
    blinkLED(NOKIA_LED);
  }
 if (itunesMetro.check() == 1) { // check if the metro has passed it's interval .
    blinkLED(ITUNES_LED);
  }
 if (limewireMetro.check() == 1) { // check if the metro has passed it's interval .
    blinkLED(LIMEWIRE_LED);
  }
 if (rhapsodyMetro.check() == 1) { // check if the metro has passed it's interval .
    blinkLED(RHAPSODY_LED);
 }
 if (napsterMetro.check() == 1) { // check if the metro has passed it's interval .
    blinkLED(NAPSTER_LED);
 }
 if (lalaMetro.check() == 1) { // check if the metro has passed it's interval .
    blinkLED(LALA_LED);
 }
}
 
void delayWithBlink(int delay){
 for(int i=0; i &lt;= delay; i++){
  blinkLEDS();
 }
}
 
void blinkLED(int pin){
  digitalWrite(pin, LOW);
  delay(BLINK_DELAY);
  digitalWrite(pin,HIGH);
}