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;


Ethernet enabled server room thermometer

After my first "blinky" thermometer was taken down for looking "too unprofessional," I moved on to craft a more subtle (and functional) way to get the job done. This time,  with an Arduino Uno, an Ethernet Shield, and a DHT11 temperature sensor. The code is a combination of Ladyada's DHT code and the Arduino example Ethernet code with only tiny modifications. The enclosure was purchased at Jameco.

The result is monitored in Nagios and Cacti. If anyone builds one and needs help with Nagios/Cacti implementation, let me know.

The HTML output is intentionally boring so as to be easily readable by monitoring software:

TemperatureC: 28.00
TemperatureF: 82.40
Humidity: 53.00


  Web  Server Thermometer

A simple web server that shows the value of a DHT11
using an Arduino Wiznet Ethernet shield. 

* DHT11 attached to pin 2
* Ethernet shield attached to pins 10, 11, 12, 13

Web server code: 
created 18 Dec 2009
by David A. Mellis
modified 4 Sep 2010
by Tom Igoe

DHT code written by ladyada
Public Domain

Combining the two by thoughtfix
July, 2011


#include <SPI.h>
#include <Ethernet.h>
#include "DHT.h"

#define DHTTYPE DHT11   // DHT 11 
#define DHTPIN 2     // DHT pin

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x4B, 0x21 };
byte ip[] = { 192,168,1, 223 };

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
Server server(80);

void setup()
  // start the Ethernet connection and the server:

  Ethernet.begin(mac, ip);

void loop()
  // listen for incoming clients
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = t*1.8+32; 
  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");

          // output the value of each analog input pin
          client.print("TemperatureC: "); 
          client.println("<br />");
          client.print("TemperatureF: "); 
          client.println("<br />");
          client.print("Humidity: "); 
          client.println("<br />");
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
    // give the web browser time to receive the data
    // close the connection:

Arduino server room thermometer (Blinky)

This is the first generation of the project with only visual alerts. The second generation was Ethernet enabled.

At my last job, I rarely had to set foot in my server room. The air conditioning unit, however, sometimes falls behind in the summer. I wanted something that would grab the attention of people walking by if it were to go over 80F ambient temperature. Except for a little wiring, the parts list is 100% Adafruit stock:


That's $31.75 if you have an UNO handy, $30 more if you don't. 

To build the LCD shield: http://forums.adafruit.com/viewtopic.php?f=31&p=112887#p112887

A long section of ribbon cable (I used 7 wires - more than I need) to go around the door and a little wire, time, and solder to assemble the bits together are all that is left. I have the proto shield's LEDs on pins 12 and 13, the LCD shield exactly how I described it built in a previous thread, and the temperature sensor on (analog 0) pin 14. I have analog 1 and 2 going to the back breadboard too just in case I want to use them.

On the ribbon cable, I am using VIN to power the display. This way the power supply can sit inside the server room and won't be hanging off the wall in the "public area." The barrel jack was perfect for that. 

Make sure to get the required libraries for the temperature sensor and LCD from the product links above or it'll never compile. The code is ugly and poorly commented, but it does the job. I even got lazy and read the temperature through two different functions (one as a string, one as an int) because I hate converting back and forth. 


// Arduino "FREAK OUT OVER 80F" thermometer

#include <PCD8544.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "String.h"
#include "WProgram.h"

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 14

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;
PCD8544 nokia = PCD8544(7, 6, 5, 4, 3);
char msg[125];
int flash = 0;
int currTemp;

void setup(void)
  // start serial port
  Serial.println("Dallas Temperature IC Control Library Demo");
  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");
  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
  sensors.setResolution(insideThermometer, 9);
  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  // back to normal
  pinMode(13, OUTPUT); // Green  LED
  pinMode(12, OUTPUT); // Red LED 
  digitalWrite(12, HIGH);

void loop(void)

  sensors.requestTemperatures(); // Send the command to get temperatures
  String msgHead = "The current   server room   temp is ";
  String termMessage = msgHead + fetchTemp(insideThermometer) + "F " + "\0";
  int msglen = (termMessage.length()+1); // count the characters, add 3 just in case
  Serial.println(" - message length");
  termMessage.toCharArray(msg,msglen); // Convert it to an array called msg
  Serial.print("Attempted message ");
  nokia.drawstring(0, 0, msg);
  if (numTemp(insideThermometer) > 80){
    for (int flash = 1; flash < 10; flash++){
    digitalWrite(13, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(12, HIGH);
    digitalWrite(13, LOW);
  else {


// function to print a device address
void printAddress(DeviceAddress deviceAddress)
  for (uint8_t i = 0; i < 8; i++)
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);

String fetchTemp(DeviceAddress deviceAddress)
  float tempC = sensors.getTempC(deviceAddress);
  int tempF = DallasTemperature::toFahrenheit(tempC);
  String reportTemp = tempF;
  String reportText = reportTemp + "F";
  return reportTemp;

int numTemp(DeviceAddress deviceAddress)
  float tempC = sensors.getTempC(deviceAddress);
  int tempF = DallasTemperature::toFahrenheit(tempC);
  return tempF;

The Frankenmac

The Powermac G5 Cube was a unique aesthetic design. I found one on Craigslist for an extremely low price and decided to combine it with my then-unused Mac Mini (Mid-2007 Core2Duo 1.83) and make a more modern, usable machine. 

First, all the guts were carefully removed leaving only the chassis. Some metal needed to be cut through the bottom of the G5 cage to access the new ports. Thanks to Kevin R. for help on that one.

The center of the G5 cube was one very large heat sink that had to be cut with a hacksaw to make space but preserve the original sliding locks.

Assembly was relatively easy after that - fitting a second 750GB hard drive over a Firewire connection and bridging a Silverstone slot-loading ITX form factor DVD-RW using a JAE50 to SATA adapter harvested from a laptop drive caddy. 


Chumby-driven Superhero Phone

The Chumby is a fascinating little embedded Linux device designed to be a desktop widget player. Hardware and software are all open platforms and the Chumby developers encourage hackers to dissect and improve upon them. 

I found an 80's style "big red telephone" as would be used to call a nocturnal echo-locating flying mammal man and built the Chumby into it. The entire experience was published in Make Magazine, Vol 16.