Get Free Shipping & Prusaments with the Prusa XL Summer Deal!

CanineQuest

An interactive puzzle toy that challenges your dog’s mind with fun, distracting sounds and rewards!
43h 20m
14× print file
0.10 mm
0.40 mm
603.00 g
Prusa MK4S & MMU3
32
13
0
652
updated April 27, 2025

Description

PDF

Dog Training as an Audio Adventure – a CanineQuest

Three puzzle levels to challenge your dog. Dog barking, doorbells, bicycle bells or cat meows are played to break their concentration.

In addition to three classic dog puzzles, CanineQuest offers the ability to play audio files in a continuous loop – either immediately or with a delay. This is designed to challenge your dog and help desensitize them to triggering sounds. The delayed reward should capture their attention – not the distracting noise.

 

 

Functions

  • Dog puzzle slide button
  • Dog puzzle bayonet lock
  • Dog puzzle locked drawer
  • Delayed audio playback Sounds
  • Status LED
  • Rechargeable battery operation
  • Play-, stop-, skip-, previous- button
  • Delay potentiometer 0s-60s
  • Volume potentiometer
  • Dog-friendly cotton cords
  • MMU Ready Designs

 

 

 

 

Management Summary

CanineQuest is a dog toy that challenges a dog's intelligence. Three different puzzle levels offer something for every dog. A sliding puzzle, a bayonet lock puzzle and a secured drawer puzzle.

A sound board is built in to break the dog's concentration and challenge it further. You can play your own sounds on it. The sounds can be delayed by up to one minute using the delay function. 
The volume is set using a rotary switch. The standard audio control buttons are installed.
 

The charge level and charge control of the built-in battery can be checked on the underside. To prevent the animal from reaching the battery, the charging socket is secured with a sliding plate.
 

To prevent damage to the surface on which it is played, the feet are fitted with felts.
 

The device is NOT intended for unsupervised play. Care has been taken to ensure that most of the parts are too large to swallow. However, rechargeable batteries are installed and these can harm animals, people and the environment if damaged. For this reason, CanineQuest should only be used when accompanied by a human.

 

Hardware and Software Used

Mechanical

Name
Quantity
M3 threaded insert34
M3 x 12mm pan-head screw8
M3 x 6mm pan-head screw 20
M3 x 25mm cylinder head screws4
M3 x 35mm cylinder head screws 4
20mm felt glides8 optional
cotton cord 5mm>6m

Electrical

Arduino Nano1
DFPlayer1
1kOhm resistor 1
Speaker - 3W 8Ω 1
Lithium battery shield for 2x 18650 1
18650 lithium-ion battery 2900mAh 2
10k Ohm rotary potentiometer2
Pushbutton IP67 stainless steel 16mm 2P 2
Pushbutton with RGB illumination 5V - stainless steel 4
KW1-103-7 Micro roller switch 1 optional
WAGO 221-413 1
WAGO 221-4151
Various strands of wire 
Solder 
Cable ties 

Tools

Name
3D printer with minimum 200mmx200mm buildplate
Soldering iron
Knife for cleaning edges
Allen key set
Side cutter
Wire stripper

Software

Name
Version
Arduino IDE1.8.19 was used for the development
PrusaSlicer 2.8.1 was used for the development
KiCadNot relevant for recreating, but used in prototyping
OnshapeNot relevant for recreating, but used in prototyping

 

Wiring Diagram

 

Code

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%CanineQuest%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%//
//Spring 2025
//https://www.printables.com/@BGDglider_2502284

//######################################################################//
//######################################################################//
///////////////////////////////////INIT///////////////////////////////////
//######################################################################//
//######################################################################//

/****************************** Libraries *******************************/
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

/*************************** Communication ******************************/
SoftwareSerial mySoftwareSerial(10, 11);  // RX, TX
DFRobotDFPlayerMini myDFPlayer;
int pause = 0;

/************************** Declare button ******************************/
const int playButton = 7;   // Play Button
const int stopButton = 2;   // Stop Button
const int nextButton = 4;   // Next Button
const int prevButton = 5;   // Previous Button

/****************************** RGB LED *********************************/
const int greenPin = 3;
const int redPin = 9;
const int bluePin = 6;

unsigned long ledTimer = 0;         // Timer for LED flashing intervals

const int ledStopInterval = 800;    // Interval in milliseconds for stop flashing
const int ledWaitInterval = 200;    // Interval in milliseconds for wait flashing
const int ledFaultInterval = 500;   // Interval in milliseconds for fault flashing

int ledState = 0;                   // Status LED: 0 = stopped, 1 = playing song, 2 = error

/*********************** Declare potentiometer **************************/
const int volumePin = A3;           // Potentiometer 1 for volume
const int timingPin = A1;           // Potentiometer 2 for song delay

int volumeValue = 0;
int timingValue = 0;

unsigned long previousMillis = 0;   // Start time of the timer
unsigned long delayTime;            // Variable for the delay (dynamically controlled)

/*************************** Declare debounce ***************************/
bool debounceButton(int buttonPin) {
  static unsigned long lastPressTimes[6] = {0}; // Array for several buttons
  const int debounceDelay = 200;    // Waiting time in milliseconds

  int buttonIndex = buttonPin - 2;  // If push-button pins start at 2 (2 = index 0, 3 = index 1, etc.)

  if (digitalRead(buttonPin) == LOW) { // Button pressed
    if (millis() - lastPressTimes[buttonIndex] > debounceDelay) { 
      lastPressTimes[buttonIndex] = millis();  
      return true;                  // Valid actuation
    }
  }
  return false;                     // No valid button press
}

//######################################################################//
//######################################################################//
///////////////////////////////////SETUP//////////////////////////////////
//######################################################################//
//######################################################################//

void setup() {
  // Serial communication with the module
  mySoftwareSerial.begin(9600);
  // Initialize Arduino serial
  Serial.begin(115200);

  /************************* Initialize button **************************/
  pinMode(playButton, INPUT_PULLUP);
  pinMode(stopButton, INPUT_PULLUP);
  pinMode(nextButton, INPUT_PULLUP);
  pinMode(prevButton, INPUT_PULLUP);

/*************************** Initialize LED *****************************/
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);

/********************** Initialize potentiometer ************************/
  pinMode(volumePin, INPUT);      // Pin for the volume potentiometer
  pinMode(timingPin, INPUT);      // Pin for the delay potentiometer

/************************** Audio Management *****************************/
  if (!myDFPlayer.begin(mySoftwareSerial)) {
    while (true)
      ;
  }

  myDFPlayer.setTimeOut(500);  // Serial timeout 500ms
  myDFPlayer.volume(10);        // Volume 10
  myDFPlayer.EQ(0);            // Normal equalization
  myDFPlayer.play(1);  // Spielt Song 1 beim Starten
  myDFPlayer.enableLoop();  // Aktiviert das Looping für den Song

/************************ LED Startup Pulse *****************************/
  for (int brightness = 0; brightness <= 255; brightness++) {  // Increase brightness from 0 to 255
    analogWrite(greenPin, brightness);
    delay(5);  // Smooth transition
  }
  
  for (int brightness = 255; brightness >= 0; brightness--) {  // Increase brightness from 255 to 0
    analogWrite(greenPin, brightness);
    delay(5);  // Smooth transition
  }
}

//######################################################################//
//######################################################################//
///////////////////////////////////LOOP///////////////////////////////////
//######################################################################//
//######################################################################//

void loop() {
  

/**************************** Potentiometer *****************************/
                                              // Adjust volume via potentiometer
  volumeValue = analogRead(volumePin);        // Read the value of the volume potentiometer

  int vol = map(volumeValue, 0, 1023, 0, 30); // Mapping to the 0-30 range (volume control)
  myDFPlayer.volume(vol);

/************************ Potentiometer und Timer ***********************/
 timingValue = analogRead(timingPin);         // Read the value of the timing potentiometer
 
  delayTime = map(timingValue, 0, 1023, 1000, 60000);  //Mapping: 1 second to 60 seconds

  if (millis() - previousMillis >= delayTime) {  
    previousMillis = millis();                // Reset timer

    if (myDFPlayer.readState() == 512) {      // When song finished
      myDFPlayer.start();                     // Repeat song
    }
  }

/********************************* LED **********************************/
  int16_t playerState = myDFPlayer.readState();  // Lesen des aktuellen Player-Status

  switch (playerState) {
    case 513:  // Song spielt
      digitalWrite(redPin, LOW);
      digitalWrite(greenPin, LOW);
      digitalWrite(bluePin, HIGH);
      break;
  
    case 512:           // Delay active
      if (millis() - ledTimer > ledWaitInterval) {
        ledTimer = millis();
        digitalWrite(bluePin, !digitalRead(bluePin));
      }
      break;

    case 514:         // Song stopped
      if (millis() - ledTimer > ledStopInterval) {
        ledTimer = millis();
        digitalWrite(bluePin, !digitalRead(bluePin));
      }
      break;

    case 0:             // Error state
      if (millis() - ledTimer > ledFaultInterval) {
        ledTimer = millis();
        digitalWrite(redPin, !digitalRead(redPin));
      }
      break;

    default:
      digitalWrite(redPin, LOW);
      digitalWrite(greenPin, LOW);
      digitalWrite(bluePin, LOW);
      break;
  }
 
/***************************** Status button ****************************/
bool playPressed = debounceButton(playButton);
bool stopPressed = debounceButton(stopButton);
bool nextPressed = debounceButton(nextButton);
bool prevPressed = debounceButton(prevButton);

/******************************* STOP ***********************************/
    if (stopPressed) {
      myDFPlayer.stop();
    }

/*************************** PAUSE-CONTINUE *****************************/
    if (playPressed) {
      pause = !pause;
      if (pause == 0) {
        myDFPlayer.start();
      }
      if (pause == 1) {
        myDFPlayer.pause();
      }
    }

/*************************** Previous ***********************************/
    if (prevPressed) {
      myDFPlayer.previous();
    }

/********************************* Next *********************************/
    if (nextPressed) {
      myDFPlayer.next();
    }
}

 

Printing Instructions

Sliding Pivot

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimNo
Quantity1
MMUThere are two versions. One without logo and one with logo, the logo can be colored.
Print OrientationStanding Normal

Bayonet lever

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsYes
BrimNo
Quantity2
MMUNo
Print OrientationUpside down

Base

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsYes (Everywhere)
BrimYes
Quantity1
MMUNo
Print OrientationStanding Normal

Middle

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsYes (Everywhere)
BrimYes
Quantity1
MMUNo
Print OrientationStanding Normal

Top

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsYes (Everywhere)
BrimYes
Quantity1
MMUOperating aids and the logo are embedded in the top and can be colored as desired.
Print OrientationUpside down

Speaker cover

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimNo
Quantity1
MMUThe logo is embedded in the speaker cover and can be colored as desired.
Print OrientationUpside down

Push-button panel

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimYes
Quantity1
MMUNo
Print OrientationIf textured sheet metal, on visible side, otherwise inside

Potentiometer panel

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimYes
Quantity1
MMUNo
Print OrientationIf textured sheet metal, on visible side, otherwise inside

Potentiometer knob

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimNo
Quantity2
MMUA line is embedded in the potentiometer knob. This can be colored.
Print OrientationStanding

Charging socket Cover

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimNo
Quantity1
MMUA battery drawing is embedded. This can be colored.
Print OrientationOutside top

Drawer

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsYes (Everywhere)
BrimNo
Quantity1
MMUNo
Print OrientationStanding Normal

Drawer Front

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimYes
Quantity1
MMUNo
Print OrientationOn visible side

Drawer Pin

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimNo
Quantity1
MMUNo
Print OrientationStanding Normal

PCB-Holder Nano

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimNo
Quantity1
MMUNo
Print OrientationProne Normal

PCB-Holder DFPlayer

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimNo
Quantity1
MMUNo
Print OrientationProne Normal

Feet

Material  PLA
Nozzle0.40mm
Layer Height0.10mm
Infill15%
SupportsNo
BrimNo
Quantity8
MMUNo
Print OrientationStanding Normal

 

Assembly Instructions

Base

Start with the base, it needs 14 threaded inserts. 4 for the battery mounting, 4 for the speaker mounting, 2 for the circuit board aids (optional) and 2 each for the front mounting of the switch plate and potentiometer plate.

It requires 8 inserts on the underside to attach the felt feet.

The two WAGOs are glued in the middle. The 5 will be the - terminal block and the 3 will be the + terminal block.

Marriage of electrics and chassis

I recommend testing the electrical setup on a breadboard beforehand. The buttons and potentiometers are inserted into the planned potentiometer panel and push-button panel. The PCB-holder aids can be used to hold the PCB in place if necessary. Fix the PCB with hot glue if necessary. Here it pays to use wires that are not too thick (0.75 mm2 is the maximum ;-) ) and to plan some reserve. In this configuration, the electrics can be tested in the devinitive position before the device is closed.

Two potentiometer knobs can be plugged onto the potentiometers. The potentiometer knobs can be colored with MMU so that a line indicates the position.

Middle

4 threaded inserts are used here.

Drawer

The drawer and drawer front are glued here.

A cord is threaded through the drawer holes and tied at the front. A plait is then knotted according to taste. A diamond knot with 2 cords was knotted here.

Build middle section on base

It is important to install the following parts before connecting the base and the middle: 

Install the whole electrical setup minus potentiometer panel and push-button panel in the base

Insert the charging socket cover into the guide in the base

Insert the drawer into the drawer recess in the middle

Leave the wires labeled looking out of the corresponding openings so that the button plate and the potentiometer plate can be easily connected after the middle and base have been mounted.

Up to this point, a USB cable can also be connected to the nano so that code adjustments can still be made.

Fitting the feet (optional)

8 feet are attached to the base with M3 x 12mm pan-head screws.

Then glue on the felts.

Other individual parts

A cord was also passed through the drawer pin and tied to the front. A diamond knot pattern was also knotted here with a second cord.

Cotton cord is also glued onto the bayonet lever. This means that any bites are not made directly into the PLA, but are cushioned in the cotton. The sliding pivot should now also be ready to be installed straight away.

The speaker cover is installed in the next step. If an MMU is available, the part can be colored accordingly.

Prepare the top

With MMU function the CanineQuest logo and the operating pictograms can be colored.

4 threaded inserts are used here. Further 2 each for the front mounting of the switch plate and potentiometer plate.

Now the speaker cover can be glued to the top.

Mount the top on the middle

Sliding pivot must be placed on the middle here, after which it can no longer be inserted.

The top can now be placed on the middle and screwed down from below via the last holes using M3 x 35mm cylinder head screws.

Done !

Demo and Usage Instructions

Before the dog can solve the puzzles, the trainer must use the Play, Stop, Next, Previous buttons to select the sound that is to distract the dog. In addition, an appropriate volume should be set using the volume control. Then set the delay between 0-60 seconds with the Delay control. If the puzzle has been prepared with food, it is now ready to be presented to the dog.
While the dog is trying to solve the three puzzle levels, the sound can be changed and the delay and volume can be adjusted.
Repeat until the desired training result has been achieved :).

LED

The built-in LED indicates the status of the CanineQuest.

Green Startup
Blue Plays audio
Flashing blue 800msAudio stopped
Flashing blue 200msIn the delay before new audio is played
Flashing Red 500msMalfunction

 

Charging CanineQuest

 

 

 

 

 

 

 

 

Open the charging cover

 

 

 

 

 

 

 

 

Either charging via micro usb or usb c

 

 

 

 

 

 

 

 

 

The charge status of the CanineQuest can be read on the underside. The 5 charge status LEDs can be seen through the clear PLA.

Prepare audio files

The SD card must be empty. The desired audio files are then saved on it. The files must be labeled as follows: 001, 002, 003, 004, 005, 006 and so on.

Further information can be found in the DFPlayer manual.

Troubleshooting

If the LED flashes red, an error has been detected.

-Is the SD card inserted and formatted correctly?

-Is the DFPlayer correctly connected to the Nano?

Idea

Our dog was disturbed by a very specific bird call. The goal of this project was to desensitize him to that sound in a naturally playful way.

Prototype

I used the following PLA in my prototype:

  • Buddy3D PLA White
  • 3djake ecoPLA Wood Dark Brown
  • 3djake ecoPLA Black
  • 3djake ecoPLA light blue

 

Tags



Awarded in the contest


2
Smart Pet Gadgets with Arduino
145 entries | February 27 – April 27, 2025

Model origin

The author marked this model as their own original creation.

License