loading

This instructable was created in fulfillment of the project requirement of the Makecourse at the University of South Florida (www.makecourse.com)

This project is a small-form prototype for a Whac-A-Mouse cat toy.

The following are design constraints given in the course:

  1. The object must be completely designed and simulated in Inventor before it is built.
  2. It must contain 3D printed moving components that interact with the electronic control circuit.
  3. It must be controlled by, or interact, via the Arduino and kit components (use of additional components is encouraged) in some creative way.
  4. It must have a creative (i.e no simple switch) on/off or control mechanism (remote control, touch sensor etc.)
  5. The standard enclosure must be used. All cutouts in the enclosure must be designed in the 3D simulation and professionally implemented. The best way is usually to print the enclosure and/or the lid with the cutouts and fixtures integrated to hold whatever you need to mount.
  6. The final design must be completed and work, be neatly manufactured with precision, and be original. There will be no A grades for incomplete and/or shoddy put together projects.

These design constraints were observed for the design on this prototype. You do not need to follow these constraints for your project.

The concept is the same as Whac-A-Mole but miniaturized & tailored for the feline species. In this instructable, I will be showing you how to create this toy for your cats.

Step 1: Gather Materials

Main Components:

  • 1 Enclosure Bottom (CAD file provided below. Use a larger enclosure for more fun)
  • 2 Servo mount sliders (CAD file provided below)
  • 1 Enclosure Top (CAD file provided below)
  • 2 3D printed servo arms (CAD file provided below)
  • 2 Compressed catnip balls
  • 1 Arduino Uno or equivalent
  • 2 USB Cables
  • 2 Servo Motors - (Use more servos and a larger enclosure for more fun)
  • 1 Adafruit Perma-Proto Quar
  • 1 IR receiver
  • 1 IR Remote
  • 1 Mini breadboard (or smaller)
  • 2 Power rails (or equivalent wiring)
  • 1 9v power adapter
  • 1 6v battery mount
  • 1 Green 3mm LED
  • 1 Empty water bottle

Other Suggested Components:

  • Assorted jumper cables (wiring)
  • Small screws for mounting
  • Solder
  • Soldering Iron
  • Sand Paper - various grit sizes
  • JB Weld Epoxy
  • XTC 3D Print coating
  • Spray paint
  • Hand files
  • Dreme / Drill with drill bits
  • Lighter
  • Shrink Tubing
  • Black Feathers
  • Small zip ties
  • Raised Alphabet Stickers

Step 2: 3D Printing & Preparation

You may choose to either use the CAD files provided below or create your own custom enclosure.

I also suggest making your project out of natural materials such as rope. Cats prefer natural materials.

The video below shows how the mechanism should function.


After 3D printing begin preparing the parts:

  • Thoroughly sand 3D printed parts to your liking using various grit sandpaper.
  • Drilling a hole for the 3mm Green LED in the lower right hand corner of the box (or incorporate hole in CAD file before printing).
  • Filing down a square section for the IR receiver (or incorporate space in CAD file before printing).
  • Epoxy the servo saver to the 3D printed servo arm.
  • Attach compressed catnip ball to servo arm using a sufficient length & diameter screw.
  • Mount servo onto servo sliding back mount with epoxy or sufficient length & diameter screws.
  • Mount servo arm & compressed catnip ball assembly to servo.

The zip file below contains all 3D CAD files printed for this project. While other CAD models were used in this simulation, the other CAD files seen in the simulation above are not needed for 3D printing.

Step 3: Prepare the Circuitry

The first image shows how to wire up your Whac-A-Mouse project. Simply follow the pin connections on the Fritzing diagram.

The second image shows the actual electrical component setup in the project enclosure.

Fritzing diagram provided below.

For a detailed overview on how the Adafruit FX Sound Board works visit:

https://learn.adafruit.com/adafruit-audio-fx-sound...

Step 4: Prepare the Arduino Code

Include the library attached below. The servo library is the default servo library that comes with the Arduino sketch software.

Define Constant Variables

You will have to set these values depending on the protocol and remote codes that you are using. These are from my hobby remote. View the attached IRLib library for references on the IRLib protocol.

#define MY_PROTOCOL NEC
#define RIGHT_ARROW 0xFF02FD // PLAY main loop (power)
#define LEFT_ARROW 0xFF22DD // SERVO POSITION 2
#define POWER 0xFFA25D // SERVO POSITION 2 POWER
#define PLAY 0xFFC23D // PLAY AUTO LOOP
#define RETURN 0xFFB04F // LEAVE AUTOMATIC LOOP
#define MUTE 0xFFE21D // OFF

const int SFX_4 = 4; const int SFX_2 = 5;
const int SFX_RST = 6;
const int SFX_vol = 7;
const int sensor1_pwr = A4;
const int sensor2_pwr = A5;
const int sensor1 = A0;
const int sensor2 = A1;
const int LEDON = 10;

Define Changing Variables

int _SFX_4 = HIGH;
int _SFX_2 = HIGH;
int _SFX_RST = HIGH;
int _SFX_vol = HIGH;
int pos1;
int pos2;
int Read1NEW = 400;
int Read1OLD = 400;
int Read2NEW = 400;
int Read2OLD = 400;
int state = 0
int n = 0;
int m = 0;
int w = 0;
int prevMillis = 0;
long previousMillis = 0;

Define servos:

Servo servo1;  // Define servo
Servo servo2; // Define servo

Use this segment of code for the IR receiver:

IRrecv My_Receiver(11); //Receive on pin 11
IRdecode My_Decoder;

Setup:

void setup(){ // begin setup
Serial.begin(9600); // Begin serial communication
My_Receiver.No_Output(); // Turn off any unused IR LED output circuit
My_Receiver.enableIRIn(); // Starts the receiver for IR remote

Define Pin Modes

pinMode(SFX_2,OUTPUT);
digitalWrite(SFX_2,_SFX_2);
pinMode(SFX_4,OUTPUT);
digitalWrite(SFX_4,_SFX_4);
pinMode(SFX_vol,OUTPUT);
digitalWrite(SFX_vol,_SFX_vol);
pinMode(SFX_RST,OUTPUT);
digitalWrite(SFX_RST,_SFX_RST);
pinMode(sensor1_pwr,OUTPUT);
digitalWrite(sensor1_pwr,HIGH);
pinMode(sensor1_pwr,OUTPUT);
digitalWrite(sensor1_pwr,HIGH);
pinMode(sensor2_pwr,OUTPUT);
digitalWrite(sensor2_pwr,HIGH);
pinMode(LEDON,OUTPUT);
digitalWrite(LEDON,LOW);

Attach Servos:

servo1.attach(8);
servo2.attach(9);
} // end setup

Main Loop:

This segment of code is commented so I will not repeat the codes purpose.

void loop(){ // begin main loop
bailout1:{

servo1.detach();  // Detach Servo, prevents servo noise
servo2.detach();  // Detach Servo, prevents servo noise

int V1 = 0;   //  Variable for while loop below

while (V1 == 0){
if (My_Receiver.GetResults(&My_Decoder)) {
My_Decoder.decode();
if(My_Decoder.decode_type==MY_PROTOCOL) {
switch(My_Decoder.value) {

case MUTE:{
digitalWrite(LEDON,LOW);
Serial.println("POWER OFF");
servo1.attach(8);  // Attaches servo 1
servo2.attach(9);  // Attaches servo 2
servo1.write(95);  // low position is 95 deg
servo2.write(100);  // low position is 100 deg
delay(500);
goto bailout1;
}

case POWER:{
Serial.println("POWER ON");
digitalWrite(LEDON,HIGH);
int V2 = 0;
while (V2 == 0)
{
//  Detach all servos so that vibrations sensors do not pick up any
//  servo vibration or whine.
//----------------------------------------------------------------------
servo1.detach();
servo2.detach();
//       Nested Loop Wich Sets Initial Conditions for SFX board
//       In this case, it is used for adjusting volume.
//       Go to  https://learn.adafruit.com/adafruit-audio-fx-soun...
//       for a detailed tutorial on how the Adafruit FX board works.
//       The segment of code below is essentially turning the volume
//       down by a crude method. 
//----------------------------------------------------------------------
while(n < 1){
n++;
Serial.print("Resetting FX Sound Board...");
digitalWrite(SFX_RST,LOW);
delay(40);
digitalWrite(SFX_RST,HIGH);
Serial.println("Complete"); 
}
while(m < 26){
m++;  
digitalWrite(SFX_vol,LOW);
delay(40);
digitalWrite(SFX_vol,HIGH);
delay(40);
if(m == 26){
Serial.println("Complete");
}
if(m == 1){
Serial.print("Checking Volume Level...");
}}
//----------------------------------------------------------------------
bailout2:{  // Used to escape from nested loops below
//----------------------------------------------------------------------
//                     Remote Control Interface
//----------------------------------------------------------------------
//  For info on how to use the IR remote control with the Arduino
//  visit  https://github.com/cyborg5/IRLib
//  There are manuals and examples.
//----------------------------------------------------------------------
if (My_Receiver.GetResults(&My_Decoder)) {
My_Decoder.decode();
if(My_Decoder.decode_type==MY_PROTOCOL) {
switch(My_Decoder.value) {
//----------------------------------------------------------------------
// The next two case statements are used to alternate servo positions
// with the push of the button (right or left arrow on IR remote)
//----------------------------------------------------------------------

case MUTE:{
digitalWrite(LEDON,LOW);
Serial.println("POWER OFF");
servo1.attach(8);  // Attaches servo 1
servo2.attach(9);  // Attaches servo 2
servo1.write(95);  // low position is 95 deg   
servo2.write(100);  // low position is 100 deg
delay(500);
goto bailout1;  // exit ON loop
}

case LEFT_ARROW:{ servo1.attach(8); // Attaches servo 1 servo2.attach(9); // Attaches servo 2
Serial.println("MANUAL PLAY 1"); digitalWrite(SFX_4,LOW); // enables sound delay(400); // delay for sound digitalWrite(SFX_4,HIGH); // enables sound servo1.write(95); // High position is 125 deg servo2.write(75); // low position is 100 deg delay(2000); // delay for timing state = 1; // state for determining which sensor was last break; // exit loop } case RIGHT_ARROW: { servo1.attach(8); // Attaches servo 1 servo2.attach(9); // Attaches servo 2 Serial.println("MANUAL PLAY 2"); digitalWrite(SFX_4,LOW); // enables sound delay(400); // delay for sound digitalWrite(SFX_4,HIGH); // enables sound servo1.write(125); // low position is 95 deg servo2.write(100); // high position is 75 deg delay(2000); // delay for timing state = 0; // state for determining which sensor was last break; // exit loop } //********************************************************************** // This segment enables the automated play mode //********************************************************************** case PLAY: { Serial.println("Entering Automated Play Mode"); int q = 0; while(q==0) { //---------------------------------------------------------------------- // This segment of code is used to break out of the automated play mode //---------------------------------------------------------------------- if (My_Receiver.GetResults(&My_Decoder)) { My_Decoder.decode(); if(My_Decoder.decode_type==MY_PROTOCOL) { switch(My_Decoder.value) { case RETURN: { Serial.println("Leaving Automated Play Mode"); delay(10); servo1.attach(8); // Attaches servo 1 servo2.attach(9); // Attaches servo 2 servo1.write(95); // low position is 95 deg servo2.write(100); // low position is 100 deg delay(500); w=0; goto bailout2; // exits play loop }}} My_Receiver.resume(); } //---------------------------------------------------------------------- // Initially positions servo at beginning of automated play mode //---------------------------------------------------------------------- while(w < 1) { w++; // variable for loop servo1.attach(8); // Attaches servo 1 servo2.attach(9); // Attaches servo 2 delay(1); // delay for stability servo1.write(95); // positions servo High is 120 deg servo2.write(75); // positions servo low is 100 deg delay(20); // delay for timing servo1.detach(); // Detach Servo, prevents servo noise servo2.detach(); // Detach Servo, prevents servo noise //---------------------------------------------------------------------- //This segment Plays song to indicate you have entered automatic play mode //---------------------------------------------------------------------- digitalWrite(SFX_2,LOW); delay(400); digitalWrite(SFX_2,HIGH); } //---------------------------------------------------------------------- // Stores readings for sensor 1 & 2 in a variable //---------------------------------------------------------------------- Read1NEW = analogRead(sensor1); // stores sensor value delay(1); // delay for stability Read2NEW = analogRead(sensor2); // stores sensor value delay(1); // delay for stability //---------------------------------------------------------------------- // Changes servo positions when a sensor is disturbed //---------------------------------------------------------------------- //---------------------------------------------------------------------- // SERVO / SENSOR 1 CONDITIONAL STATEMENT //---------------------------------------------------------------------- if((Read1NEW > 750) && (state == 0)) { Serial.println("Disturbance Detected in Sensor 1"); //---------------------------------------------------------------------- // This segment Plays sound indicating ball has been disturbed //---------------------------------------------------------------------- digitalWrite(SFX_4,LOW); delay(360); digitalWrite(SFX_4,HIGH); //---------------------------------------------------------------------- Read1NEW = 0; // stores sensor reading for sensor 1 Read2NEW = 0; // stores sensor reading for sensor 2 digitalWrite(sensor1_pwr,LOW); // temp disables sensor digitalWrite(sensor2_pwr,LOW); // temp disables sensor servo1.attach(8); // Attaches servo 1 servo2.attach(9); // Attaches servo 2 delay(1500); servo1.write(95); // Up position is 125 servo2.write(75); // Down position is 100 servo1.detach(); // Detach Servo, prevents servo noise servo2.detach(); // Detach Servo, prevents servo noise delay(1000); // delay for timing state = 1; // state for determining which sensor was last } //---------------------------------------------------------------------- // SERVO / SENSOR 2 CONDITIONAL STATEMENT //---------------------------------------------------------------------- if((Read2NEW > 750) && (state == 1)) { Serial.println("Disturbance Detected in Sensor 2"); //---------------------------------------------------------------------- // This segment Plays sound indicating ball has been disturbed //---------------------------------------------------------------------- digitalWrite(SFX_4,LOW); delay(360); digitalWrite(SFX_4,HIGH); //---------------------------------------------------------------------- Read1NEW = 0; // stores sensor reading for sensor 1 Read2NEW = 0; // stores sensor reading for sensor 2 digitalWrite(sensor1_pwr,LOW); // temp disables sensor digitalWrite(sensor2_pwr,LOW); // temp disables sensor servo1.attach(8); // Attaches servo 1 servo2.attach(9); // Attaches servo 2 delay(1500); // delay for timing servo1.write(125); // low is 95 servo2.write(100); // high is 75 servo1.detach(); // Detach Servo, prevents servo noise servo2.detach(); // Detach Servo, prevents servo noise delay(1000); // delay for timing state = 0; // state for determining which sensor was last } else { digitalWrite(SFX_4,HIGH); // Keeps sound effect pin high (OFF) if ((analogRead(sensor2) < 350) && (analogRead(sensor1) < 350)) { digitalWrite(sensor1_pwr,HIGH); // enables sensor digitalWrite(sensor2_pwr,HIGH); // enables sensor }}}}}} My_Receiver.resume(); }}}}}} My_Receiver.resume(); }}}} //********************************************************************** //**********************************************************************

Step 5: Make Final Preperations

Once you are done finishing your project enclosure, wiring the circuit, and uploading the code to the Arduino you can begin putting it all together.

Take the following next steps:

  • Epoxy Arduino mount spacers to base
  • Epoxy Adafruit FX Sound Board spacers to base
  • Epoxy the speaker to the box
  • Epoxy battery mounts to base
  • Epoxy power rails to base
  • Epoxy IR sensor to designated opening
  • Zip tie sensors to servo arms
  • Epoxy feathers to bottom of top

Once the epoxy dries:

  • Mount the Arduino to the mount spacers
  • Mount the Adafruit FX Sound Board to the mount spacers
  • Connect all jumper wires to designated pins based on Fritzing diagram
  • Install batteries
  • Slide servos into their slots

Finish the enclosure with spray paint or some other form of finish. I suggest you try epoxying rope to your enclosure to make a duel purpose scratch pad plus toy. Remember to wipe the paint off IR receiver or you may have issues communicating with the Arduino.

Once the paint is dry:

  • Epoxy green LED to designated hole & connect jumper wires to designated pins.

Lastly, as a safety measure for your cat, cut a water bottle in half length wise and across to create a half arc sheet of plastic. Tap the bottom of this sheet with electrical tape. The bottom can be spray painted black or any color of your choosing. This piece will rest over the electronics before the top is mounted and will prevent the cat from snagging a wire should their paw go down the hole.

Disclaimer: This is my first time making anything of this nature. I am not a coder or an electrical engineer nor am I an expert at making Instructables. If you have some suggestions please let me know and I will try to implement them when I have time between school and work. I hope your cats enjoy this toy as much as mine! Just don't let them see you with the remote. Mine stop playing when they realize I am in control.

<p>This is cute. I love these whack-a-mole type games. Thanks for sharing!</p>

About This Instructable

720views

4favorites

License:

More by ashable:Whac-A-Mouse Prototype 
Add instructable to: