Wednesday, March 31, 2010

March Madness Challenge - Day 31

Whew, made it. Tonights project adds three potentiometers to might brightness calibration technique. Turns out it's important to examine ones assumptions. I discovered that I had to map values in distinct steps to keep the numbers within the range of my minimum maximum. If I hadn't hooked up the potentiometers and then outputted the values to see what my eyes were experience it would have taken much longer to realize this issue. So now I can go back and fix some older code.

I'd like to do a manual calibration for brightness and compare it to the automatic version. Since the analogRead function yields a 10 bit value at 4.9mV per unit it's possible to calculate what resistor needs to be place on each color in order to calibrate them with physical resistors and then not need the Arduino to calculate the relative values.

http://www.youtube.com/watch?v=QmNnJd9drYs




int redPin = 9;    // LED connected to digital pin 9
int greenPin = 11;
int bluePin = 10;
int pins[] = 
{
    redPin, greenPin, bluePin
};

int photoPin = 0;
int redPot = 1;
int greenPot = 2;
int bluePot = 3;

int photoVal = -1;
int rr, gg, bb = -1;
int minmax, rmax, gmax, bmax = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Start");
  
  pinMode(redPin, OUTPUT);     
  pinMode(greenPin, OUTPUT);     
  pinMode(bluePin, OUTPUT);  
  digitalWrite(redPin, HIGH);
  digitalWrite(greenPin, HIGH);
  digitalWrite(bluePin, HIGH); 

  digitalWrite(redPin, LOW);
  delay(500);
  rmax = analogRead(photoPin);
  digitalWrite(redPin, HIGH);

  digitalWrite(greenPin, LOW);
  delay(500);
  gmax = analogRead(photoPin);
  digitalWrite(greenPin, HIGH);

  digitalWrite(bluePin, LOW);
  delay(500);
  bmax = analogRead(photoPin);
  digitalWrite(bluePin, HIGH);
  
   sendMax();
   minmax = min(rmax, min(gmax, bmax));
   setRGB(255, 255, 255);
}

void setRGB(int red, int green, int blue) 
{
  //These values are the 10 bit values, they need to be mapped to minmax
    //For some reason some values were mapping negative
  red = map(red, 0, 1023, 0, minmax);
  green = map(green, 0, 1023, 0, minmax);
  blue = map(blue, 0, 1023, 0, minmax);
  sendRGB(red, green, blue); 
  
  red = map(red, 0, minmax, 255, 0);
  green = map(green, 0, minmax,  255, 0);
  blue = map(blue, 0, minmax,  255, 0);

  analogWrite(redPin, red);
  analogWrite(greenPin, green);
  analogWrite(bluePin, blue);
  sendRGB(red, green, blue);
}

void sendRGB(int red, int green, int blue) 
{
      Serial.print(" { \"red\" : ");
      Serial.print(red);
      Serial.print(", \"green\" : ");
      Serial.print(green);
      Serial.print(", \"blue\" : ");
      Serial.print(blue);
      Serial.print("}");
}

void sendMax()
{

    Serial.print(" { \"rmax\" : ");
    Serial.print(rmax);
    Serial.print(", \"gmax\" : ");
    Serial.print(gmax);
    Serial.print(", \"bmax\" : ");
    Serial.print(bmax);
    Serial.println("}");
}



void loop() 
{
  rr = analogRead(redPot);
  gg = analogRead(greenPot);
  bb = analogRead(bluePot);
  setRGB(rr, gg, bb);
  sendRGB(rr, gg, bb);
  Serial.print(" { \"minmax\" : ");
  Serial.print(minmax);
  Serial.println("}");
  
}

Tuesday, March 30, 2010

March Madness Challenge - Day 30

Example of a sha1 signed query string from a form. This is useful if you are calling a REST method from a web service. Next time I do this I'm going to look at the code posted here: http://code.google.com/p/crypto-js/

Here's the important part:

str = $("form").serialize().split("&").sort().join("&");
hex_str = hex_sha1(str);
console.log(str + "&sig=" + hex_str);


Full code:

Monday, March 29, 2010

March Madness Challenge - Day 29

A little more experimenting with Second Life. Decided to work with LLSetPrimtive. It allows for the changing of many of the prim options. This code tests scale, rotation, and changing the location of the prim. For fun my avatar was being harassed by a Dalek, and I sat on the test object and took a ride. The machine wasn't powerful enough to take a nice smooth video so this will have to do.

This code could be crossed with the httpserver mechanism and it could be controlled from outside of Second Life.

http://www.youtube.com/watch?v=eZWtsDzr0Qw



// touch to trigger binary actions involving llSetPrimitiveParams

integer trigger=FALSE;

default
{
    touch_start(integer nn)
    {
        if (trigger==FALSE)
        { 
            llSetPrimitiveParams([PRIM_POINT_LIGHT, TRUE, <1, 1, 1>, 1.0, 10.0, 0.75] ); 
            llSetPrimitiveParams([PRIM_SIZE, <0.5, 0.5, 0.5>]);
            llSetPrimitiveParams( [PRIM_ROTATION, ZERO_ROTATION] );
            rotation  yrot =  llEuler2Rot( < 0, 15 * DEG_TO_RAD, 0 > );
            integer ii;
            for (ii = 0; ii < 59; ii++)
            {
                llSetPrimitiveParams( [PRIM_ROTATION, llGetRot() * yrot] );
            }
            llSetPrimitiveParams([PRIM_POSITION, llGetPos() + <0,0,1>]); 
            trigger=TRUE; 
        }
        else
        { 
            llSetPrimitiveParams([PRIM_POINT_LIGHT, FALSE, <1, 1, 1>, 1.0, 10.0, 0.75] );
            llSetPrimitiveParams([PRIM_SIZE, <2, 2, 2>]);
            integer ii;
            integer increase;
            for (ii = 0; ii < 50; ii++)
            {
                llSetPrimitiveParams([PRIM_POSITION, llGetPos() + <0,0,1>]); 
            }

            for (ii = 0; ii < 50; ii++)
            {
                llSetPrimitiveParams([PRIM_POSITION, llGetPos() + <0,0,-1>]); 
            }
            trigger=FALSE;
        }
    }
}

Sunday, March 28, 2010

March Madness Challenge - Day 28

I got two prims to talk to to each other in Second Life over the httprequest and httpserver mechanism. Lot's of uses for this. This is the mechanism I use to get data in and out of Second Life, also it can be used to pass information between objects in Second Life, however, there are more effective mechanism for intra/inter prim communication in Second Life. Would be neat to see some scripting that was capable with shared media. Hopefully, I get to explore it more later. For now here's the code to get it working.

httpserver.lsl
key requestURL;
string gURI;
integer CHANNEL = 43;
integer LINK_TARGET = -1;
integer gPosterPrim = 1;

default
{
 
    state_entry() {
        requestURL = llRequestURL();     // Request that an URL be assigned to me.
        llOwnerSay((string) llGetLinkNumber());
        llOwnerSay((string) llGetNumberOfPrims());
        llMessageLinked(gPosterPrim,0,gURI,gURI);
    }
 
    on_rez(integer param)
    {   // Triggered when the object is rezzed, like after the object has been sold from a vendor
        llResetScript();//By resetting the script on rez forces the listen to re-register.
    }
    touch_start(integer number)
    {
        
        llOwnerSay("My URI: " + gURI);
        llSay(0,"linknum: " + (string)llGetLinkNumber());
        llSay(0, gURI);
        llMessageLinked(gPosterPrim,0,gURI,gURI);
            
    }
    
    link_message(integer sender_num, integer num, string msg, key id) {
        llOwnerSay(msg);
        llMessageLinked(gPosterPrim,0,gURI,gURI);
        
    }
    
    changed (integer change) {
        if (change && CHANGED_REGION ) {
            requestURL = llRequestURL();     // Request that an URL be assigned to me.
        }
        else {
            llOwnerSay("No need to update URL.");   
        }    
    }
    
    
     http_request(key id, string method, string body) {
 
        if ((method == URL_REQUEST_GRANTED) && (id == requestURL) ){
            // An URL has been assigned to me.
            llOwnerSay("LSL server obj: " + (string)llGetKey());
            llOwnerSay("URI: " + body);
            llSay(CHANNEL, body);
            gURI = body;
            requestURL = NULL_KEY;
        }

 
        else if ((method == URL_REQUEST_DENIED) && (id == requestURL)) {
            // I could not obtain a URL
            llOwnerSay("There was a problem, and an URL was not assigned: " + body);
            requestURL = NULL_KEY;
        }
 
        else if (method == "POST") {

            list headers = [ "x-script-url", 
                                "x-path-info", 
                                "x-query-string", 
                                "x-remote-ip", 
                                "user-agent", 
                                "x-secondlife-shard",           
                                "x-secondlife-object-name",     
                                "x-secondlife-object-key",      
                                "x-secondlife-region",          
                                "x-secondlife-local-position",  
                                "x-secondlife-local-rotation",  
                                "x-secondlife-local-velocity",  
                                "x-secondlife-owner-name",      
                                "x-secondlife-owner-key"    
                                ];
                integer pos = ~llGetListLength(headers);
                while( ++pos )
                    {
                        string header = llList2String(headers, pos);
                        llOwnerSay(header + ": " + llGetHTTPHeader(id, header));
                    }            
            
            // Anincoming message was received.
            string time =  llGetTimestamp();
            llOwnerSay("lslhttpserver (" + time + ") Received information from the outside: " + body);
            
            llHTTPResponse(id,200,"Thank you for calling. All of our operators are busy.");
        }
        
    
 
 
        else {
            // An incoming message has come in using a method that has not been anticipated.
            llHTTPResponse(id,405,"Unsupported Method");
        }
    }
 
}


post.lsl

key requestid; // just to check if we're getting the result we've asked for; all scripts in the same object get the same replies
string uri;
integer listen_handle;
string gURI;
key gServerPrimKey;
integer gPrimServer = 2;

default
{
    state_entry()
    {   
     
        llMessageLinked(gPrimServer,0,"Send gPrimURI","Send gPrimURI");
    }

    on_rez(integer param)
    {   // Triggered when the object is rezzed, like after the object has been sold from a vendor
        llResetScript();//By resetting the script on rez forces the listen to re-register.
    }
  
      link_message(integer sender_num, integer num, string msg, key id) {
        llOwnerSay(msg);
        gURI = msg;
      
    }
    
    touch_start(integer number)
    {
       
         llOwnerSay("My URI: " + gURI);
        llSay(0,"linknum: " + (string)llGetLinkNumber());
        llSay(0, gURI);
        llMessageLinked(gPrimServer,0,"Send gPrimURI","Send gPrimURI");
        
    
        requestid = llHTTPRequest(gURI, 
            [HTTP_METHOD, "POST",
             HTTP_MIMETYPE, "application/x-www-form-urlencoded"],
            "time=" +  llGetTimestamp()  +"¶meter2=world");
    
        
            
    }

    http_response(key request_id, integer status, list metadata, string body)
    {
        string time =  llGetTimestamp();
        
        
        if (request_id == requestid)
             llOwnerSay( "http resp(" + time + ") key: " + (string)request_id);
             llOwnerSay( "http resp(" + time + ") status: " + (string)status);
             llOwnerSay( "http resp(" + time + ") metadata: " + (string)metadata);
             llOwnerSay( "http resp(" + time + ") body: " + body);
             llWhisper(10, " Whisper to test box");


    }
}

Saturday, March 27, 2010

March Madness Challenge - Day 27

A little more work with Seriality API

I wrote a quick serial console for the Seriality API using jQuery, also, I have the RGB slider control project written. However, the serial.write() function seems to not do anything today. I went back to my original on/off code from Day 23 and it failed to work too, even though it had worked fine originally. So I'm going to post the code for the Serial Console and call it a night, and use some fresh eyes tomorrow to figure out why the one way communication is happening.

Friday, March 26, 2010

March Madness Challenge - Day 26

Took me a bit to get a strategy that passed most tests. I'll have to look at this one again in the morning. It has some nice features, and some mystery features. Using seriality API I could use QUnit to test the string parsing. Ok, so what this thing does is take a string of 3 numbers separated by commas, and feed it over the serial port to the Arduino. The code looks for commas and then asks is this the first, or second comma. There is no third comma so it simply checks nn value to say is this the third value. If so it sets it.

It only set's the values if it understands and leaves the values with the previous value. This should be a nice feature if used with sliders because there would be no off and on flickering it just stays on at the last combination it had.

This program also just echoes back the setting sent to it. Nice thing to look for for debugging. This is also a tool to be used for testing since, I know what went in should match what come out.

Finally, I added a map function that reverses HIGH, LOW and makes to analog numbers feel more natural. Also, I need to find a way to test that using the map function the way I'm using it really results in balance colors.


/*
* Day 26 RGB calibrated fading code with serial controls
*/
char str[11];

int redPin = 9; // LED connected to digital pin 9
int greenPin = 11;
int bluePin = 10;
int pins[] =
{
redPin, greenPin, bluePin
};

int photoPin = 0;
int photoVal = -1;
int rr, gg, bb = -1;
int minmax, rmax, gmax, bmax = 0;

void setup() {
Serial.begin(9600);
Serial.println("Start");

pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
digitalWrite(redPin, HIGH);
digitalWrite(greenPin, HIGH);
digitalWrite(bluePin, HIGH);

digitalWrite(redPin, LOW);
delay(500);
rmax = analogRead(photoPin);
digitalWrite(redPin, HIGH);

digitalWrite(greenPin, LOW);
delay(500);
gmax = analogRead(photoPin);
digitalWrite(greenPin, HIGH);

digitalWrite(bluePin, LOW);
delay(500);
bmax = analogRead(photoPin);
digitalWrite(bluePin, HIGH);

sendMax();
minmax = min(rmax, min(gmax, bmax));
setRGB(255, 255, 255);
}

void setRGB(int red, int green, int blue)
{
red = map(red, 0, minmax, 255, 0);
green = map(green, 0, minmax, 255, 0);
blue = map(blue, 0, minmax, 255, 0);
analogWrite(redPin, red);
analogWrite(greenPin, green);
analogWrite(bluePin, blue);
}

void sendRGB(int red, int green, int blue)
{
Serial.print(" { \"red\" : ");
Serial.print(red);
Serial.print(", \"green\" : ");
Serial.print(green);
Serial.print(", \"blue\" : ");
Serial.print(blue);
Serial.println("}");
}

void sendMax()
{

Serial.print(" { \"rmax\" : ");
Serial.print(rmax);
Serial.print(", \"gmax\" : ");
Serial.print(gmax);
Serial.print(", \"bmax\" : ");
Serial.print(bmax);
Serial.println("}");
}



void loop()
{
int ii = 0;
int nn = 0;
char num[2];
int rgb = 0;
boolean keepgoing = true;

while (keepgoing)
{
while (Serial.available() )
{
{
str[ii] = Serial.read();
num[nn] = str[ii];
//Echo the character as you type
//Serial.write(str[ii]);

if (str[ii] == 44)
{
if (rgb == 0)
{
rr = atoi(num);
nn = -1;
rgb++;
}
else if (rgb == 1)
{
gg = atoi(num);
nn = -1;
rgb++;
}
}
if (str[ii] == 0x0d )
{
keepgoing = false;
if (rgb == 2)
{
bb = atoi(num);
nn = -1;
rgb = 0;
}
sendRGB(rr,gg, bb);
setRGB(rr, gg, bb);
}
ii++;
nn++;
}
}
}
str[ii] = 0;
Serial.println();
Serial.println(str);
setRGB(rr, gg, bb);

}




Thursday, March 25, 2010

March Madness Challenge - Day 24

Yea, tonight some serial programming. With advice from Mark and John I got a nice Serial Echo program for the Arduino. I need to learn some basics about serial communication and have a tool to debug the communication from web page over Seriality to the Arduino.

/*
* Echo Serial on the Arduino
* with advice from Mark Sproul
*/
char str[10];


void setup() {
Serial.begin(9600);
Serial.println("Start");
}

void loop()
{
int ii = 0;
boolean keepgoing = true;
while (keepgoing)
{
while (Serial.available() )
{
{
str[ii] = Serial.read();
//Echo the character as you type
//Serial.write(str[ii]);
if (str[ii] == 0x0d )
{
keepgoing = false;
}
ii++;
}
}
}
str[ii] = 0;
Serial.println();
Serial.println(str);
delay(200);
}

Wednesday, March 24, 2010

March Madness Challenge - Day 24

Tonight's project is modifying the example RGB slider mixer example from jQuery and crossing it with the Seriality API. I now have an HTML. JQuery, and JQuery UI structure to be connected to an RGB Led, Photoresistor, and Arduino. Tomorrow I'll do the Arduino portion. So I promise tomorrow night will be much more interesting.

Also, I need to figure out how to use the BitBucket embed. Would be much nicer.

Screen is awesome

I was looking for a quick and easy way to look in on a serail port for Mac OS X and came across a tip to use "screen." I really like screen in general, but this really is nice.

Look for your serial port:
ls /dev/tty.*

screen /dev/tty.usbserial-ADxxx

and you are goog to go!

Tuesday, March 23, 2010

March Madness Challenge - Day 23

Today's March Madness will be done in less than 30 minutes. Tick, Tick, Tick, .... Erg, bugs, took 2 hours, and still bugs

I was thinking how neat it would be to be able to reach out to a serial device through the browser. Did some quick searching and found the Seriality API browser plugin. Tested it out and it works well on Mac OS X, and in Firefox. So for tonight I will take my JSON RGB Calibration project and hook it to a web page hosted locally in a web browser.

Started to move my code over to Bit Bucket. The project code can be found here: March Madness

I've got a nifty on off switch. It's a pause on color and other weird things, thing.





//*
* The RGB Calibrator
*
* Find, and monitor max brightness of red, green, and blue in an RGB led
*/


int redPin = 9; // LED connected to digital pin 9
int greenPin = 11;
int bluePin = 10;
int pins[] =
{
redPin, greenPin, bluePin
};
int i =0;

int photoPin = 0;
int potPin = 1;

int photoVal = -1;
int r,g,b = -1;
int rmax, gmax, bmax = 0;
int rmin, gmin, bmin = 1024;
char on = '-';
long interval = 500;
long previousMillis = 0;

void setup()
{
Serial.begin(9600);
// Serial.println("Setup done");

pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
digitalWrite(redPin, HIGH);
digitalWrite(greenPin, HIGH);
digitalWrite(bluePin, HIGH);

digitalWrite(redPin, LOW);
delay(1000);
digitalWrite(redPin, HIGH);

digitalWrite(greenPin, LOW);
delay(1000);
digitalWrite(greenPin, HIGH);

digitalWrite(bluePin, LOW);
delay(1000);
digitalWrite(bluePin, HIGH);

}


void loop()
{
if (i > 2) //The number of LEDS being measured
{
i = 0;
}
if (Serial.available()) {
on = Serial.read();
}

if (on == '!' ) {
digitalWrite(pins[i], LOW);
photoVal = analogRead(photoPin);


switch (i)
{
case 0: //red led
r = photoVal;
rmin = min(rmin, r);
rmax = max(rmax, r);
break;
case 1: //green led
g = photoVal;
gmin = min(gmin, g);
gmax = max(gmax, g);
break;
case 2: //blue led
b = photoVal;
bmin = min(bmin, b);
bmax = max(bmax, b);
break;
default: //should not happen
break;

}
Serial.print ("{ \"entry\" :");
Serial.print(" { \"photoVal\" : ");
Serial.print(photoVal);

Serial.print(", \"rmax\" : ");
Serial.print(rmax);
Serial.print(", \"gmax\" : ");
Serial.print(gmax);
Serial.print(", \"bmax\" : ");
Serial.print(bmax);

Serial.print(", \"rmin\" : ");
Serial.print(rmin);
Serial.print(", \"gmin\" : ");
Serial.print(gmin);
Serial.print(", \"bmin\" : ");
Serial.print(bmin);

Serial.print(", \"r\" : ");
Serial.print(r);
Serial.print(", \"g\" : ");
Serial.print(g);
Serial.print(", \"b\" : ");
Serial.print(b);
Serial.println("}}");

if (millis() - previousMillis > interval) {
previousMillis = millis();
digitalWrite(pins[i], HIGH);
i++;
}
}
else
{
digitalWrite(pins[i], HIGH);
}
}




Monday, March 22, 2010

March Madness Challenge - Day 22

Thought about what I was going to do, figured it would be some twist yesterday, and lo it was. Based on some sample code, and mixing it with simplejson I'm loading json data from the Arduino over serail and transforming it into a Python dictionary. This is neat for few things. One is that is formatted to be Python friendly or anything that reads JSON. it can easily be hooked up to something like a web framework like Django, Pylons, etc. I'll show the test Python code and then the updated Arduino code.

Python

import serial
import simplejson as json

ser = serial.Serial('/dev/tty.usbserial-A7004qpc',19200)
while 1:
try:
entry = json.loads(ser.readline())
print entry
print entry[u'entry'].keys()
except KeyboardInterrupt:
raise
except:
print "value not json"




Arduino RGB Calibration JSON code

/*
* The RGB Calibrator
*
* Find, and monitor max brightness of red, green, and blue in an RGB led
*/


int redPin = 9; // LED connected to digital pin 9
int greenPin = 11;
int bluePin = 10;
int pins[] =
{
redPin, greenPin, bluePin
};
int i =0;

int photoPin = 0;
int potPin = 1;

int photoVal = -1;
int r,g,b = -1;
int rmax, gmax, bmax = 0;
int rmin, gmin, bmin = 1024;

long interval = 500;
long previousMillis = 0;

void setup()
{
Serial.begin(19200);
// Serial.println("Setup done");

pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
digitalWrite(redPin, HIGH);
digitalWrite(greenPin, HIGH);
digitalWrite(bluePin, HIGH);

digitalWrite(redPin, LOW);
delay(1000);
digitalWrite(redPin, HIGH);

digitalWrite(greenPin, LOW);
delay(1000);
digitalWrite(greenPin, HIGH);

digitalWrite(bluePin, LOW);
delay(1000);
digitalWrite(bluePin, HIGH);

}


void loop()
{
if (i > 2) //The number of LEDS being measured
{
i = 0;
}

digitalWrite(pins[i], LOW);
photoVal = analogRead(photoPin);


switch (i)
{
case 0: //red led
r = photoVal;
rmin = min(rmin, r);
rmax = max(rmax, r);
break;
case 1: //green led
g = photoVal;
gmin = min(gmin, g);
gmax = max(gmax, g);
break;
case 2: //blue led
b = photoVal;
bmin = min(bmin, b);
bmax = max(bmax, b);
break;
default: //should not happen
break;

}
Serial.print ("{ \"entry\" :");
Serial.print(" { \"photoVal\" : ");
Serial.print(photoVal);

Serial.print(", \"rmax\" : ");
Serial.print(rmax);
Serial.print(", \"gmax\" : ");
Serial.print(gmax);
Serial.print(", \"bmax\" : ");
Serial.print(bmax);

Serial.print(", \"rmin\" : ");
Serial.print(rmin);
Serial.print(", \"gmin\" : ");
Serial.print(gmin);
Serial.print(", \"bmin\" : ");
Serial.print(bmin);

Serial.print(", \"r\" : ");
Serial.print(r);
Serial.print(", \"g\" : ");
Serial.print(g);
Serial.print(", \"b\" : ");
Serial.print(b);
Serial.println("}}");

if (millis() - previousMillis > interval) {
previousMillis = millis();
digitalWrite(pins[i], HIGH);
i++;
}
}

Sunday, March 21, 2010

March Madness Challenge - Day 21

Worked on the AnnoyAltron 2000 yesterday, the RGB didn't really have good color calibration. So I'm planning to hook a Potentiometer to the RGB LED, next to a Photoresistor on an analog port for the Arduino, and measure the brightness. Then find the correct resistance needed for mixing the RGB colors.

Hmmm.... interesting maybe this could be made automatic and not need a manual override. If it appears one is brighter than another after calibration a manual setting should be possible.

Well. After a bit of work I got the basics of this running. I ran to a very interesting set of issues. The RGB led I used is common anode vs common cathode. So after a while of confusion it was resolved that LOW is on, and HIGH is off for that configuration for the Arduino. That brought up the question of why does the AnnoyLatron work at all then. Turns, out I was writing analog values to RGB led. What that did was show values from dark to bright, as opposed to on and off values. So the larger the number the dimmer it got. Smaller the number the brighter it got. It worked in inverse. So for this kind of project it didn't matter too much. I'll go look at the code a little later and see if there were any other "interesting" things in there.

Anyway, once that was resolved the rest was pretty simple, but testing it out and making sure the basics were right took a lot of time. I also ended up with a few questions like how do the analog pins sample and return the values detected. I want to confirm that it's strictly a voltage reading. Then I started worrying about noise, and calibrating the calibrator. I had a potentiometer hooked to the pin 1 next the photoresistor pin 0. I pulled that off the bread board, and the values changed to be more consistent. Also, there was light in the room. I was treating that as a constant.

Things did stabilize. So I was getting decent readings, and I got some decent data on max brightness. However, there was a real problem with the detecting minimum brightness. I figured out a few obvious issues, but some where the min is being assigned a 0, and I can't tell if that is a real reading or not. Also, once maxs and mins are found I didn't provide a way to have maxs and mins readjust overtime and experimentation. THe program needs a reset to adjust as things change. So if I do add some potentiometers to calibrate the brightness, I would need to be able to find those new values without restarting.

Not perfect but way fun.



/*
* The RGB Calibrator
*
* Find, and monitor max brightness of red, green, and blue in an RGB led
*/


int redPin = 9; // LED connected to digital pin 9
int greenPin = 11;
int bluePin = 10;
int pins[] =
{
redPin, greenPin, bluePin
};
int i =0;

int photoPin = 0;
int potPin = 1;

int photoVal = -1;
int r,g,b = -1;
int rmax, gmax, bmax = 0;
int rmin, gmin, bmin = 1024;

long interval = 500;
long previousMillis = 0;

void setup()
{
Serial.begin(19200);
Serial.println("Setup done");

pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
digitalWrite(redPin, HIGH);
digitalWrite(greenPin, HIGH);
digitalWrite(bluePin, HIGH);

digitalWrite(redPin, LOW);
delay(1000);
digitalWrite(redPin, HIGH);

digitalWrite(greenPin, LOW);
delay(1000);
digitalWrite(greenPin, HIGH);

digitalWrite(bluePin, LOW);
delay(1000);
digitalWrite(bluePin, HIGH);

}


void loop()
{
if (i > 2) //The number of LEDS being measured
{
i = 0;
}

digitalWrite(pins[i], LOW);
photoVal = analogRead(photoPin);


switch (i)
{
case 0: //red led
r = photoVal;
rmin = min(rmin, r);
rmax = max(rmax, r);
break;
case 1: //green led
g = photoVal;
gmin = min(gmin, g);
gmax = max(gmax, g);
break;
case 2: //blue led
b = photoVal;
bmin = min(bmin, b);
bmax = max(bmax, b);
break;
default: //should not happen
break;

}

Serial.print(" photoVal: ");
Serial.print(photoVal);

Serial.print(" rmax: ");
Serial.print(rmax);
Serial.print(" gmax: ");
Serial.print(gmax);
Serial.print(" bmax: ");
Serial.print(bmax);

Serial.print(" rmin: ");
Serial.print(rmin);
Serial.print(" gmin: ");
Serial.print(gmin);
Serial.print(" bmin: ");
Serial.print(bmin);

Serial.print(" r: ");
Serial.print(r);
Serial.print(" g: ");
Serial.print(g);
Serial.print(" b: ");
Serial.println(b);

if (millis() - previousMillis > interval) {
previousMillis = millis();
digitalWrite(pins[i], HIGH);
i++;
}
}

Saturday, March 20, 2010

March Madness Challenge - Day 20

Allright. Something interesting for the night. Updated the accelerated LED project, and added a piezo buzzer. So now I offer you the AnnoyALatron 2000. All the RGB goodness brought to you with sound. It's a shaky device that changes pitch as you shake it. Who knew vigorous shaking could do so much for so few. :-P


http://www.youtube.com/watch?v=qobngrJLDNw



/*
* The AnnoyAlatron 2000
*
* Accelorometer controled red, green, blue leds, and piezo buzzer
* ADXL335
*/
#define NOTE_C6 1047
#define NOTE_E6 1319
#define NOTE_G6 1568

int notes[] = {
NOTE_C6, NOTE_E6,NOTE_G6 };

int piezoPin = 8;
int greenPin = 9; // LED connected to digital pin 9
int redPin = 10;
int bluePin = 11;
int Z = 0;
int Y = 1;
int X = 2;
int r,g,b = 0;
int xmax, ymax, zmax = 0;
int xmin, ymin, zmin = 1024;
float xg, yg, zg;

void rgb (int r, int g, int b)
{
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);

}


//From the Adafruit forums
float to_g(const int axis_value)
{
const float arduino_power_supply = 5;
const float sensor_power_supply = 3.3;
const float zero_g_bias = sensor_power_supply / 2;
float voltage = axis_value * arduino_power_supply / 1024;
return (voltage - zero_g_bias) * 1000 / 330;
}

void setup()
{
Serial.begin(19200);
Serial.println("Setup done");
tone(piezoPin, notes[0], 200);
tone(piezoPin, notes[1], 200);
tone(piezoPin, notes[2], 200);

}


void loop()
{

r = analogRead(Z);
g = analogRead(Y);
b = analogRead(X);

xg = to_g(b);
yg = to_g(g);
zg = to_g(r);

Serial.print(" X: ");
Serial.print(b);
Serial.print(" xg: ");
Serial.print(xg);
Serial.print(" Y: ");
Serial.print(g);
Serial.print(" yg: ");
Serial.print(yg);
Serial.print(" Z: ");
Serial.print(r);
Serial.print(" zg: ");
Serial.println(zg);

xmin = min(xmin, b);
ymin = min(ymin, g);
zmin = min(zmin, r);

xmax = max(xmax, b);
ymax = max(ymax, g);
zmax = max(zmax, r);

tone(piezoPin, (r + notes[0]), 10);
tone(piezoPin, (g + notes[1]), 10);
tone(piezoPin, (b + notes[2]), 10);

r = map(r, zmin, zmax, 0, 255);
g = map(g, ymin, ymax, 0, 255);
b = map(b, xmin, xmax, 0, 255);

rgb(r, g, b);

}


Friday, March 19, 2010

March Madness Challenge - Day 19

Ok Google, why does your Google Apps Script not have any decent search features. Let's look at the API for contacts. If your grep for search nope nothing, nada. There is findByEmailAddress, but I have to know what I'm looking for not a substring. This goes with events, I can search the calendar application and search for words related to my events, but the API doesn't contain a search feature. You have to select an event by date. Not so useful. Anyway onto tonight's March madness.

Non working code, sorry.


function getAllContacts() {
var contacts = ContactsApp.getAllContacts();
for (var i = 0; i < contacts.lengh; i++)
{
var contact = [];
contact.push(contacts[i].getFullName());
contact.push(contacts[i].getPrimaryEmail());
contact.push(contacts[i].getEmailAddresses());
contact.push(contacts[i].getHomeAddress());
contact.push(contacts[i].getWorkAddress());
contact.push(contacts[i].getPager());
contact.push(contacts[i].getHomeFax());
contact.push(contacts[i].getWorkFax());
contact.push(contacts[i].getHomePhone());
contact.push(contacts[i].getWorkPhone());
contact.push(contacts[i].getMobilePhone());
contact.push(contacts[i].getNotes());
contact.push(contacts[i].getUserDefinedField());
contact.push(contacts[i].getUserDefinedFields());
range = SpreadsheetApp.getActiveSheet().getRange((3+i),1,1,contact.length);
range.setValues([contact]);
}
}

Thursday, March 18, 2010

March Madness Challenge - Day 18


//Apply force and torque to large sphere in Second LIfe
default
{
touch(integer i)
{
llSetStatus(STATUS_PHYSICS, TRUE);
llSetForceAndTorque(<0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF>, <10,0x7FFFFFFF,10>,0);
}
}

Wednesday, March 17, 2010

March Madness Day 17

Experimentation with representations of JSON in Python. This program takes some test data in a file of formatted JSON data from stdio and loads it into memory and then prints out the version in memory.

testdata.json

{"foo":"bar", "baz":1, "a":2}


jsonstdio.py

import sys
import json

def getjson(jd):
jsondata = json.loads(jd)
print "JSON Data: "
print repr(jsondata)


def main():
stdin = sys.stdin.read()
getjson(stdin)

if __name__=="__main__":
main()




How to run:
python jsonstdio.py < testdata.json

Tuesday, March 16, 2010

March Madness Challenge - Day 16

Wired and ADXL335 accelerometer to RGB leds. Thought neat I've got a simple program. Oops, the only difference between the Joystick controlled RGB LED was that I was measuring X, Y, and Z axis. Three variable between two programs. Yikes, that sounds a lot like a rule violation. So in the last few minutes I've added self calibration to the device. I didn't have time to work out the math and turn the numbers into something meaning so I did something to make it more meaningful to an LED. x, y, and z max and min values are now checked and set so depending on the most recent max and mins the widest led action occurs.


/*
* Accelerometer controlled red, green, blue leds
* ADXL35
*/


int redPin = 9; // LED connected to digital pin 9
int greenPin = 10;
int bluePin = 11;
int Z = 0;
int Y = 1;
int X = 2;
int r,g,b = 0;
int xmax, ymax, zmax = 0;
int xmin, ymin, zmin = 1024;

void rgb (int r, int g, int b)
{
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);

}

void setup() {
Serial.begin(9600);
Serial.println("Setup done");
}


void loop() {

r = analogRead(Z);
g = analogRead(Y);
b = analogRead(X);

xmin = min(xmin, b);
ymin = min(ymin, g);
zmin = min(zmin, r);

xmax = max(xmax, b);
ymax = max(ymax, g);
zmax = max(zmax, r);
/*
Serial.print("xmin: ");
Serial.print(xmin);
Serial.print(", xmax: ");
Serial.print(xmax);
Serial.print(" ymin: ");
Serial.print(ymin);
Serial.print(", zmax: ");
Serial.println(zmax);
*/


r = map(r, zmin, zmax, 0, 255);
g = map(g, ymin, ymax, 0, 255);
b = map(b, xmin, xmax, 0, 255);

rgb(r, g, b);
/*
Serial.print(r);
Serial.print(", ");
Serial.print(g);
Serial.print(", ");
Serial.println(b);
*/

}


Monday, March 15, 2010

March Madness Challenge - Day 15

This time tried to create Events from a Google Spreadsheet. Came close but ran out of time. The time parsing was messed up. I could not find clear docs about the format of the Spreadsheet date that would be compatible with the Javascript Date function. None of the options looked to be a visual match. Adding a menu item called "makeEvent" worked. Selecting info from the active row seemed to work well. Even though I really wanted getDataRange inside of a range. I new the number of columns so I could just grab what I needed. Lastly, the "options" part of createEvent(title, starttime, endtime, options) was a Javascript Object. This always ended up blank, probably an error on my part. But no multi value examples were available.

I did find this useful set of examples when I was flailing around Maintaing a Google Calendar from a Spreadsheet, Reprise.


function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "MakeEvent", functionName: "getEventFromSpreadSheet"} ];
sheet.addMenu("Events", menuEntries);
}

function getEventFromSpreadSheet () {

var range = SpreadsheetApp.getActiveRange();

var vals = range.getValues();
var Title = vals[0];
var Description = vals[1];
var Summary = vals[2];
var StartTime = vals[3];
var EndTime = vals[4];
var Location = vals[5];
var Guests = vals[6];
var GuestsStatus = vals[7];
var Invites = vals[8];
var Options = {description: Description,
guests: Guests,
location: Location,
sendInvites: Invites
};
makeEvent(Title, StartTime, EndTime, Options);
}

function makeEvent(Title, StartTime, EndTime, Options) {
var cal = CalendarApp.getDefaultCalendar();
cal.createEvent(Title, new Date(StartTime), new Date(EndTime), {location:'blah loc'}, {description: 'blah desc'});
}


W00t the fixes just clicked. Given my comments below here is the fixed code:

function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "MakeEvent", functionName: "getEventFromSpreadSheet"} ];
sheet.addMenu("Events", menuEntries);
}

function getEventFromSpreadSheet () {

var range = SpreadsheetApp.getActiveRange();

var vals = range.getValues();
var Title = vals[0][0];
var Description = vals[0][1];
var Summary = vals[0][2];
var StartTime = vals[0][3];
var EndTime = vals[0][4];
var Location = vals[0][5];
var Guests = vals[0][6];
var GuestsStatus = vals[0][7];
var Invites = vals[0][8];
var Options = {description: Description,
guests: Guests,
location: Location,
sendInvites: Invites
};

makeEvent(Title, StartTime, EndTime, Options);
}

function makeEvent(Title, StartTime, EndTime, Options) {
var cal = CalendarApp.getDefaultCalendar();
cal.createEvent(Title, new Date(StartTime), new Date(EndTime), Options);
}



And here is the CSV of the spreadsheet I tested with:

Title,Description,Summary,StartTime,EndTime,Location,Guests,GuestsStatus
MyTest,MyTest Description,MyTest Summary,9/22/2010 10:00:00,9/22/2010 11:00:00,Home Test,0000@noemail.gmail.com,yes
MyTest1,MyTest Description,MyTest Summary,10/22/2010 0:00:00,10/22/2010 0:00:00,Home Test,0000@noemail.gmail.com,yes

Sunday, March 14, 2010

March Madness Challenge - Day 14

I wrote some code earlier that scraped the guest from an event in the Google Calendar the hard way. With a little bit of searching around it looks Google Apps Scripting is the right solution. So in keeping with the spirit of March Madness I will need to do something more than rewrite that entry. These functions dump the entire Default Calendar events into a Google Spreadsheet. I would have liked to have write a script that get's the guests from one event, creates a new event and invites them to it, but I got side tracked.



I really liked the Logger object, but it started causing errors so I removed that code. I put it back and everything seemed good so I moved on.

Hint to get oriented for selecting range values:

var range = SpreadsheetApp.getActiveSheet().getRange(1,1,1,8);
Browser.msgBox("row: " + range.getRowIndex() + " rows: " + range.getNumRows() + " col: " + range.getColumnIndex() + " cols: " + range.getNumColumns() + " Vals: " + range.getValues());



The code for tonight. Make a Google Apps Script and paste the code in. However, I use the JSON.stringify library for the full dump of the event Object. It has to be pasted in at the bottom of the file. You can get that code here:


This code dumps the entire object including the functions. So if you need analyze what Google is doing this approach get's every piece of data and method for the object. Some times it's nice to get all the detail. As a short cut I use JSON.stringify to dump the data held in some of the fields. If you can read the JSON this is nice because it directly translates into the object, and you can keep drilling down.


function dumpEventObject() {
// The code below will retrieve all the events for the user's default calendar and
// display the description of the first event
var cal = CalendarApp.getDefaultCalendar();
var events = cal.getEvents(new Date("July 21, 2009 EST"), new Date());
var text = "";
var range;

event = [];

Logger.log(JSON.stringify(events[0]));

//set the headers
var key;
for (key in events[0]){
event.push(key);
}

range = SpreadsheetApp.getActiveSheet().getRange(2,1,1,event.length);
range.setValues([event]);

//add the dat into appropriate rows/columns
var i;
for (i = 0; i < events.length; i++)
{
event = [];
for (ev in events[i] )
{
if (typeof events[i][ev] != 'function') {
event.push(JSON.stringify(events[i][ev]));
} else {
event.push(events[i][ev]);
}
}

range = SpreadsheetApp.getActiveSheet().getRange((3+i),1,1,event.length);
range.setValues([event]);
}
}




Dumps only the data. This is useful to get information you need and work with. I can see cleaning this up more and really make a nice library. This doesn't use JSON.stringify. It iterates through any arrays and separates them on a new line. So all the email address for guests of an event are clearly listed.


function dumpEventData () {
// The code below will retrieve all the events for the user's default calendar and
// display the description of the first event
var cal = CalendarApp.getDefaultCalendar();
var events = cal.getEvents(new Date("July 21, 2009 EST"), new Date());
var event = [];

//set the headers
for (var key in events[0]){
if ((typeof events[0][key] != 'function' ) && ( typeof events[0][key] != 'undefined' ) ){
event.push(key);
}
}
var range = SpreadsheetApp.getActiveSheet().getRange(2,1,1,event.length);
range.setValues([event]);

for (var i = 0; i < events.length; i++)
{
event = [];
for (key in events[i] )
{
if ((typeof events[i][key] != 'function' ) && ( typeof events[i][key] != 'undefined' ) ){
if ((typeof events[i][key] == 'object') && (events[i][key].length))
{
var txt = "";
for (var k in events[i][key])
{
txt = txt + events[i][key][k] + "\n";
}
event.push(txt);
}
else
{
event.push(events[i][key]);
}
}
}
range = SpreadsheetApp.getActiveSheet().getRange((3+i),1,1,event.length);
range.setValues([event]);
}
}



I'm pretty excited about this new capability. If anyone has feedback I'd appreciate it. This is my first rough crack at Google Apps Scripting. I think there is some amazing potential here.

Saturday, March 13, 2010

March Madness Challenge - Day 13

Exploration of the zip, izip functions in Python. The code doesn't really get to the meaning and best use of the zip, and izip functions. Another piece of code I'm going to have to revisit later. I'll be exploring Python test frameworks soon, hopefully, I can revisit the testing and bench marking using one of the official Python frameworks.


from itertools import izip

c1 = ["ft","fu","fs","fv"]
c2 = ["gt","gu","gs","gv"]
c3 = ["ht","hu","hs","hv"]
c4 = ["it","iu","is","iv"]

c = [c1,c2,c3,c4]
ind = ["r1","r2","r3","r4"]

def showit(c):
for i in c:
for k in i:
print k
def izipit(c):
for (i,k) in izip(ind, c):
print i
print k

def zipit(ind, c):
d = dict(zip(ind, c))
return d

print "showit(c)"
showit(c)
print "izipit(c)"
izipit(c)
print "zipit(c)"
print zipit(ind, c)

Friday, March 12, 2010

March Madness Challenge - Day 12

I've been at the Virtual Worlds Best Practices in Education Conference all day. I've learning all kinds of neat stuff about mixed reality, real reality, virtual reality, and lots of stuff in between. The 3D world in this case is Second Life from the Linden Lab people. They came out with a beta browser and there's lot's of neat potential. The shared media component is really nice. I can create a panel and post to my blog on it now. What I'm really waiting for is the ability to export/import 3D objects to standard 3D tools like Blender. So it would be great to build stuff in or out of Second Life, and then be able to send it to a Makerbot or Mendel for printing.

In the meantime I wrote this script which sends messages from the sender prim to the receiver prim and tells it to fade away the more it is clicked.



The Red Message Sending Box/Prim:

integer chan = -12878;

default
{
state_entry()
{
llOwnerSay( "Sending prim ready");
}

touch_start(integer total_number)
{
llSay(chan, "Hello, this is from RK");
}
}


The Blue Spinny Thing that receives messages from Red Message Box.

float spin_rate = 0.1;
integer chan = -12878;
float alpha = 1.0;

default
{
state_entry()
{
llSay(0, "Hello, Avatar!");
llListen(chan, "", "", "");
llTargetOmega(<1.0,0.0,0.0>,spin_rate,0.2);
}


listen(integer channel, string name, key id, string message)
{
llSay(0,"I heard:"+message);
alpha = alpha - 0.1;
llSetAlpha(alpha,ALL_SIDES);
if (alpha < 0.0)
{
alpha = 1.0;
}
}

}

Thursday, March 11, 2010

March Madness Challenge - Day 11

Hello kwargs

#test the default args

def test2args(arg1="default1", arg2="default2"):
print "arg1: " + arg1
print "arg2: " + arg2

def test2argskwargs(arg1="default1", arg2="default2", **kwargs):
print "arg1: " + arg1
print "arg2: " + arg2
for k, v in kwargs:
print "%s=%s" % (k, v)



test2args()
test2args("1","2")
args = ("3","4")

test2args(*args)
#test2args(a="5", b="6")
test2argskwargs("3","4", a="5", b="6")

Wednesday, March 10, 2010

March Madness Challenge - Day 10

Ok. Fighting back from last minute code, and then trying to fix it the next day. My little fixes managed to break barely working code. So, let's look at a a testing framework for Javascript called Qunit. QUnit is a jQuery based testing framework. Once you've got the basic html in place just include the necessary css and Javascript and you are up and running. Since my previous code had some issues with cookies I figured I would use QUnit to do a couple of test of how cookies work. I'll probably do more variations on this theme, but until then. Here's the code need to quickly test if cookies exist, cookies are created, etc.

Live Page


<!DOCTYPE html>
<html>
<head>
<title>QUnit Cookie test</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<script type="text/javascript" src="http://www.google.com/jsapi?key=ABQIAAAAyOcYQmrUZiRTkZD33sBhThSYG2nKbTfLUqOyuY0R-KaU9CNsSxQHWg8je-XfTEMamlZKbXxG4Z752A">
</script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true">
</script>
<script type="text/javascript" charset="utf-8">
google.load("jquery", "1.4.2");
</script>
<link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css" media="screen" />
<script type="text/javascript" src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script>
<script type="text/javascript" src="jquery.cookies.2.2.0.min.js">
</script>

<script type="text/javascript" charset="utf-8">
$(document).ready(function() {

test("a basic test example", function() {
ok( true, "this test is fine" );
var value = "hello";
equals( "hello", value, "We expect value to be hello" );
});

test("Are cookies available?", function() {
ok(true, $.cookies.test());
});

//Are there existing cookies
test("Is there an existing cookie?", function() {
equals(true, $.cookies.get('newcookie')[0].test, "Cookie exists from last time.");
});

//Load cookie values nd check

//Create a new cookie test
test("Created new cookie.", function () {
var markers = [];
var marker = {test: true, date: new Date() } ;
markers.push(marker);
$.cookies.set('newcookie', markers);
var cookiedata = $.cookies.get('newcookie');
equals(true, cookiedata[0].test, "Cookie data is true");
});
//if not created create cookie data

//find and display existing markers
});
</script>
<style type="text/css">
div.c1 {width:100%; height:100%}
</style>
</head>
<body>
<h1 id="qunit-header">QUnit Cookie Tests</h1>
<h2 id="qunit-banner"></h2>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
</body>
</html>

Tuesday, March 09, 2010

March Madness Challenge - Day 9

Another last minute post. Attempting to save marker data as JSON array in a Cookie in a jQuery friendly way. I ran out of time to test the code. In theory it should work.

Preview URL

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Where in the world is my dog pooin!</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="http://www.google.com/jsapi?key=ABQIAAAAyOcYQmrUZiRTkZD33sBhThSYG2nKbTfLUqOyuY0R-KaU9CNsSxQHWg8je-XfTEMamlZKbXxG4Z752A"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script type="text/javascript" charset="utf-8">
google.load("jquery", "1.4.2");
</script>

<script type="text/javascript" src="jquery.cookies.2.2.0.min.js"></script>

<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var markers = [];
function setPosition(position) {
console.log("setPosition: lat: " + position.coords.latitude + " lng: " + position.coords.longitude );
var location = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
console.log("Map: " + map);
map.setCenter(location, 13);
addMarker(location, "Quality: " + $("input[name='quality']:checked").val() + "Date: " + new Date());
}

function addMarker(location, msg) {
var marker = new google.maps.Marker({
position: location,
map: map,
title: msg
});
markers.push(marker);
$.cookies.set('dogdata', markers);
}

function detectBrowser() {
var useragent = navigator.userAgent;
var mapdiv = document.getElementById("map_canvas");

if (useragent.indexOf('iPhone') != -1 || useragent.indexOf('Android') != -1 ) {
mapdiv.style.width = '100%';
mapdiv.style.height = '100%';
} else {
mapdiv.style.width = '600px';
mapdiv.style.height = '800px';
}
}

if( !$.cookies.test() )
{
alert("Please enable cookies for this program to track very important information");
}

//if not created create cookie data

//find and display existing markers

var latlng = new google.maps.LatLng(-34.397, 150.644);
var myOptions = {
zoom: 14,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

$("#setcenter").bind("click", function(e){
console.log("bind click");
navigator.geolocation.getCurrentPosition(setPosition);
});

if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(setPosition);
} else {
alert("navigator.geolocation not available.");

}
// detectBrowser();
navigator.geolocation.getCurrentPosition(setPosition);
});
</script>
</head>
<body >
<h1>Warning the SQLite poo storage db is not installed yet.</h1>
<h2>This means you have to never reload the page to record all the necessary poo data.</h2>
<div>Where in the world does my dog poo?</div>

<div>Use the geolocation information to mark the spots your dog marks, with optional quality indicator.</div>

<form name="controls">
<div>Quality: </div>
<input type="radio" name="quality" value="1">1</input>
<input type="radio" name="quality" value="2">2</input>
<input type="radio" name="quality" value="3" checked="checked">3</input>

<input type="radio" name="quality" value="4">4</input>
<input type="radio" name="quality" value="5">5</input>
<button name="setcenter" id="setcenter">Mark!</button>
</form>
<div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>

Monday, March 08, 2010

March Madness Challenge - Day 8

This is the beginning of something special for all the dog lovers in the world. Using Google Maps API version 3, and jQuery you can now mark on a map where and the quality of your dogs poo. Unfortunately, this program is a two parter. Today's portion allows you to mark the location of the poo, and track it as long as you never reload the web page. The next update will use the SQLite option in HTML to store and retrieve poo data.

Compatibiltiy note: Marking poo locations works in Firefox 3.5 and higher, iPhone, and maybe Droid. When SQLite is added it will end up being only iPhone or Droid.

One thing that took way too much time to debug was how get the code recognized as HTML5. One way is to strip out all the things indicating that it's not HTML 5 and include only an html tag by itself. This let's the browser choose.

And here's the code:


<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Where in the world is my dog pooin!</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="http://www.google.com/jsapi?key=ABQIAAAAyOcYQmrUZiRTkZD33sBhThSYG2nKbTfLUqOyuY0R-KaU9CNsSxQHWg8je-XfTEMamlZKbXxG4Z752A"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script type="text/javascript" charset="utf-8">
google.load("jquery", "1.4.2");
</script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
function setPosition(position) {
console.log("setPosition: lat: " + position.coords.latitude + " lng: " + position.coords.longitude );
var location = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
console.log("Map: " + map);
map.setCenter(location, 13);
addMarker(location, "msg");
}

function addMarker(location, msg) {
var marker = new google.maps.Marker({
position: location,
map: map,
title: msg
});
}

function detectBrowser() {
var useragent = navigator.userAgent;
var mapdiv = document.getElementById("map_canvas");

if (useragent.indexOf('iPhone') != -1 || useragent.indexOf('Android') != -1 ) {
mapdiv.style.width = '100%';
mapdiv.style.height = '100%';
} else {
mapdiv.style.width = '600px';
mapdiv.style.height = '800px';
}
}

var latlng = new google.maps.LatLng(-34.397, 150.644);
var myOptions = {
zoom: 14,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

$("#setcenter").bind("click", function(e){
console.log("bind click");
navigator.geolocation.getCurrentPosition(setPosition);
});

if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(setPosition);
} else {
alert("navigator.geolocation not available.");

}
// detectBrowser();
navigator.geolocation.getCurrentPosition(setPosition);
});
</script>
</head>
<body >
<h1>Warning the SQLite poo storage db is not installed yet.</h1>
<h2>This means you have to never reload the page to record all the necessary poo data.</h2>
<div>Where in the world does my dog poo?</div>
<div>Use the geolocation information to mark the spots your dog marks, with optional quality indicator.</div>

<form name="controls">
<div>Quality: </div>
<input type="radio" name="quality" value="1">1</input>
<input type="radio" name="quality" value="2">2</input>
<input type="radio" name="quality" value="3">3</input>
<input type="radio" name="quality" value="4">4</input>
<input type="radio" name="quality" value="5">5</input>
<button name="setcenter" id="setcenter">Mark!</button>
</form>
<div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>

Sunday, March 07, 2010

March Madness Challenge - Day 7

Thumb joystick controlled RGB LED!!!

Yesterdays entry was way unsatisfying. I wanted to enumerate all the possible RGB combinations, but was impatient, and made errors. Today's project took on the issue of determining what exact PWM values were set on this RGB led, and getting a starting point to calibrate the brightness between leds so get a decent color mix. Well, I didn't get to the issue of calibration, but I did get connect 2 thumb joysticks to the led and adjust the brightness values by reading the joystick data. Hook up 3 potentiometers and you can dial the exact combination RGB values you want.




/*
* 3 Potentiometers or Joystick controled rgb led
*/


int redPin = 9; // LED connected to digital pin 9
int greenPin = 10;
int bluePin = 11;
int potR = 0;
int potG = 1;
int potB = 2;
int r,g,b = 0;

void rgb (int r, int g, int b)
{
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);

}

void setup() {
Serial.begin(9600);
Serial.println("Setup done");
}


void loop() {

r = analogRead(potR);
g = analogRead(potG);
b = analogRead(potB);

r = map(r, 0, 1023, 0, 255);
g = map(g, 0, 1023, 0, 255);
b = map(b, 0, 1023, 0, 255);

rgb(r, g, b);
Serial.print(r);
Serial.print(", ");
Serial.print(g);
Serial.print(", ");
Serial.println(b);


}




Saturday, March 06, 2010

March Madness Challenge - Day 6

Loss of brain power leads to coding RGB LED enumeration for Arduino. Tired going to bed soon.


int redPin = 9; // LED connected to digital pin 9
int greenPin = 10;
int bluePin = 11;

void fadeIn(int pin, int fadeInc, int delayValue)
{
for (int fadeValue = 0; fadeValue<= 255; fadeValue += fadeInc)
{
analogWrite(pin, fadeValue);
delay(delayValue);
}
}

// fade out from max to min in increments
void fadeOut(int pin, int fadeInc, int delayValue)
{
for (int fadeValue = 255; fadeValue >= 0; fadeValue -= fadeInc)
{
analogWrite(pin, fadeValue);
delay(delayValue);
}
}

void rgb (int r, int g, int b)
{
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);
delay(30);
}

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

// diagnostic lights on
fadeIn(redPin, 5, 60);
fadeOut(redPin, 5, 60);
analogWrite(redPin, 0);
delay(30);
fadeIn(greenPin, 5, 60);
fadeOut(greenPin, 5, 60);
analogWrite(greenPin, 0);
delay(30);
fadeIn(bluePin, 5, 60);
fadeOut(bluePin, 5, 60);
analogWrite(bluePin, 0);
delay(30);
Serial.print(redPin);
Serial.print(", ");
Serial.print(greenPin);
Serial.print(", ");
Serial.println(bluePin);

}


void loop() {
for (int r = 0; r <= 255; r++)
{
for (int g = 0; g <= 255; g++)
{
for (int b = 0; b <= 255; b++)
{
rgb(r, g, b);
Serial.print(r);
Serial.print(", ");
Serial.print(g);
Serial.print(", ");
Serial.println(b);

}
}
}
}

Friday, March 05, 2010

March Madness Challenge - Day 5

For tonight's March madness I will be demonstrating a variation on the theme of storing your private key locally. This program will up the ante and store your username and password as a QRCode. This way only a few machines can compromise your accounts when you take a picture of your username/password for decryption. Inspired by the following super high security tech technology: SafeBerg Technology

A bit of preparation is required. I'm using the python library huBarcode. You will need to run some flavor of "git clone git://github.com/hudora/huBarcode.git" followed by python setup.py install. Last option: sudo easy_install huBarcode

This code would have worked brilliantly if not for this error:
IOError: [Errno 2] No such file or directory: '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/huBarcode-0.56p5-py2.4.egg/qrcode/qrcode_data/qrv1_0.dat'

And here is the code:



#
# Turn a username/password into a QRCode
#
#
import getopt
import sys
import getpass
import qrcode

#Describe usage
def usage():
print "-h, --help\n -v, --verbose\n -u, --username\n -p, --password\n -f, --filename\n"

def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "h:u:pvf:", ["help", "username=", "password", "filename"])
except getopt.GetoptError, err:
#print help information and exit:
print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
username = None
password = None
verbose = False
filename = "default.png"

for o, a in opts:
if o == "-v":
verbose = True
elif o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-u", "--username"):
username = a
if verbose:
print "username: " + username
elif o in ("-p", "--password"):
password = getpass.getpass("Enter password: ")
if verbose:
print "password: " + password
elif o in ("-f", "--filename"):
filename = a;
if verbose:
print "filename: " + filename
else:
assert False, "unhandled option"
if username is None:
print "-u, --username was not given"
usage()
sys.exit(2)
if password is None:
print "-p, --password was not given"
usage()
sys.exit(2)


encoder = qrcode.QRCodeEncoder( username + "\n" + password)
print encoder.get_ascii()
encoder.save(filename, 3)

if __name__ == "__main__":
main()

Thursday, March 04, 2010

March Madness Challenge - Day 4

Kept thinking about yesterday's setTimeout and how to chain it into a a color show. Inspired the by the Trippy RGB Waves kit. I wanted to create a Javascript simulation of the rgb color show. The Trippy RGB Waves kit uses an array called lightTab to hold information about the hold time, fade time, and the rgb color values. So I took that array an implemented in Javascript. In order to display values I built a test page, test css, test Javascript. I ran out of time to write the fader. So I have a color show based on the lightTab array. setTimeout is used in a recursive fashion. The issues run into were needing to make sure the lightTab was global, and that an anonymous function was used to call the function in the site time out. Here's the example:

setTimeout("runShow(" + (i + 1) + ")", holdTime);
setTimeout(function () {runShow(i + 1);}, holdTime);

If I was executing more code or had more values in my function then anonymous function route is much easier to type, and less error prone. Other thing, I love jQuery, but none of my Javascript entries have used it. Sort of just checking out the plain old DOM and seeing what can be done.

Without further ado here is the html, css, and js.

test.html
====

====

rgb.css
====

====

rgb.js
====

====

Wednesday, March 03, 2010

March Madness Challenge - Day 3

Another long day, but I did come. up with something that I needed for another project. It turns out the closest thing Javascript has to sleep(ms) or delay(ms) is setTimeout. Which is nice but is tricky to use in a synchronous environment. So in terms of matching what happens on an AVR chip or an Arduino. It's time for a delay(ms) script.

setTimeout("showColor(red,green,blue)",holdTime);


function showColor(red, green, blue)
{
document.getElementById("leddisplay").style.backgroundColor="rgb(" + red + "," + green + "," + blue + ")";
}


Well not really. I wrote the delay function, but it's not the recommended technique. Why block all actions on a page waiting for one thing to happen. The above code is closer. But doesn't solve the key issues. The setTimeout needs to have values assigned for red, green, and blue for the showColor function. Additionally, this code requires a web page. I needed to upload that. I needed to assign an event listener, and lastly had to resolve an issue about setTimeout being inside a loop. The issue being the loop sets all the "setTimeout"s as quickly as possible, so all time outs occur almost in parallel. I could be wrong about that, but I did have some kind of issue. I needed to examine Javascript fader examples more closely, and I would have figured it out, but ran out of time.

Ok. I wrote a super quick brute force demonstration of the problem. This requires Firebug in order to run. Paste the following code into the Firebug console. Warning whatever web page you are viewing in firebug will go through some awful color contortions.

function showColor(red, green, blue)
{ document.body.style.backgroundColor="rgb(" + red + "," + green + "," + blue + ")";
console.log("Color set");
}
console.log("Start");
console.log('setTimeout("showColor(0,0,0)",10000);');
setTimeout("showColor(0,0,0)",10000);
console.log('setTimeout("showColor(10,10,10)",9000);');
setTimeout("showColor(10,10,10)",9000);
console.log('setTimeout("showColor(100,100,100)",8000);');
setTimeout("showColor(100,100,100)",8000);
console.log('setTimeout("showColor(200,200,200)",7000);');
setTimeout("showColor(200,200,200)",7000);
console.log('setTimeout("showColor(200,0,0)",6000);');
setTimeout("showColor(200,0,0)",6000);
console.log('setTimeout("showColor(100,0,0)",5000);');
setTimeout("showColor(100,0,0)",5000);
console.log('setTimeout("showColor(0,100,0)",4000);');
setTimeout("showColor(0,100,0)",4000);
console.log('setTimeout("showColor(0,100,100)",3000);');
setTimeout("showColor(0,100,100)",3000);
console.log("Done")


So nesting the setTimeout inside SetTimeout should be interesting. Onto the next challenge.

Tuesday, March 02, 2010

March Madness Challenge - Day 2

Ok. Time was a bit of challenge today. I wanted to learn more about getopt, and figure out how it differed from optparse. I definitely learned about some of those differences. So tonights program uses getpass to collect a username, password combination. This is pretty unoriginal, but it did help me learn about getopt. I would like to try variation on determining mandatory fields, optional fields, and fields in combination.


#
# Hello World Get Opt for Python
#
#
import getopt
import sys
import getpass

#Describe usage
def usage():
print "-h, --help\n -v, --verbose\n -u, --username\n -p, --password\n"

def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "h:u:pv", ["help", "username=", "password"])
except getopt.GetoptError, err:
#print help information and exit:
print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
username = None
password = None
verbose = False

for o, a in opts:
if o == "-v":
verbose = True
elif o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-u", "--username"):
username = a
print "username: " + username
elif o in ("-p", "--password"):
password = getpass.getpass("Enter password: ")
print "password: " + password
else:
assert False, "unhandled option"

if __name__ == "__main__":
main()

Monday, March 01, 2010

March Madness Challenge - Day 1

Several of my partners in craziness at FUBAR Labs, the local New Jersey Hackerpsace. Have taken on March Madness. Write a program a day for a month. Well I'm jumping in on day one with a piece of code that solves one of PIAs I experience when trying to get the emails off of Google Calendar Events. Wish there was a feature that allowed you to make a group based off of an event. Anyway, the following code is how to get a list of guests from a Google Calendar event. Pop the list into an alert box, then cut and paste for your own use.
---
/*
* Get list of emails address from the guests invited to a Google event
*/
(function () {
var guests, emails;
//Handily there is class associated to each guest
guests = document.getElementsByClassName("guest");
emails = "";
//iterate the guests
for (var i in guests)
{
if (guests.hasOwnProperty(i))
{
//each guest name/email is the first child textContent of guest element
emails = emails + guests[i].childNodes[0].textContent + ",\n";
}
}
alert(emails);
})();
---
In order to run this you need to can run it in the Firebug console. Testing this, you need to create a Google Calendar Event add a few people to it. Find an old event with people in the guest list.

Another way to run this would be as a Greasemonkey script. Hey, that might be a good project for tomorrow.

I did discover the source code for Google Hosted applications is not quite the same as it's standard gmail offerings. To run this in a hosted environment you would need to use the following to select the guests:

(function () {
var guests, emails, guest, tmp;
guests = document.getElementsByClassName("ep-gl-guest");
emails = "";
guest = "";
tmp = "";

for ( var i in guests)
{
if (guests.hasOwnProperty(i))
{
guest = guests[i].id;
tmp = guest.split(":i");
emails = emails + tmp[1] + ",\n";
}
}
alert(emails);
})();
//Final Note: Not Happy with editor at Blogger.com