Skip to content

Electronics

Electronic Test

Matrix Display Test(Blinking)

The first component I’ll be needing for my project id the matrix display so for the eyes of the bot. While testing and learning about this component, I was able to change up and make a few different animations!

hearteye

The first code i worked with’s delay was too long, so after some adjuesting and changing up the code it finally worked the way i wanted it too

This is how the eye animation turned out in the end!!

The code for the blinking eye is from chatgpt.

#include <LedControl.h>

// DIN = 12, CLK = 11, CS = 10
LedControl lc = LedControl(12, 11, 10, 1);
byte eyeOpen[8] = {
  B01111110,
  B10000001,
  B10000001,
  B10111101,
  B10111101,
  B10000001,
  B10000001,
  B01111110
};
// Half-closed eye (top lid coming down) (vertical flipped)
byte eyeHalfClosed1[8] = {
 B00001110,
  B00110010,
  B01000010,
  B01111110,
  B01111110,
  B01000010,
  B00110010,
  B00001110
};

// Closed eye (vertical flipped)
byte eyeClosed[8] = {
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000
};

// Half-closed eye (bottom lid going up) (vertical flipped)
byte eyeHalfClosed2[8] = {
  B00001110,
  B00110010,
  B01000010,
  B01111110,
  B01111110,
  B01000010,
  B00110010,
  B00001110
};
void setup() {
  lc.shutdown(0, false);       
  lc.setIntensity(0, 8);       
  lc.clearDisplay(0);          
}

void loop() {
  displayFrame(eyeOpen);
  delay(6000);

  displayFrame(eyeHalfClosed1);
  delay(500);

  displayFrame(eyeClosed);
  delay(1000);

  displayFrame(eyeHalfClosed2);
  delay(500);
}

void displayFrame(byte frame[8]) {
  for (int i = 0; i < 8; i++) {
    lc.setRow(0, i, frame[i]);
  }
}

This Arduino code uses the LedControl library to animate an eye on an 8×8 LED matrix. It defines four frames representing different eye states: fully open, half-closed (top lid down), fully closed, and half-closed (bottom lid up). In setup(), the LED matrix is initialized, brightness is set, and the display is cleared. In the loop(), the frames are shown sequentially with delays to simulate blinking: the eye stays open for 6 seconds, then gradually closes and reopens with shorter intervals, creating a natural blinking effect. The displayFrame function handles drawing each 8×8 frame on the matrix by setting each row’s LEDs according to the byte patterns.

Motor and Ultrasonic Testing(Movement)

I needed to interconnect the motor and the ultrasonic for the obstical avodiding.

I firstly started with the motor as i needed to work with learning how to use a motor driver as well.

How It works

A motor is a device that converts electrical energy into mechanical motion, allowing objects to move or rotate.

A motor driver acts as an interface between a microcontroller and a motor, safely supplying the higher current and voltage the motor needs. It receives low-power control signals from the microcontroller—such as direction commands or speed control via PWM—and uses them to drive the motor appropriately. Essentially, the motor driver lets the controller “talk” to the motor safely and effectively.

After I was comfortable with using the motor, I interconnected it to an ultrasonic

#include <NewPing.h>

// === Motor A control pins ===
const int in1 = 2;  // D2
const int in2 = 3;  // D3

// === Motor B control pins ===
const int in3 = 4;  // D4
const int in4 = 5;  // D5

// === Ultrasonic sensor pins ===
#define sensorPin1 7   // Obstacle sensor
#define sensorPin2 10  // Petting sensor
#define MAX_DISTANCE 200

// === Thresholds ===
const int obstacleThreshold = 15; // Obstacle distance threshold (in cm)
const int pettingThreshold = 10;  // Petting detection range (in cm)

// === NewPing objects ===
NewPing sonar1(sensorPin1, sensorPin1, MAX_DISTANCE);
NewPing sonar2(sensorPin2, sensorPin2, MAX_DISTANCE);

void setup() {
  // Motor pins
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);

  // Stop motors at startup
  stopMotors();

  Serial.begin(115200); // Debugging output
}
void loop() {
  delay(100); // Small delay between loops

  unsigned int obstacleDist = sonar1.ping_cm();
  unsigned int pettingDist = sonar2.ping_cm();

  Serial.print("Obstacle: ");
  Serial.print(obstacleDist);
  Serial.print(" cm\t");

  Serial.print("Petting: ");
  Serial.print(pettingDist);
  Serial.println(" cm");

  // === Obstacle Detection Logic ===
  if (obstacleDist > 0 && obstacleDist < obstacleThreshold) {
    Serial.println("🚧 Obstacle detected! Stopping before backing up...");
    stopMotors();
    delay(3000);    // 🛑 Stop for 3 seconds before moving back
    Serial.println("Backing up...");
    backward();
    delay(1000);
    right();
    delay(1000);
    stopMotors();
  }
  // === Petting Detection Logic ===
  else if (pettingDist > 0 && pettingDist < pettingThreshold) {
    Serial.println("🐾 Petting detected! Responding...");
    stopMotors();
    delay(2000);  // Stand still for a while or react
  }
  else {
    forward();
  }
}
// === Motion Functions ===
void forward() {
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
}
void backward() {
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
}
void left() {
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
}
void right() {
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
}
void stopMotors() {
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
}

This Arduino code controls a two-motor robot equipped with two ultrasonic sensors: one for obstacle detection and another for petting detection. Motors A and B are controlled via pins 2–5, with functions defined for moving forward, backward, turning left or right, and stopping. The NewPing library is used to read distance measurements from the ultrasonic sensors. In the loop(), the robot constantly checks distances: if an obstacle is detected within 15 cm, it stops, backs up, turns right, and resumes; if a petting gesture is detected within 10 cm, it stops and waits briefly, simulating a response. If neither condition is met, the robot moves forward, and all sensor readings are printed via Serial for debugging. Essentially, the code enables the robot to navigate autonomously while responding to obstacles and interactive gestures.

Ultrasonic (Pettling)

I wanted my bot be very pet like so to do that, one feature i decided to add was a petting feature. Basicly, when you place your hand on top of the bot, theres an ultrasonic there. The bot stops and makes a few expressions whenit detects your hand, making it seem like petting.

Heres how it works!

#include <NewPing.h>
// === Motor A control pins ===
const int in1 = 2;  // D2
const int in2 = 3;  // D3
// === Motor B control pins ===
const int in3 = 4;  // D4
const int in4 = 5;  // D5
// === Ultrasonic sensor pins ===
#define sensorPin1 7   // Obstacle sensor
#define sensorPin2 10  // Petting sensor
#define MAX_DISTANCE 200
// === Thresholds ===
const int obstacleThreshold = 15; // Obstacle distance threshold (in cm)
const int pettingThreshold = 10;  // Petting detection range (in cm)
// === NewPing objects ===
NewPing sonar1(sensorPin1, sensorPin1, MAX_DISTANCE);
NewPing sonar2(sensorPin2, sensorPin2, MAX_DISTANCE);
void setup() {
  // Motor pins
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  // Stop motors at startup
  stopMotors();
  Serial.begin(115200); // Debugging output
}
void loop() {
  delay(100); // Small delay between loops
  unsigned int obstacleDist = sonar1.ping_cm();
  unsigned int pettingDist = sonar2.ping_cm();
  Serial.print("Obstacle: ");
  Serial.print(obstacleDist);
  Serial.print(" cm\t");
  Serial.print("Petting: ");
  Serial.print(pettingDist);
  Serial.println(" cm");
  // === Obstacle Detection Logic ===
  if (obstacleDist > 0 && obstacleDist < obstacleThreshold) {
    Serial.println("🚧 Obstacle detected! Stopping, then reversing...");
    stopMotors();
    delay(2000);    // 🛑 Stop for 2 seconds
    backward();
    delay(4000);    // Reverse for 4 seconds
    right();
    delay(1800);    // Turn right for 1 second
    stopMotors();
  }
  // === Petting Detection Logic ===
  else if (pettingDist > 0 && pettingDist < pettingThreshold) {
    Serial.println("🐾 Petting detected! Responding...");
    stopMotors();
    delay(2000);  // Pause to "enjoy" the petting
  }
  else {
    forward(); // Keep moving forward
  }
}
// === Motion Functions ===
void forward() {
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
}
void backward() {
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
}
void left() {
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
}
void right() {
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
}
void stopMotors() {
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
}

This code controls a small robot using two DC motors and two ultrasonic sensors managed through the NewPing library. It constantly reads distance values from the obstacle sensor and the “petting” sensor, printing both to the Serial Monitor for debugging. If an obstacle is detected closer than 15 cm, the robot stops, waits, reverses for a few seconds, turns right, and then stops again before continuing. If the petting sensor detects something within 10 cm, the robot pauses briefly as a reaction. If neither sensor is triggered, the robot continues moving forward. The motion functions—forward(), backward(), left(), right(), and stopMotors()—control the two motors by setting the direction pins HIGH or LOW, enabling the robot to navigate autonomously and respond to interaction.

All components

Finally, after learning all the different components, I linked it all together. So now, when theres obsticsl sensing or petting, a expression changes as well.

#include <NewPing.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

// === Motor Pins ===
const int in1 = 2;
const int in2 = 3;
const int in3 = 4;
const int in4 = 5;

// === Sensor Pins ===
#define sensorPin1 7   // Obstacle sensor
#define sensorPin2 10  // Petting sensor
#define MAX_DISTANCE 200

const int obstacleThreshold = 15;
const int pettingThreshold = 10;

// === Display Setup ===
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 1
#define DATA_PIN 9
#define CS_PIN 10
#define CLK_PIN 8

MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

// === Eye Frames ===
byte eyeOpen[8] = {
  B01111110,
  B10000001,
  B10000001,
  B10111101,
  B10111101,
  B10000001,
  B10000001,
  B01111110
};

byte eyeHalfClosed[8] = {
  B00001110,
  B00110010,
  B01000010,
  B01111110,
  B01111110,
  B01000010,
  B00110010,
  B00001110
};

byte eyeClosed[8] = {
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000
};

byte eyeHeart[8] = {
  B00000000,
  B00000000,
  B01100000,
  B00011000,
  B00000110,
  B00011000,
  B01100000,
  B00000000
};
// === Sensor Objects ===
NewPing sonar1(sensorPin1, sensorPin1, MAX_DISTANCE);
NewPing sonar2(sensorPin2, sensorPin2, MAX_DISTANCE);

void setup() {
  // Motor setup
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  stopMotors();

  // Display setup
  mx.begin();
  mx.clear();
  displayFrame(eyeOpen);

  Serial.begin(115200);
}
void loop() {
  delay(100);
  unsigned int obstacleDist = sonar1.ping_cm();
  unsigned int pettingDist = sonar2.ping_cm();

  Serial.print("Obstacle: ");
  Serial.print(obstacleDist);
  Serial.print(" cm\t");

  Serial.print("Petting: ");
  Serial.print(pettingDist);
  Serial.println(" cm");

  // === Obstacle Detected ===
  if (obstacleDist > 0 && obstacleDist < obstacleThreshold) {
    Serial.println("🚧 Obstacle detected!");

    stopMotors();
    blinkEyes();        // Blink animation
    delay(2000);        // Pause
    backward();
    delay(4000);        // Move back
    right();
    delay(1500);        // Turn
    forward();
  }
  // === Petting Detected ===
  else if (pettingDist > 0 && pettingDist < pettingThreshold) {
    Serial.println("🐾 Petting detected!");
    stopMotors();
    displayFrame(eyeHeart);
    delay(3000);
    displayFrame(eyeOpen); // Restore
  }
  // === Normal Behavior ===
  else {
    forward();
    displayFrame(eyeOpen);  // Keep eyes open
  }
}
// === Motion Control ===
void forward() {
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
}
void backward() {
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
}
void right() {
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
}
void stopMotors() {
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
}
// === Display Functions ===
void displayFrame(byte matrix[8]) {
  for (int row = 0; row < 8; row++) {
    mx.setRow(0, row, matrix[row]);
  }
}
void blinkEyes() {
  displayFrame(eyeOpen);
  delay(600);
  displayFrame(eyeHalfClosed);
  delay(300);
  displayFrame(eyeClosed);
  delay(1000);
  displayFrame(eyeHalfClosed);
  delay(300);
  displayFrame(eyeOpen);
}

This code controls a robot that moves using two motors, senses its surroundings with ultrasonic sensors, and displays eye animations on an 8×8 LED matrix. When an obstacle is detected, the robot stops, performs a blink animation, reverses, and turns away. When someone pets it, the robot shows heart-shaped eyes for a moment. If nothing is detected, it simply moves forward with open eyes. The motor functions handle direction control, while the display functions update the LED matrix to match the robot’s expressions, making its movement and reactions more animated and lifelike.

Run through

Finally, Heres a test of my first assembly of everything together!

Heres how the assembling process looked. I was double checking the connections here

Heres the obstical avoiding

Spinn of the bot

Heres the petting function

That concludes my project then.

Design Files

mcb

Thank youu!


Last update: December 6, 2025