回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

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

头像 驴友花雕 2025.03.20 16 0

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屏幕上的显示效果,检查动画是否流畅、颜色是否正确、位置是否准确等。如果发现问题,要及时分析原因并进行修改,直到达到预期的效果。

01-.jpg

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

00-0.jpg

【花雕动手做】基于 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[0];  // 获取命令字符
        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);  // 发送参数
        }
    }
}

这段代码实现了一个基于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),按顺序循环播放所有动画。
用户可以通过串口命令关闭演示模式并手动选择动画。

二、​关键代码段分析
​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控制眼睛的移动方向。
在移动过程中伴随轻微的眨眼效果。

​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. 串口交互

if (Serial.available()) { // 如果串口有数据
String data = Serial.readString(); // 读取串口数据
data.trim(); // 去除数据前后空格
char cmd = data[0]; // 获取命令字符
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眼睛动画项目,适合用于嵌入式设备的趣味展示或交互设计。通过串口命令和动画索引的结合,用户可以灵活控制动画效果。未来可以通过增加更多动画、优化性能和增强交互功能进一步提升项目的趣味性和实用性。

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

00071.gif

00 (1).jpg
00 (2).jpg

实验记录视频(33秒)

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


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

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

 

01.jpg

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

 

03 (1).jpg
03 (2).jpg
03 (3).jpg

评论

user-avatar
icon 他的勋章
    展开更多