// AI generated.
// I asked Claude Haiku 4.5 to combine the two sketches.
// The original two sketches are in the txt files.
#include <Servo.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ============ SERVO SETUP ============
Servo xServo;
Servo yServo;
int joystickXPin = A0;
int joystickYPin = A1;
int servoxPin = 9;
int servoyPin = 8;
int posX = 45;
int posY = 45;
int tolerance = 10;
int rychlost = 10;
// ============ DISPLAY SETUP ============
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
float pupilX = 64;
float pupilY = 32;
unsigned long dalsiMrknuti;
// ============================================================
// INITIALIZE
// ============================================================
void setup()
{
xServo.attach(servoxPin);
yServo.attach(servoyPin);
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
randomSeed(analogRead(A0));
pupilX = 64;
pupilY = 32;
nakresliOko(pupilX, pupilY, 42);
nastavDalsiMrknuti();
delay(1000);
}
// ============================================================
// MAIN LOOP
// ============================================================
void loop()
{
int joystickX = analogRead(joystickXPin);
int joystickY = analogRead(joystickYPin);
Serial.print("X: ");
Serial.print(joystickX);
Serial.print(" Y: ");
Serial.println(joystickY);
// Map joystick values (0-1023) to servo angles (45-135)
int targetX = map(joystickX, 0, 1023, 45, 135);
int targetY = map(joystickY, 0, 1023, 45, 135);
// Update servo positions
xServo.write(targetX);
yServo.write(targetY);
// Map joystick to display coordinates (0-1023 -> 30-98 for X, 13-51 for Y)
int displayX = map(joystickX, 0, 1023, 30, 98);
int displayY = map(joystickY, 0, 1023, 13, 51);
// Smooth eye movement to target
koukniNa(displayX, displayY);
// ============ BLINK TIMING ============
if (millis() >= dalsiMrknuti)
{
mrkni();
nastavDalsiMrknuti();
}
delay(50);
}
// ============================================================
// DRAW EYE
// ============================================================
void nakresliOko(float x, float y, int vyska)
{
display.clearDisplay();
display.fillRoundRect(
x - 19,
y - vyska / 2,
38,
vyska,
9,
SSD1306_WHITE
);
display.display();
}
// ============================================================
// SMOOTH EYE MOVEMENT
// ============================================================
void koukniNa(int x, int y)
{
float startX = pupilX;
float startY = pupilY;
float dx = x - startX;
float dy = y - startY;
int vzdalenost = max(abs((int)dx), abs((int)dy));
if (vzdalenost == 0)
return;
int kroky = max(10, vzdalenost / 2);
for (int i = 1; i <= kroky; i++)
{
float t = (float)i / kroky;
float p = t * t * (3.0 - 2.0 * t); // Smooth acceleration/deceleration
pupilX = startX + dx * p;
pupilY = startY + dy * p;
nakresliOko(pupilX, pupilY, 42);
delay(5);
}
pupilX = x;
pupilY = y;
nakresliOko(pupilX, pupilY, 42);
}
// ============================================================
// BLINK
// ============================================================
void mrkni()
{
// Close
for (int vyska = 42; vyska >= 2; vyska -= 3)
{
nakresliOko(pupilX, pupilY, vyska);
delay(7);
}
delay(45);
// Open
for (int vyska = 2; vyska <= 42; vyska += 3)
{
nakresliOko(pupilX, pupilY, vyska);
delay(7);
}
nakresliOko(pupilX, pupilY, 42);
}
// ============================================================
// SET NEXT BLINK TIME
// ============================================================
void nastavDalsiMrknuti()
{
dalsiMrknuti = millis() + random(5000, 10001);
}
X
Y
Two OLED displays parallel
with the same I2C address
might not work.
X
Y