September 2, 2013

How to lazily entertain a cat (Part 1)

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 VsupplyVdiodeR, 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

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:
  1. Put a servo perpendicularly on the other one;
  2. Fix the laser on the topmost servo;
  3. Plug everything together.
    1. Servos on the Controller;
    2. Laser and servos power to the USB power (available on the controller);
    3. 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:

"""
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()
view raw random_servo.py hosted with ❤ by GitHub
And there you go! Next up on Part 2 we'll see how to hook up this setup to a webcam using OpenCV to analyze movement and create organic-like movement. Stay tuned!

I shamelessly offer you a couple of photos of my cat:

No comments:

Post a Comment