Cats kept at home can often be left alone for extended periods of time due to our busy schedules, which can lead to them feeling lonely, anxious, and lacking in both physical and mental stimulation. To address this, we are considering designing an automatic cat teaser to provide entertainment and companionship for our feline friend while we’re away. This device would mimic human interaction by moving a laser to attract the cat’s attention, prompting it to engage in physical activities that simulate hunting instincts. Our goal is to ensure our cat remains active, healthy, and mentally stimulated, even when we are unable to be present. By creating a happier and more engaging home environment, we can help our cat thrive amidst our hectic lifestyles.
Bill of MaterialsHardware- Xiao ESP32C3
- Grove Vision AI V2
- Laser Module
- Multi-function expansion board based on XIAO
- Servo*2
- Servo mount
- Arduino IDE
- Fusion 360
- SenseCraft
- 3D printer
- Soldering iron
Seeed Studio XIAO ESP32C3 is an IoT mini development board based on the Espressif ESP32-C3 WiFi/Bluetooth dual-mode chip. ESP32-C3 is a 32-bit RISC-V CPU, which includes an FPU (Floating Point Unit) for 32-bit single-precision arithmetic with powerful computing power. It has excellent radio frequency performance, supporting IEEE 802.11 b/g/n WiFi, and Bluetooth 5 (LE) protocols. This board comes included with an external antenna to increase the signal strength for your wireless applications. It also has a small and exquisite form-factor combined with a single-sided surface-mountable design. It is equipped with rich interfaces and has 11 digital I/O that can be used as PWM pins and 4 analog I/O that can be used as ADC pins. It supports four serial interfaces such as UART, I2C and SPI. There is also a small reset button and a bootloader mode button on the board. XIAO ESP32C3 is fully compatible with the Grove Shield for Seeeduino XIAO and Seeeduino XIAO Expansion board except for the Seeeduino XIAO Expansion board, the SWD spring contacts on the board will not be compatible.
With regard to the features highlighted above, XIAO ESP32C3 is positioned as a high-performance, low-power, cost-effective IoT mini development board, suitable for low-power IoT applications and wireless wearable applications.
Grove Vision AI V2 overviewIt is an MCU-based vision AI module powered by Arm Cortex-M55 & Ethos-U55. It supports TensorFlow and PyTorch frameworks and is compatible with Arduino IDE. With the SenseCraft AI algorithm platform, trained ML models can be deployed to the sensor without the need for coding. It features a standard CSI interface, an onboard digital microphone and an SD card slot, making it highly suitable for various embedded AI vision projects.
Below is a block diagram of the Grove Vision AI (V2) system, including the camera and the main controller.
With various interfaces like IIC, UART, SPI, and Type-C, this board has expansive capabilities and can be easily connected to popular products such as Seeed Studio XIAO, Grove, Raspberry Pi, beagleboard and ESP-based products for further development. For instance, integrating Grove Vision AI V2 with XIAO can effortlessly access the interface and data of Grove Vision AI V2 through Arduino, Micropython, CircuitPython, and PlatformIO, and conveniently connect to the cloud or dedicated servers like Home Assistance.
Connecting to a CSI interface cameraOnce you have the Grove Vision AI V2 and camera ready to go, then you can connect them via the CSI connection cable. When connecting, please pay attention to the direction of the row of pins and don't plug them in backwards.
2. SenseCraft Web Toolkit
The SenseCraft Web Toolkit is a visual model deployment tool included in SSCMA (Seeed SenseCraft Model Assistant). The tool allows you to easily deploy models to a variety of platforms with simple operations. The tool provides a user-friendly interface and does not require any coding.
Follow the steps below to launch SenseCraft-Web-Toolkit:
- Open the SenseCraft-Web-Toolkit website.https://seeed-studio.github.io/SenseCraft-Web-Toolkit/#/setup/process
- Please use a Type-C type cable to connect Grove Vision AI V2 to your computer,then select the "Grove Vision AI V2" click the "connect".
- In the new window that pops up, select the correct COM port for the device and click the Connect button.
- Select the Pet Detection model, which recognises and distinguishes between dogs and cats. Then click Send.
- Step 1. Download and Install the latest version of Arduino IDE according to your operating system
- Step 2. Launch the Arduino application
- Step 3. Add ESP32 board package to your Arduino IDE
Navigate to File > Preferences, and fill "Additional Boards Manager URLs" with the url below: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Navigate to Tools > Board > Boards Manager..., type the keyword "esp32" in the search box, select the latest version of esp32, and install it.
- Step 4. Select your board and port
Board
Navigate to Tools > Board > ESP32 Arduino and select "XIAO_ESP32C3". The list of board is a little long and you need to roll to the buttom to reach it.
Port
Navigate to Tools > Port and select the serial port name of the connected XIAO ESP32C3. This is likely to be COM3 or higher (COM1 and COM2 are usually reserved for hardware serial ports).
- Step 5. Arduino SSMA library installation
Dowload the Arduino SSMA library as.zip file from Github
Since you have downloaded the zip Library, open your Arduino IDE, click on Sketch > Include Library > Add.ZIP Library. Choose the zip file you just downloaded,and if the library install correct, you will see Library added to your libraries in the notice window. Which means the library is installed successfully.
Go to the Sketch Project menu and select Include Libraries > Manage Libraries.... This will open the Library Manager. In the search bar at the top of the Library Manager, type ArduinoJSON. the search results will list the ArduinoJSON library. There will be an Install button next to the library. Click the Install button and the Arduino IDE will automatically download and install the library into your Arduino development environment.
You will also need a library to drive the servo, type ESP32Sever in the search bar at the top of the library manager, select the corresponding library and click the "Install" button, the Arduino IDE will automatically download and install the library into your Arduino development environment.
Now that software setup is completed, it's time to move on to the production project !
Servo Mount Installation
Firstly, locate and mark the camera and laser on the servo, and after drilling the holes, mount the camera, laser and servos on top of the servo mount.
Ps: It is recommended that you first refer to Sketch 1 to set the servos all the way to 90 degrees before installation to prevent damage to the servos or servo mount in subsequent operations.
Sketch 1
#include <ESP32Servo.h>
#define SERVO_X_PIN D6
#define SERVO_Y_PIN D7
Servo myservo1;
Servo myservo2;
void setup() {
Serial.begin(115200);
myservo1.attach(SERVO_X_PIN );
myservo2.attach(SERVO_Y_PIN );
}
void loop() {
myservo1.write(90);
myservo2.write(90);
delay(30);
}
WiringThe Grove Vision AI V2 is simply connected to the IIC interface of the XIAO through the Grove interface.
The wiring of other devices shows as below
As a result of the current lightweight servo mount, the mountmoves unstably when the servo operates. To address this issue, we can enhance the stability of the device by affixing it to a plastic or wooden board, or utilizing 3D printed parts to increase the counterweight. This modification will ensure that the entire system remains stable, even when the servo is in operation.
This project, at the beginning of the project, was intended to operate the cat teaser on a desktop, so I created a simple box appearance
However, after practical testing, it was found that placing the cat teaser on the wall could yield even better results, so some changes were made to its appearance. But I haven't printted it out yet...
This project is developed using Arduino IDE, the logic of the code is :
1. Activate the cat teaser when a cat passes by the camera
2. Move the laser to a random place, then detect if the cat follows the laser point (re-entering the camera range) and swing it slightly to attract the cat.
3. If the cat is detected to follow the laser point, then the laser will be moved to the next point.
4. If the cat play a certain number of times, the device will enter sleep mode, and wait for a certain period of time to wake up.
Sketch 2
#include <ESP32Servo.h>
#include <Seeed_Arduino_SSCMA.h>
// define the pin which conect to servo
#define SERVO_X_PIN D6 // control the angle of x axis
#define SERVO_Y_PIN D7 // control the angle of y axis
// define the laser pin
#define Laser_Pin 8
// define the x and y limition
#define X_MIN 0
#define X_MAX 240
#define Y_MIN 0
#define Y_MAX 240
#define Central_coor_X 120;
#define Central_coor_Y 120;
// define PID parameter
#define kp 0.1
#define ki 0.001
#define kd 0
// set the sleep time to one hour
#define uS_TO_S_FACTOR 1000000ULL
#define TIME_TO_SLEEP 60*60
RTC_DATA_ATTR int bootCount = 0;
// creat Servo object
Servo servoX;
Servo servoY;
SSCMA AI;
// Create initial angle, centre angle, adjust according to reality
const float C_angle_x = 90;
const float C_angle_y = 60;
float Last_angle_x = C_angle_x;
float Last_angle_y = C_angle_y;
int errror = 2;
int speed = 50;
/*
Print the reason of wakeup
*/
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
}
}
void sleep_in_loop(){
delay(100);
Serial.println("wake");
Serial.println("Going to sleep now");
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
Serial.flush();
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
// 停止转动
void stop_rotate(void) {
digitalWrite(D6, HIGH);
delayMicroseconds(1500);
digitalWrite(D6, LOW);
}
/*
Brief:
Detedt the cat
Collect the imge info three times, if the the average score is over 60 that means there is a cat
In the image
input:
return:
Return Ture -- there is a cat in the image
Return False -- did not find a cat yet
*/
bool check_cat(){
Serial.println("checking ");
int total_score = 0;
float average_score;
int c_n;
int j = 0;
while( j < 3 ){
if(!AI.invoke()) {
if (AI.boxes().size() > 0){
for (int i = 0; i < AI.boxes().size(); i++){
// if only want to detect the cat use if(AI.boxes()[i].target == 0)
if(AI.boxes()[i].target == 0 || AI.boxes()[i].target == 1){
c_n = i;
total_score += int(AI.boxes()[i].score);
}
}
}
j++;
}
}
// you can tune total_score/3The contrast value to better identify cats/dogs.
if(total_score/3 > 60){
Serial.println(total_score/3);
return true;
}else{
return false;
}
}
/*
Brief:
Attract cat
shaking to attract the cat while detecting if the cat is in the camera
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Attach : Whether to attract or not, 0 is required to attract.
*/
void attact_cat(int angleX, int angleY, int Attact){
int d = 1;
int n = random(1, 5); //ramdom pick a number from 1~5
//Increases as the y-axis angle becomes smaller
float vibrate = map(angleY,100,35,5,10);
if(Attach == 0){
switch (n) {
case 1:
for(int i = 0; i < 6; i++){
servoX.write(angleX + vibrate);
vibrate = -vibrate;
delay(100);
}
break;
case 2:
for(int i = 0; i < 6; i++){
servoY.write(angleY + vibrate);
vibrate = -vibrate;
delay(100);
}
break;
case 3:
delay(100);
break;
case 4:
delay(100);
break;
}
}
delay(100);
}
/*
Brief:
Move laser/camera to specified angle
Input:
angleX : current x-axis angle
angleY : current y-axis angle
target_x : target x-axis angle
target_y : target y-axis angle
Return value:
No return value
*/
void go_to_target(int angleX, int angleY, int target_x, int target_y){
int offet_set_X = target_x - angleX;
int offet_set_Y = target_y - angleY;
float deltaDergeeX = offet_set_X * kp;
float deltaDergeeY = offet_set_Y * kp;
for(int i = 0; i < 10; i++){
float angleX = Last_angle_x + deltaDergeeX;
float angleY = Last_angle_y + deltaDergeeY;
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
brief:
Move laser/camera to centre
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Return value:
No return value
*/
void back_to_centrel(int angleX, int angleY){
int offet_set_X = C_angle_x - angleX;
int offet_set_Y = C_angle_y - angleY;
float deltaDergeeX = offet_set_X * kp;
float deltaDergeeY = offet_set_Y * kp;
for(int i = 0; i < 10; i++){
float angleX = Last_angle_x + deltaDergeeX;
float angleY = Last_angle_y + deltaDergeeY;
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
brief
Moving laser folding motion in x axis
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Return value:
No return value
*/
void forward_back_X(int angleX, int angleY) {
int total_dergee = 4;
int n = 0;
int Attach = 0;
for (int i = 0; i < total_dergee; i++) {
while(!check_cat()){
attact_cat(Last_angle_x,Last_angle_y, Attach);
n++;
if(n > 20){
digitalWrite(Laser_Pin, LOW);
Attach = 1;
}
}
n = 0;
Attach = 0;
if (i < total_dergee / 4) {
angleX = 120;
} else if (i < total_dergee / 2) {
angleX = 60;
} else if (i < total_dergee / 4 * 3) {
angleX = 120;
} else {
angleX = 60;
}
angleY = 60;
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
brief
Move the laser along the Y-axis folding line movement, can be modified according to the following code to do real curved movement:
void Laser_Curve_X(int angleX, int angleY) {
int total_dergee = 4*12;
const int remember_x = angleX;
const int remember_y = angleY;
for (int i = 0; i < total_dergee; i++) {
// Serial.println(i);
if (i < total_dergee / 4) {
angleX += 3;
} else if (i < total_dergee / 2) {
angleX -= 3 ;
} else if (i < total_dergee / 4 * 3) {
angleX += 3;
} else {
angleX -= 3;
}
angleY += 3;
if(angleX >= 150 || angleY >= 150 ){
i = total_dergee;
break;
}
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(50);
}
angleX = remember_x;
angleY = remember_y;
Last_angle_x = angleX;
Last_angle_y = angleY;
servoX.write(remember_x);
servoY.write(remember_y);
// Laser_Curve_Back_X(Last_angle_x, Last_angle_y);
Serial.println("Laser_Curve_X done");
delay(1000);
}
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Return value:
No return value
*/
void Laser_Curve_X(int angleX, int angleY) {
int total_dergee = 4;
int n = 0;
int Attach = 0;
for (int i = 0; i < total_dergee; i++) {
while(!check_cat()){
attact_cat(Last_angle_x,Last_angle_y,Attach);
n++;
if(n > 20){
digitalWrite(Laser_Pin, LOW);
Attach= 1;
}else{
}
}
n = 0;
Attach= 0;
digitalWrite(Laser_Pin, HIGH);
if (i < total_dergee / 4) {
angleX = 130;
} else if (i < total_dergee / 2) {
angleX = 70 ;
} else if (i < total_dergee / 4 * 3) {
angleX = 130;
} else {
angleX = 70;
}
angleY += 2 ;
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
brief:
Move the laser along the Y-axis in reverse zigzag motion
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Return value:
No return value
*/
void Laser_Curve_Back_X(int angleX, int angleY) {
int total_dergee = 4;
int n = 0;
int Attach = 0;
for (int i = 0; i < total_dergee; i++) {
while(!check_cat()){
attact_cat(Last_angle_x,Last_angle_y,Attach);
n++;
if(n > 20){
digitalWrite(Laser_Pin, LOW);
Attach= 1;
// delay(5000);
}
}
n = 0;
Attach=0;
digitalWrite(Laser_Pin, HIGH);
if (i < total_dergee / 4) {
angleX = 80;
} else if (i < total_dergee / 2) {
angleX = 130;
} else if (i < total_dergee / 4 * 3) {
angleX = 70;
} else {
angleX = 130;
}
angleY -= 5;
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
brief:
Moving the laser along the X-axis folding line
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Return value:
No return value
*/
void Laser_Curve_Y(int angleX, int angleY) {
int total_dergee = 4;
const int remember_x = angleX;
const int remember_y = angleY;
int n = 0;
int Attach = 0;
for (int i = 0; i < total_dergee; i++) {
while(!check_cat()){
attact_cat(Last_angle_x,Last_angle_y,Attach);
n++;
if(n > 20){
digitalWrite(Laser_Pin, LOW);
Attach= 1;
}
}
n = 0;
Attach=0;
digitalWrite(Laser_Pin, HIGH);
if (i < total_dergee / 4) {
angleY = 70;
} else if (i < total_dergee / 2) {
angleY = 45;
} else if (i < total_dergee / 4 * 3) {
angleY = 70;
} else {
angleY = 45;
}
angleX += 5;
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
Brief:
Moving the laser in a reverse zigzag motion along the X-axis
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Return value:
No return value
*/
void Laser_Curve_Back_Y(int angleX, int angleY) {
int total_dergee = 4;
int n = 0;
int Attach = 0;
for (int i = 0; i < total_dergee; i++) {
while(!check_cat()){
attact_cat(Last_angle_x,Last_angle_y,Attach);
n++;
if(n > 20){
digitalWrite(Laser_Pin, LOW);
Attach= 1;
}
}
n = 0;
Attach=0;
digitalWrite(Laser_Pin, HIGH);
if (i < total_dergee / 4) {
angleY = 45;
} else if (i < total_dergee / 2) {
angleY = 70;
} else if (i < total_dergee / 4 * 3) {
angleY = 45;
} else {
angleY = 70;
}
angleX -= 5;
// if(angleX <= 30){
// Serial.println("too much");
// i = total_dergee;
// break;
// }
// Serial.println("angleY");
// Serial.println(angleY);
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
Brief:
Move the laser in a circular motion
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Return value:
No return value
*/
void Laser_Cricle(int angleX, int angleY) {
int total_dergee = 4;
int n = 0;
int Attach = 0;
for (int i = 0; i < total_dergee; i++) {
while(!check_cat()){
attact_cat(Last_angle_x,Last_angle_y,Attach);
n++;
if(n > 20){
digitalWrite(Laser_Pin, LOW);
Attach= 1;
}
}
n = 0;
Attach=0;
digitalWrite(Laser_Pin, HIGH);
if (i < total_dergee / 4) {
angleX = 140;
angleY = 45;
} else if (i < total_dergee / 2) {
angleX = 90;
angleY = 30;
} else if (i < total_dergee / 4 * 3) {
angleX = 60;
angleY = 45;
} else {
angleX = 90;
angleY = 60;
}
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
brief:
Move the laser in a reverse circle motion
Input:
angleX : current x-axis angle
angleY : current y-axis angle
Return value:
No return value
*/
void Laser_Cricle_Back(int angleX, int angleY) {
int total_dergee = 4;
int n = 0;
int Attach = 0;
for (int i = 0; i < total_dergee; i++) {
while(!check_cat()){
attact_cat(Last_angle_x,Last_angle_y,Attach);
n++;
if(n > 20){
digitalWrite(Laser_Pin, LOW);
Attach= 1;
}
}
n = 0;
Attach=0;
digitalWrite(Laser_Pin, HIGH);
if (i < total_dergee / 4) {
angleX = 50 ;
angleY = 45;
} else if (i < total_dergee / 2) {
angleX = 90;
angleY = 30;
} else if (i < total_dergee / 4 * 3) {
angleX = 140;
angleY = 45;
} else {
angleX = 90;
angleY = 60 ;
}
if(angleX <= 30 || angleY <= 40 ){
Serial.println("too much");
i = total_dergee;
break;
}
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
delay(speed);
}
}
/*
Brief:
PID control can be used for following, although it will be too slow compared to a cat you can try
It for human face following
Input:
x : x-axis coordinate of the object in the camera.
y : y-axis coordinate of the object in the camera.
Return value:
No return value
*/
void server_control(int x, int y)
{
float targetAngleX = map(x, X_MAX, X_MIN, 0, 180);
float targetAngleY = map(y, Y_MIN, Y_MAX, 0, 180);
int offet_set_X = targetAngleX - 90;
int offet_set_Y = targetAngleY - 90;
float deltaDergeeX = offet_set_X * kp;
float deltaDergeeY = offet_set_Y * kp;
float angleX = Last_angle_x + deltaDergeeX;
float angleY = Last_angle_y + deltaDergeeY + errror;
servoX.write(angleX);
servoY.write(angleY);
Last_angle_x = angleX;
Last_angle_y = angleY;
}
void setup() {
Serial.begin(9600);
AI.begin();
// set the laser pin to output
pinMode(Laser_Pin, OUTPUT);
// set the servo pin to output
digitalWrite(SERVO_X_PIN, HIGH);
digitalWrite(SERVO_Y_PIN, HIGH);
delayMicroseconds(1500);
digitalWrite(SERVO_X_PIN, LOW);
digitalWrite(SERVO_Y_PIN, LOW);
servoX.attach(SERVO_X_PIN);
servoY.attach(SERVO_Y_PIN);
servoX.write(Last_angle_x);
servoY.write(Last_angle_y);
delay(1000);
//increase and print the boot count on every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
print_wakeup_reason();
/*
Set the wakeup time to 1 hour
*/
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
" Seconds");
}
void loop() {
Serial.println("one loop finish");
if (!AI.invoke()) {
//Since it was found that lasers can also be used to tease dogs, if you need to tease cats //exclusively you can change the condition to
//if (AI.boxes().size() > 0 && AI.boxes()[0].score >= 70 && target == 0 )
// You can adjust the contrast value of AI.boxes()[0].score to better recognise cats/dogs.
if (AI.boxes().size() > 0 && AI.boxes()[0].score >= 70 ) //&& target == 0 // 如果是猫
{
server_control(AI.boxes()[0].x, AI.boxes()[0].y);
delay(500);
//trun on the laser
digitalWrite(Laser_Pin, HIGH);
Serial.println("invoke success");
// active the laser motion
for (int i = 0; i < 20; i ++){
delay(50);
int n = random(1, 6);
Serial.print(" movtion is ");
switch (n) {
case 1:
Serial.println(n);
Laser_Curve_X(Last_angle_x, Last_angle_y);
back_to_centrel(Last_angle_x, Last_angle_y);
break;
case 2:
Serial.println(n);
Laser_Cricle(Last_angle_x, Last_angle_y);
back_to_centrel(Last_angle_x, Last_angle_y);
break;
case 3:
Serial.println(n);
Laser_Curve_Y(Last_angle_x, Last_angle_y);
back_to_centrel(Last_angle_x, Last_angle_y);
break;
case 4:
Serial.println(n);
Laser_Curve_Back_Y(Last_angle_x, Last_angle_y);
back_to_centrel(Last_angle_x, Last_angle_y);
break;
case 5:
Serial.println(n);
Laser_Curve_Back_X(Last_angle_x, Last_angle_y);
back_to_centrel(Last_angle_x, Last_angle_y);
break;
// case 6:
// Serial.println(n);
// forward_back_X(Last_angle_x, Last_angle_y);
// back_to_centrel(Last_angle_x, Last_angle_y);
// break;
}
}
digitalWrite(Laser_Pin, LOW);
back_to_centrel(Last_angle_x, Last_angle_y);
Last_angle_x = 90;
Last_angle_y = 60;
servoX.write(Last_angle_x);
servoY.write(Last_angle_y);
// delay(10000);
sleep_in_loop();
Serial.println("rest");
// angleX = Last_angle_x ;
// angleY = Last_angle_y ;
}
delay(500);
}
delay(500);
}
All the programs of this project are shown above. Sketch 2 uses the Grove Vision AI V2 image recognition module, the Seeed_Arduino_SSCMA library, the ESP32Servo library and some custom functions to implement a laser cat toy. it processes the image captured by the camera to achieve cat recognition by calling the API of SSCMA library. By controlling the laser pins, the programme is able to control the switching of the laser pointer and the movement of the laser pointer on the x-axis and y-axis.
The programme sets up an auto-sleep function, so that when no cat is detected, the device will enter the sleep state to wake up at regular intervals in order to conserve power.
It is designed with a variety of laser movement modes, including folding movement and circle movement, which can attract the cat's attention and increase the fun of interacting with the cat. In order to increase the fun of teasing the cat, the programme sets up the function of randomly selecting the teasing activity, randomly selecting a movement mode to interact with the pet.
Project focus:When I was first time to use Grove vision AI V2, I refered to the sample code provided in the library:
Sketch 3
#include <Seeed_Arduino_SSCMA.h>
SSCMA AI;
void setup()
{
AI.begin();
Serial.begin(9600);
}
void loop()
{
if (!AI.invoke())
{
Serial.println("invoke success");
Serial.print("perf: prepocess=");
Serial.print(AI.perf().prepocess);
Serial.print(", inference=");
Serial.print(AI.perf().inference);
Serial.print(", postpocess=");
Serial.println(AI.perf().postprocess);
for (int i = 0; i < AI.boxes().size(); i++)
{
Serial.print("Box[");
Serial.print(i);
Serial.print("] target=");
Serial.print(AI.boxes()[i].target);
Serial.print(", score=");
Serial.print(AI.boxes()[i].score);
Serial.print(", x=");
Serial.print(AI.boxes()[i].x);
Serial.print(", y=");
Serial.print(AI.boxes()[i].y);
Serial.print(", w=");
Serial.print(AI.boxes()[i].w);
Serial.print(", h=");
Serial.println(AI.boxes()[i].h);
}
for (int i = 0; i < AI.classes().size(); i++)
{
Serial.print("Class[");
Serial.print(i);
Serial.print("] target=");
Serial.print(AI.classes()[i].target);
Serial.print(", score=");
Serial.println(AI.classes()[i].score);
}
for (int i = 0; i < AI.points().size(); i++)
{
Serial.print("Point[");
Serial.print(i);
Serial.print("] target=");
Serial.print(AI.points()[i].target);
Serial.print(", score=");
Serial.print(AI.points()[i].score);
Serial.print(", x=");
Serial.print(AI.points()[i].x);
Serial.print(", y=");
Serial.println(AI.points()[i].y);
}
}
}
The sketch processes and prints out detailed information about the results of the inference, including:
· Bounding boxes (boxes()) that identify the locations and dimensions of detected objects in the form of x and y coordinates, width, and height.
· Classifications (classes()) that identify the categories of detected objects along with their confidence scores.
· Points (points()) that represent specific features or keypoints of detected objects, along with their x and y coordinates and confidence scores.
In this project,when the target equal to 0,that means there is a cat in the camera;when the target equal to 1,there is a dog in the camera, ie :
AI.boxes()[i].target == 0
And only a confidence score higher than 70, the device will be activated to perform the action, i.e:
AI.boxes()[i].score > 70
Future Improvements:Additional features:
1. Enhanced Interactivity: The system can be upgraded to include more interactive features for both dogs and cats. For instance, integrating an automatic feeding mechanism that rewards the pet with a small snack after a certain number of interactions, such as chasing the laser a set number of times. This not only encourages physical activity but also provides a rewarding experience for the pet.
2. Audio Engagement: Incorporating an MP3 module to play sounds can further attract pets and enhance interaction. Different sounds can be used to grab the pet’s attention or to signal the start of a play session.
User Experience Optimization:
1. OLED Display: Adding an OLED screen will allow users to easily monitor their pet’s daily activity levels and interaction history. This visual feedback provides a clear overview of the pet’s engagement with the device.
2. Remote Control and Monitoring: Leveraging the WIFI capabilities of the XIAO ESP32C3, users can remotely control the device to interact with their pets from anywhere. This feature also enables real-time checking of the pet’s status, ensuring that users can stay connected with their furry friends even when they are away.
Demonstration of the productSummaryThis project showcases the application of AI in pet care, demonstrating the practicality and effectiveness of the Grove Vision AI V2 as a powerful yet user-friendly image recognition solution. It opens up possibilities for the creation of smart, interactive devices that enrich the lives of pets and their owners alike.
The recognition technology used in this project, which can identify both dogs and cats, has diverse applications. It can be utilized in various scenarios such as intelligent feeders, pet monitoring systems, and more. The Grove Vision AI V2 module not only recognizes pets but also has the capability to recognize human, gestures, and more, making it a versatile and accessible tool for creators. This module simplifies the process of implementing image recognition in smart devices, allowing for the rapid development of innovative ideas.
Comments
Please log in or sign up to comment.