Laser-powered Cat Entertainment System (LCES)
Cats love lasers.So let's build a Laser-powered Cat Entertainment System (LCES). It's a fancy name for a laser that shakes autonomously. I know this has already been done a million times and is even manufactured and sold, but, hey! The fun is in the journey and not the destination!
This project is split in two parts. The first section will cover the physical system per se while the second one will discuss interactivity using a webcam.
For part 1, you will need:
- A Laser;
- Two servomotors;
- A servo controller;
Laser
I used a cheap diode and resistor combo from DealExtreme.com, but any diode would do. Disassembling one you found at the flea market is another good alternative. While playing with it, remember that it is a diode, which means that they must be supplied in current. Applying a voltage source to it will cause it to burn. How can I create a current supply, you ask? For low power applications, using a resistor in series with the diode would kick in its V=R·I, effectively limiting the current in the diode to Vsupply−VdiodeR, if you are interested by school stuff. That won't work on higher power application because the resistor's resistance varies with its temperature.Be careful to use a low power laser because you don't want to burn your cat's retina!
Servomotors
For the servomotors, I've got my hands on two Futaba S3004, but any servomotor will do. You will want one with a disc horn large enough to support the second servo and the second one with arms, X or star-shaped. What are the differences? Check Figure 1.
![]() |
Figure 1: Types of horns. Sorry, no arm because I didn't had one in hand. Just think of it as an X with two opposites branches cut off. |
Servo controller
As for the servo controller, I will use a Pololu Micro Maestro 6, which can be seen in Figure 2.
![]() |
The red wire is a bypass to power the servos using the 5V from the USB.
Using an already made servo controller is the simplest solution but you can always
Hardware recap
- [~2$ ] 1x Laser - Such as this one;
- [~6$ ] 2x Servomotor - Such as the Tower Pro SG-5010;
- [~20$] 1x Servo controller - Such as the Pololu Micro Maestro 6;
Your mileage may vary on prices, be sure to browse a bit before purchasing to find better or cheaper parts.
Design
The assembly is quite simple:
- Put a servo perpendicularly on the other one;
- Fix the laser on the topmost servo;
- Plug everything together.
- Servos on the Controller;
- Laser and servos power to the USB power (available on the controller);
- Controller to the computer.
This is the look of the final design once you've plugged everything together.
Software
Now that the hardware parts are all ready, we can start coding. Here is a small example of randomly waving the laser around using Python.
You will need to install pyserial, first. In fact, I recommend you to create a virtualenv with Python 3.3, install setuptools and pip and then execute pip install pyserial. This works on Linux, Windows and Mac.
Make sure you've configured correctly your Pololu using the Maestro Control Center (provided with the driver). This means activating either the USB Dual Port or USB Chain mode, setting the channels properly (I recommend putting every non-used channel to Input for safety) and setting the Mini SSC offset and Timeout to zero. The other options are optional.
So here's the code:
You will need to install pyserial, first. In fact, I recommend you to create a virtualenv with Python 3.3, install setuptools and pip and then execute pip install pyserial. This works on Linux, Windows and Mac.
Make sure you've configured correctly your Pololu using the Maestro Control Center (provided with the driver). This means activating either the USB Dual Port or USB Chain mode, setting the channels properly (I recommend putting every non-used channel to Input for safety) and setting the Mini SSC offset and Timeout to zero. The other options are optional.
So here's the code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Example of how to move randomly two servos plugged in the 5th and 6th channel | |
(slot 4 & 5) of a Pololu Micro Maestro 6. | |
This script requires pyserial. | |
""" | |
from random import randrange, uniform | |
from time import sleep | |
from struct import pack | |
import serial | |
class PololuConn(object): | |
"""Encapsulates Pololu communications.""" | |
def __init__(self, port, port_speed=9600): | |
"""Creates a connection to the Pololu. | |
:param port: | |
The serial port linked to the Pololu. Is of the form r'\\\\.\\COM3' | |
on Windows and '/dev/ttyUSB1' on Linux. | |
:type port: str | |
:param port_speed: The speed of the port (default 9600) | |
:type port_speed: int | |
:exception ValueError: | |
Will be raised when parameter are out of range, e.g. baud rate, | |
data bits. | |
:exception SerialException: | |
In case the device can not be found or can not be configured. | |
""" | |
self.ser = serial.Serial(port, port_speed) | |
def setSpeed(self, channel, speed): | |
"""Sets the speed of the servos plugged in channels. | |
The protocol for the Pololu is described in this page: | |
# http://www.pololu.com/docs/0J40/5.e | |
:param channels: channel to change speed. | |
:type channels: int | |
:param speed: Speed to set the servo. | |
:type speed: int | |
""" | |
self.ser.write(pack("BBBB", 0x87, channel, speed, 0x00)) | |
def move(self, channel, destination): | |
"""Move the servos plugged in channels to their destinations. | |
Motion is done using the Mini-SSC protocol described in this page: | |
http://www.pololu.com/docs/0J40/5.c | |
:param channels: Channel to move. | |
:type type: int | |
:param destinations: Destination angle between 0 and 255. | |
:type destinations: int | |
""" | |
self.ser.write(pack("BBB", 0xff, channel, destination)) | |
def close(self): | |
"""Close the connection to the Pololu.""" | |
self.ser.close() | |
def main(): | |
"""Connects to a Pololu and then moves randomly its channels 4 and 5.""" | |
# These constants defines the servo range. | |
SERVOS_USED = (4, 5) | |
SERVO_RANGE = (0x40, 0xA0) | |
DELAY_RANGE = (0.05, 0.70) | |
conn = PololuConn(port=r'\\.\COM3') | |
# Set speed | |
for servo in SERVOS_USED: | |
conn.setSpeed(servo, 0x15) | |
# Main random destination loop | |
try: | |
while True: | |
for servo in SERVOS_USED: | |
destination = randrange(*SERVO_RANGE) | |
conn.move(servo, destination) | |
sleep(uniform(*DELAY_RANGE)) | |
except KeyboardInterrupt: | |
conn.close() | |
if __name__ == '__main__': | |
main() |
I shamelessly offer you a couple of photos of my cat:
No comments:
Post a Comment