Parts List
- Webcam of your choice (I used a Logitech C510 HD Webcam) — keep in mind that you’re going to want to mount it to the pan/tilt bracket somehow
- Arduino Uno
- Pan/Tilt Bracket from SparkFun
- 2x Small Servos
- PC Board or breadboard (I like these from RadioShack)
- Red LED
- 330 ohm resistor
- Male break-away pin headers
- Wire
- Wood, metal, or plastic for your base
- Screws, nuts, and washers for mounting everything
Assembling the pan/tilt unit
Arduino connections
Arduino Code
Code available at Github here: https://github.com/jessicaaustin/robotics-projects/tree/master/pan-tilt-unit
Once you’ve uploaded the following code to your Arduino, you should be able to control the pan/tilt unit via the Serial Monitor.
#include <Servo.h> Servo pan_servo; Servo tilt_servo; int incomingByte; void setup() { // attach the servos and startup the serial connection pan_servo.attach(9); tilt_servo.attach(8); Serial.begin(9600); resetAll(); } void loop() { // check to see if something was sent via the serial connection if (Serial.available() > 0) { incomingByte = Serial.read(); // move the servos based on the byte sent if (incomingByte == 'e') { moveServo(tilt_servo, 1); } else if (incomingByte == 'x') { moveServo(tilt_servo, -1); } else if (incomingByte == 'd') { moveServo(pan_servo, 1); } else if (incomingByte == 's') { moveServo(pan_servo, -1); } else if (incomingByte == 'r') { resetAll(); } else if (incomingByte == '/') { Serial.println("pan: " + pan_servo.read()); Serial.println("tilt: " + tilt_servo.read()); } } } // move the servo a given amount void moveServo(Servo servo, int delta) { int previousValue = servo.read(); int newValue = previousValue + delta; if (newValue > 180 || newValue < 30) { return; } servo.write(newValue); } // put the servos back to the "default" position void resetAll() { reset(pan_servo); reset(tilt_servo); } // put a servo back to the "default" position (100 deg) void reset(Servo servo) { int newPos = 130; int previousPos = servo.read(); if (newPos > previousPos) { for (int i=previousPos; i<newPos; i++) { servo.write(i); delay(15); } } else { for (int i=previousPos; i>newPos; i--) { servo.write(i); delay(15); } } }
Controlling the Arduino via a script
I used todbot‘s arduno-serial.c program to control the Arduino via the command line.
Get arduino-serial.c and test it out:
wget http://todbot.com/arduino/host/arduino-serial/arduino-serial.c gcc -o arduino-serial arduino-serial.c # test moving the camera up and to the right ./arduino-serial -b 9600 -p /dev/tty.usbmodem3d11 -s dddddddddddddddeeeeeeeeeeeeeee
Running the script via Apache HTTP Server
At this point, someone could ssh in to the computer running the camera and control it via the command line, but I wanted to have a slightly more sophisticated interface. I decided to go with a simple jQuery-powered web page that hits a CGI script served up by apache. (Note: of course, if you want people to be able to control the camera from outside your local network, you’ll need a static IP address for your machine. In that case, you should probably also make sure you set up basic authentication for your apache server.)
If you’re running OSX, apache is already installed. You can start it up by running sudo apachectl start
, the config is located at /etc/apache2
, and the DocumentRoot points to /Library/WebServer/
by default.
cd /Library/Webserver/CGI-Executables vim pan-tilt.cgi
pan-tilt.cgi
is the following ruby script:
#!/opt/local/bin/ruby query_string=`echo $QUERY_STRING` if query_string.length != 0 `/opt/local/bin/arduino-serial -b 9600 -p /dev/tty.usbmodem3d11 -s #{query_string}` result=`echo $?` result=result.gsub(/n/,"") end print "Content-type: application/jsonnn" print "{"result": "#{result}"}n"
Finally, create the web page:
cd /Library/Webserver/Documents vim pan-tilt.html
pan-tilt.html:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script> <script>// <![CDATA[ // send the input to the cgi script // note: sending 3x the input for every keypress, to make the movement smoother var submitInput = function(input) { $.post("/cgi-bin/pan-tilt.cgi?" + input + input + input); }; // submit input when someone presses a key down $(document).keydown(function(event) { console.log(event.keyCode); switch(event.keyCode) { case 82: submitInput('r'); break; case 83: submitInput('s'); break; case 68: submitInput('d'); break; case 69: submitInput('e'); break; case 88: submitInput('x'); break; case 37: submitInput('s'); break; case 39: submitInput('d'); break; case 38: submitInput('e'); break; case 40: submitInput('x'); break; default: } }); // ]]></script> <h1>Pan/Tilt Camera Control</h1> <div> <table> <tbody> <tr> <td></td> <td>&amp;uarr;</td> <td></td> </tr> <tr> <td>&amp;larr;</td> <td>r</td> <td>&amp;rarr;</td> </tr> <tr> <td></td> <td>&amp;darr;</td> <td></td> </tr> </tbody> </table> <table> <tbody> <tr> <td></td> <td>e</td> <td></td> </tr> <tr> <td>s</td> <td>r</td> <td>d</td> </tr> <tr> <td></td> <td>x</td> <td></td> </tr> </tbody> </table> </div> <div style="clear: left;"> todo: add security</div>
Testing
At this point you should be able to go http://localhost/pan-tilt.html and control the camera from there. Check out the video below!