Newbie creating a talking cat button box

Hello everyone!

I am about a month into using my arduino uno and have an ambitious goal in mind that I want to take on. It will basically be a button box that allows my cats to communicate with me, much like the buttons many people have trained their dogs and cats with on many social media groups. I want to take it further though with a few new features.

  1. When a button is pressed that button lights up the contained LED for about a second ( easy, can do that already )
  2. When a button is pressed it prints a set word to the liquidcrystal display ( easy, can do that already ) BUT I want it to store combinations of button presses, which I am lost on. So if my cat hits the "want" button and the "treat" button the display will first display "want" then shift that over and display "want treat"
  3. When a button is pressed a pre-recorded mp3 of my voice saying "treat" or "want" etc will play over a speaker. I plan on using a serial to MP3 player with a pair of cheap powered speakers. Seems straight forward enough.
  4. Now this is where it will get fairly complex and I have 0 idea what i'm doing. I'd like to use an esp32 to communicate with my phone via bluetooth so that I can A: look at what my cats have said while I have been gone and B: send messages to the ESP32 so that it plays back to the cats.

For the 4th feature the idea in my head is my cat pushes the buttons and says, "want treat" which I can view on my phone as well. Then to talk back to them I can send "no treat" and it will play the mp3s AND blink each led switch at the same time.

NOW, with all that out of the way, I am in no way looking for a handout of code and to have everyone do this project for me. I am merely looking for suggestions on books, videos, lessons that I can examine and practice that will eventually teach me how to do all this on my own.

I will likely start small, only having the button box flash lights and play the mp3s. That is doable. Then I will ( I assume ) use the EEPROM to store what the cats have said which will display on a liquid crystal display, maybe figuring out with some additional buttons how to scroll through what they have said. Then lastly I will figure out the bluetooth communication idea.

I appreciate all your input and help. Thank you.

That is a LONG way from starting small. Start with only one button switch and learn to program to recognize it being pressed and being released.

  • Suggest you forget about two button combinations.
    Just have a Treat button, a Belly Scratch button, a Catnip button etc.
    When a button is pressed, make a unique sound with maybe LED effects.

  • If the cat masters the above, then and only then proceed with more complex stuff.

1 Like

I recommend a DFplayer Mini module. Very easy to use. Takes a micro-SD card on which you can record your words as MP3 files. Can drive a small speaker directly.

Do you have a video or article that can recommend that explains how to do this?

This also allows you to display debug messages if the serial to the host PC is busy or not available.

Thanks everyone for the input and help. Already have parts on order.

I realize I haven't been super clear on my current skill level.

Using tinkercad I've already built a basic model that prints to a liquid crystal display, blinks an led when the button is pressed etc.

Where im having trouble is having words combined when pressed.

I will look up how to keep text in a character array. Will this be a viable option for storage for the later goal of bluetooth communication to a phone or will I need to learn how to store data in the eeprom?

Thanks again everyone!

Alrighty everyone! Here is my code so far which only prints to the LCD using a char array and lights an led.

I will begin adding the MP3 functionality soon. I am recording my voice later today so I have all the files I need.

I also just ordered an ESP32 so I can use bluetooth to control the board via the RemoteXY app using bluetooth. It seems to be a really simple way to add some simple controls and modifying the code to adapt to my application shouldn't be too hard.

The code is pasted below. Any issues anyone sees or ways I can improve the code would be awesome! I appreciate all your help so far.

#include <Adafruit_LiquidCrystal.h>

//setting up display?
Adafruit_LiquidCrystal lcd_1(0);

//here are all the controls for the LCD
// lcd_1.setCursor(0, 1);
//lcd_1.print( WHATEVER );
//lcd_1.setBacklight(1);
//lcd_1.setBacklight(0)
//lcd_1.begin(16, 2);

//array for holding strings for the screen
char screenLine1 [16];
char screenLine2 [16];
//arrays for the various words
char food [] = "food";
char treat [] = "treat";
char water [] = "water";
char play [] = "play";
char cuddle [] = "cuddle";
char yes [] = "yes";
char no [] = "no";
char want [] = "want";
char later [] = "later";
char now [] = "now";
//CHAR ARRAY INSTRUCTIONS
//

//setup different buttons
const int button1 = 2;
const int button2 = 3;
const int button3 = 4;
const int button4 = 5;
const int button5 = 6;


//setup different leds
const int led1 = 7;
const int led2 = 8;
const int led3 = 9;
const int led4 = 10;
const int led5 = 11;

//setup button states
int buttonState1 = 0;
int buttonState2 = 0;
int buttonState3 = 0;
int buttonState4 = 0;
int buttonState5 = 0;

void setup()
{
  
  
 //welcome screen
  lcd_1.setBacklight(1);
  delay(500);
  lcd_1.begin(16, 2);
  lcd_1.print("  Lets talk to");
  lcd_1.setCursor(0, 1);
  lcd_1.print("   the cats!");
  delay(1000);
  lcd_1.clear();
  lcd_1.setBacklight(0);
  
 //setup inputs
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(button3, INPUT_PULLUP);
  pinMode(button4, INPUT_PULLUP);
  pinMode(button5, INPUT_PULLUP);
  
 //setup outputs
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(led5, OUTPUT);
  
  
}

void loop()
{
  lcd_1.begin(16, 2);
  lcd_1.print(screenLine1);
  lcd_1.setCursor(0, 1);
  lcd_1.print(screenLine2);
  
  //setup button states
  buttonState1 = digitalRead(button1);
  buttonState2 = digitalRead(button2);
  buttonState3 = digitalRead(button3);
  buttonState4 = digitalRead(button4);
  buttonState5 = digitalRead(button5);
  
//Setting Up Button 1 ( WANT )//
 if (buttonState1 == LOW) 
 {
    // turn LED on:
    digitalWrite(led1, HIGH);
   strncpy (screenLine1, screenLine2, 16);
   delay(50);
   strncpy (screenLine2, want, 16);
  } 
  else {
    // turn LED off:
    digitalWrite(led1, LOW);
    }
/////////////////////////////////  
//Setting Up Button 2 ( NO )//
 if (buttonState2 == LOW) 
 {
    // turn LED on:
    digitalWrite(led2, HIGH);
   strncpy (screenLine1, screenLine2, 16);
   delay(50);
   strncpy (screenLine2, no, 16);
  } 
  else {
    // turn LED off:
    digitalWrite(led2, LOW);
    }
/////////////////////////////////  
//Setting Up Button 3 ( YES )//
 if (buttonState3 == LOW) 
 {
    // turn LED on:
    digitalWrite(led3, HIGH);
   strncpy (screenLine1, screenLine2, 16);
   delay(50);
   strncpy (screenLine2, yes, 16);
  } 
  else {
    // turn LED off:
    digitalWrite(led3, LOW);
    }
/////////////////////////////////  
//Setting Up Button 4 ( WATER )//
 if (buttonState4 == LOW) 
 {
    // turn LED on:
    digitalWrite(led4, HIGH);
   strncpy (screenLine1, screenLine2, 16);
   delay(50);
   strncpy (screenLine2, water, 16);
  } 
  else {
    // turn LED off:
    digitalWrite(led4, LOW);
    }
/////////////////////////////////
//Setting Up Button 5 ( TREAT )//
 if (buttonState5 == LOW) 
 {
    // turn LED on:
    digitalWrite(led5, HIGH);
   strncpy (screenLine1, screenLine2, 16);
   delay(50);
   strncpy (screenLine2, treat, 16);
  } 
  else {
    // turn LED off:
    digitalWrite(led5, LOW);
    }
/////////////////////////////////
  
  
}

I had a feeling that I was being very repetitive and that this could all be condensed somehow. Thanks!

I spent the day studying arrays and WOW what a huge chunk of code i've erased. Its amazing.

Now, the issue i'm running into is the LED's won't continue to stay lit when I press them, they merely blip for a second. Also the serial bus is printing when the button is pressed, then again when the button is released. Here is the code. I'm sure its a simple mistake.


// Setting up each button input pin
                 //index = 0, 1, 2, 3, 4
const int buttonPin [5] = {2, 3, 4, 5, 6}; 

 // Setting up each led output pin
const int ledPin [5] = {7, 8, 9, 10, 11};

// Setting up each button state ( 5 total for the 5 buttons)
int buttonState [5] = {0, 0, 0, 0, 0};
int lastButtonState [5] = {0, 0, 0, 0, 0};

//setting up the array of words
char words[5][6] = {
{"want"}, {"no"}, {"yes"}, {"water"}, {"treat"}
};


void setup() {

  //Setting the ledPin array as a set of outputs
 for (int i = 0; i < 5; i++) {
 pinMode(ledPin[i], OUTPUT); 
 }
  // initialize the pushbutton pins as an input:
 for (int i = 0; i < 5; i++) {
  pinMode(buttonPin[i], INPUT_PULLUP);
 }
//serial communication has BEGUN! BEAM THE MOTHERSHIP!
 Serial.begin(9600);
}


void loop() {
  // read the state of the pushbutton value:
  for (int i = 0; i < 5; i++) {
  buttonState[i] = digitalRead(buttonPin[i]);
  }

  // Button Code
  //Setting up button state to check for state change
  //ERROR. Only flashes LED quickly instead of holding it
  for (int i = 0; i < 5; i++){
    if (buttonState[i] != lastButtonState[i]) { 
    if (buttonState[i] == LOW)
    // turn LED on:
    digitalWrite(ledPin[i], HIGH);
    Serial.println(words[i]);
   
  } else {
    // turn LED off:
    digitalWrite(ledPin[i], LOW);
  }
  delay(50);
  lastButtonState[i] = buttonState[i];
  }
  

}

   


Hello aaronfidelisrecine

Welcome to the best Arduino Forum ever.

Please see below the modification of your sketch.

// Setting up each button input pin
//index = 0, 1, 2, 3, 4
const int buttonPin [5] = {2, 3, 4, 5, 6};
// Setting up each led output pin
const int ledPin [5] = {7, 8, 9, 10, 11};
// Setting up each button state ( 5 total for the 5 buttons)
int buttonState [5] = {0, 0, 0, 0, 0};
int lastButtonState [5] = {0, 0, 0, 0, 0};
//setting up the array of words
char words[5][6] = {
  {"want"}, {"no"}, {"yes"}, {"water"}, {"treat"}
};
void setup() {
  //Setting the ledPin array as a set of outputs
  for (int i = 0; i < 5; i++) {
    pinMode(ledPin[i], OUTPUT);
  }
  // initialize the pushbutton pins as an input:
  for (int i = 0; i < 5; i++) {
    pinMode(buttonPin[i], INPUT_PULLUP);
  }
  //serial communication has BEGUN! BEAM THE MOTHERSHIP!
  Serial.begin(9600);
}
void loop()
{
  // read the state of the pushbutton value:
  for (int i = 0; i < 5; i++) {
    buttonState[i] = digitalRead(buttonPin[i]);
  }
  // Button Code
  //Setting up button state to check for state change
  //ERROR. Only flashes LED quickly instead of holding it
  for (int i = 0; i < 5; i++)
  {
    if (buttonState[i] != lastButtonState[i])
    {
      if (buttonState[i] == LOW)
      {
        // toogle LED
        digitalWrite(ledPin[i], digitalRead(ledPin[i]) ? LOW : HIGH);
        Serial.println(words[i]);
      }
    }
    else
    {
      // turn LED off:
      //      digitalWrite(ledPin[i], LOW);
    }
    delay(50);
    lastButtonState[i] = buttonState[i];
  }
}

hth

Thank you everyone! I found that it indeed was the placement of my braces that was the issue and I had no idea about the auto format tool! WHAT an amazing feature!

Thank you paulpaulson for the rewrite, thats a slick way to condense everything down.

I have begun the physical prototyping phase with a cheap basket flipped upside down and drilled out for the buttons.

Currently researching the DFplayer Mini module. It looks like the easiest way to program for it is to connect a set of data pins from the ESP32 to the DFplayer and call for each track using the command 0x03(NUM) with an array.

I will also have to figure out how to set certain pins on the ESP32 as data pins, but from what i'm reading online it seems to be pretty straight forward.

Looks great, and I just emailed Pez to tell them they should make Pez dispenser compatible cat treats. I'm seeing the dispenser in your picture - how cool would it be if the cat pressed a button and a servo activated the Pez dispenser?

Hahahah im pretty sure if I built it my cats would break their paws button mashing until they popped from eating treats :joy:

1 Like

I’m totally new to this so I unfortunately am no help with the code, however, I might recommend skipping the yes button as it is quite a complex response. Instead of asking the cat “Do you want a treat” and expecting a “yes” or “no” response I would recommend using open ended questions and having them respond with their request ie. “treats”, “food”, “cuddles”, “water”, etc.

I came across your post while searching for something similar. I am hoping to make a cat speech midi board that when the button is pressed will say the word out loud using a speaker. Where mine differs is the use of a digital display. Instead, I am more interested in having it log all button presses so I can track how frequently and at what times the buttons are pressed in a spreadsheet. Eventually as a long-term goal it would be awesome to integrate an RFID reader that could identify which cat pressed the button by reading their microchip. This technology is already in use in some automated pet doors and pet feeders.

ALRIGHTY. Here is where I am at now.

I have been running individual code in different sketches to understand the concepts and now is the time to migrate over the various experiments. I have now learned how to 1. establish Bluetooth communication from the ESP32 to my Android and monitor the serial bus on my phone. 2. Establish a wifi connection to my router and print the current time 3. Store integers in the EEPROM and print the data from the EEPROM to the serial monitor.

I have a strange problem though when trying to bring the EEPROM code over to the cat button master code.

When pressing two button sequentially the code stops working.

So I will hit treat, it will write the words array index to the EEPROM ( instead of using a string and taking up more space ) and then it reads that same EEPROM address and writes it to an int variable named eepromWord. Then it prints the current eepromWord to the serial bus.

I have a feeling I am using the EEPROM incorrectly, but don't know where my error is. My code is below. Thanks everyone for your help.

#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include <EEPROM.h>

// Use pins 17 and 16 to communicate with DFPlayer Mini
static const uint8_t PIN_MP3_TX = 17;  // Connects to module's RX
static const uint8_t PIN_MP3_RX = 16;  // Connects to module's TX
SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

// Create the Player object
DFRobotDFPlayerMini player;

//sets up the index for the current word to be stored to the eeprom
int eepromWord = 0;

// Setting up each button input pin
const int buttonPin[5] = { 23, 22, 21, 19, 18 };

// Setting up each led output pin
const int ledPin[5] = { 34, 35, 32, 33, 25 };

// Setting up each button state ( 5 total for the 5 buttons)
int buttonState[5] = { 0, 0, 0, 0, 0 };
int lastButtonState[5] = { 0, 0, 0, 0, 0 };

//setting up the array of words
char words[5][6] = {
  { "want" }, { "no" }, { "yes" }, { "later" }, { "treat" }
};

//setting up the mp3 array
const int mp3Song[5] = { 3, 2, 1, 4, 7 };


void setup() {
  EEPROM.begin(20);
  // Start communication with DFPlayer Mini
  if (player.begin(softwareSerial)) {
    Serial.println("OK");

    // Set volume to maximum (0 to 30).
    player.volume(30);
    // Play the first MP3 file on the SD card

  } else {
    Serial.println("Connecting to DFPlayer Mini failed!");
  }

  //Setting the ledPin array as a set of outputs
  for (int i = 0; i < 5; i++) {
    pinMode(ledPin[i], OUTPUT);
  }
  // initialize the pushbutton pins as an input:
  for (int i = 0; i < 5; i++) {
    pinMode(buttonPin[i], INPUT_PULLUP);
  }
  //serial communication has BEGUN! BEAM THE MOTHERSHIP!
  Serial.begin(9600);
  //
  softwareSerial.begin(9600);
}


void loop() {
  // read the state of the pushbutton value:
  for (int i = 0; i < 5; i++) {
    buttonState[i] = digitalRead(buttonPin[i]);
  }

  // Button Code
  //Setting up button state to check for state change
  for (int i = 0; i < 5; i++) {
    if (buttonState[i] != lastButtonState[i]) {
      if (buttonState[i] == LOW) {
        // turn LED on:
        digitalWrite(ledPin[i], HIGH);
        player.play(mp3Song[i]);
        EEPROM.write(i, i);
        EEPROM.commit();
        eepromWord = EEPROM.read(i);
        Serial.println(words[eepromWord]);
      } else {
        // turn LED off:
        digitalWrite(ledPin[i], LOW);
      }
      delay(50);
      lastButtonState[i] = buttonState[i];
    }
  }
}

The idea is to have a continuous log saved showing the date and time stored everytime it runs. Maybe a sd card to a text file would be a better method.

I want to be able to look at trends and data log my cats behaviors to look for short and long term patterns indefinitely without ever losing the data.

So ideally it would look like
TREAT pressed on 7/13/23 @ 7:36AM

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.