Tuesday, December 31, 2013

Gear Project Fail

Inspired by these mechanical movements animations, I thought it would be fun to figure out how to make some gears out of one of my favorite building material, cardboard. Turns out making working gears is harder than I thought. I thought one gear 12" in diameter with 16 teeth and one 6" in diameter with 8 teeth would work well, and I guess they could if the teeth were designed correctly. My gears stick because the teeth catch on each other. Further research is needed, but I would like to find something easy enough to cut out of cardboard yet able to move easily. There is a lot of information on spur gears, which is what these turn out to be.





Sunday, December 29, 2013

How Do You Measure Programmers' Productivity

I love this quote from Len Shustek's article for The Computer Museum on MacPaint and QuickDraw:
How do you measure programmer productivity?
When the Lisa team was pushing to finalize their software in 1982, project managers started requiring programmers to submit weekly forms reporting on the number of lines of code they had written. Bill Atkinson thought that was silly. For the week in which he had rewritten QuickDraw’s region calculation routines to be six times faster and 2000 lines shorter, he put “-2000″ on the form. After a few more weeks the managers stopped asking him to fill out the form, and he gladly complied.
 I was going to say it reminded me of how Adobe had started charging developers per centimeter of  Actionscript code, but then remembered that was an April Fools. I guess one that made an impression.

Thursday, November 28, 2013

Student Machinima in OpenSim With Greenscreen

I have a student, 11th grader, working on one of the most complex tech projects ever. Her English teacher gave an open-ended project assignment for students to make something that depicts a scene from Bram Stoker's Dracula. She decided to make a machinima that would require up to four avatars, all controlled and filmed by herself, in one week.
I think Rand Spiro's Cognitive Flexibility Theory describes the use of technology to solve creative problems well. Of course there are optimal setups for creating machinima but here I had to help a student realize a very complex project with minimal training and portable equipment, as she had to complete it over the Thanksgiving weekend.
So here's what I came up with. I will find out on Monday how successful it will have been:

  1. We have a school OpenSim virtual world, but currently port forwarding is not set up in the firewall, so it's not an option for working at home. She has a Mac so she couldn't use SoaS. So we set up her own sim, installing MySQL, Mono, and Diva distro. After a few hiccups she was up and running.
  2. We needed the Diva account functionality to set up the character and camera person accounts and I had chosen Imprudence for a viewer and for some reason the Diva splash page wasn't showing up. I found Singularity which turns out to be quite awesome.
  3. Next was loaning her a PC she could use for the filming. I put Fraps and Singularity on it and taught her how to change her MyWorld.ini and RegionConfig.ini files to reflect her LAN IP so the PC could log into her sim. I taught her how to use Fraps, which is dead simple.
  4. For multiple avatars in the same scene, all directed by her, she would need a green floor and background, which she would then have to edit together in a video editor. She made some nice avatar costumes and developed gestures from the stock opensim animations.
  5. She would have preferred to edit the footage in iMovie on her Mac, as would I, but having the files on the PC in AVI format complicated things, as they would have to be converted to MOV for iMovie. It was too much for me to explain and add to the workflow. So I opted for having her use Movie Maker on the PC. That decision could prove to be the project's undoing as greenscreen is very hard to work with in WMM. We'll see. You have to use WMM 6.0 and install RehanFX shaders, and syncing the overlaid clips is almost impossible. It seems pretty much just set up to make cheesy music videos with ridiculous backgrounds. But it would have to work.
  6. UPDATE: I am happy to say she managed to get the DVI  files copied to her Mac, and used either Perian or Evom to convert them. iMovie makes clip editing much easier, even after applying the greenscreen.
  7. So the greenscreen workflow consists of syncing two avatar clips, applying the greenscreen so they both appear over green. Export that, and reimport it. Add a third avatar clip and sync those. Apply the greenscreen filter again and export that. Repeat for the fourth avatar clip. Finally, reimport that and greenscreen it with the chosen background image, and if possible figure out how to work in multiple background images for scene changes, which I'm not even sure is possible.
I hope all this works, we'll see.
UPDATE: She completed the video and it came out amazingly well! Here it is. She did end up figuring our how to convert the files from DVI to MOV and move them to iMovie. That should teach me to assume something will be too hard for someone.

Monday, November 18, 2013

Programming TETRIX Servos With leJOS NXJ

The last time I taught my high school robotics class I used RobotC to program TETRIX servos. The RobotC API provides the functions servoValue, servo, and servoChangeRate. From the documentation we learned that the only way you can be sure not to push your servo against a physical barrier and damage it is to avoid setting it to a position it can't reach. The easy programming also allowed us to avoid learning about how servos really work. leJOS NXJ has tools for dealing with servos that afford a much better learning experience, in my opinion. The leJOS API provides setRange(), setAngle(), setPulseWidth(), getAngle(), and getPluseWidth(). At the very least you will need to call setRange and setAngle on servos. That's because setAngle depends on a range of movement having been set with setRange. With leJOS it behooves you to set servos to a safe range of movement before moving it around, and to do so you have to understand something about how pulse width modulation makes servos run. Two articles do an excellent job explaining how to servos work , one from Jameco Electronics and one from Science Buddies. But there is still a gap of information when it comes to using the setRange and setAngle methods. The documentation provides the following:

public void setRange(int microsecLOW, int microsecHIGH, int travelRange) "Set the allowable pulse width operating range of this servo in microseconds and the total travel range. Default for pulse width at instantiation is 750 & 2250 microseconds. Default for travel is 200 degrees. " The parameters are defined as follows:
microsecLOW - The low end of the servos response/operating range in microseconds
microsecHIGH - The high end of the servos response/operating range in microseconds
travelRange - The total mechanical travel range of the servo in degrees
To better understand what these values mean I created some diagrams that make clear the function of each parameter.
The minimum and maximum PWM allowed are 750 and 2250, but if you use these  you are in danger of hitting the robot.
If the servo horn is attached such that the servo's physical stops are tilted the arm can hit the robot even with a safe min and max PWM range.
The third argument to setRange sets the number of programmable positions  between the min and max limits.
Setting the travelRange to 10, for example, will greatly reduce the precision it is capable of.

Saturday, November 02, 2013

Brushbots!

Monday, October 14, 2013

Music class for use with leJOS NXJ playNote and playTone methods

As an exercise I've written a Music class that makes writing NXT melodies easier by allowing note values to be passed instead of frequencies. I used this page as a reference: http://www.phy.mtu.edu/~suits/notefreqs.html. Any suggestions are appreciated. I hope someone finds it useful! Here's a little vid: http://blogs.hewittnet.org/robotics/files/2013/10/IMG_1008.mov

import lejos.nxt.Sound;
public class Music {
    private static String[] notes = { "C3", "C#3", "Db3", "D3", "D#3", "Eb3",
            "E3", "F3", "F#3", "Gb3", "G3", "G#3", "Ab3", "A3", "A#3", "Bb3",
            "B3", "C4", "C#4", "Db4", "D4", "D#4", "Eb4", "E4", "F4", "F#4",
            "Gb4", "G4", "G#4", "Ab4", "A4", "A#4", "Bb4", "B4", "C5", "C#5",
            "Db5", "D5", "D#5", "Eb5", "E5", "F5", "F#5", "Gb5", "G5", "G#5",
            "Ab5", "A5", "A#5", "Bb5", "B5", "C6" };
    private static float[] frequency = { 130.81f, 138.59f, 138.59f, 146.83f,
            155.56f, 155.56f, 164.81f, 174.61f, 185.0f, 185.0f, 196.0f,
            207.65f, 207.65f, 220.0f, 233.08f, 233.08f, 246.94f, 261.63f,
            277.18f, 277.18f, 293.66f, 311.13f, 311.13f, 329.63f, 349.23f,
            369.99f, 369.99f, 392.0f, 415.3f, 415.3f, 440.0f, 466.16f, 466.16f,
            493.88f, 523.25f, 554.37f, 554.37f, 587.33f, 622.25f, 622.25f,
            659.26f, 698.46f, 739.99f, 739.99f, 783.99f, 830.61f, 830.61f,
            880.0f, 932.33f, 932.33f, 987.77f, 1046.5f };
    /**
     * method uses playTone method
     * @param note is a String representation of the musical note in range C3-C6. See notes[] for allowed values
     * @param duration is note duration in ms
     */
    public void musicTone(String note, int duration) {
        for (int i = 0; i < notes.length; i++) {
            if(note.equals(notes[i])) {
                Sound.playTone((int)frequency[i], duration);
                Sound.pause(duration);
            }
        }
    }
    /**
     * method uses playNote method with Sound.XYLOPHONE as instrument argument
     * @param note is a String representation of the musical note in range C3-C6. See notes[] for allowed values
     * @param duration
     */
    public void musicXylo(String note, int duration) {
        for (int i = 0; i < notes.length; i++) {
            if(note.equals(notes[i])) {
                Sound.playNote(Sound.XYLOPHONE,(int)frequency[i], duration);
            }
        }
    }
    /**
     * method uses playNote method with Sound.PIANO as instrument argument
     * @param note is a String representation of the musical note in range C3-C6. See notes[] for allowed values
     * @param duration
     */    
    public void musicPiano(String note, int duration) {
        for (int i = 0; i < notes.length; i++) {
            if(note.equals(notes[i])) {
                Sound.playNote(Sound.PIANO,(int)frequency[i], duration);
            }
        }
    }
    /**
     * method uses playNote method with Sound.FLUTE as instrument argument
     * @param note is a String representation of the musical note in range C3-C6. See notes[] for allowed values
     * @param duration
     */        
    public void musicFlute(String note, int duration) {
        for (int i = 0; i < notes.length; i++) {
            if(note.equals(notes[i])) {
                Sound.playNote(Sound.FLUTE,(int)frequency[i], duration);
            }
        }
    }
}
Here is an example implementation of the class:

import lejos.nxt.Sound;

public class MusicTest {
    private static String[] melody = { "C4", "D4", "E4", "C4", 
        "E4", "C4",    "E4"};

    public static void main(String[] args) {
        Music music = new Music();
        for (int i = 0; i < melody.length; i++) {
            music.musicPiano(melody[i], 300);
            System.out.println(melody[i]);
        }
        Sound.pause(300);
        for (int i = 0; i < melody.length; i++) {
            music.musicTone(melody[i], 300);
            System.out.println(melody[i]);
        }
    }
}

Sunday, October 06, 2013

Processing.js Save Part of Sketch Window

I'm working on a save feature for a web app for drawing musical compositions. I want to make sure you can save your drawn composition and reload them instead of having to recreate them. Processing.js  has a save() method but I was thinking it was a dead end because it saves either the whole sketch window or a loaded image in the sketch, of which the drawn composition is neither. But this tip from the forum saved the day. Use get() to capture the region where the composition is drawn and define that as an image, then call save on that!
void trySaveImage() {
  if(mouseX > width-40 && mouseY < 40) {
    PImage drawWindow = get(20, top, width-20, height-top);
    drawWindow.save("drawing.png");
  }
}

Now I just have to figure out how to load the saved image...

Tuesday, September 24, 2013

Computer Science Texts

There is no best text to use in a computer science course, but I've found two that I'm really happy with for the high school robotics course I'm teaching this year. For the first semester we're programming Lego NXT robots with TETRIX building parts and motors and I have to support both Mac and PC os's, so I'm teaching Java. There's a great library for doing just this called leJOS NXJ and we're going over many of the Java concepts using the book Head First Java, 2nd edition.
For the second semester we'll be switching to Arduino and doing a mixture of physical computing and robotics projects. I am still working out the details of the curriculum, but I want to use Beginning C With Arduino by Jack Purdum as a base text. Purdum goes into the details of C concepts in a very clear and concise way while many other Arduino books give a lot of examples without giving much rhyme or reason as to why sample programs are written as they are. So I hope to highlight differences between techniques used in Java and C.

Saturday, May 04, 2013

Using Switches with Arduino and Processing

The short story here is you can use INPUT_PULLUP when coding switches in Arduino but this is not available at the time of this post in the Arduino library for Processing if you want to code your switch that way. In the latter case you have to wire your switch with a pull-up or pull-down resistor.

Now the long story. The Arduino IDE 1.0.1 forward has added a very convenient argument to the pinMode() function for using switches. Instead of just setting a switch pin to pinMode(switchPin, INPUT) you can use pinMode(switchPin, INPUT_PULLUP). This uses the Arduino's internal resistors to pull a switch pin HIGH by default so you don't get fluctuating readings on your switch. The switch is really easy to wire this way, just wire from the input pin to the switch, then to ground. When you want to read whether the switch is pressed, use the condition if(digitalRead(switchPin==LOW)).
Image source: arduino.cc
But the INPUT_PULLUP option is not available in the current arduino library for Processing, which allows Processing to talk to the Arduino through the Firmata firmware running on the Arduino. The Processing arduino library hasn't been updated since 2011 (11/11/11 to be exact--weird).

Without the use of the INPUT_PULLUP argument a switch has to be wired with a pull-up or pull-down configuration, which is a bit more complicated. This Ladyada tutorial covers the wiring of pull-up and pull-down resistors very nicely. The image below uses a pull-up resistor, in which the switch is connected on one side to its input pin with a 100 ohm resistor and to Vin with a 10K ohm resistor, and then to ground on its other side, pulling it high by default.
Image source: ladyada.net
All of this came up in my classroom because I have a couple students working on a project where they want to press buttons to play audio files on their computer. So the Processing/Arduino configuration is necessary.

Monday, April 01, 2013

Tricolor LED update: soldered up

I moved the led from breadboard to pc board, added a 9V to barrel plug and I have a nice little night light! I don't know how long the battery will last though...

Monday, March 25, 2013

Tricolor LED Project 3: Color mixing and Crossfades

This project just uses Arduino and the tricolor LED to make random mixed colors and crossfades. The LED is wired like in this diagram:  http://arduino.cc/en/uploads/Tutorial/readASCIIString_bb.png
Program code is below:




Program code:
int r,g,b;
int LEDs[] = {r,g,b};

int brightness = 3; 
int fadeAmount = 3; 
int pick1,pick2,pick3;
int PICKS[] = {pick1,pick2,pick3};

void setup()  { 
  for(int i = 0;i < 3;i++) {
    LEDs[i] = i+9;
    pinMode(LEDs[i],OUTPUT);
    PICKS[i] = random(3);
  }
  //Serial.begin(9600);
} 

void loop()  { 
  if(brightness == 3) {
    for(int i = 0;i < 3;i++) {
      PICKS[i] = random(3);
    }//end for
  }//endif
  for(int i = 0;i < 3;i++) {
      switch(PICKS[i]) {
      case 0:
        analogWrite(LEDs[i], brightness);
        break;
      case 1:
        analogWrite(LEDs[i], -brightness);
        break;
      case 2:
        analogWrite(LEDs[i], 255);
        break;
      }//end switch
  }//end for
  brightness += fadeAmount;
  if (brightness < 4 || brightness == 255) {
    fadeAmount = -fadeAmount ; 
  }     
  delay(30);                            
}


Tricolor LED Project 2: Color Slider


Processing and Arduino project 2 uses a tricolor LED and a screen interface to mix colors with sliders. That's a ping pong ball on the LED. The LED is wired like in this diagram: http://arduino.cc/en/uploads/Tutorial/readASCIIString_bb.png. Remember when doing projects with Arduino thru Processing, follow these steps: http://playground.arduino.cc/interfacing/processing
The code is published below:




Main code:

//arduino begin
import processing.serial.*; //for serial communication with any device
import cc.arduino.*; //for Arduino library methods
Arduino arduino; //create Arduino object from library
int rd = 9; 
int blu = 10; 
int grn = 11; 
//arduino end
Circle circle;
Slider[] slider = new Slider[3];
int[] xpos = new int[3];
int[] ypos = new int[3];

void setup() {
  //arduino begin
  println(Arduino.list());//show me which COM port Arduino is using
  arduino = new Arduino(this, Arduino.list()[4], 57600);
  arduino.pinMode(rd, Arduino.OUTPUT);
  arduino.pinMode(blu, Arduino.OUTPUT);
  arduino.pinMode(grn, Arduino.OUTPUT);
  //arduino end
  size(500,530);
  smooth();
  for (int i = 0; i < xpos.length; i++) {
    xpos[i] = (i+1)*30;
  }
  noStroke();
  circle = new Circle();
  for(int i = 0; i < slider.length; i++) {
    slider[i] = new Slider();
    ypos[i] = height-10;
  }//end for
}//end setup

void draw() {
  background(100);
  circle.setColorVars();
  circle.display();
  for(int i = 0; i < slider.length; i++) {
    int[] r = {255,0,0};
    int[] g = {0,255,0};
    int[] b = {0,0,255};
    slider[i].displayRect(r[i],g[i],b[i],xpos[i]);
    slider[i].displayHandle(xpos[i],ypos[i]);
  }//end for
}//end draw

void mouseDragged() {
  for(int i = 0;i < slider.length; i++) {
    slider[i].dragging();
  }
}

Circle class:

class Circle {
  int r = 0;
  int g = 0;
  int b = 0;
  PFont f;
  
  Circle() {
    f = createFont("Arial", 30,true);
    textFont(f);
  }//end const
  
  void setColorVars() {
    r = 255 - ypos[0]/2+5;
    g = 255 - ypos[1]/2+5;
    b = 255 - ypos[2]/2+5;
  }

  void display() {
    fill(r,g,b);
    ellipse(width/2+50,height/2,250,250);
    textAlign(CENTER);
    text("(" + r + "," + g + "," + b + ")", width/2+50,40);
    arduino.analogWrite(rd,255-r);
    arduino.analogWrite(blu,255-b);
    arduino.analogWrite(grn,255-g);
  }//end void
}//end class
Slider class:

class Slider {
  int btm = height-10;
  int tp = 10;

  Slider() {
  }
  
  void displayRect(int r, int g, int b, int x) {
    fill(r,g,b);
    rectMode(CENTER);
    rect(x,height/2,20,510);
  }
  
  void displayHandle(int x, int y) {
    fill(0);
    rectMode(CENTER);
    rect(x,y,20,20);
  }
  
  void dragging() {
    if(mouseY >= tp && mouseY <= btm) {
      if(dist(mouseX,mouseY,xpos[0],ypos[0]) < 15) {
        ypos[0] = mouseY;
      }//endif
      if(dist(mouseX,mouseY,xpos[1],ypos[1]) < 15) {
        ypos[1] = mouseY;
      }//endif
      if(dist(mouseX,mouseY,xpos[2],ypos[2]) < 15) {
        ypos[2] = mouseY;
      }//endif
    }//endif
  }//end void
} //end class

Tricolor LED Project 1: Color Picker

I'm using Processing and Arduino to make some interactive light projects with a tricolor LED with some nice results. The first is an app that shows how digital colors mix. That's a ping pong ball on the LED. The LED is wired like in this diagram: http://arduino.cc/en/uploads/Tutorial/readASCIIString_bb.png. Remember when doing projects with Arduino thru Processing, follow these steps: http://playground.arduino.cc/interfacing/processing
The code is published below:




//COMMON ANODE TO 5V
import processing.serial.*; //for serial communication with any device
import cc.arduino.*; //for Arduino library methods
Arduino arduino; //create Arduino object from library
Circle circle;
Button[] button = new Button[3];
Led[] led = new Led[3];
boolean r_on,g_on,b_on;

void setup() {
  println(Arduino.list());//show me which COM port Arduino is using
  arduino = new Arduino(this, Arduino.list()[4], 57600);
  size(500,500);
  smooth();
  noStroke();
  circle = new Circle();
  for(int i = 0; i < button.length; i++) {
    button[i] = new Button();
    led[i] = new Led();
  }//end for
}//end setup

void draw() {
  background(100);
  if(r_on && !g_on && !b_on) {
    circle.setColor(255,0,0);
    for(int i = 0;i < button.length; i++) {
      button[i].redOn();
      led[i].redOn();
    }//endfor
  } else if(!r_on && g_on && !b_on) {
    circle.setColor(0,255,0);
    for(int i = 0;i < button.length; i++) {
      button[i].greenOn();
      led[i].greenOn();
    }//endfor
  } else if(!r_on && !g_on && b_on) {
    circle.setColor(0,0,255);
    for(int i=0; i < button.length; i++) {
      button[i].blueOn();
      led[i].blueOn();
   }//endfor
  } else if(r_on && g_on && !b_on) {
    circle.setColor(255,255,0);
    for(int i=0; i < button.length; i++) {
      button[i].yellowOn();
      led[i].yellowOn();
    }//endfor
  } else if(r_on && !g_on && b_on) {
    circle.setColor(255,0,255);
    for(int i=0; i < button.length; i++) {
      button[i].magentaOn();
      led[i].magentaOn();
    }//endfor
  } else if(!r_on && g_on && b_on) {
    circle.setColor(0,255,255);
    for(int i=0; i < button.length; i++) {
      button[i].cyanOn();
      led[i].cyanOn();
    }//endfor
  } else if(r_on && g_on && b_on){
    circle.setColor(255,255,255);
    for(int i=0; i < button.length; i++) {
      button[i].whiteOn();
      led[i].whiteOn();
    }//endfor
  } else {
    circle.setColor(0,0,0);
    for(int i = 0; i < button.length; i++) {
      button[i].blackOn();
      led[i].blackOn();
    }//endfor
  }//endelse
  circle.display();
}//end draw

void mousePressed() {
  if(dist(mouseX,mouseY,width/4,height/5*4) < 25) {
    r_on = !r_on;
  }
  if(dist(mouseX,mouseY,width/2,height/5*4) < 25) {
    g_on = !g_on;
  }
  if(dist(mouseX,mouseY,width/4*3,height/5*4) < 25) {
    b_on = !b_on;
  }
}//end void
Circle class:
class Circle {
  int rC = 0;
  int gC = 0;
  int bC = 0;
  PFont f;
  
  Circle() {
    f = createFont("Arial", 30,true);
    textFont(f);
  }//end const
  
  void setColor(int red,int green, int blue) {
    rC = red;
    gC = green;
    bC = blue;
  }//end void
  
  void display() {
    fill(rC,gC,bC);
    ellipse(width/2,height/2-50,250,250);
    textAlign(CENTER);
    text("(" + rC + "," + gC + "," + bC + ")", width/2,40);
  }//end void  
}//end class

Button class:
class Button {
  //arrays for r,g,b values for 3 buttons
  int[] r = new int[3];
  int[] g = new int[3];
  int[] b = new int[3];
  int[] xpos = new int[3];

  Button() {
  xpos[0] = width/4;
  xpos[1] = width/2;
  xpos[2] = width/4*3;
}
  
  void display(int br, int bg, int bb, int x) {
    fill(br,bg,bb);
    ellipse(x,height/5*4,50,50);
  }
  
  void redOn() {
    for(int i=0; i < button.length; i++) {
      if(i == 0) {
        r[i] = 255;
      } else {
        r[i] = 0;
      }
      g[i] = 0;
      b[i] = 0;
      button[i].display(r[i],g[i],b[i],xpos[i]);
    }
  }
  
  void greenOn() {
    for(int i=0; i < button.length; i++) {
      if(i == 1) {
        g[i] = 255;
      } else {
        g[i] = 0;
      }
      r[i] = 0;
      b[i] = 0;
      button[i].display(r[i],g[i],b[i],xpos[i]);
    }//endfor
  }//endvoid

  void blueOn() {
    for(int i=0; i < button.length; i++) {
      if(i == 2) {
        b[i] = 255;
      } else {
        b[i] = 0;
      }
      r[i] = 0;
      g[i] = 0;
      button[i].display(r[i],g[i],b[i],xpos[i]);
    }//endfor
  }//endvoid

  void yellowOn() {
    for(int i=0; i < button.length; i++) {
       if(i == 0) {
        r[i] = 255;
      } else {
        r[i] = 0;
      }
       if(i == 1) {
        g[i] = 255;
      } else {
        g[i] = 0;
      }
      b[i] = 0;
      button[i].display(r[i],g[i],b[i],xpos[i]);
    }//endfor
  }//endvoid

  void magentaOn() {
    for(int i=0; i < button.length; i++) {
       if(i == 0) {
        r[i] = 255;
      } else {
        r[i] = 0;
      }
       if(i == 2) {
        b[i] = 255;
      } else {
        b[i] = 0;
      }
      g[i] = 0;
      button[i].display(r[i],g[i],b[i],xpos[i]);
    }//endfor
  }//endvoid

  void cyanOn() {
    for(int i=0; i < button.length; i++) {
       if(i == 1) {
        g[i] = 255;
      } else {
        g[i] = 0;
      }
       if(i == 2) {
        b[i] = 255;
      } else {
        b[i] = 0;
      }
      r[i] = 0;
      button[i].display(r[i],g[i],b[i],xpos[i]);
    }//endfor
  }//endvoid

  void whiteOn() {
    for(int i=0; i < button.length; i++) {
       if(i == 0) {
        r[i] = 255;
      } else {
        r[i] = 0;
      }
       if(i == 1) {
        g[i] = 255;
      } else {
        g[i] = 0;
      }
       if(i == 2) {
        b[i] = 255;
      } else {
        b[i] = 0;
      }
      button[i].display(r[i],g[i],b[i],xpos[i]);
    }//endfor
  }//endvoid

  void blackOn() {
    for(int i=0; i < button.length; i++) {
      button[i].display(0,0,0,xpos[i]);
    }//endfor
  }//endvoid
}//end class

Led class:
class Led{
  int rd,blu,grn;
  int colors[] = {rd,blu,grn};//array for LED colors
  
  Led() {
    for(int i = 0; i < colors.length; i++) {
      colors[i] = i+9;//assign arduino pins
      arduino.pinMode(colors[i], Arduino.OUTPUT);//pins to output
    }
  }
  
  void redOn() {
    for(int i=0; i < button.length; i++) {
      //array is "rd,blu,grn", LOW is on, HIGH is off!
      if(i == 0) {
        arduino.digitalWrite(colors[i], Arduino.LOW);
      } else {
        arduino.digitalWrite(colors[i], Arduino.HIGH);
      }
    }//endfor
  }//endvoid
  
  void greenOn() {
    for(int i=0; i < button.length; i++) {
      if(i == 2) {
        arduino.digitalWrite(colors[i], Arduino.LOW);
      } else {
        arduino.digitalWrite(colors[i], Arduino.HIGH);
      }
    }//endfor
  }//end void

  void blueOn() {
    for(int i=0; i < button.length; i++) {
      if(i == 1) {
        arduino.digitalWrite(colors[i], Arduino.LOW);
      } else {
        arduino.digitalWrite(colors[i], Arduino.HIGH);
      }
    }//endfor
  }//end void
  
  void yellowOn() {
    for(int i=0; i < button.length; i++) {
      if(i == 1) {
        arduino.digitalWrite(colors[i], Arduino.HIGH);
      } else {
        arduino.digitalWrite(colors[i], Arduino.LOW);
      }
    }//endfor
  }//end void
  
  void magentaOn() {
    for(int i=0; i < button.length; i++) {
      if(i == 2) {
        arduino.digitalWrite(colors[i], Arduino.HIGH);
      } else {
        arduino.digitalWrite(colors[i], Arduino.LOW);
      }
    }//endfor
  }//end void

  void cyanOn() {
    for(int i=0; i < button.length; i++) {
      if(i == 0) {
        arduino.digitalWrite(colors[i], Arduino.HIGH);
      } else {
        arduino.digitalWrite(colors[i], Arduino.LOW);
      }
    }//endfor
  }//end void

  void whiteOn() {
    for(int i=0; i < button.length; i++) {
      arduino.digitalWrite(colors[i], Arduino.LOW);
    }//endfor
  }//end void

  void blackOn() {
    for(int i=0; i < button.length; i++) {
      arduino.digitalWrite(colors[i], Arduino.HIGH);
    }//endfor
  }//end void
}//endclass

Sunday, February 10, 2013

Pygame on 64-bit Mac OS

I'm in the process of porting my instructional programming environment from Windows to Mac (10.8). That's Processing, Arduino, Python, Pygame, HTML editors and FTP apps, Scratch, Logo for GoGo Board.

  • Processing: easy, but connecting to an Arduino through Processing, still working on it
  • Arduino: easy
  • Python: tricky, downgrade to 2.7.3 for 32-bit, then Pygame will run.
  • Pygame: easy, once above is done
  • FileZilla: easy
  • HTML editor, TextWrangler
  • Scratch: easy, 2.0 is now online!
  • Logo for GoGo Board: no Mac driver? Not sure but working on it.