Minor Update: Site Overhaul

With the help of Monroe, thoughtfix.com has been entirely redesigned. With the help of Squarespace, all previous content has been ported over to this new design. I love it. Thank you! 

I have been spending time working on an Openbeam Kossel Pro 3D printer and, thanks to the forums, we got it working happily. I also have been immersing myself in more PC gaming (you can guess my Steam ID) and building machines capable of that. I look forward to hacking SteamOS when it is ready. Get to it, Valve!

I uploaded the Kossel Pro build log to my Galleries up there. Finally: I left San Francisco and moved about 20 miles down the Bay. It was cost prohibitive to live in the city for even one more year. Tech companies need to stop opening offices downtown (Uber, Twitter, Reddit) unless they pay people a proportionally higher salary to afford living there.



Maker Faire Bay Area photo album

Long overdue update

I have not been managing this nearly as much as I should, so here' a quick bullet-point update on my projects at the conclusion of Maker Faire 2014:


  • New job, new home! I moved to downtown San Francisco to accept a job there. My apartment is much smaller (naturally - it's SF) so I don't have as much space for both robotics and 3D printing. I do have enough space to switch between the two.
  • The Printrbot Plus v2 is fun, but it's getting an overhaul in parts - more metal for structural stability and more rigidity for speed, plus a transition from 3mm to 1.75mm filament and an aluminum extruder.
  • Someone left behind a Botiful robot when changing offices. I contacted Claire, the designer, to see if anyone lost their Kickstarter rewards but she had no way of knowing. With her help, I got it working again and it's a lot of fun.
  • I am giving up on drones as a hobby as long as I live in SF. It's too windy and crowded and I don't want to hurt the drone or a person.
  • My favorite update: I backed and received Super Awesome Sylvia and EMSL's WaterColorBot and have truly wicked plans for expanding on the hardware. I have to thank Lenore and Windell from Evil Mad Scientist Labs for the inspiration and support.

That's all for now. 


Sparkfun ITG-3200 Gyroscope Example Arduino Code

The official documentation and example code on Sparkfun's Site is very slightly broken and not updated for Arduino 1.0. I fixed it and sent it to them. Also posting it here:

Original author: 
Basic Example Sketch for the ITG-3200 (http://www.sparkfun.com/products/9801)
SparkFun Electronics 2011
Ryan Owens
This code is public domain buy you buy me a beer if you use this and we meet someday (Beerware license).
Updated some variables and Arduino 1.0 compatibility:
Daniel Gentleman
Will take coffee in place of beer.
To use this example code, attach:
Arduino  :  ITG-3200 Breakout
3.3V  :  VDD
3.3V  :  VIO
GND   :  GND
SDA   :  A4
SCL   :  A5
Load the sketch and open the serial window at 9600 bps. Arduino will output the raw X,Y and Z axis data being read from the gyroscope.
//The Wire library is used for I2C communication
#include <Wire.h>
//This is a list of registers in the ITG-3200. Registers are parameters that determine how the sensor will behave, or they can hold data that represent the
//sensors current status.
//To learn more about the registers on the ITG-3200, download and read the datasheet.
char WHO_AM_I = 0x00;
char SMPLRT_DIV= 0x15;
char DLPF_FS = 0x16;
char GYRO_XOUT_H = 0x1D;
char GYRO_XOUT_L = 0x1E;
char GYRO_YOUT_H = 0x1F;
char GYRO_YOUT_L = 0x20;
char GYRO_ZOUT_H = 0x21;
char GYRO_ZOUT_L = 0x22;
//This is a list of settings that can be loaded into the registers.
//DLPF, Full Scale Register Bits
//FS_SEL must be set to 3 for proper operation
//Set DLPF_CFG to 3 for 1kHz Fint and 42 Hz Low Pass Filter
char DLPF_CFG_0 = (1<<0);
char DLPF_CFG_1 = (1<<1);
char DLPF_CFG_2 = (1<<2);
char DLPF_FS_SEL_0 = (1<<3);
char DLPF_FS_SEL_1 = (1<<4);
//I2C devices each have an address. The address is defined in the datasheet for the device. The ITG-3200 breakout board can have different address depending on how
//the jumper on top of the board is configured. By default, the jumper is connected to the VDD pin. When the jumper is connected to the VDD pin the I2C address
//is 0x69.
char itgAddress = 0x69;
//In the setup section of the sketch the serial port will be configured, the i2c communication will be initialized, and the itg-3200 will be configured.
void setup()
  //Create a serial connection using a 9600bps baud rate.
  //Initialize the I2C communication. This will set the Arduino up as the 'Master' device.
  //Read the WHO_AM_I register and print the result
  char id=0; 
  id = itgRead(itgAddress, 0x00);  
  Serial.print("ID: ");
  Serial.println(id, HEX);
  //Configure the gyroscope
  //Set the gyroscope scale for the outputs to +/-2000 degrees per second
  itgWrite(itgAddress, DLPF_FS, (DLPF_FS_SEL_0|DLPF_FS_SEL_1|DLPF_CFG_0));
  //Set the sample rate to 100 hz
  itgWrite(itgAddress, SMPLRT_DIV, 9);
//The loop section of the sketch will read the X,Y and Z output rates from the gyroscope and output them in the Serial Terminal
void loop()
  //Create variables to hold the output rates.
  int xRate, yRate, zRate;
  //Read the x,y and z output rates from the gyroscope.
  xRate = readX();
  yRate = readY();
  zRate = readZ();
  //Print the output rates to the terminal, seperated by a TAB character.
  Serial.print(xRate);  //fixed variables here from original code. DG.
  //Wait 10ms before reading the values again. (Remember, the output rate was set to 100hz and 1reading per 10ms = 100hz.)
//This function will write a value to a register on the itg-3200.
//  char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
//  char registerAddress: The address of the register on the sensor that should be written to.
//  char data: The value to be written to the specified register.
void itgWrite(char address, char registerAddress, char data)
  //Initiate a communication sequence with the desired i2c device
  //Tell the I2C address which register we are writing to
  //Send the value to write to the specified register
  //End the communication sequence
//This function will read the data from a specified register on the ITG-3200 and return the value.
//  char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
//  char registerAddress: The address of the register on the sensor that should be read
//  unsigned char: The value currently residing in the specified register
unsigned char itgRead(char address, char registerAddress)
  //This variable will hold the contents read from the i2c device.
  unsigned char data=0;
  //Send the register address to be read.
  //Send the Register Address
  //End the communication sequence.
  //Ask the I2C device for data
  Wire.requestFrom(address, 1);
  //Wait for a response from the I2C device
    //Save the data sent from the I2C device
    data = Wire.read();
  //End the communication sequence.
  //Return the data read during the operation
  return data;
//This function is used to read the X-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second. 
//Usage: int xRate = readX();
int readX(void)
  int data=0;
  data = itgRead(itgAddress, GYRO_XOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_XOUT_L);  
  return data;
//This function is used to read the Y-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second. 
//Usage: int yRate = readY();
int readY(void)
  int data=0;
  data = itgRead(itgAddress, GYRO_YOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_YOUT_L);  
  return data;
//This function is used to read the Z-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second. 
//Usage: int zRate = readZ();
int readZ(void)
  int data=0;
  data = itgRead(itgAddress, GYRO_ZOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_ZOUT_L);  
  return data;


Arduino, BOE Shield, PING, and a servo

The video above is in two parts: first with a crawler kit and then with wheels. Switching back to wheels required a code modification to change the time it takes to turn. 
All the parts in the video were released for the original STAMP/Propeller chips, but the code below will get you off and running on the Arduino shield. Only digital pins 10, 11, 12, and 13 are used, so any shield that does not require those pins is available for use. 
// BOE Shield code from "Robotics with the BOE Bot"
// Roaming With Whiskers source, modified to use a PING)))
// sensor on the PING))) servo bracket.
// Using code from the Ping))) example sketch.
#include <Servo.h>                           // Include servo library
Servo servoLeft;                             // Declare left, right and Ping))) servos
Servo servoRight;
Servo PingServo;
int minSafeDist = 11 ;                        // Minimum distance in inches
int pingPin = 10;                             // PING input on 10 so the last servo port is used.
int centerDist, leftDist, rightDist;          // Define distance variables
long duration, inches, cm;                    // Define variables for Ping)))
void setup()                                 // Built-in initialization block
  tone(4, 3000, 1000);                       // Play tone for 1 second
  delay(1000);                               // Delay to finish tone
  servoLeft.attach(13);                      // Attach left signal to pin 13 
  servoRight.attach(12);                     // Attach right signal to pin 12
void loop(){
  if(inches >= minSafeDist) /* If the inches in front of an object is greater than or equal to the minimum safe distance (11 inches), react*/
    forward (121); //Go Forward
    delay(110); // Wait 0.11 seconds
  else // If not:
    LookAround(); // Check your surroundings for best route
    if(rightDist > leftDist) // If the right distance is greater than the left distance , turn right
      turnRight (250); // Turn Right      
    else if (leftDist > rightDist) // If the left distance is greater than the right distance , turn left
      turnLeft (250); // Turn Left
      backward (250); // Go Backward
    delay (250);
void forward(int time)                       // Forward function
  servoLeft.writeMicroseconds(1700);         // Left wheel counterclockwise
  servoRight.writeMicroseconds(1300);        // Right wheel clockwise
  delay(time);                               // Maneuver for time ms
void turnLeft(int time)                      // Left turn function
  servoLeft.writeMicroseconds(1300);         // Left wheel clockwise
  servoRight.writeMicroseconds(1300);        // Right wheel clockwise
  delay(time);                               // Maneuver for time ms
void turnRight(int time)                     // Right turn function
  servoLeft.writeMicroseconds(1700);         // Left wheel counterclockwise
  servoRight.writeMicroseconds(1700);        // Right wheel counterclockwise
  delay(time);                               // Maneuver for time ms
void backward(int time)                      // Backward function
  servoLeft.writeMicroseconds(1300);         // Left wheel clockwise
  servoRight.writeMicroseconds(1700);        // Right wheel counterclockwise
  delay(time);                               // Maneuver for time ms
unsigned long ping() {
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW); //Send a low pulse
  delayMicroseconds(2); // wait for two microseconds
  digitalWrite(pingPin, HIGH); // Send a high pulse
  delayMicroseconds(5); // wait for 5 micro seconds
  digitalWrite(pingPin, LOW); // send a low pulse
  pinMode(pingPin,INPUT); // switch the Pingpin to input
  duration = pulseIn(pingPin, HIGH); //listen for echo
  /*Convert micro seconds to Inches
  cm = microsecondsToCentimeters(duration);
  inches = microsecondsToInches(duration);
long microsecondsToInches(long microseconds) // converts time to a distance
  return microseconds / 74 / 2;
long microsecondsToCentimeters(long microseconds) // converts time to a distance
  return microseconds / 29 / 2;
void LookAhead() {
  PingServo.write(90);// angle to look forward
  delay(175); // wait 0.175 seconds
void LookAround(){
  PingServo.write(20); // 20° angle
  delay(320); // wait 0.32 seconds
  rightDist = inches; //get the right distance
  PingServo.write(160); // look to the other side
  delay(620); // wait 0.62 seconds
  leftDist = inches; // get the left distance
  PingServo.write(90); // 90° angle
  delay(275); // wait 0.275 seconds


BOE Shield Crawler Kit notes/video

The crawler kit was a big pain to build, but it looks cool! It is essential to use the correct screws and nuts exactly as described in the instructions. Long screws and lock nuts are at the "knees," tapping screws in the pivots, and a nice comfortable drilled hole for the servo horn. 

CODE! The robot is functionally identical to the standard "navigation with whiskers" bot but the whiskers are higher from the ground and bounce up and down. In general - it is far less reliable. Any code included for turns should have durations about four to six times longer to allow for the added turning time of the crawler.

Some tips:


  • If you break your servo horn while cutting/drilling the extra space for the bolt, don't worry too much: The other three spokes will do just fine. If you completely break your servo horn, the horns that came with the original BOE Shield kit work fine.
  • Don't let the diagram on the middle legs confuse you - they're both assembled the same way.
  • Double check your washers before tightening the bolts on the middle legs. The one closest to the servo horn is a 1/8" spacer and looks twice as thick as the other nylon washers.
  • Needle-nose pliers are very useful in tightening those lock nuts - but don't over-tighten them!A good measure its to tighten them just enough to allow the friction of a leg to keep it from spinning downward with gravity, then slightly loosen it from there.
  • My crawler kit was four washers short. I easily found matching nylon washers at Lowes (Hillman #6 nylon flat washers)

BOE Shield Whisker Kit

This video is a direct follow-up on my last post. It just shows the next step of growth on the BOE Bot.

Some notes on assembly:


It's VERY difficult to use the nylon spacer near the mounting header by the AREF pin. I skipped using the spacer and just used the screw and nut - tightening it until it felt snug.

Between ShieldSetup and building your robot, it actually IS important to do the servo centering. Both of the servos I got were not centered.

The 1" aluminum standoffs and screws aren't attached to the shield when it is shipped. The instructions are there for people who followed the introduction course and mounted the shield before the 
In the same bag, there are two lengths of screws and all fit the standoffs. USE THE SHORT SCREWS FOR THE STANDOFFS. The long screws are needed to mount the servos.

Tires: Annoying!

Spare parts: All bolts are used. Two spare "tire" rubber bands are included. Once you assemble the base kit, you'll have two long screws, two short risers, and two nylon washers left over as well. Those are used for the whisker kit.

Example sketch notes:
Many of the example sketches run all the code in void setup() so they only run once and stop. This means the servo test code will only run once. If your power switch is in the wrong position and you start the test, hit the reset button and see if it runs.

Parallax BOE Shield for Arduino: First Look

I'm a big fan of Parallax and adafruit industries, so was glad to learn that they are now stocking the Parallax BOE Shield for Arduino. I already owned this kit but have yet to have time to play with it. The video above is an unboxing of the BOE Shield, PING))) sensor mounting bracket, and crawler kit. 
The original Parallax BOE-Bot uses Propeller controller and is very good for learning robotics in that environment. The lessons, documentation, and examples are quite detailed. With a focus on education, Parallax wisely decided to expand this platform into Arduino territory. The only "required" pins for the shield are two of 10, 11, 12, and 13. You can choose which two in your Arduino code. The rest can be used with your normal stackable Arduino shields.
To get a general idea of the BOE Shield and completed robot in action, take a look at adafruit's new product announcement.
Here's a photo of the crawler kit sitting on an original BOE bot (borrowed from Parallax's site) that I intend to use with the BOE Shield.
I'll be posting all my source code and a bunch of pictures or videos, but it will all pale in comparison to the online book from Parallax.
Stay tuned for more!


R2-D2 Laser Robot for Cats

This is an expanded modification for the Laser ToyBot for Cats to fit into an R2-D2 toy. The entire project can be built with significantly less work without using the R2-D2, but the astromech droid had a lot more flair. First: How to make it work from scratch:

The first revision was just an Ardweeny on a proto board with some hot-glue attaching the continuous rotation servo horn to a project box. It spins in horizontal circles, randomly changing directions while also randomly changing vertical angle. The vertical servo must be "tuned" so it is consistently pointing toward the ground unless you enjoy having your cats climb the walls. 

Simple parts:

  1. Ardweeny (Maker Shed)
  2. Adafruit 1/2 Size Perma-Proto Board (adafruit)
  3. Micro Servo and perhaps some 10uF capacitors to clean up the noise (adafruit)
  4. Sparkfun TTL Laser and 10k resistor (Sparkfun) 
  5. Continuous Rotation Servo (adafruit)
  6. 3xAAA battery holder (adafruit)

Advanced/Optional parts:

  1. RobotShop pan kit for either Futaba or Hitec servos. I went with the Hitec version and modified a Hitec HS-422 servo for continuous rotation. Futaba continuous rotation servos are more widely available without modification, but the Futaba pan kit is more expensive. The servo I linked above is a Futaba servo.
  2. R2-D2 model. I used a Diamond Select bank I found on Amazon but can't find it anymore.
  3. Shape Lock molding plastic. (Maker Shed)
  4. On-Off button and LED. This beauty from adafruit does both

Simple assembly:

In my non-Droid version, I simply sandwiched the servos between the proto board and the battery holder then used hot glue to affix the continuous rotation servo to a project enclosure. It worked fine, but was not sturdy. The switch to the Perma-Proto board was ideal as shown here:

Pin assignment:

  • Vertical (standard) servo: 10
  • Horizontal (continuous rotation) servo: 9
  • Laser diode: 8  (The diode is TTL controlled and uses a 10k resistor to ground)
  • Power LED: 7

That's all that is needed to get a basic laser toy running. Fitting it into the R2-D2 robot was a bit more challenging. I needed to find a way to allow the entire R2-D2 head to spin freely without tangling wires and I didn't have a slip ring (but adafruit does now) so I decided to make the entire electronic device rotate. Finding the DDP155 Pan System from RobotShop and mounting it upside down solved that for me. I screwed in a few risers to the rotating plate to lift it higher into the droid model. 


When working with ShapeLock, be aware that the hot plastic will bond to other plastics. To get a very close form, insulate other plastic areas with aluminum foil until the cooling completes. ShapeLock can be cut with a Dremel rotary tool with a plastic or wood cutting bit at 5-8k RPM. Going over 10k causes the plastic to melt. USE SAFETY GLASSES when using a rotary tool. Little bits of white plastic in the eye are not fun.

The most difficult part of the R2-D2 enclosure was the centering and balancing of the head on the RobotShop pan kit. This took several tries. Thankfully ShapeLock can simply be melted down and re-molded. 

That's it for the construction. The rest is just source code. Enjoy!


/* Arduino laser cat toy
 2012 Daniel Gentleman
 Creative Commons Attribution license
 Laser diode attached to a standard servo for vertical movement
 Continuous rotation servo for horizontal spinning
 Power LED (optional) 
#include <Servo.h> 
Servo myservoh;  // Horizontal servo - continuous rotation
Servo myservov; // Vertical servo - standard 
unsigned int duration = 0;
int lasttime1 = 0;
int lasttime2 = 0;
int randstart = 0;
int randend = 0;
int pos = 0;
int laser = 8; // TTL laser diode on pin 8
int vpos = 80; 
int powerLed = 7; // Power LED on pin 7
void setup()
  myservoh.attach(9); // Continuous rotation servo on pin 9
  myservov.attach(10); // Standard servo on pin 8
  pinMode(laser, OUTPUT);
  pinMode(powerLed, OUTPUT);
  digitalWrite(laser, LOW);  // Turn ON the laser 
  digitalWrite(powerLed, HIGH); // Turn ON the power LED
void loop()
  int vaxis = random(50,120); // Range of vertical movement (50-120 here)
  lasttime1 = millis();
  randstart =  random(200, 19990); // Tune these for your preferred random behavior
  randend =  random(2000, 2400);
  while(pos <= randend) // Random horizontal spinning 
    pos += 1;
  vaxis = random(70,100);
  myservov.write(vaxis); // Random vertical movement
  duration = millis() - lasttime1;
  lasttime2 = millis();
  while(pos >= randstart)
  vaxis = random(70,100);
  duration = millis() - lasttime2;
  duration = millis() - lasttime1;


Sparkfun RGB LED and RGB Light Sensor

I can't quite figure this one out: it's VERY delicate and I can't get consistant color results with the built-on LED on or off. I know if it gets a UV light, it shows a lot of purple and if it gets hit with a red laser it maxes out the red LED. Anyhow... Video and code! 



Expanded to use the Sparkfun RGB LED on pins 3, 5, and 6, sending
PWM signals as 1/10 of the result. YouTube video of this in action at
Use of the RGB LED changes added by thoughtfix 2/2012
Inherited OSHW license.
Original comments below.
An Arduino code example for interfacing with the 
HDJD-S822-QR999 Color Sensor.  Put an object in front of the
sensor and look at the serial monitor to see the values the sensor
is reading.  Scaling factors and gains may have to be adjusted
for your application.
by: Jordan McConnell
 SparkFun Electronics
 created on: 1/24/12
 license: OSHW 1.0, http://freedomdefined.org/OSHW
Connect the gain pins of the sensor to digital pins 7 - 12 (or ground).
Connect the led pin to digital 13.
Connect Vr to analog 0, Vg to analog 1, and Vb to analog 2.
// Define pins
const int ledpin = 13;
const int GSR1 = 12;
const int GSR0 = 11;
const int GSG1 = 10;
const int GSG0 = 9;
const int GSB1 = 8;
const int GSB0 = 7;
const int redLed = 3;
const int greenLed = 5;
const int blueLed = 6;
int redpin = A0;
int greenpin = A1;
int bluepin = A2;
// Sensor read values
int red = 0;
int green = 0;
int blue = 0;
int redBright = 0;
int greenBright = 0;
int blueBright = 0;
void setup() 
  pinMode(ledpin, OUTPUT);
  pinMode(GSR1, OUTPUT);
  pinMode(GSR0, OUTPUT);
  pinMode(GSG1, OUTPUT);
  pinMode(GSG0, OUTPUT);
  pinMode(GSB1, OUTPUT);
  pinMode(GSB0, OUTPUT);
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);
  // Turn on the LED
  digitalWrite(ledpin, LOW);
  // Set the gain of each sensor
  digitalWrite(GSR1, LOW);
  digitalWrite(GSR0, LOW);
  digitalWrite(GSG1, LOW);
  digitalWrite(GSG0, LOW);
  digitalWrite(GSB1, LOW);
  digitalWrite(GSB0, LOW);
void loop() 
  // Read sensors
  // On page 7 of the datasheet, there is a graph of the 
  // spectral responsivity of the chip.  Scaling factors were
  // selected based on this graph so that the gain of each 
  // color is closer to being equal
  red = analogRead(redpin) * 10;
  green = analogRead(greenpin) * 14;
  blue = analogRead(bluepin) * 17;
  redBright = red/10;
  greenBright = green/10;
  blueBright = blue/10;
  // Print values to the serial monitor
  Serial.print("Red: ");
  Serial.print(red, DEC);
  analogWrite(redLed, redBright);
  Serial.print("\t\tGreen: ");
  Serial.print(green, DEC);
  analogWrite(greenLed, greenBright);
  Serial.print("\tBlue: ");
  Serial.println(blue, DEC);
  analogWrite(blueLed, blueBright);
/*Expanded to use the Sparkfun RGB LED on pins 3, 5, and 6, sendingPWM signals as 1/10 of the result. YouTube video of this in action at
Use of the RGB LED changes added by thoughtfix 2/2012Inherited OSHW license.Original comments below.*/
/*An Arduino code example for interfacing with the HDJD-S822-QR999 Color Sensor.  Put an object in front of thesensor and look at the serial monitor to see the values the sensoris reading.  Scaling factors and gains may have to be adjustedfor your application.
by: Jordan McConnell SparkFun Electronics created on: 1/24/12 license: OSHW 1.0, http://freedomdefined.org/OSHW Connect the gain pins of the sensor to digital pins 7 - 12 (or ground).Connect the led pin to digital 13.Connect Vr to analog 0, Vg to analog 1, and Vb to analog 2.*/

// Define pinsconst int ledpin = 13;const int GSR1 = 12;const int GSR0 = 11;const int GSG1 = 10;const int GSG0 = 9;const int GSB1 = 8;const int GSB0 = 7;const int redLed = 3;const int greenLed = 5;const int blueLed = 6;
int redpin = A0;int greenpin = A1;int bluepin = A2;
// Sensor read valuesint red = 0;int green = 0;int blue = 0;int redBright = 0;int greenBright = 0;int blueBright = 0;
void setup() {  Serial.begin(9600);
  pinMode(ledpin, OUTPUT);  pinMode(GSR1, OUTPUT);  pinMode(GSR0, OUTPUT);  pinMode(GSG1, OUTPUT);  pinMode(GSG0, OUTPUT);  pinMode(GSB1, OUTPUT);  pinMode(GSB0, OUTPUT);  pinMode(redLed, OUTPUT);  pinMode(greenLed, OUTPUT);  pinMode(blueLed, OUTPUT);
  // Turn on the LED  digitalWrite(ledpin, LOW);    // Set the gain of each sensor  digitalWrite(GSR1, LOW);  digitalWrite(GSR0, LOW);  digitalWrite(GSG1, LOW);  digitalWrite(GSG0, LOW);  digitalWrite(GSB1, LOW);  digitalWrite(GSB0, LOW);}
void loop() {    // Read sensors  // On page 7 of the datasheet, there is a graph of the   // spectral responsivity of the chip.  Scaling factors were  // selected based on this graph so that the gain of each   // color is closer to being equal  red = analogRead(redpin) * 10;  green = analogRead(greenpin) * 14;  blue = analogRead(bluepin) * 17;  redBright = red/10;  greenBright = green/10;  blueBright = blue/10;
  // Print values to the serial monitor  Serial.print("Red: ");  Serial.print(red, DEC);  analogWrite(redLed, redBright);  Serial.print("\t\tGreen: ");  Serial.print(green, DEC);  analogWrite(greenLed, greenBright);  Serial.print("\tBlue: ");  Serial.println(blue, DEC);  analogWrite(blueLed, blueBright);  delay(20);}