How to Build a Cosmic Critter Pet with Raspberry Pi Pico

A tiny alien pet with tilt-based moods, nebula lights, and chirpy sounds

Raspberry Pi PicoPetsBeginner40 minutes5 components

Updated

How to Build a Cosmic Critter Pet with Raspberry Pi Pico
For illustrative purposes only
On this page

What you'll build

In this guide you will bring a Cosmic Critter to life on a Raspberry Pi Pico using an MPU6050 accelerometer, a 0.96-inch OLED display for its animated face, a WS2812B LED ring for nebula-inspired ambient lighting, and a piezo buzzer for chirps and purrs. The critter's mood changes in real time based on how you tilt and handle the device -- hold it level and it drifts into a calm trance with slow-pulsing blue LEDs, tilt it sharply and it gets excited with rapid rainbow sparkles and high-pitched trills, leave it still too long and it grows bored with droopy eyes and a dim amber glow. The result is a pocket-sized alien companion that reacts to your every move.

The Raspberry Pi Pico is an excellent platform for beginners because MicroPython lets you write, test, and tweak code without a compile step. This project teaches you how to read accelerometer data over I2C on the Pico, map tilt angles to discrete mood states using threshold logic, drive a NeoPixel LED ring with the Pico's PIO state machine for flicker-free animations, and generate melodic tones on a buzzer using PWM. You will also learn how to render simple bitmap animations on the OLED, giving the critter expressive eyes, a mouth, and antennae that wiggle when it is happy.

When you finish you will have a self-contained interactive toy that runs from a USB power bank or a pair of AAA batteries. The code is organized into clean modules for mood logic, LED patterns, face animation, and sound effects, so you can easily add new moods, create your own critter species with different personalities, or wire up additional sensors like a light-dependent resistor to make the critter react to darkness. It is a perfect first Pico project that teaches real embedded programming concepts while producing something genuinely fun to play with. For an ESP32-based take on the virtual pet concept, check out the ClawdBot Tamagotchi which uses buttons instead of motion for interaction.

Wiring diagram

Wiring diagram

Interactive wiring diagram

Components needed

ComponentTypeQtyBuy
MPU6050 Motion Sensorsensor1€4.75
SSD1306 OLEDdisplay1€4.30
WS2812B LED Ringactuator1
Piezo Buzzeractuator1€4.75
Mood Buttonother1€8.30

Prices and availability are indicative and may have been updated by the supplier. Schematik may earn a commission from purchases made through affiliate links.

Assembly

1

Wire the Pico control core

Connect MPU6050 and SSD1306 to Raspberry Pi Pico I2C pins (SDA GP4, SCL GP5). Add the mood button to GP14 with pull-up wiring.

2

Add lights and chirps

Connect WS2812 DIN to GP12 and buzzer signal to GP15, then upload to watch the critter react to tilt and button presses.

Pin assignments

PinConnectionType
GPIO 4pico-imu-1 SDAI2C
GPIO 5pico-imu-1 SCLI2C
GPIO 4pico-oled-1 SDAI2C
GPIO 5pico-oled-1 SCLI2C
GPIO 12pico-led-ring-1 DINDATA
GPIO 15pico-buzzer-1 SIGPWM
GPIO 14pico-mode-button-1 SIGDIGITAL

Code

#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_SSD1306.h>
#include <FastLED.h>

#define SDA_PIN 4
#define SCL_PIN 5
#define BTN_PIN 14
#define BUZZER_PIN 15
#define LED_PIN 12
#define NUM_LEDS 12

Adafruit_MPU6050 mpu;
Adafruit_SSD1306 display(128, 64, &Wire, -1);
CRGB leds[NUM_LEDS];

enum Mood { HAPPY, SLEEPY, DIZZY, HYPER };
Mood mood = HAPPY;
unsigned long lastChirpMs = 0;

const char* moodName(Mood m) {
  switch (m) {
    case HAPPY: return "Happy";
    case SLEEPY: return "Sleepy";
    case DIZZY: return "Dizzy";
    case HYPER: return "Hyper";
    default: return "Unknown";
  }
}

void renderMoodLights(Mood m) {
  switch (m) {
    case HAPPY:
      fill_solid(leds, NUM_LEDS, CRGB(0, 120, 255));
      break;
    case SLEEPY:
      fill_solid(leds, NUM_LEDS, CRGB(64, 0, 120));
      break;
    case DIZZY:
      for (int i = 0; i < NUM_LEDS; i++) {
        leds[i] = CHSV((millis() / 12 + i * 14) % 255, 255, 120);
      }
      break;
    case HYPER:
      for (int i = 0; i < NUM_LEDS; i++) {
        leds[i] = (i % 2 == 0) ? CRGB::OrangeRed : CRGB::Gold;
      }
      break;
  }
  FastLED.show();
}

void chirp(Mood m) {
  switch (m) {
    case HAPPY: tone(BUZZER_PIN, 1400, 70); break;
    case SLEEPY: tone(BUZZER_PIN, 750, 120); break;
    case DIZZY: tone(BUZZER_PIN, 1800, 40); break;
    case HYPER: tone(BUZZER_PIN, 2200, 50); break;
  }
}

void setup() {
  Wire.begin(SDA_PIN, SCL_PIN);
  mpu.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
  FastLED.setBrightness(120);
  pinMode(BTN_PIN, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT);
}

void loop() {
  sensors_event_t a, g, t;
  mpu.getEvent(&a, &g, &t);

  if (a.acceleration.x > 4.5f) mood = HYPER;
  else if (a.acceleration.x < -4.5f) mood = SLEEPY;
  else if (fabs(a.acceleration.y) > 6.0f) mood = DIZZY;
  else mood = HAPPY;

  if (!digitalRead(BTN_PIN)) {
    mood = static_cast<Mood>((mood + 1) % 4);
    chirp(mood);
    delay(160);
  }

  if (millis() - lastChirpMs > 2800) {
    chirp(mood);
    lastChirpMs = millis();
  }

  renderMoodLights(mood);

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Pico Cosmic Critter");
  display.print("Mood: ");
  display.println(moodName(mood));
  display.print("Tilt X: ");
  display.println(a.acceleration.x, 1);
  display.print("Tilt Y: ");
  display.println(a.acceleration.y, 1);
  display.println("BTN: cycle mood");
  display.display();

  delay(60);
}

// Run this and build other cool things at schematik.io
Libraries: Adafruit MPU6050, Adafruit SSD1306, Adafruit GFX Library, FastLED