驴友花雕 发表于 2025-3-20 12:08:42

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

Arduino OLED之机器人眼睛动画
一、主要特点
(一)生动形象的表现力
​模拟真实眼神:通过OLED屏幕展示机器人眼睛动画,可以生动地模拟出机器人的各种眼神状态,如好奇、警觉、友好等。这种形象化的表现方式能够让机器人更具亲和力和交互性,使用户更容易与机器人建立情感连接。
​丰富的表情变化:可以实现多种表情的切换和过渡动画,从简单的睁眼、闭眼到复杂的眨眼、斜视等动作,为机器人赋予更加丰富的个性和情感表达能力。
(二)高度的可定制性
​动画效果自定义:开发者可以根据具体需求设计和定制各种不同的动画效果。例如,可以设置眼睛的闪烁频率、颜色变化、移动轨迹等参数,以满足不同应用场景下的个性化要求。
​与机器人功能结合:眼睛动画可以与机器人的其他功能紧密结合,如语音交互、动作执行等。当机器人接收到特定指令或处于不同工作状态时,眼睛动画可以相应地做出变化,增强机器人的整体表现力和用户体验。
(三)低资源占用与高效运行
​适合嵌入式系统:Arduino平台本身资源相对有限,而OLED屏幕显示眼睛动画所需的计算资源和存储空间较小。这使得在资源受限的嵌入式系统中,如小型机器人、智能玩具等,能够轻松实现复杂的眼睛动画效果,同时保证系统的稳定运行。
​实时响应能力:由于OLED屏幕的刷新速度较快,配合优化的动画算法,机器人眼睛动画可以实现实时响应。例如,在与用户进行交互时,机器人能够迅速根据用户的动作或语音指令做出相应的眼神变化,提供更加流畅和自然的交互体验。
(四)易于集成与扩展
​简单的硬件连接:OLED屏幕通常采用I2C或SPI等标准通信接口,与Arduino板连接方便。只需将相应的引脚连接到Arduino板上,即可实现与机器人的集成,无需复杂的硬件设计。
​丰富的软件支持:Arduino社区提供了大量的开源库和示例代码,用于控制OLED屏幕和处理动画效果。开发者可以利用这些资源快速搭建机器人眼睛动画系统,并在此基础上进行二次开发和功能扩展。
二、应用场景
(一)教育与科普领域
​机器人教育套件:在机器人教育套件中,添加眼睛动画功能可以使机器人更加生动有趣,吸引学生的注意力。例如,在编程教学中,学生可以通过编写代码来控制机器人眼睛的动画效果,加深对编程逻辑和机器人控制的理解。
​科普展览与互动体验:在科技馆、博物馆等场所的科普展览中,带有眼睛动画的机器人可以作为互动展品,向观众展示机器人的基本原理和功能。观众可以通过与机器人进行简单的交互,观察机器人眼睛的变化,增加对科技的兴趣和了解。
(二)智能家居领域
​智能管家机器人:在智能家居环境中,智能管家机器人可以通过眼睛动画来表达不同的状态和情感。例如,当机器人检测到主人回家时,可以通过眨眼、微笑等动画效果表示欢迎;当出现异常情况时,如烟雾报警,机器人可以用惊恐的眼神提示主人。
​儿童陪伴机器人:针对儿童的陪伴机器人可以利用眼睛动画来增强与儿童的互动。例如,在讲故事、玩游戏的过程中,机器人可以根据情节变化展示相应的眼神,使陪伴过程更加生动有趣,有助于儿童的智力开发和情感培养。
(三)娱乐与玩具领域
​智能玩具机器人:在智能玩具机器人中,眼睛动画可以增加玩具的趣味性和吸引力。例如,玩具机器人可以根据不同的游戏模式展示不同的眼神,或者在播放音乐、故事时配合相应的眼神动作,为儿童带来更加丰富的娱乐体验。
​互动表演机器人:在一些舞台表演、活动现场等场合,互动表演机器人可以通过眼睛动画来增强表演效果。例如,机器人可以与演员进行眼神互动,或者根据音乐节奏展示不同的眼神变化,为观众带来全新的视觉体验。
(四)工业与商业领域
​服务机器人:在商场、酒店等服务场所的服务机器人中,眼睛动画可以用于向顾客传达信息。例如,当机器人引导顾客前往指定位置时,可以通过眼神提示顾客跟随;当机器人遇到障碍物或需要帮助时,可以用困惑的眼神提示工作人员。
​广告宣传机器人:在一些商业活动或展览中,广告宣传机器人可以通过眼睛动画来吸引观众的注意力。例如,机器人的眼睛可以根据广告内容展示不同的表情和动作,使广告宣传更加生动形象,提高宣传效果。
三、需要注意的事项
(一)动画设计与优化
​避免过度复杂:虽然OLED屏幕能够支持丰富的动画效果,但过于复杂的动画可能会导致系统资源紧张,影响机器人的其他功能运行。因此,在设计眼睛动画时,应尽量保持简洁明了,避免过多的细节和不必要的动画元素。
​优化动画算法:为了确保眼睛动画的流畅性和实时性,需要对动画算法进行优化。例如,可以采用插值算法来实现平滑的过渡效果,减少动画帧之间的跳跃感;同时,合理控制动画的帧率和刷新频率,避免因刷新过快导致系统负载过高。
(二)色彩搭配与对比度
​选择合适的颜色:在选择眼睛动画的颜色时,要考虑OLED屏幕的特性和环境光线的影响。避免使用过于刺眼或难以辨认的颜色组合,确保眼睛动画在不同的光照条件下都能清晰可见。
​保证足够的对比度:为了使眼睛动画更加醒目和易于观察,需要保证眼睛与背景之间有足够的对比度。例如,在白色背景下,可以使用黑色或深色的眼睛图案;在黑色背景下,则可以使用白色或亮色的眼睛图案。
(三)硬件兼容性与稳定性
​检查OLED屏幕兼容性:在使用OLED屏幕实现机器人眼睛动画之前,需要确保所选的OLED屏幕与Arduino板以及其他相关硬件设备兼容。不同型号的OLED屏幕可能在通信协议、电气特性等方面存在差异,需要进行充分的测试和验证。
​确保硬件连接稳定:良好的硬件连接是保证眼睛动画正常显示的基础。在连接OLED屏幕和Arduino板时,要注意引脚的正确连接和焊接质量,避免出现松动、接触不良等问题。同时,要考虑电磁干扰等因素对硬件稳定性的影响,采取相应的防护措施。
(四)软件编程与调试
​正确配置库文件和引脚:在使用Arduino控制OLED屏幕显示眼睛动画时,需要正确配置相关的库文件和引脚。不同的OLED屏幕可能需要使用不同的驱动库,要根据实际情况选择合适的库文件,并按照文档说明正确设置引脚模式和参数。
​进行充分的调试:在编写和实现眼睛动画程序后,需要进行充分的调试工作。通过观察OLED屏幕上的显示效果,检查动画是否流畅、颜色是否正确、位置是否准确等。如果发现问题,要及时分析原因并进行修改,直到达到预期的效果。



驴友花雕 发表于 2025-3-20 12:10:27

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

方案二:基于SSD1306 OLED屏幕的眼睛动画演示,支持多种动画效果(如眨眼、移动、开心表情等),并可以通过串口控制动画播放。代码结构清晰,功能模块化,便于扩展和修改。


驴友花雕 发表于 2025-3-20 12:32:10

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

【花雕动手做】基于 Arduino 的机器人 OLED 眼睛动画:呈现多样情绪,增强交互魅力
方案二:实验开源代码

/*
【花雕动手做】为 Arduino 机器人创建迷人的 OLED 眼睛动画!
   实验项目之二:OLED 眼睛:呈现多样情绪,增强交互魅力
*/

#include <SPI.h>                // 引入SPI通信库,用于支持SPI协议
#include <Wire.h>               // 引入I2C通信库,用于支持I2C协议
#include <Adafruit_GFX.h>       // 引入Adafruit图形库,提供基本图形绘制功能
#include <Adafruit_SSD1306.h>   // 引入Adafruit SSD1306 OLED屏幕驱动库

#define SCREEN_WIDTH 128      // 定义OLED屏幕的宽度为128像素
#define SCREEN_HEIGHT 64      // 定义OLED屏幕的高度为64像素
#define OLED_RESET -1         // 定义OLED复位引脚为-1(表示共享Arduino复位引脚)
#define SCREEN_ADDRESS 0x3C   // 定义OLED屏幕的I2C地址为0x3C(根据屏幕型号选择)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);// 创建SSD1306屏幕对象,使用I2C通信

int demo_mode = 1;            // 定义演示模式标志,1表示循环播放动画
static const int max_animation_index = 8;// 定义最大动画索引为8
int current_animation_index = 0;// 定义当前动画索引为0

int ref_eye_height = 40;      // 定义参考眼睛高度为40像素
int ref_eye_width = 40;         // 定义参考眼睛宽度为40像素
int ref_space_between_eye = 10; // 定义两只眼睛之间的间距为10像素
int ref_corner_radius = 10;   // 定义眼睛圆角半径为10像素

int left_eye_height = ref_eye_height;// 定义左眼当前高度为参考高度
int left_eye_width = ref_eye_width;    // 定义左眼当前宽度为参考宽度
int left_eye_x = 32;                   // 定义左眼X坐标为32
int left_eye_y = 32;                   // 定义左眼Y坐标为32
int right_eye_x = 32 + ref_eye_width + ref_space_between_eye;// 定义右眼X坐标为左眼X坐标加上眼睛宽度和间距
int right_eye_y = 32;                   // 定义右眼Y坐标为32
int right_eye_height = ref_eye_height;// 定义右眼当前高度为参考高度
int right_eye_width = ref_eye_width;    // 定义右眼当前宽度为参考宽度

void draw_eyes(bool update = true) {// 定义绘制眼睛函数,update参数控制是否更新屏幕
    display.clearDisplay();         // 清空屏幕
    int x = int(left_eye_x - left_eye_width / 2);// 计算左眼的左上角X坐标
    int y = int(left_eye_y - left_eye_height / 2); // 计算左眼的左上角Y坐标
    display.fillRoundRect(x, y, left_eye_width, left_eye_height, ref_corner_radius, SSD1306_WHITE);// 绘制左眼
    x = int(right_eye_x - right_eye_width / 2);    // 计算右眼的左上角X坐标
    y = int(right_eye_y - right_eye_height / 2);   // 计算右眼的左上角Y坐标
    display.fillRoundRect(x, y, right_eye_width, right_eye_height, ref_corner_radius, SSD1306_WHITE);// 绘制右眼
    if (update) {// 如果update为true
      display.display();// 更新屏幕显示
    }
}

void center_eyes(bool update = true) {// 定义将眼睛居中函数,update参数控制是否更新屏幕
    left_eye_height = ref_eye_height;// 重置左眼高度为参考高度
    left_eye_width = ref_eye_width;    // 重置左眼宽度为参考宽度
    right_eye_height = ref_eye_height; // 重置右眼高度为参考高度
    right_eye_width = ref_eye_width;   // 重置右眼宽度为参考宽度
    left_eye_x = SCREEN_WIDTH / 2 - ref_eye_width / 2 - ref_space_between_eye / 2;// 计算左眼X坐标
    left_eye_y = SCREEN_HEIGHT / 2;    // 计算左眼Y坐标
    right_eye_x = SCREEN_WIDTH / 2 + ref_eye_width / 2 + ref_space_between_eye / 2;// 计算右眼X坐标
    right_eye_y = SCREEN_HEIGHT / 2;   // 计算右眼Y坐标
    draw_eyes(update);// 调用绘制眼睛函数
}

void blink(int speed = 12) {// 定义眨眼函数,speed参数控制眨眼速度
    draw_eyes();// 绘制眼睛
    for (int i = 0; i < 3; i++) {// 循环3次,模拟眼睛闭合
      left_eye_height -= speed;// 左眼高度减小
      right_eye_height -= speed; // 右眼高度减小
      draw_eyes();// 绘制眼睛
      delay(1);   // 延迟1毫秒
    }
    for (int i = 0; i < 3; i++) {// 循环3次,模拟眼睛睁开
      left_eye_height += speed;// 左眼高度增加
      right_eye_height += speed; // 右眼高度增加
      draw_eyes();// 绘制眼睛
      delay(1);   // 延迟1毫秒
    }
}

void sleep() {// 定义睡眠函数
    left_eye_height = 2;// 左眼高度设置为2像素
    right_eye_height = 2; // 右眼高度设置为2像素
    draw_eyes(true);      // 绘制眼睛并更新屏幕
}

void wakeup() {// 定义唤醒函数
    sleep();// 调用睡眠函数
    for (int h = 0; h <= ref_eye_height; h += 2) {// 循环增加眼睛高度
      left_eye_height = h;// 左眼高度增加
      right_eye_height = h; // 右眼高度增加
      draw_eyes(true);      // 绘制眼睛并更新屏幕
    }
}

void happy_eye() {// 定义开心眼睛函数
    center_eyes(false);// 将眼睛居中,但不更新屏幕
    int offset = ref_eye_height / 2;// 定义偏移量为眼睛高度的一半
    for (int i = 0; i < 10; i++) {// 循环10次,模拟开心表情
      display.fillTriangle(left_eye_x - left_eye_width / 2 - 1, left_eye_y + offset, left_eye_x + left_eye_width / 2 + 1, left_eye_y + 5 + offset, left_eye_x - left_eye_width / 2 - 1, left_eye_y + left_eye_height + offset, SSD1306_BLACK);// 绘制左眼下方的倒三角形
      display.fillTriangle(right_eye_x + right_eye_width / 2 + 1, right_eye_y + offset, right_eye_x - left_eye_width / 2 - 1, right_eye_y + 5 + offset, right_eye_x + right_eye_width / 2 + 1, right_eye_y + right_eye_height + offset, SSD1306_BLACK);// 绘制右眼下方的倒三角形
      offset -= 2;// 偏移量减少
      display.display();// 更新屏幕
      delay(1);   // 延迟1毫秒
    }
    display.display();// 更新屏幕
    delay(1000);       // 延迟1秒
}

void saccade(int direction_x, int direction_y) {// 定义快速眼动函数
    int direction_x_movement_amplitude = 8;// 定义X方向移动幅度
    int direction_y_movement_amplitude = 6;// 定义Y方向移动幅度
    int blink_amplitude = 8;                // 定义眨眼幅度
    for (int i = 0; i < 1; i++) {// 循环1次,模拟眼睛快速移动
      left_eye_x += direction_x_movement_amplitude * direction_x;// 左眼X坐标移动
      right_eye_x += direction_x_movement_amplitude * direction_x; // 右眼X坐标移动
      left_eye_y += direction_y_movement_amplitude * direction_y;// 左眼Y坐标移动
      right_eye_y += direction_y_movement_amplitude * direction_y; // 右眼Y坐标移动
      right_eye_height -= blink_amplitude;// 右眼高度减小
      left_eye_height -= blink_amplitude;   // 左眼高度减小
      draw_eyes();// 绘制眼睛
      delay(1);   // 延迟1毫秒
    }
    for (int i = 0; i < 1; i++) {// 循环1次,恢复眼睛状态
      left_eye_x += direction_x_movement_amplitude * direction_x;// 左眼X坐标移动
      right_eye_x += direction_x_movement_amplitude * direction_x; // 右眼X坐标移动
      left_eye_y += direction_y_movement_amplitude * direction_y;// 左眼Y坐标移动
      right_eye_y += direction_y_movement_amplitude * direction_y; // 右眼Y坐标移动
      right_eye_height += blink_amplitude;// 右眼高度增加
      left_eye_height += blink_amplitude;   // 左眼高度增加
      draw_eyes();// 绘制眼睛
      delay(1);   // 延迟1毫秒
    }
}

void move_big_eye(int direction) {// 定义大眼睛移动函数
    int direction_oversize = 1;   // 定义眼睛放大幅度
    int direction_movement_amplitude = 2;// 定义移动幅度
    int blink_amplitude = 5;       // 定义眨眼幅度
    for (int i = 0; i < 3; i++) {// 循环3次,模拟眼睛移动和放大
      left_eye_x += direction_movement_amplitude * direction;// 左眼X坐标移动
      right_eye_x += direction_movement_amplitude * direction; // 右眼X坐标移动
      right_eye_height -= blink_amplitude;// 右眼高度减小
      left_eye_height -= blink_amplitude;   // 左眼高度减小
      if (direction > 0) {// 如果方向为正
            right_eye_height += direction_oversize;// 右眼高度增加
            right_eye_width += direction_oversize;   // 右眼宽度增加
      } else {// 如果方向为负
            left_eye_height += direction_oversize;   // 左眼高度增加
            left_eye_width += direction_oversize;    // 左眼宽度增加
      }
      draw_eyes();// 绘制眼睛
      delay(1);   // 延迟1毫秒
    }
    for (int i = 0; i < 3; i++) {// 循环3次,恢复眼睛状态
      left_eye_x += direction_movement_amplitude * direction;// 左眼X坐标移动
      right_eye_x += direction_movement_amplitude * direction; // 右眼X坐标移动
      right_eye_height += blink_amplitude;// 右眼高度增加
      left_eye_height += blink_amplitude;   // 左眼高度增加
      if (direction > 0) {// 如果方向为正
            right_eye_height += direction_oversize;// 右眼高度增加
            right_eye_width += direction_oversize;   // 右眼宽度增加
      } else {// 如果方向为负
            left_eye_height += direction_oversize;   // 左眼高度增加
            left_eye_width += direction_oversize;    // 左眼宽度增加
      }
      draw_eyes();// 绘制眼睛
      delay(1);   // 延迟1毫秒
    }
    delay(1000);// 延迟1秒
    center_eyes();// 将眼睛居中
}

void move_right_big_eye() {
    move_big_eye(1);// 调用 move_big_eye 函数,传入方向参数 1(向右)
}

void move_left_big_eye() {
    move_big_eye(-1); // 调用 move_big_eye 函数,传入方向参数 -1(向左)
}

void launch_animation_with_index(int animation_index) {// 定义根据动画索引播放动画的函数
    if (animation_index > max_animation_index) {// 如果动画索引超过最大值
      animation_index = max_animation_index;    // 将动画索引设置为最大值
    }

    switch (animation_index) {// 根据动画索引选择动画
      case 0:
            wakeup();// 播放唤醒动画
            break;
      case 1:
            center_eyes(true);// 播放眼睛居中动画
            break;
      case 2:
            move_right_big_eye();// 播放右眼放大动画
            break;
      case 3:
            move_left_big_eye();   // 播放左眼放大动画
            break;
      case 4:
            blink(10);// 播放眨眼动画(速度10)
            break;
      case 5:
            blink(20);// 播放眨眼动画(速度20)
            break;
      case 6:
            happy_eye();// 播放开心眼睛动画
            break;
      case 7:
            sleep();// 播放睡眠动画
            break;
      case 8:
            center_eyes(true);// 播放眼睛居中动画
            for (int i = 0; i < 20; i++) {// 随机快速眼动
                int dir_x = random(-1, 2);// 随机X方向
                int dir_y = random(-1, 2);// 随机Y方向
                saccade(dir_x, dir_y);      // 播放快速眼动动画
                delay(1);                  // 延迟1毫秒
                saccade(-dir_x, -dir_y);   // 恢复眼睛位置
                delay(1);                  // 延迟1毫秒
            }
            break;
    }
}

void setup() {// 定义初始化函数
    display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);// 初始化屏幕
    Serial.begin(115200);// 初始化串口通信
    display.clearDisplay();// 清空屏幕
    display.setTextSize(1);// 设置文本大小为1
    display.setTextColor(SSD1306_WHITE);// 设置文本颜色为白色
    display.setCursor(0, 0);// 设置文本起始位置
    display.println(F("Intellar.ca"));// 显示文本
    display.display();// 更新屏幕
    delay(2000);// 延迟2秒
    sleep();// 调用睡眠函数
    delay(2000);// 延迟2秒
}

void loop() {// 定义主循环函数
    if (demo_mode == 1) {// 如果演示模式为1
      launch_animation_with_index(current_animation_index++);// 播放当前动画
      if (current_animation_index > max_animation_index) {// 如果动画索引超过最大值
            current_animation_index = 0;// 重置动画索引
      }
    }
    if (Serial.available()) {// 如果串口有数据
      String data = Serial.readString();// 读取串口数据
      data.trim();// 去除数据前后空格
      char cmd = data;// 获取命令字符
      if (cmd == 'A') {// 如果命令为'A'
            demo_mode = 0;// 关闭演示模式
            String arg = data.substring(1, data.length());// 获取参数
            int anim = arg.toInt();// 将参数转换为整数
            launch_animation_with_index(anim);// 播放指定动画
            Serial.print(cmd);// 发送命令字符
            Serial.print(arg);// 发送参数
      }
    }
}

驴友花雕 发表于 2025-3-20 13:31:06

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

这段代码实现了一个基于Arduino的OLED眼睛动画项目,能够通过OLED屏幕展示多种眼睛表情和动作(如眨眼、开心、睡眠、快速眼动等)。

一、​功能解析
1、​OLED屏幕初始化

使用Adafruit_SSD1306库驱动OLED屏幕。
屏幕分辨率为128x64像素,采用I2C通信,地址为0x3C。
初始化后,屏幕会显示"Intellar.ca"文本,随后进入睡眠状态。

2、​眼睛动画

提供了多种眼睛动画效果,包括:
​唤醒(wakeup)​:眼睛从极小的状态逐渐放大到正常大小。
​居中(center_eyes)​:将眼睛重置到屏幕中央。
​眨眼(blink)​:模拟眼睛快速闭合和睁开。
​开心(happy_eye)​:在眼睛下方绘制倒三角形,模拟开心的表情。
​睡眠(sleep)​:眼睛缩小到极小的状态。
​大眼睛移动(move_big_eye)​:眼睛放大并随机移动。
​快速眼动(saccade)​:眼睛快速移动并伴随轻微的眨眼效果。
动画通过调整眼睛的宽度、高度、位置和形状实现。

3、​动画索引

使用launch_animation_with_index函数根据动画索引播放不同的动画。
支持通过串口命令切换动画模式。

4、​串口与交互

通过串口接收命令,允许用户动态选择动画。
命令格式为A<动画索引>,例如A2播放右眼放大动画。

5、演示模式

默认进入演示模式(demo_mode = 1),按顺序循环播放所有动画。
用户可以通过串口命令关闭演示模式并手动选择动画。

驴友花雕 发表于 2025-3-20 13:34:53

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

二、​关键代码段分析
​1. 眼睛绘制函数

void draw_eyes(bool update = true) {

    display.clearDisplay(); // 清空屏幕

    int x = int(left_eye_x - left_eye_width / 2);// 计算左眼的左上角X坐标

    int y = int(left_eye_y - left_eye_height / 2); // 计算左眼的左上角Y坐标

    display.fillRoundRect(x, y, left_eye_width, left_eye_height, ref_corner_radius, SSD1306_WHITE);// 绘制左眼

    x = int(right_eye_x - right_eye_width / 2);    // 计算右眼的左上角X坐标

    y = int(right_eye_y - right_eye_height / 2);   // 计算右眼的左上角Y坐标

    display.fillRoundRect(x, y, right_eye_width, right_eye_height, ref_corner_radius, SSD1306_WHITE);// 绘制右眼

    if (update) {// 如果update为true

      display.display();// 更新屏幕显示

    }

}
​功能:绘制左右眼睛,使用fillRoundRect绘制圆角矩形表示眼睛。
​扩展性:
可以通过调整ref_corner_radius改变眼睛的圆角程度。
可以在眼睛内部绘制瞳孔或其他装饰。

​2. 眨眼函数

void blink(int speed = 12) {
    draw_eyes();// 绘制眼睛
    for (int i = 0; i < 3; i++) {// 循环3次,模拟眼睛闭合
      left_eye_height -= speed;// 左眼高度减小
      right_eye_height -= speed; // 右眼高度减小
      draw_eyes();// 绘制眼睛
      delay(1);   // 延迟1毫秒
    }
    for (int i = 0; i < 3; i++) {// 循环3次,模拟眼睛睁开
      left_eye_height += speed;// 左眼高度增加
      right_eye_height += speed; // 右眼高度增加
      draw_eyes();// 绘制眼睛
      delay(1);   // 延迟1毫秒
    }
}


​功能:模拟眼睛的快速闭合和睁开。
​关键点:
使用left_eye_height和right_eye_height动态调整眼睛的高度。
通过delay(1)控制眨眼的速度。

​3. 快速眼动函数

void saccade(int direction_x, int direction_y) {

    int direction_x_movement_amplitude = 8;// 定义X方向移动幅度

    int direction_y_movement_amplitude = 6;// 定义Y方向移动幅度

    int blink_amplitude = 8;                // 定义眨眼幅度

    for (int i = 0; i < 1; i++) {// 循环1次,模拟眼睛快速移动

      left_eye_x += direction_x_movement_amplitude * direction_x;// 左眼X坐标移动

      right_eye_x += direction_x_movement_amplitude * direction_x; // 右眼X坐标移动

      left_eye_y += direction_y_movement_amplitude * direction_y;// 左眼Y坐标移动

      right_eye_y += direction_y_movement_amplitude * direction_y; // 右眼Y坐标移动

      right_eye_height -= blink_amplitude;// 右眼高度减小

      left_eye_height -= blink_amplitude;   // 左眼高度减小

      draw_eyes();// 绘制眼睛

      delay(1);   // 延迟1毫秒

    }

    for (int i = 0; i < 1; i++) {// 循环1次,恢复眼睛状态

      left_eye_x += direction_x_movement_amplitude * direction_x;// 左眼X坐标移动

      right_eye_x += direction_x_movement_amplitude * direction_x; // 右眼X坐标移动

      left_eye_y += direction_y_movement_amplitude * direction_y;// 左眼Y坐标移动

      right_eye_y += direction_y_movement_amplitude * direction_y; // 右眼Y坐标移动

      right_eye_height += blink_amplitude;// 右眼高度增加

      left_eye_height += blink_amplitude;   // 左眼高度增加

      draw_eyes();// 绘制眼睛

      delay(1);   // 延迟1毫秒

    }

}

​功能:模拟眼睛的快速移动(如扫视)。
​关键点:
使用direction_x和direction_y控制眼睛的移动方向。
在移动过程中伴随轻微的眨眼效果。


驴友花雕 发表于 2025-3-20 13:36:10

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

​4. 动画索引切换

void launch_animation_with_index(int animation_index) {

    if (animation_index > max_animation_index) {// 如果动画索引超过最大值

      animation_index = max_animation_index;    // 将动画索引设置为最大值

    }



    switch (animation_index) {// 根据动画索引选择动画

      case 0: wakeup();break;

      case 1: center_eyes(true);break;

      case 2: move_right_big_eye();break;

      case 3: move_left_big_eye();   break;

      case 4: blink(10);break;

      case 5: blink(20);break;

      case 6: happy_eye();break;

      case 7: sleep();break;

      case 8: center_eyes(true); for (int i = 0; i < 20; i++) { saccade(random(-1, 2), random(-1, 2)); delay(1); saccade(-random(-1, 2), -random(-1, 2)); delay(1); } break;

    }

}
​功能:根据动画索引播放对应的动画。
​扩展性:
可以通过增加case分支添加更多动画效果。
使用random函数实现随机快速眼动。

​5. 串口与交互

i
f (Serial.available()) {// 如果串口有数据

    String data = Serial.readString();// 读取串口数据

    data.trim();// 去除数据前后空格

    char cmd = data;// 获取命令字符

    if (cmd == 'A') {// 如果命令为'A'

      demo_mode = 0;// 关闭演示模式

      String arg = data.substring(1, data.length());// 获取参数

      int anim = arg.toInt();// 将参数转换为整数

      launch_animation_with_index(anim);// 播放指定动画

      Serial.print(cmd);// 发送命令字符

      Serial.print(arg);// 发送参数

    }

}
​功能:通过串口接收命令,动态选择动画。
​命令格式:A<动画索引>,例如A2播放右眼放大动画。

四、​扩展建议
1、​增加更多动画效果
添加更多表情,如惊讶、生气、流泪等。
使用display.drawCircle绘制瞳孔,并实现瞳孔的动态跟随。

2、​优化动画性能
减少delay的使用,改用millis()实现非阻塞动画。
使用双缓冲技术(如果支持)提高动画流畅度。

3、​增强交互功能
添加触摸屏支持,允许用户通过触摸选择动画。
结合传感器(如加速度计)实现基于动作的眼睛反应。

4、​多眼睛互动
增加更多眼睛,模拟群体眼睛的互动效果。
实现眼睛之间的同步或随机运动。

​总结
这段代码实现了一个功能丰富的OLED眼睛动画项目,适合用于嵌入式设备的趣味展示或交互设计。通过串口命令和动画索引的结合,用户可以灵活控制动画效果。未来可以通过增加更多动画、优化性能和增强交互功能进一步提升项目的趣味性和实用性。

驴友花雕 发表于 2025-3-20 13:58:47

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

基本的演示模式,实验场景图动态图



驴友花雕 发表于 2025-3-20 14:00:11

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力




驴友花雕 发表于 2025-3-20 14:23:56

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

实验记录视频(33秒)

【【花雕动手做】基于 Arduino 的机器人 OLED 眼睛动画:呈现多样情绪,增强交互魅力】


https://www.bilibili.com/video/BV1SYXAYaEnQ/?share_source=copy_web&vd_source=371a292a55e5ca9be994cbb4a86cc987


https://www.bilibili.com/video/BV1SYXAYaEnQ/?share_source=copy_web&vd_source=371a292a55e5ca9be994cbb4a86cc987


驴友花雕 发表于 2025-3-20 15:45:54

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

通过串口输入A1-A8,可以指定动画眼睛的模式



驴友花雕 发表于 2025-3-20 15:49:26

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力

​眼睛动画
提供了多种眼睛动画效果,包括:
​唤醒(wakeup)​:眼睛从极小的状态逐渐放大到正常大小。
​居中(center_eyes)​:将眼睛重置到屏幕中央。
​眨眼(blink)​:模拟眼睛快速闭合和睁开。
​开心(happy_eye)​:在眼睛下方绘制倒三角形,模拟开心的表情。
​睡眠(sleep)​:眼睛缩小到极小的状态。
​大眼睛移动(move_big_eye)​:眼睛放大并随机移动。
​快速眼动(saccade)​:眼睛快速移动并伴随轻微的眨眼效果。
动画通过调整眼睛的宽度、高度、位置和形状实现。



驴友花雕 发表于 2025-3-20 15:50:43

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力




驴友花雕 发表于 2025-3-23 07:53:34

【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力


页: [1]
查看完整版本: 【花雕动手做】OLED 眼睛:呈现多样情绪,增强交互魅力